@cedros/login-react 0.0.19 → 0.0.20

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/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const I=require("./useAuth-X6Ds6WW4.cjs"),T=require("./useCedrosLogin-C9MrcZvh.cjs"),e=require("react/jsx-runtime"),l=require("react"),V=require("./LoadingSpinner-d6sSxgQN.cjs"),Ds=require("./sanitization-Bo_tn-L2.cjs"),K=require("./EmailRegisterForm-CdTuvJmf.cjs"),Pe=require("./validation-BuGQrA-K.cjs"),G=require("./ErrorMessage-CHbYbVi2.cjs"),Is=require("./GoogleLoginButton-D7CoMXLq.cjs"),xe=require("./mobileWalletAdapter-DOdmFAk0.cjs"),te=require("./PermissionsSection-BPbE-hNx.cjs"),_t=require("./useSystemSettings-DRrreszl.cjs"),ve=require("./AutosaveStatus-BjLMt52a.cjs"),Fs=require("./useOrgs-DDVRCaVi.cjs"),qe=require("./AdminDepositList-b2AXtLg0.cjs"),fe=require("./AdminWithdrawalHistory-DL9zbu2b.cjs"),Le=require("./useUsersStatsSummary-8qY7iP4G.cjs"),Ot=require("./StatsBar-DTUZCwDD.cjs"),ge=require("./plugin-BgMAc6DA.cjs"),qt=require("./AuthenticationSettings-Cu0S0Z7s.cjs"),zt=require("./EmbeddedWalletSettings-C7H0E8Uz.cjs"),_e=require("./EmailSettings-Dq3mfUr2.cjs"),Us=require("./CreditSystemSettings-DO-dUcxN.cjs"),Vt=require("./ServerSettings-CqDd59iM.cjs"),ie=require("./shamir-CiBczzDN.cjs"),Qr=require("./useAdminDeposits-BkkCwHWp.cjs"),Ws=require("./WebhookSettings-WMJ5zPjY.cjs");function ze(s){return s instanceof Uint8Array||ArrayBuffer.isView(s)&&s.constructor.name==="Uint8Array"}function Ht(s,t){return Array.isArray(t)?t.length===0?!0:s?t.every(o=>typeof o=="string"):t.every(o=>Number.isSafeInteger(o)):!1}function Kr(s){if(typeof s!="function")throw new Error("function expected");return!0}function Ve(s,t){if(typeof t!="string")throw new Error(`${s}: string expected`);return!0}function Ne(s){if(!Number.isSafeInteger(s))throw new Error(`invalid integer: ${s}`)}function He(s){if(!Array.isArray(s))throw new Error("array expected")}function Qe(s,t){if(!Ht(!0,t))throw new Error(`${s}: array of strings expected`)}function Qt(s,t){if(!Ht(!1,t))throw new Error(`${s}: array of numbers expected`)}function Yr(...s){const t=n=>n,o=(n,c)=>i=>n(c(i)),a=s.map(n=>n.encode).reduceRight(o,t),r=s.map(n=>n.decode).reduce(o,t);return{encode:a,decode:r}}function Gr(s){const t=typeof s=="string"?s.split(""):s,o=t.length;Qe("alphabet",t);const a=new Map(t.map((r,n)=>[r,n]));return{encode:r=>(He(r),r.map(n=>{if(!Number.isSafeInteger(n)||n<0||n>=o)throw new Error(`alphabet.encode: digit index outside alphabet "${n}". Allowed: ${s}`);return t[n]})),decode:r=>(He(r),r.map(n=>{Ve("alphabet.decode",n);const c=a.get(n);if(c===void 0)throw new Error(`Unknown letter: "${n}". Allowed: ${s}`);return c}))}}function $r(s=""){return Ve("join",s),{encode:t=>(Qe("join.decode",t),t.join(s)),decode:t=>(Ve("join.decode",t),t.split(s))}}function Jr(s,t="="){return Ne(s),Ve("padding",t),{encode(o){for(Qe("padding.encode",o);o.length*s%8;)o.push(t);return o},decode(o){Qe("padding.decode",o);let a=o.length;if(a*s%8)throw new Error("padding: invalid, string should have whole number of bytes");for(;a>0&&o[a-1]===t;a--)if((a-1)*s%8===0)throw new Error("padding: invalid, string has too much padding");return o.slice(0,a)}}}function Ts(s,t,o){if(t<2)throw new Error(`convertRadix: invalid from=${t}, base cannot be less than 2`);if(o<2)throw new Error(`convertRadix: invalid to=${o}, base cannot be less than 2`);if(He(s),!s.length)return[];let a=0;const r=[],n=Array.from(s,i=>{if(Ne(i),i<0||i>=t)throw new Error(`invalid integer: ${i}`);return i}),c=n.length;for(;;){let i=0,d=!0;for(let u=a;u<c;u++){const h=n[u],f=t*i,m=f+h;if(!Number.isSafeInteger(m)||f/t!==i||m-h!==f)throw new Error("convertRadix: carry overflow");const w=m/o;i=m%o;const g=Math.floor(w);if(n[u]=g,!Number.isSafeInteger(g)||g*o+i!==m)throw new Error("convertRadix: carry overflow");if(d)g?d=!1:a=u;else continue}if(r.push(i),d)break}for(let i=0;i<s.length-1&&s[i]===0;i++)r.push(0);return r.reverse()}const Kt=(s,t)=>t===0?s:Kt(t,s%t),Ke=(s,t)=>s+(t-Kt(s,t)),ns=(()=>{let s=[];for(let t=0;t<40;t++)s.push(2**t);return s})();function Bs(s,t,o,a){if(He(s),t<=0||t>32)throw new Error(`convertRadix2: wrong from=${t}`);if(o<=0||o>32)throw new Error(`convertRadix2: wrong to=${o}`);if(Ke(t,o)>32)throw new Error(`convertRadix2: carry overflow from=${t} to=${o} carryBits=${Ke(t,o)}`);let r=0,n=0;const c=ns[t],i=ns[o]-1,d=[];for(const u of s){if(Ne(u),u>=c)throw new Error(`convertRadix2: invalid data word=${u} from=${t}`);if(r=r<<t|u,n+t>32)throw new Error(`convertRadix2: carry overflow pos=${n} from=${t}`);for(n+=t;n>=o;n-=o)d.push((r>>n-o&i)>>>0);const h=ns[n];if(h===void 0)throw new Error("invalid carry");r&=h-1}if(r=r<<o-n&i,!a&&n>=t)throw new Error("Excess padding");if(!a&&r>0)throw new Error(`Non-zero padding: ${r}`);return a&&n>0&&d.push(r>>>0),d}function Xr(s){Ne(s);const t=2**8;return{encode:o=>{if(!ze(o))throw new Error("radix.encode input should be Uint8Array");return Ts(Array.from(o),t,s)},decode:o=>(Qt("radix.decode",o),Uint8Array.from(Ts(o,s,t)))}}function Zr(s,t=!1){if(Ne(s),s<=0||s>32)throw new Error("radix2: bits should be in (0..32]");if(Ke(8,s)>32||Ke(s,8)>32)throw new Error("radix2: carry overflow");return{encode:o=>{if(!ze(o))throw new Error("radix2.encode input should be Uint8Array");return Bs(Array.from(o),8,s,!t)},decode:o=>(Qt("radix2.decode",o),Uint8Array.from(Bs(o,s,8,t)))}}function eo(s,t){return Ne(s),Kr(t),{encode(o){if(!ze(o))throw new Error("checksum.encode: input should be Uint8Array");const a=t(o).slice(0,s),r=new Uint8Array(o.length+s);return r.set(o),r.set(a,o.length),r},decode(o){if(!ze(o))throw new Error("checksum.decode: input should be Uint8Array");const a=o.slice(0,-s),r=o.slice(-s),n=t(a).slice(0,s);for(let c=0;c<s;c++)if(n[c]!==r[c])throw new Error("Invalid checksum");return a}}}const Ie={alphabet:Gr,chain:Yr,checksum:eo,convertRadix:Ts,convertRadix2:Bs,radix:Xr,radix2:Zr,join:$r,padding:Jr};const so=s=>s[0]==="あいこくしん";function to(s){if(typeof s!="string")throw new TypeError("invalid mnemonic type: "+typeof s);return s.normalize("NFKD")}function ro(s){const t=to(s),o=t.split(" ");if(![12,15,18,21,24].includes(o.length))throw new Error("Invalid mnemonic");return{nfkd:t,words:o}}function Yt(s){ie.abytes(s,16,20,24,28,32)}const oo=s=>{const t=8-s.length/4;return new Uint8Array([ie.sha256(s)[0]>>t<<t])};function Gt(s){if(!Array.isArray(s)||s.length!==2048||typeof s[0]!="string")throw new Error("Wordlist: expected array of 2048 strings");return s.forEach(t=>{if(typeof t!="string")throw new Error("wordlist: non-string element: "+t)}),Ie.chain(Ie.checksum(1,oo),Ie.radix2(11,!0),Ie.alphabet(s))}function _s(s,t){const{words:o}=ro(s),a=Gt(t).decode(o);return Yt(a),a}function $t(s,t){return Yt(s),Gt(t).encode(s).join(so(t)?" ":" ")}function Os(s,t){try{_s(s,t)}catch{return!1}return!0}const he=`abandon
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const I=require("./useAuth-X6Ds6WW4.cjs"),T=require("./useCedrosLogin-C9MrcZvh.cjs"),e=require("react/jsx-runtime"),l=require("react"),V=require("./LoadingSpinner-d6sSxgQN.cjs"),Ds=require("./sanitization-Bo_tn-L2.cjs"),K=require("./EmailRegisterForm-CdTuvJmf.cjs"),Pe=require("./validation-BuGQrA-K.cjs"),G=require("./ErrorMessage-CHbYbVi2.cjs"),Is=require("./GoogleLoginButton-D7CoMXLq.cjs"),xe=require("./mobileWalletAdapter-7TOM-TF8.cjs"),te=require("./PermissionsSection-BPbE-hNx.cjs"),_t=require("./useSystemSettings-DRrreszl.cjs"),ve=require("./AutosaveStatus-BjLMt52a.cjs"),Fs=require("./useOrgs-DDVRCaVi.cjs"),qe=require("./AdminDepositList-b2AXtLg0.cjs"),fe=require("./AdminWithdrawalHistory-DL9zbu2b.cjs"),Le=require("./useUsersStatsSummary-8qY7iP4G.cjs"),Ot=require("./StatsBar-DTUZCwDD.cjs"),ge=require("./plugin-BgMAc6DA.cjs"),qt=require("./AuthenticationSettings-Cu0S0Z7s.cjs"),zt=require("./EmbeddedWalletSettings-C7H0E8Uz.cjs"),_e=require("./EmailSettings-Dq3mfUr2.cjs"),Us=require("./CreditSystemSettings-DO-dUcxN.cjs"),Vt=require("./ServerSettings-CqDd59iM.cjs"),ie=require("./shamir-CiBczzDN.cjs"),Qr=require("./useAdminDeposits-BkkCwHWp.cjs"),Ws=require("./WebhookSettings-WMJ5zPjY.cjs");function ze(s){return s instanceof Uint8Array||ArrayBuffer.isView(s)&&s.constructor.name==="Uint8Array"}function Ht(s,t){return Array.isArray(t)?t.length===0?!0:s?t.every(o=>typeof o=="string"):t.every(o=>Number.isSafeInteger(o)):!1}function Kr(s){if(typeof s!="function")throw new Error("function expected");return!0}function Ve(s,t){if(typeof t!="string")throw new Error(`${s}: string expected`);return!0}function Ne(s){if(!Number.isSafeInteger(s))throw new Error(`invalid integer: ${s}`)}function He(s){if(!Array.isArray(s))throw new Error("array expected")}function Qe(s,t){if(!Ht(!0,t))throw new Error(`${s}: array of strings expected`)}function Qt(s,t){if(!Ht(!1,t))throw new Error(`${s}: array of numbers expected`)}function Yr(...s){const t=n=>n,o=(n,c)=>i=>n(c(i)),a=s.map(n=>n.encode).reduceRight(o,t),r=s.map(n=>n.decode).reduce(o,t);return{encode:a,decode:r}}function Gr(s){const t=typeof s=="string"?s.split(""):s,o=t.length;Qe("alphabet",t);const a=new Map(t.map((r,n)=>[r,n]));return{encode:r=>(He(r),r.map(n=>{if(!Number.isSafeInteger(n)||n<0||n>=o)throw new Error(`alphabet.encode: digit index outside alphabet "${n}". Allowed: ${s}`);return t[n]})),decode:r=>(He(r),r.map(n=>{Ve("alphabet.decode",n);const c=a.get(n);if(c===void 0)throw new Error(`Unknown letter: "${n}". Allowed: ${s}`);return c}))}}function $r(s=""){return Ve("join",s),{encode:t=>(Qe("join.decode",t),t.join(s)),decode:t=>(Ve("join.decode",t),t.split(s))}}function Jr(s,t="="){return Ne(s),Ve("padding",t),{encode(o){for(Qe("padding.encode",o);o.length*s%8;)o.push(t);return o},decode(o){Qe("padding.decode",o);let a=o.length;if(a*s%8)throw new Error("padding: invalid, string should have whole number of bytes");for(;a>0&&o[a-1]===t;a--)if((a-1)*s%8===0)throw new Error("padding: invalid, string has too much padding");return o.slice(0,a)}}}function Ts(s,t,o){if(t<2)throw new Error(`convertRadix: invalid from=${t}, base cannot be less than 2`);if(o<2)throw new Error(`convertRadix: invalid to=${o}, base cannot be less than 2`);if(He(s),!s.length)return[];let a=0;const r=[],n=Array.from(s,i=>{if(Ne(i),i<0||i>=t)throw new Error(`invalid integer: ${i}`);return i}),c=n.length;for(;;){let i=0,d=!0;for(let u=a;u<c;u++){const h=n[u],f=t*i,m=f+h;if(!Number.isSafeInteger(m)||f/t!==i||m-h!==f)throw new Error("convertRadix: carry overflow");const w=m/o;i=m%o;const g=Math.floor(w);if(n[u]=g,!Number.isSafeInteger(g)||g*o+i!==m)throw new Error("convertRadix: carry overflow");if(d)g?d=!1:a=u;else continue}if(r.push(i),d)break}for(let i=0;i<s.length-1&&s[i]===0;i++)r.push(0);return r.reverse()}const Kt=(s,t)=>t===0?s:Kt(t,s%t),Ke=(s,t)=>s+(t-Kt(s,t)),ns=(()=>{let s=[];for(let t=0;t<40;t++)s.push(2**t);return s})();function Bs(s,t,o,a){if(He(s),t<=0||t>32)throw new Error(`convertRadix2: wrong from=${t}`);if(o<=0||o>32)throw new Error(`convertRadix2: wrong to=${o}`);if(Ke(t,o)>32)throw new Error(`convertRadix2: carry overflow from=${t} to=${o} carryBits=${Ke(t,o)}`);let r=0,n=0;const c=ns[t],i=ns[o]-1,d=[];for(const u of s){if(Ne(u),u>=c)throw new Error(`convertRadix2: invalid data word=${u} from=${t}`);if(r=r<<t|u,n+t>32)throw new Error(`convertRadix2: carry overflow pos=${n} from=${t}`);for(n+=t;n>=o;n-=o)d.push((r>>n-o&i)>>>0);const h=ns[n];if(h===void 0)throw new Error("invalid carry");r&=h-1}if(r=r<<o-n&i,!a&&n>=t)throw new Error("Excess padding");if(!a&&r>0)throw new Error(`Non-zero padding: ${r}`);return a&&n>0&&d.push(r>>>0),d}function Xr(s){Ne(s);const t=2**8;return{encode:o=>{if(!ze(o))throw new Error("radix.encode input should be Uint8Array");return Ts(Array.from(o),t,s)},decode:o=>(Qt("radix.decode",o),Uint8Array.from(Ts(o,s,t)))}}function Zr(s,t=!1){if(Ne(s),s<=0||s>32)throw new Error("radix2: bits should be in (0..32]");if(Ke(8,s)>32||Ke(s,8)>32)throw new Error("radix2: carry overflow");return{encode:o=>{if(!ze(o))throw new Error("radix2.encode input should be Uint8Array");return Bs(Array.from(o),8,s,!t)},decode:o=>(Qt("radix2.decode",o),Uint8Array.from(Bs(o,s,8,t)))}}function eo(s,t){return Ne(s),Kr(t),{encode(o){if(!ze(o))throw new Error("checksum.encode: input should be Uint8Array");const a=t(o).slice(0,s),r=new Uint8Array(o.length+s);return r.set(o),r.set(a,o.length),r},decode(o){if(!ze(o))throw new Error("checksum.decode: input should be Uint8Array");const a=o.slice(0,-s),r=o.slice(-s),n=t(a).slice(0,s);for(let c=0;c<s;c++)if(n[c]!==r[c])throw new Error("Invalid checksum");return a}}}const Ie={alphabet:Gr,chain:Yr,checksum:eo,convertRadix:Ts,convertRadix2:Bs,radix:Xr,radix2:Zr,join:$r,padding:Jr};const so=s=>s[0]==="あいこくしん";function to(s){if(typeof s!="string")throw new TypeError("invalid mnemonic type: "+typeof s);return s.normalize("NFKD")}function ro(s){const t=to(s),o=t.split(" ");if(![12,15,18,21,24].includes(o.length))throw new Error("Invalid mnemonic");return{nfkd:t,words:o}}function Yt(s){ie.abytes(s,16,20,24,28,32)}const oo=s=>{const t=8-s.length/4;return new Uint8Array([ie.sha256(s)[0]>>t<<t])};function Gt(s){if(!Array.isArray(s)||s.length!==2048||typeof s[0]!="string")throw new Error("Wordlist: expected array of 2048 strings");return s.forEach(t=>{if(typeof t!="string")throw new Error("wordlist: non-string element: "+t)}),Ie.chain(Ie.checksum(1,oo),Ie.radix2(11,!0),Ie.alphabet(s))}function _s(s,t){const{words:o}=ro(s),a=Gt(t).decode(o);return Yt(a),a}function $t(s,t){return Yt(s),Gt(t).encode(s).join(so(t)?" ":" ")}function Os(s,t){try{_s(s,t)}catch{return!1}return!0}const he=`abandon
2
2
  ability
3
3
  able
4
4
  about
package/dist/index.js CHANGED
@@ -12,8 +12,8 @@ import { b as Ks, v as Ut } from "./validation-B8kMV3BL.js";
12
12
  import { E as ee } from "./ErrorMessage-CcEK0pYO.js";
13
13
  import { G as Gs } from "./GoogleLoginButton-B6qnNMZp.js";
14
14
  import { u as zc } from "./GoogleLoginButton-B6qnNMZp.js";
15
- import { d as Jt, S as $s } from "./mobileWalletAdapter-BulleEbi.js";
16
- import { r as Hc, u as Qc } from "./mobileWalletAdapter-BulleEbi.js";
15
+ import { d as Jt, S as $s } from "./mobileWalletAdapter-CtTXtZlH.js";
16
+ import { r as Hc, u as Qc } from "./mobileWalletAdapter-CtTXtZlH.js";
17
17
  import { c as Js, d as Xs, u as Zs, a as eo, M as to, I as ro, b as so, P as oo } from "./PermissionsSection-CighC1p6.js";
18
18
  import { u as no } from "./useSystemSettings-DBlAMjFi.js";
19
19
  import { C as ao, S as Qr, a as io, u as co, A as lo } from "./AutosaveStatus-BKc7T2Tw.js";
@@ -0,0 +1 @@
1
+ "use strict";const n=require("react/jsx-runtime"),o=require("react"),A=require("./useCedrosLogin-C9MrcZvh.cjs"),T=require("./validation-BuGQrA-K.cjs"),J=require("./LoadingSpinner-d6sSxgQN.cjs");function H(){const{config:e,_internal:t}=A.useCedrosLogin(),[l,s]=o.useState(!1),[N,u]=o.useState(null),p=o.useMemo(()=>new A.ApiClient({baseUrl:e.serverUrl,timeoutMs:e.requestTimeout,retryAttempts:e.retryAttempts}),[e.serverUrl,e.requestTimeout,e.retryAttempts]),r=o.useCallback(async g=>{if(!T.validateSolanaPublicKey(g)){const h={code:"INVALID_PUBLIC_KEY",message:"Invalid Solana public key format"};throw u(h),h}s(!0),u(null);try{return await p.post("/solana/challenge",{publicKey:g},{credentials:"omit"})}catch(h){const c=A.handleApiError(h,"Failed to get challenge");throw u(c),c}finally{s(!1)}},[p]),y=o.useCallback(async(g,h,c)=>{if(!T.validateSolanaPublicKey(g)){const i={code:"INVALID_PUBLIC_KEY",message:"Invalid Solana public key format"};throw u(i),i}s(!0),u(null);try{const i=await p.post("/solana",{publicKey:g,signature:h,message:c});return e.callbacks?.onLoginSuccess?.(i.user,"solana"),t?.handleLoginSuccess(i.user,i.tokens),i}catch(i){const d=A.handleApiError(i,"Solana sign-in failed");throw u(d),d}finally{s(!1)}},[p,e.callbacks,t]),S=o.useCallback(()=>u(null),[]);return{requestChallenge:r,signIn:y,isLoading:l,error:N,clearError:S}}const K=["phantom","solflare","backpack","glow","slope","sollet","coin98","clover","mathWallet","ledger","torus","walletconnect"];function M(e){if(!e||typeof e!="object")return!1;const t=e;return typeof t.connect=="function"||typeof t.signMessage=="function"||typeof t.signTransaction=="function"||"isConnected"in t}function Q(){try{const e=window.__wallet_standard__;if(e&&typeof e=="object"&&"get"in e&&typeof e.get=="function"){const t=e.get();return Array.isArray(t)&&t.length>0}}catch{}return!1}function X(){if(typeof window>"u")return!1;const e=window;for(const t of K){const l=e[t];if(l&&typeof l=="object"&&"solana"in l&&M(l.solana))return!0}return!!(M(e.solana)||Q())}const q={phantom:"Phantom",solflare:"Solflare",backpack:"Backpack",glow:"Glow",slope:"Slope",sollet:"Sollet",coin98:"Coin98",clover:"Clover",mathWallet:"MathWallet",ledger:"Ledger",torus:"Torus",walletconnect:"WalletConnect",solana:"Solana Wallet"},U="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 24 24' fill='none' stroke='%236366f1' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 12V7H5a2 2 0 0 1 0-4h14v4'/%3E%3Cpath d='M3 5v14a2 2 0 0 0 2 2h16v-5'/%3E%3Cpath d='M18 12a2 2 0 0 0 0 4h4v-4Z'/%3E%3C/svg%3E",ee={phantom:"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 128 128'%3E%3Crect width='128' height='128' rx='26' fill='%23AB9FF2'/%3E%3Cpath d='M110.5 64.2c-.3-3-3-5.2-6-4.8-13.6 1.6-25 7.1-33.5 15.9-5.3 5.4-9 11.7-11.3 18.5-1.1 3.3.7 6.9 4.1 7.9 3.3 1.1 6.9-.7 7.9-4.1 1.7-5.1 4.5-9.7 8.3-13.6 6.4-6.6 15-10.7 25.5-12 3-.3 5.2-3 4.8-6l.2-1.8zM110.2 43.8c-.3-3-3-5.2-6-4.8-25.2 3-44.1 18-53.5 39.2-1.3 2.9.1 6.3 3.1 7.6s6.3-.1 7.6-3.1c7.9-17.9 23.8-30.5 45.8-33.1 3-.3 5.2-3 4.8-6l-1.8-1.8zM44.8 44.5c2.9-1.5 4.1-5.1 2.5-8-1.5-2.9-5.1-4.1-8-2.5C24.4 42.1 16 57.9 16 75.8c0 3.3 2.7 6 6 6s6-2.7 6-6c0-14 6.5-26.3 16.8-31.3z' fill='%23FFFDF8'/%3E%3C/svg%3E",solflare:"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 128 128'%3E%3Crect width='128' height='128' rx='26' fill='%23FC7227'/%3E%3Cpath d='M64 28l28 36-28 36-28-36z' fill='%23fff'/%3E%3C/svg%3E",backpack:"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 128 128'%3E%3Crect width='128' height='128' rx='26' fill='%23E33E3F'/%3E%3Cpath d='M48 42h32v8H48zM40 54h48v36H40z' fill='%23fff'/%3E%3C/svg%3E"};function te(){if(typeof window>"u")return[];const e=window,t=[];for(const l of K){const s=e[l];s&&typeof s=="object"&&"solana"in s&&M(s.solana)&&t.push({key:l,name:q[l]??l,icon:ee[l]??U,provider:s.solana})}return t.length===0&&M(e.solana)&&t.push({key:"solana",name:q.solana,icon:U,provider:e.solana}),t}function ae(e){if(e instanceof Uint8Array)return e;if(e&&typeof e=="object"&&"signature"in e&&e.signature instanceof Uint8Array)return e.signature;throw new Error("Wallet returned invalid signature format")}function ne({onSuccess:e,onError:t,className:l="",variant:s="default",size:N="md",disabled:u=!1,hideIfNoWallet:p=!0,walletContext:r}){const{requestChallenge:y,signIn:S,isLoading:g}=H(),[h,c]=o.useState(!1),[i,d]=o.useState(!1),[_,j]=o.useState(!1),m=o.useRef(!1),[k]=o.useState(()=>r?[]:te()),v=r?.connected??!1,W=r?.connecting??!1,C=r?.publicKey,b=r?.signMessage,B=r?.wallet,L=(r?.wallets??[]).filter(a=>a.adapter.readyState==="Installed"||a.adapter.readyState==="Loadable"),R=r?L.length>0:k.length>0,I=o.useCallback(async()=>{if(!m.current){if(!C||!b){t?.(new Error("Wallet not ready"));return}m.current=!0;try{const a=C.toBase58(),f=await y(a),w=new TextEncoder().encode(f.message),E=await b(w);if(!(E instanceof Uint8Array)||E.length===0)throw new Error("Wallet returned invalid signature");let x;try{x=btoa(String.fromCharCode(...E))}catch{throw new Error("Failed to encode signature")}await S(a,x,f.message),e?.()}catch(a){const f=a instanceof Error?a:new Error(String(a));t?.(f)}finally{m.current=!1,d(!1)}}},[C,b,y,S,e,t]),z=o.useCallback(async a=>{if(!m.current){m.current=!0,d(!0);try{const w=(await a.provider.connect()).publicKey.toBase58(),E=await y(w),x=new TextEncoder().encode(E.message),Z=await a.provider.signMessage(x),P=ae(Z);if(P.length===0)throw new Error("Wallet returned empty signature");let D;try{D=btoa(String.fromCharCode(...P))}catch{throw new Error("Failed to encode signature")}await S(w,D,E.message),e?.()}catch(f){const w=f instanceof Error?f:new Error(String(f));w.message.includes("User rejected")||w.message.includes("user reject")?t?.(new Error("Wallet action was cancelled")):t?.(w)}finally{m.current=!1,d(!1)}}},[y,S,e,t]);if(o.useEffect(()=>{_&&B&&!v&&!W&&r?.connect&&(j(!1),r.connect().catch(a=>{t?.(a instanceof Error?a:new Error(String(a))),d(!1)}))},[_,B,v,W,r,t]),o.useEffect(()=>{i&&v&&C&&b&&!m.current&&I().catch(()=>{})},[i,v,C,b,I]),p&&!R)return null;const O=async()=>{u||g||W||(r?v&&C&&b?(d(!0),await I()):B?(d(!0),j(!0)):L.length===1?(r.select(L[0].adapter.name),d(!0),j(!0)):L.length>1?c(!0):t?.(new Error("No Solana wallet found. Please install Phantom or another Solana wallet.")):k.length===1?await z(k[0]):k.length>1?c(!0):t?.(new Error("No Solana wallet found. Please install Phantom or another Solana wallet.")))},V=a=>{c(!1),r?.select(a),d(!0),j(!0)},Y=a=>{c(!1),z(a).catch(()=>{})},$={sm:"cedros-button-sm",md:"cedros-button-md",lg:"cedros-button-lg"},G={default:"cedros-button-social",outline:"cedros-button-social-outline"},F=g||W||i&&!v;return n.jsxs(n.Fragment,{children:[n.jsxs("button",{type:"button",className:`cedros-button ${G[s]} ${$[N]} ${l}`,onClick:O,disabled:u||F,"aria-label":"Continue with Solana",children:[F?n.jsx(J.LoadingSpinner,{size:"sm"}):n.jsxs("svg",{className:"cedros-button-icon",width:"18",height:"18",viewBox:"0 0 128 128",fill:"currentColor","aria-hidden":"true",children:[n.jsx("path",{d:"M25.38 96.04a4.35 4.35 0 0 1 3.07-1.27h91.68c1.93 0 2.9 2.34 1.54 3.7l-17.71 17.72a4.35 4.35 0 0 1-3.07 1.27H9.21c-1.93 0-2.9-2.34-1.54-3.7l17.71-17.72z"}),n.jsx("path",{d:"M25.38 11.81a4.47 4.47 0 0 1 3.07-1.27h91.68c1.93 0 2.9 2.34 1.54 3.7L103.96 31.96a4.35 4.35 0 0 1-3.07 1.27H9.21c-1.93 0-2.9-2.34-1.54-3.7L25.38 11.81z"}),n.jsx("path",{d:"M102.62 53.76a4.35 4.35 0 0 0-3.07-1.27H7.87c-1.93 0-2.9 2.34-1.54 3.7l17.71 17.72a4.35 4.35 0 0 0 3.07 1.27h91.68c1.93 0 2.9-2.34 1.54-3.7L102.62 53.76z"})]}),n.jsx("span",{children:"Continue with Solana"})]}),h&&n.jsx("div",{className:"cedros-modal-backdrop",onClick:()=>c(!1),role:"presentation",children:n.jsxs("div",{className:"cedros-modal cedros-wallet-selector",role:"dialog","aria-modal":"true","aria-labelledby":"wallet-selector-title",onClick:a=>a.stopPropagation(),children:[n.jsxs("div",{className:"cedros-modal-header",children:[n.jsx("h2",{id:"wallet-selector-title",className:"cedros-modal-title",children:"Select Wallet"}),n.jsx("button",{type:"button",className:"cedros-modal-close",onClick:()=>c(!1),"aria-label":"Close",children:n.jsx("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none","aria-hidden":"true",children:n.jsx("path",{d:"M18 6L6 18M6 6l12 12",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round"})})})]}),n.jsx("div",{className:"cedros-modal-content",children:n.jsx("div",{className:"cedros-wallet-list",children:r?L.map(a=>n.jsxs("button",{type:"button",className:"cedros-wallet-option",onClick:()=>V(a.adapter.name),children:[n.jsx("img",{src:a.adapter.icon,alt:"",width:"32",height:"32",className:"cedros-wallet-icon"}),n.jsx("span",{children:a.adapter.name})]},a.adapter.name)):k.map(a=>n.jsxs("button",{type:"button",className:"cedros-wallet-option",onClick:()=>Y(a),children:[n.jsx("img",{src:a.icon,alt:"",width:"32",height:"32",className:"cedros-wallet-icon"}),n.jsx("span",{children:a.name})]},a.key))})})]})})]})}function se(e){if(typeof window>"u")return!1;try{const t=require("@solana-mobile/wallet-standard-mobile"),l=e?.chains??["solana:mainnet"],s={appIdentity:{name:e?.name,uri:e?.uri,icon:e?.icon},chains:l};return typeof t.createDefaultAuthorizationCache=="function"&&(s.authorizationCache=t.createDefaultAuthorizationCache()),typeof t.createDefaultChainSelector=="function"&&(s.chainSelector=t.createDefaultChainSelector()),typeof t.createDefaultWalletNotFoundHandler=="function"&&(s.onWalletNotFound=t.createDefaultWalletNotFoundHandler()),t.registerMwa(s),!0}catch{return!1}}exports.SolanaLoginButton=ne;exports.detectSolanaWallets=X;exports.registerMobileWallet=se;exports.useSolanaAuth=H;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mobileWalletAdapter-7TOM-TF8.cjs","sources":["../src/hooks/useSolanaAuth.ts","../src/utils/walletDetection.ts","../src/utils/browserWalletAdapter.ts","../src/components/solana/SolanaLoginButton.tsx","../src/utils/mobileWalletAdapter.ts"],"sourcesContent":["import { useState, useCallback, useMemo } from 'react';\nimport { useCedrosLogin } from '../context/useCedrosLogin';\nimport { ApiClient, handleApiError } from '../utils/apiClient';\nimport { validateSolanaPublicKey } from '../utils/validation';\nimport type { AuthResponse, AuthError, ChallengeResponse } from '../types';\n\nexport interface UseSolanaAuthReturn {\n requestChallenge: (publicKey: string) => Promise<ChallengeResponse>;\n signIn: (publicKey: string, signature: string, message: string) => Promise<AuthResponse>;\n isLoading: boolean;\n error: AuthError | null;\n clearError: () => void;\n}\n\n/**\n * Hook for Solana wallet authentication.\n *\n * @example\n * ```tsx\n * function SolanaLogin() {\n * const { requestChallenge, signIn, isLoading } = useSolanaAuth();\n * const { publicKey, signMessage } = useWallet();\n *\n * const handleLogin = async () => {\n * const challenge = await requestChallenge(publicKey.toBase58());\n * const signature = await signMessage(new TextEncoder().encode(challenge.message));\n * const result = await signIn(\n * publicKey.toBase58(),\n * Buffer.from(signature).toString('base64'),\n * challenge.message\n * );\n * };\n * }\n * ```\n */\nexport function useSolanaAuth(): UseSolanaAuthReturn {\n const { config, _internal } = useCedrosLogin();\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<AuthError | null>(null);\n\n const apiClient = useMemo(\n () =>\n new ApiClient({\n baseUrl: config.serverUrl,\n timeoutMs: config.requestTimeout,\n retryAttempts: config.retryAttempts,\n }),\n [config.serverUrl, config.requestTimeout, config.retryAttempts]\n );\n\n const requestChallenge = useCallback(\n async (publicKey: string): Promise<ChallengeResponse> => {\n // Validate public key format before making API call\n if (!validateSolanaPublicKey(publicKey)) {\n const authError: AuthError = {\n code: 'INVALID_PUBLIC_KEY',\n message: 'Invalid Solana public key format',\n };\n setError(authError);\n throw authError;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const data = await apiClient.post<ChallengeResponse>(\n '/solana/challenge',\n { publicKey },\n { credentials: 'omit' }\n );\n return data;\n } catch (err) {\n const authError = handleApiError(err, 'Failed to get challenge');\n setError(authError);\n throw authError;\n } finally {\n setIsLoading(false);\n }\n },\n [apiClient]\n );\n\n const signIn = useCallback(\n async (publicKey: string, signature: string, message: string): Promise<AuthResponse> => {\n // Validate public key format before making API call\n if (!validateSolanaPublicKey(publicKey)) {\n const authError: AuthError = {\n code: 'INVALID_PUBLIC_KEY',\n message: 'Invalid Solana public key format',\n };\n setError(authError);\n throw authError;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const data = await apiClient.post<AuthResponse>('/solana', {\n publicKey,\n signature,\n message,\n });\n config.callbacks?.onLoginSuccess?.(data.user, 'solana');\n _internal?.handleLoginSuccess(data.user, data.tokens);\n return data;\n } catch (err) {\n const authError = handleApiError(err, 'Solana sign-in failed');\n setError(authError);\n throw authError;\n } finally {\n setIsLoading(false);\n }\n },\n [apiClient, config.callbacks, _internal]\n );\n\n const clearError = useCallback(() => setError(null), []);\n\n return {\n requestChallenge,\n signIn,\n isLoading,\n error,\n clearError,\n };\n}\n","/**\n * Wallet detection utilities for Solana browser wallets\n */\n\n/**\n * Type for window with potential Solana wallet extensions\n */\nexport interface WindowWithWallets extends Window {\n phantom?: { solana?: unknown };\n solflare?: { solana?: unknown };\n backpack?: { solana?: unknown };\n glow?: { solana?: unknown };\n slope?: { solana?: unknown };\n sollet?: { solana?: unknown };\n coin98?: { solana?: unknown };\n clover?: { solana?: unknown };\n mathWallet?: { solana?: unknown };\n ledger?: { solana?: unknown };\n torus?: { solana?: unknown };\n walletconnect?: { solana?: unknown };\n solana?: unknown;\n}\n\n/**\n * Known Solana wallet provider names to check for on the window object\n */\ntype WalletProviderName = Exclude<keyof WindowWithWallets, keyof Window>;\n\nexport const WALLET_PROVIDERS: WalletProviderName[] = [\n 'phantom',\n 'solflare',\n 'backpack',\n 'glow',\n 'slope',\n 'sollet',\n 'coin98',\n 'clover',\n 'mathWallet',\n 'ledger',\n 'torus',\n 'walletconnect',\n];\n\n/**\n * UI-9 FIX: Validates that a wallet provider object has expected Solana wallet methods.\n * Prevents spoofed wallet objects from being accepted.\n */\nexport function isValidSolanaProvider(provider: unknown): boolean {\n if (!provider || typeof provider !== 'object') return false;\n const wallet = provider as Record<string, unknown>;\n // Check for at least one expected wallet method/property\n // Real wallets have connect, signMessage, signTransaction, etc.\n return (\n typeof wallet.connect === 'function' ||\n typeof wallet.signMessage === 'function' ||\n typeof wallet.signTransaction === 'function' ||\n 'isConnected' in wallet\n );\n}\n\n/**\n * Check for wallets registered via the Wallet Standard protocol.\n * MWA (via @solana-mobile/wallet-standard-mobile) registers this way.\n */\nfunction hasWalletStandardWallets(): boolean {\n try {\n // The wallet-standard protocol exposes registered wallets via a global\n const walletStandard = (window as unknown as Record<string, unknown>)['__wallet_standard__'];\n if (\n walletStandard &&\n typeof walletStandard === 'object' &&\n 'get' in walletStandard &&\n typeof (walletStandard as Record<string, unknown>).get === 'function'\n ) {\n const wallets = (walletStandard as { get: () => unknown[] }).get();\n return Array.isArray(wallets) && wallets.length > 0;\n }\n } catch {\n // Not available\n }\n return false;\n}\n\n/**\n * Detects if any Solana wallet extensions are installed in the browser.\n * Checks for common wallet adapters like Phantom, Solflare, Backpack, etc.\n *\n * @returns true if at least one Solana wallet is detected\n *\n * @example\n * ```tsx\n * if (detectSolanaWallets()) {\n * // Show Solana login button\n * }\n * ```\n */\nexport function detectSolanaWallets(): boolean {\n if (typeof window === 'undefined') {\n return false;\n }\n\n const win = window as WindowWithWallets;\n\n // Check window object for wallet injections\n // UI-9: Validate wallet has expected methods to reject spoofed providers\n for (const provider of WALLET_PROVIDERS) {\n const walletObj = win[provider];\n if (\n walletObj &&\n typeof walletObj === 'object' &&\n 'solana' in walletObj &&\n isValidSolanaProvider(walletObj.solana)\n ) {\n return true;\n }\n }\n\n // Check for generic Solana provider (e.g., from some mobile wallet browsers)\n // UI-9: Also validate generic provider\n if (isValidSolanaProvider(win.solana)) {\n return true;\n }\n\n // Check for wallet-standard registered wallets (e.g., MWA via registerMwa())\n if (hasWalletStandardWallets()) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Returns list of detected Solana wallet names (for debugging/display)\n *\n * @returns Array of detected wallet provider names\n */\nexport function getDetectedWalletNames(): string[] {\n if (typeof window === 'undefined') {\n return [];\n }\n\n const win = window as WindowWithWallets;\n const detected: string[] = [];\n\n // UI-9: Use validation to reject spoofed providers\n for (const provider of WALLET_PROVIDERS) {\n const walletObj = win[provider];\n if (\n walletObj &&\n typeof walletObj === 'object' &&\n 'solana' in walletObj &&\n isValidSolanaProvider(walletObj.solana)\n ) {\n detected.push(provider);\n }\n }\n\n if (isValidSolanaProvider(win.solana) && detected.length === 0) {\n detected.push('solana');\n }\n\n return detected;\n}\n","/**\n * Direct browser wallet adapter for Solana wallets.\n *\n * Enumerates detected browser wallet extensions and provides a normalized\n * interface for connect + sign, bypassing the need for @solana/wallet-adapter-react.\n */\nimport {\n isValidSolanaProvider,\n WALLET_PROVIDERS,\n type WindowWithWallets,\n} from './walletDetection';\n\n/** Raw Solana wallet provider interface (e.g. window.phantom.solana) */\nexport interface SolanaProvider {\n connect: () => Promise<{ publicKey: { toBase58: () => string } }>;\n signMessage: (message: Uint8Array) => Promise<Uint8Array | { signature: Uint8Array }>;\n disconnect?: () => Promise<void>;\n isConnected?: boolean;\n publicKey?: { toBase58: () => string } | null;\n}\n\n/** A detected browser wallet ready for interaction */\nexport interface BrowserWallet {\n /** Internal key matching WALLET_PROVIDERS or 'solana' for generic */\n key: string;\n /** Human-readable display name */\n name: string;\n /** Data URI icon for rendering */\n icon: string;\n /** The raw provider object */\n provider: SolanaProvider;\n}\n\nconst WALLET_DISPLAY_NAMES: Record<string, string> = {\n phantom: 'Phantom',\n solflare: 'Solflare',\n backpack: 'Backpack',\n glow: 'Glow',\n slope: 'Slope',\n sollet: 'Sollet',\n coin98: 'Coin98',\n clover: 'Clover',\n mathWallet: 'MathWallet',\n ledger: 'Ledger',\n torus: 'Torus',\n walletconnect: 'WalletConnect',\n solana: 'Solana Wallet',\n};\n\n// Generic wallet SVG icon (simple wallet outline) as data URI\nconst GENERIC_WALLET_ICON =\n \"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 24 24' fill='none' stroke='%236366f1' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 12V7H5a2 2 0 0 1 0-4h14v4'/%3E%3Cpath d='M3 5v14a2 2 0 0 0 2 2h16v-5'/%3E%3Cpath d='M18 12a2 2 0 0 0 0 4h4v-4Z'/%3E%3C/svg%3E\";\n\n// Well-known wallet icons (brand-colored SVGs)\nconst WALLET_ICONS: Record<string, string> = {\n phantom:\n \"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 128 128'%3E%3Crect width='128' height='128' rx='26' fill='%23AB9FF2'/%3E%3Cpath d='M110.5 64.2c-.3-3-3-5.2-6-4.8-13.6 1.6-25 7.1-33.5 15.9-5.3 5.4-9 11.7-11.3 18.5-1.1 3.3.7 6.9 4.1 7.9 3.3 1.1 6.9-.7 7.9-4.1 1.7-5.1 4.5-9.7 8.3-13.6 6.4-6.6 15-10.7 25.5-12 3-.3 5.2-3 4.8-6l.2-1.8zM110.2 43.8c-.3-3-3-5.2-6-4.8-25.2 3-44.1 18-53.5 39.2-1.3 2.9.1 6.3 3.1 7.6s6.3-.1 7.6-3.1c7.9-17.9 23.8-30.5 45.8-33.1 3-.3 5.2-3 4.8-6l-1.8-1.8zM44.8 44.5c2.9-1.5 4.1-5.1 2.5-8-1.5-2.9-5.1-4.1-8-2.5C24.4 42.1 16 57.9 16 75.8c0 3.3 2.7 6 6 6s6-2.7 6-6c0-14 6.5-26.3 16.8-31.3z' fill='%23FFFDF8'/%3E%3C/svg%3E\",\n solflare:\n \"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 128 128'%3E%3Crect width='128' height='128' rx='26' fill='%23FC7227'/%3E%3Cpath d='M64 28l28 36-28 36-28-36z' fill='%23fff'/%3E%3C/svg%3E\",\n backpack:\n \"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 128 128'%3E%3Crect width='128' height='128' rx='26' fill='%23E33E3F'/%3E%3Cpath d='M48 42h32v8H48zM40 54h48v36H40z' fill='%23fff'/%3E%3C/svg%3E\",\n};\n\n/**\n * Enumerate detected browser wallets with display info and provider references.\n *\n * @returns Array of BrowserWallet objects for each detected, valid wallet\n */\nexport function getBrowserWallets(): BrowserWallet[] {\n if (typeof window === 'undefined') return [];\n\n const win = window as WindowWithWallets;\n const wallets: BrowserWallet[] = [];\n\n for (const key of WALLET_PROVIDERS) {\n const walletObj = win[key];\n if (\n walletObj &&\n typeof walletObj === 'object' &&\n 'solana' in walletObj &&\n isValidSolanaProvider(walletObj.solana)\n ) {\n wallets.push({\n key,\n name: WALLET_DISPLAY_NAMES[key] ?? key,\n icon: WALLET_ICONS[key] ?? GENERIC_WALLET_ICON,\n provider: walletObj.solana as SolanaProvider,\n });\n }\n }\n\n // Check for generic Solana provider when no named wallets found\n if (wallets.length === 0 && isValidSolanaProvider(win.solana)) {\n wallets.push({\n key: 'solana',\n name: WALLET_DISPLAY_NAMES.solana ?? 'Solana Wallet',\n icon: GENERIC_WALLET_ICON,\n provider: win.solana as SolanaProvider,\n });\n }\n\n return wallets;\n}\n\n/**\n * Normalize wallet signMessage return value.\n *\n * Phantom returns `{ signature: Uint8Array }`, while Solflare/Backpack\n * return raw `Uint8Array`. This handles both formats.\n *\n * @throws Error if result is neither format\n */\nexport function normalizeSignature(result: Uint8Array | { signature: Uint8Array }): Uint8Array {\n if (result instanceof Uint8Array) return result;\n\n if (\n result &&\n typeof result === 'object' &&\n 'signature' in result &&\n result.signature instanceof Uint8Array\n ) {\n return result.signature;\n }\n\n throw new Error('Wallet returned invalid signature format');\n}\n","import { useState, useEffect, useCallback, useRef } from 'react';\nimport { useSolanaAuth } from '../../hooks/useSolanaAuth';\nimport { LoadingSpinner } from '../shared/LoadingSpinner';\nimport {\n getBrowserWallets,\n normalizeSignature,\n type BrowserWallet,\n} from '../../utils/browserWalletAdapter';\n\nexport interface SolanaLoginButtonProps {\n onSuccess?: () => void;\n onError?: (error: Error) => void;\n className?: string;\n variant?: 'default' | 'outline';\n size?: 'sm' | 'md' | 'lg';\n disabled?: boolean;\n /**\n * Hide the button if no Solana wallets are detected.\n * When true (default), button renders nothing if no wallets are installed.\n * When false, button always renders (useful for showing \"install wallet\" prompts).\n * @default true\n */\n hideIfNoWallet?: boolean;\n /**\n * Solana wallet adapter context. Pass this from @solana/wallet-adapter-react's useWallet().\n * The button will handle connection and signing automatically for a one-click experience.\n */\n walletContext?: {\n publicKey: { toBase58: () => string } | null;\n signMessage: ((message: Uint8Array) => Promise<Uint8Array>) | null;\n connected: boolean;\n connecting: boolean;\n connect: () => Promise<void>;\n wallet: { adapter: { name: string } } | null;\n select: (walletName: string) => void;\n wallets: Array<{\n adapter: {\n name: string;\n icon: string;\n readyState: string;\n };\n }>;\n };\n}\n\n/**\n * Solana wallet login button with one-click authentication.\n *\n * Handles wallet connection and message signing automatically.\n * If wallet is already connected, signs immediately.\n * If not connected, connects first then auto-signs.\n */\nexport function SolanaLoginButton({\n onSuccess,\n onError,\n className = '',\n variant = 'default',\n size = 'md',\n disabled = false,\n hideIfNoWallet = true,\n walletContext,\n}: SolanaLoginButtonProps) {\n const { requestChallenge, signIn, isLoading: isAuthLoading } = useSolanaAuth();\n const [showWalletSelector, setShowWalletSelector] = useState(false);\n const [pendingLogin, setPendingLogin] = useState(false);\n const [triggerConnect, setTriggerConnect] = useState(false);\n const isProcessingRef = useRef(false);\n\n // Detect wallets from browser (used when walletContext not provided)\n // Use lazy initializer to avoid re-detecting on every render\n const [browserWallets] = useState<BrowserWallet[]>(() =>\n walletContext ? [] : getBrowserWallets()\n );\n\n const connected = walletContext?.connected ?? false;\n const connecting = walletContext?.connecting ?? false;\n const publicKey = walletContext?.publicKey;\n const signMessage = walletContext?.signMessage;\n const wallet = walletContext?.wallet;\n const wallets = walletContext?.wallets ?? [];\n\n // Get installed/ready wallets from wallet adapter context\n const installedWallets = wallets.filter(\n (w) => w.adapter.readyState === 'Installed' || w.adapter.readyState === 'Loadable'\n );\n\n // Determine if any wallets are available\n // If walletContext is provided, use its wallet list; otherwise use browser detection\n const hasWallets = walletContext ? installedWallets.length > 0 : browserWallets.length > 0;\n\n // Execute the actual sign-in flow\n const executeSignIn = useCallback(async () => {\n if (isProcessingRef.current) return;\n if (!publicKey || !signMessage) {\n onError?.(new Error('Wallet not ready'));\n return;\n }\n\n isProcessingRef.current = true;\n try {\n const pubKeyString = publicKey.toBase58();\n\n // Request challenge from server\n const challenge = await requestChallenge(pubKeyString);\n\n // Sign the message with wallet\n const messageBytes = new TextEncoder().encode(challenge.message);\n const signatureBytes = await signMessage(messageBytes);\n\n // Validate signature\n if (!(signatureBytes instanceof Uint8Array) || signatureBytes.length === 0) {\n throw new Error('Wallet returned invalid signature');\n }\n\n // Encode signature\n let signature: string;\n try {\n signature = btoa(String.fromCharCode(...signatureBytes));\n } catch {\n throw new Error('Failed to encode signature');\n }\n\n // Authenticate with server\n await signIn(pubKeyString, signature, challenge.message);\n\n onSuccess?.();\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n onError?.(error);\n } finally {\n isProcessingRef.current = false;\n setPendingLogin(false);\n }\n }, [publicKey, signMessage, requestChallenge, signIn, onSuccess, onError]);\n\n // Direct browser wallet flow: connect, challenge, sign, authenticate\n const connectAndSignDirect = useCallback(\n async (browserWallet: BrowserWallet) => {\n if (isProcessingRef.current) return;\n isProcessingRef.current = true;\n setPendingLogin(true);\n\n try {\n // Connect to the wallet\n const result = await browserWallet.provider.connect();\n const pubKeyString = result.publicKey.toBase58();\n\n // Request challenge from server\n const challenge = await requestChallenge(pubKeyString);\n\n // Sign the message\n const messageBytes = new TextEncoder().encode(challenge.message);\n const rawSignature = await browserWallet.provider.signMessage(messageBytes);\n const signatureBytes = normalizeSignature(rawSignature);\n\n if (signatureBytes.length === 0) {\n throw new Error('Wallet returned empty signature');\n }\n\n // Encode signature to base64\n let signature: string;\n try {\n signature = btoa(String.fromCharCode(...signatureBytes));\n } catch {\n throw new Error('Failed to encode signature');\n }\n\n // Authenticate with server\n await signIn(pubKeyString, signature, challenge.message);\n onSuccess?.();\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n // Gracefully handle user rejection\n if (error.message.includes('User rejected') || error.message.includes('user reject')) {\n onError?.(new Error('Wallet action was cancelled'));\n } else {\n onError?.(error);\n }\n } finally {\n isProcessingRef.current = false;\n setPendingLogin(false);\n }\n },\n [requestChallenge, signIn, onSuccess, onError]\n );\n\n // Auto-connect when wallet is selected and triggerConnect is set\n useEffect(() => {\n if (triggerConnect && wallet && !connected && !connecting && walletContext?.connect) {\n setTriggerConnect(false);\n walletContext.connect().catch((err) => {\n onError?.(err instanceof Error ? err : new Error(String(err)));\n setPendingLogin(false);\n });\n }\n }, [triggerConnect, wallet, connected, connecting, walletContext, onError]);\n\n // Auto-execute sign-in when connected with pending login\n // COMP-04: Catch unhandled rejections from executeSignIn (defensive - errors already\n // handled internally, but .catch() prevents unhandledrejection events)\n useEffect(() => {\n if (pendingLogin && connected && publicKey && signMessage && !isProcessingRef.current) {\n executeSignIn().catch(() => {\n /* Errors already passed to onError callback inside executeSignIn */\n });\n }\n }, [pendingLogin, connected, publicKey, signMessage, executeSignIn]);\n\n // Hide button if no wallets detected and hideIfNoWallet is true\n // Note: This must come after all hooks to satisfy React rules of hooks\n if (hideIfNoWallet && !hasWallets) {\n return null;\n }\n\n const handleClick = async () => {\n if (disabled || isAuthLoading || connecting) return;\n\n if (walletContext) {\n // Wallet adapter mode (walletContext provided by host)\n if (connected && publicKey && signMessage) {\n setPendingLogin(true);\n await executeSignIn();\n } else if (wallet) {\n setPendingLogin(true);\n setTriggerConnect(true);\n } else if (installedWallets.length === 1) {\n walletContext.select(installedWallets[0].adapter.name);\n setPendingLogin(true);\n setTriggerConnect(true);\n } else if (installedWallets.length > 1) {\n setShowWalletSelector(true);\n } else {\n onError?.(\n new Error('No Solana wallet found. Please install Phantom or another Solana wallet.')\n );\n }\n } else {\n // Direct browser wallet mode (no walletContext)\n if (browserWallets.length === 1) {\n await connectAndSignDirect(browserWallets[0]);\n } else if (browserWallets.length > 1) {\n setShowWalletSelector(true);\n } else {\n onError?.(\n new Error('No Solana wallet found. Please install Phantom or another Solana wallet.')\n );\n }\n }\n };\n\n const handleSelectWallet = (walletName: string) => {\n setShowWalletSelector(false);\n walletContext?.select(walletName);\n setPendingLogin(true);\n setTriggerConnect(true);\n };\n\n const handleSelectBrowserWallet = (browserWallet: BrowserWallet) => {\n setShowWalletSelector(false);\n connectAndSignDirect(browserWallet).catch(() => {\n /* Errors already passed to onError callback inside connectAndSignDirect */\n });\n };\n\n const sizeClasses = {\n sm: 'cedros-button-sm',\n md: 'cedros-button-md',\n lg: 'cedros-button-lg',\n };\n\n const variantClasses = {\n default: 'cedros-button-social',\n outline: 'cedros-button-social-outline',\n };\n\n const isLoading = isAuthLoading || connecting || (pendingLogin && !connected);\n\n return (\n <>\n <button\n type=\"button\"\n className={`cedros-button ${variantClasses[variant]} ${sizeClasses[size]} ${className}`}\n onClick={handleClick}\n disabled={disabled || isLoading}\n aria-label=\"Continue with Solana\"\n >\n {isLoading ? (\n <LoadingSpinner size=\"sm\" />\n ) : (\n <svg\n className=\"cedros-button-icon\"\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 128 128\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path d=\"M25.38 96.04a4.35 4.35 0 0 1 3.07-1.27h91.68c1.93 0 2.9 2.34 1.54 3.7l-17.71 17.72a4.35 4.35 0 0 1-3.07 1.27H9.21c-1.93 0-2.9-2.34-1.54-3.7l17.71-17.72z\" />\n <path d=\"M25.38 11.81a4.47 4.47 0 0 1 3.07-1.27h91.68c1.93 0 2.9 2.34 1.54 3.7L103.96 31.96a4.35 4.35 0 0 1-3.07 1.27H9.21c-1.93 0-2.9-2.34-1.54-3.7L25.38 11.81z\" />\n <path d=\"M102.62 53.76a4.35 4.35 0 0 0-3.07-1.27H7.87c-1.93 0-2.9 2.34-1.54 3.7l17.71 17.72a4.35 4.35 0 0 0 3.07 1.27h91.68c1.93 0 2.9-2.34 1.54-3.7L102.62 53.76z\" />\n </svg>\n )}\n <span>Continue with Solana</span>\n </button>\n\n {/* Wallet Selector Modal */}\n {showWalletSelector && (\n <div\n className=\"cedros-modal-backdrop\"\n onClick={() => setShowWalletSelector(false)}\n role=\"presentation\"\n >\n <div\n className=\"cedros-modal cedros-wallet-selector\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"wallet-selector-title\"\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"cedros-modal-header\">\n <h2 id=\"wallet-selector-title\" className=\"cedros-modal-title\">\n Select Wallet\n </h2>\n <button\n type=\"button\"\n className=\"cedros-modal-close\"\n onClick={() => setShowWalletSelector(false)}\n aria-label=\"Close\"\n >\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M18 6L6 18M6 6l12 12\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n </button>\n </div>\n <div className=\"cedros-modal-content\">\n <div className=\"cedros-wallet-list\">\n {walletContext\n ? installedWallets.map((w) => (\n <button\n key={w.adapter.name}\n type=\"button\"\n className=\"cedros-wallet-option\"\n onClick={() => handleSelectWallet(w.adapter.name)}\n >\n <img\n src={w.adapter.icon}\n alt=\"\"\n width=\"32\"\n height=\"32\"\n className=\"cedros-wallet-icon\"\n />\n <span>{w.adapter.name}</span>\n </button>\n ))\n : browserWallets.map((bw) => (\n <button\n key={bw.key}\n type=\"button\"\n className=\"cedros-wallet-option\"\n onClick={() => handleSelectBrowserWallet(bw)}\n >\n <img\n src={bw.icon}\n alt=\"\"\n width=\"32\"\n height=\"32\"\n className=\"cedros-wallet-icon\"\n />\n <span>{bw.name}</span>\n </button>\n ))}\n </div>\n </div>\n </div>\n </div>\n )}\n </>\n );\n}\n","/**\n * Mobile Wallet Adapter (MWA) registration for web.\n *\n * On Android Chrome, MWA lets users authenticate with their installed Solana\n * wallet app (e.g., Phantom, Solflare) via Android Intents — no browser\n * extension needed.\n *\n * Once registered, MWA appears as a wallet option in the wallet adapter's\n * wallet list (alongside browser extension wallets). Users see it as\n * \"Use Installed Wallet\" in the wallet selector.\n *\n * Requires the optional peer dependency: @solana-mobile/wallet-standard-mobile\n *\n * @see https://docs.solanamobile.com/get-started/web/installation\n */\n\nexport interface MobileWalletConfig {\n /** App name shown in the wallet's authorization dialog */\n name?: string;\n /** App URI for identity verification */\n uri?: string;\n /** App icon path/URL shown in the wallet dialog */\n icon?: string;\n /** Solana cluster(s) to support. Default: ['solana:mainnet'] */\n chains?: string[];\n}\n\n/**\n * Register Mobile Wallet Adapter as a wallet-standard wallet.\n *\n * Call this once at your application root (before rendering). After registration,\n * MWA automatically appears as \"Use Installed Wallet\" for users browsing on\n * Android Chrome with a Solana wallet app installed.\n *\n * Must be called in a non-SSR context (browser only). For Next.js, call in a\n * Client Component with `'use client'`.\n *\n * @example\n * ```tsx\n * import { registerMobileWallet, CedrosLoginProvider } from '@cedros/login-react';\n *\n * // Register before provider mounts\n * registerMobileWallet({ name: 'My App', uri: 'https://myapp.com' });\n *\n * function App() {\n * return (\n * <CedrosLoginProvider config={{ serverUrl: '...' }}>\n * <LoginForm />\n * </CedrosLoginProvider>\n * );\n * }\n * ```\n *\n * @returns true if registration succeeded, false if package not installed or SSR\n */\nexport function registerMobileWallet(config?: MobileWalletConfig): boolean {\n if (typeof window === 'undefined') {\n return false;\n }\n\n try {\n // Dynamic import to avoid bundling the optional peer dep\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const mwa = require('@solana-mobile/wallet-standard-mobile');\n\n const chains = config?.chains ?? ['solana:mainnet'];\n\n const registrationConfig: Record<string, unknown> = {\n appIdentity: {\n name: config?.name,\n uri: config?.uri,\n icon: config?.icon,\n },\n chains,\n };\n\n // Use built-in defaults for optional config if available\n if (typeof mwa.createDefaultAuthorizationCache === 'function') {\n registrationConfig.authorizationCache = mwa.createDefaultAuthorizationCache();\n }\n if (typeof mwa.createDefaultChainSelector === 'function') {\n registrationConfig.chainSelector = mwa.createDefaultChainSelector();\n }\n if (typeof mwa.createDefaultWalletNotFoundHandler === 'function') {\n registrationConfig.onWalletNotFound = mwa.createDefaultWalletNotFoundHandler();\n }\n\n mwa.registerMwa(registrationConfig);\n return true;\n } catch {\n // @solana-mobile/wallet-standard-mobile not installed\n return false;\n }\n}\n"],"names":["useSolanaAuth","config","_internal","useCedrosLogin","isLoading","setIsLoading","useState","error","setError","apiClient","useMemo","ApiClient","requestChallenge","useCallback","publicKey","validateSolanaPublicKey","authError","err","handleApiError","signIn","signature","message","data","clearError","WALLET_PROVIDERS","isValidSolanaProvider","provider","wallet","hasWalletStandardWallets","walletStandard","wallets","detectSolanaWallets","win","walletObj","WALLET_DISPLAY_NAMES","GENERIC_WALLET_ICON","WALLET_ICONS","getBrowserWallets","key","normalizeSignature","result","SolanaLoginButton","onSuccess","onError","className","variant","size","disabled","hideIfNoWallet","walletContext","isAuthLoading","showWalletSelector","setShowWalletSelector","pendingLogin","setPendingLogin","triggerConnect","setTriggerConnect","isProcessingRef","useRef","browserWallets","connected","connecting","signMessage","installedWallets","w","hasWallets","executeSignIn","pubKeyString","challenge","messageBytes","signatureBytes","connectAndSignDirect","browserWallet","rawSignature","useEffect","handleClick","handleSelectWallet","walletName","handleSelectBrowserWallet","sizeClasses","variantClasses","jsxs","Fragment","jsx","LoadingSpinner","e","bw","registerMobileWallet","mwa","chains","registrationConfig"],"mappings":"kMAmCO,SAASA,GAAqC,CACnD,KAAM,CAAE,OAAAC,EAAQ,UAAAC,CAAA,EAAcC,iBAAA,EACxB,CAACC,EAAWC,CAAY,EAAIC,EAAAA,SAAS,EAAK,EAC1C,CAACC,EAAOC,CAAQ,EAAIF,EAAAA,SAA2B,IAAI,EAEnDG,EAAYC,EAAAA,QAChB,IACE,IAAIC,EAAAA,UAAU,CACZ,QAASV,EAAO,UAChB,UAAWA,EAAO,eAClB,cAAeA,EAAO,aAAA,CACvB,EACH,CAACA,EAAO,UAAWA,EAAO,eAAgBA,EAAO,aAAa,CAAA,EAG1DW,EAAmBC,EAAAA,YACvB,MAAOC,GAAkD,CAEvD,GAAI,CAACC,EAAAA,wBAAwBD,CAAS,EAAG,CACvC,MAAME,EAAuB,CAC3B,KAAM,qBACN,QAAS,kCAAA,EAEX,MAAAR,EAASQ,CAAS,EACZA,CACR,CAEAX,EAAa,EAAI,EACjBG,EAAS,IAAI,EAEb,GAAI,CAMF,OALa,MAAMC,EAAU,KAC3B,oBACA,CAAE,UAAAK,CAAA,EACF,CAAE,YAAa,MAAA,CAAO,CAG1B,OAASG,EAAK,CACZ,MAAMD,EAAYE,EAAAA,eAAeD,EAAK,yBAAyB,EAC/D,MAAAT,EAASQ,CAAS,EACZA,CACR,QAAA,CACEX,EAAa,EAAK,CACpB,CACF,EACA,CAACI,CAAS,CAAA,EAGNU,EAASN,EAAAA,YACb,MAAOC,EAAmBM,EAAmBC,IAA2C,CAEtF,GAAI,CAACN,EAAAA,wBAAwBD,CAAS,EAAG,CACvC,MAAME,EAAuB,CAC3B,KAAM,qBACN,QAAS,kCAAA,EAEX,MAAAR,EAASQ,CAAS,EACZA,CACR,CAEAX,EAAa,EAAI,EACjBG,EAAS,IAAI,EAEb,GAAI,CACF,MAAMc,EAAO,MAAMb,EAAU,KAAmB,UAAW,CACzD,UAAAK,EACA,UAAAM,EACA,QAAAC,CAAA,CACD,EACD,OAAApB,EAAO,WAAW,iBAAiBqB,EAAK,KAAM,QAAQ,EACtDpB,GAAW,mBAAmBoB,EAAK,KAAMA,EAAK,MAAM,EAC7CA,CACT,OAASL,EAAK,CACZ,MAAMD,EAAYE,EAAAA,eAAeD,EAAK,uBAAuB,EAC7D,MAAAT,EAASQ,CAAS,EACZA,CACR,QAAA,CACEX,EAAa,EAAK,CACpB,CACF,EACA,CAACI,EAAWR,EAAO,UAAWC,CAAS,CAAA,EAGnCqB,EAAaV,EAAAA,YAAY,IAAML,EAAS,IAAI,EAAG,CAAA,CAAE,EAEvD,MAAO,CACL,iBAAAI,EACA,OAAAO,EACA,UAAAf,EACA,MAAAG,EACA,WAAAgB,CAAA,CAEJ,CCnGO,MAAMC,EAAyC,CACpD,UACA,WACA,WACA,OACA,QACA,SACA,SACA,SACA,aACA,SACA,QACA,eACF,EAMO,SAASC,EAAsBC,EAA4B,CAChE,GAAI,CAACA,GAAY,OAAOA,GAAa,SAAU,MAAO,GACtD,MAAMC,EAASD,EAGf,OACE,OAAOC,EAAO,SAAY,YAC1B,OAAOA,EAAO,aAAgB,YAC9B,OAAOA,EAAO,iBAAoB,YAClC,gBAAiBA,CAErB,CAMA,SAASC,GAAoC,CAC3C,GAAI,CAEF,MAAMC,EAAkB,OAA8C,oBACtE,GACEA,GACA,OAAOA,GAAmB,UAC1B,QAASA,GACT,OAAQA,EAA2C,KAAQ,WAC3D,CACA,MAAMC,EAAWD,EAA4C,IAAA,EAC7D,OAAO,MAAM,QAAQC,CAAO,GAAKA,EAAQ,OAAS,CACpD,CACF,MAAQ,CAER,CACA,MAAO,EACT,CAeO,SAASC,GAA+B,CAC7C,GAAI,OAAO,OAAW,IACpB,MAAO,GAGT,MAAMC,EAAM,OAIZ,UAAWN,KAAYF,EAAkB,CACvC,MAAMS,EAAYD,EAAIN,CAAQ,EAC9B,GACEO,GACA,OAAOA,GAAc,UACrB,WAAYA,GACZR,EAAsBQ,EAAU,MAAM,EAEtC,MAAO,EAEX,CASA,MALI,GAAAR,EAAsBO,EAAI,MAAM,GAKhCJ,IAKN,CChGA,MAAMM,EAA+C,CACnD,QAAS,UACT,SAAU,WACV,SAAU,WACV,KAAM,OACN,MAAO,QACP,OAAQ,SACR,OAAQ,SACR,OAAQ,SACR,WAAY,aACZ,OAAQ,SACR,MAAO,QACP,cAAe,gBACf,OAAQ,eACV,EAGMC,EACJ,wVAGIC,GAAuC,CAC3C,QACE,orBACF,SACE,6OACF,SACE,kPACJ,EAOO,SAASC,IAAqC,CACnD,GAAI,OAAO,OAAW,IAAa,MAAO,CAAA,EAE1C,MAAML,EAAM,OACNF,EAA2B,CAAA,EAEjC,UAAWQ,KAAOd,EAAkB,CAClC,MAAMS,EAAYD,EAAIM,CAAG,EAEvBL,GACA,OAAOA,GAAc,UACrB,WAAYA,GACZR,EAAsBQ,EAAU,MAAM,GAEtCH,EAAQ,KAAK,CACX,IAAAQ,EACA,KAAMJ,EAAqBI,CAAG,GAAKA,EACnC,KAAMF,GAAaE,CAAG,GAAKH,EAC3B,SAAUF,EAAU,MAAA,CACrB,CAEL,CAGA,OAAIH,EAAQ,SAAW,GAAKL,EAAsBO,EAAI,MAAM,GAC1DF,EAAQ,KAAK,CACX,IAAK,SACL,KAAMI,EAAqB,OAC3B,KAAMC,EACN,SAAUH,EAAI,MAAA,CACf,EAGIF,CACT,CAUO,SAASS,GAAmBC,EAA4D,CAC7F,GAAIA,aAAkB,WAAY,OAAOA,EAEzC,GACEA,GACA,OAAOA,GAAW,UAClB,cAAeA,GACfA,EAAO,qBAAqB,WAE5B,OAAOA,EAAO,UAGhB,MAAM,IAAI,MAAM,0CAA0C,CAC5D,CCzEO,SAASC,GAAkB,CAChC,UAAAC,EACA,QAAAC,EACA,UAAAC,EAAY,GACZ,QAAAC,EAAU,UACV,KAAAC,EAAO,KACP,SAAAC,EAAW,GACX,eAAAC,EAAiB,GACjB,cAAAC,CACF,EAA2B,CACzB,KAAM,CAAE,iBAAArC,EAAkB,OAAAO,EAAQ,UAAW+B,CAAA,EAAkBlD,EAAA,EACzD,CAACmD,EAAoBC,CAAqB,EAAI9C,EAAAA,SAAS,EAAK,EAC5D,CAAC+C,EAAcC,CAAe,EAAIhD,EAAAA,SAAS,EAAK,EAChD,CAACiD,EAAgBC,CAAiB,EAAIlD,EAAAA,SAAS,EAAK,EACpDmD,EAAkBC,EAAAA,OAAO,EAAK,EAI9B,CAACC,CAAc,EAAIrD,EAAAA,SAA0B,IACjD2C,EAAgB,CAAA,EAAKZ,GAAA,CAAkB,EAGnCuB,EAAYX,GAAe,WAAa,GACxCY,EAAaZ,GAAe,YAAc,GAC1CnC,EAAYmC,GAAe,UAC3Ba,EAAcb,GAAe,YAC7BtB,EAASsB,GAAe,OAIxBc,GAHUd,GAAe,SAAW,CAAA,GAGT,OAC9Be,GAAMA,EAAE,QAAQ,aAAe,aAAeA,EAAE,QAAQ,aAAe,UAAA,EAKpEC,EAAahB,EAAgBc,EAAiB,OAAS,EAAIJ,EAAe,OAAS,EAGnFO,EAAgBrD,EAAAA,YAAY,SAAY,CAC5C,GAAI,CAAA4C,EAAgB,QACpB,IAAI,CAAC3C,GAAa,CAACgD,EAAa,CAC9BnB,IAAU,IAAI,MAAM,kBAAkB,CAAC,EACvC,MACF,CAEAc,EAAgB,QAAU,GAC1B,GAAI,CACF,MAAMU,EAAerD,EAAU,SAAA,EAGzBsD,EAAY,MAAMxD,EAAiBuD,CAAY,EAG/CE,EAAe,IAAI,YAAA,EAAc,OAAOD,EAAU,OAAO,EACzDE,EAAiB,MAAMR,EAAYO,CAAY,EAGrD,GAAI,EAAEC,aAA0B,aAAeA,EAAe,SAAW,EACvE,MAAM,IAAI,MAAM,mCAAmC,EAIrD,IAAIlD,EACJ,GAAI,CACFA,EAAY,KAAK,OAAO,aAAa,GAAGkD,CAAc,CAAC,CACzD,MAAQ,CACN,MAAM,IAAI,MAAM,4BAA4B,CAC9C,CAGA,MAAMnD,EAAOgD,EAAc/C,EAAWgD,EAAU,OAAO,EAEvD1B,IAAA,CACF,OAASzB,EAAK,CACZ,MAAMV,EAAQU,aAAe,MAAQA,EAAM,IAAI,MAAM,OAAOA,CAAG,CAAC,EAChE0B,IAAUpC,CAAK,CACjB,QAAA,CACEkD,EAAgB,QAAU,GAC1BH,EAAgB,EAAK,CACvB,EACF,EAAG,CAACxC,EAAWgD,EAAalD,EAAkBO,EAAQuB,EAAWC,CAAO,CAAC,EAGnE4B,EAAuB1D,EAAAA,YAC3B,MAAO2D,GAAiC,CACtC,GAAI,CAAAf,EAAgB,QACpB,CAAAA,EAAgB,QAAU,GAC1BH,EAAgB,EAAI,EAEpB,GAAI,CAGF,MAAMa,GADS,MAAMK,EAAc,SAAS,QAAA,GAChB,UAAU,SAAA,EAGhCJ,EAAY,MAAMxD,EAAiBuD,CAAY,EAG/CE,EAAe,IAAI,YAAA,EAAc,OAAOD,EAAU,OAAO,EACzDK,EAAe,MAAMD,EAAc,SAAS,YAAYH,CAAY,EACpEC,EAAiB/B,GAAmBkC,CAAY,EAEtD,GAAIH,EAAe,SAAW,EAC5B,MAAM,IAAI,MAAM,iCAAiC,EAInD,IAAIlD,EACJ,GAAI,CACFA,EAAY,KAAK,OAAO,aAAa,GAAGkD,CAAc,CAAC,CACzD,MAAQ,CACN,MAAM,IAAI,MAAM,4BAA4B,CAC9C,CAGA,MAAMnD,EAAOgD,EAAc/C,EAAWgD,EAAU,OAAO,EACvD1B,IAAA,CACF,OAASzB,EAAK,CACZ,MAAMV,EAAQU,aAAe,MAAQA,EAAM,IAAI,MAAM,OAAOA,CAAG,CAAC,EAE5DV,EAAM,QAAQ,SAAS,eAAe,GAAKA,EAAM,QAAQ,SAAS,aAAa,EACjFoC,IAAU,IAAI,MAAM,6BAA6B,CAAC,EAElDA,IAAUpC,CAAK,CAEnB,QAAA,CACEkD,EAAgB,QAAU,GAC1BH,EAAgB,EAAK,CACvB,EACF,EACA,CAAC1C,EAAkBO,EAAQuB,EAAWC,CAAO,CAAA,EA2B/C,GAvBA+B,EAAAA,UAAU,IAAM,CACVnB,GAAkB5B,GAAU,CAACiC,GAAa,CAACC,GAAcZ,GAAe,UAC1EO,EAAkB,EAAK,EACvBP,EAAc,QAAA,EAAU,MAAOhC,GAAQ,CACrC0B,IAAU1B,aAAe,MAAQA,EAAM,IAAI,MAAM,OAAOA,CAAG,CAAC,CAAC,EAC7DqC,EAAgB,EAAK,CACvB,CAAC,EAEL,EAAG,CAACC,EAAgB5B,EAAQiC,EAAWC,EAAYZ,EAAeN,CAAO,CAAC,EAK1E+B,EAAAA,UAAU,IAAM,CACVrB,GAAgBO,GAAa9C,GAAagD,GAAe,CAACL,EAAgB,SAC5ES,EAAA,EAAgB,MAAM,IAAM,CAE5B,CAAC,CAEL,EAAG,CAACb,EAAcO,EAAW9C,EAAWgD,EAAaI,CAAa,CAAC,EAI/DlB,GAAkB,CAACiB,EACrB,OAAO,KAGT,MAAMU,EAAc,SAAY,CAC1B5B,GAAYG,GAAiBW,IAE7BZ,EAEEW,GAAa9C,GAAagD,GAC5BR,EAAgB,EAAI,EACpB,MAAMY,EAAA,GACGvC,GACT2B,EAAgB,EAAI,EACpBE,EAAkB,EAAI,GACbO,EAAiB,SAAW,GACrCd,EAAc,OAAOc,EAAiB,CAAC,EAAE,QAAQ,IAAI,EACrDT,EAAgB,EAAI,EACpBE,EAAkB,EAAI,GACbO,EAAiB,OAAS,EACnCX,EAAsB,EAAI,EAE1BT,IACE,IAAI,MAAM,0EAA0E,CAAA,EAKpFgB,EAAe,SAAW,EAC5B,MAAMY,EAAqBZ,EAAe,CAAC,CAAC,EACnCA,EAAe,OAAS,EACjCP,EAAsB,EAAI,EAE1BT,IACE,IAAI,MAAM,0EAA0E,CAAA,EAI5F,EAEMiC,EAAsBC,GAAuB,CACjDzB,EAAsB,EAAK,EAC3BH,GAAe,OAAO4B,CAAU,EAChCvB,EAAgB,EAAI,EACpBE,EAAkB,EAAI,CACxB,EAEMsB,EAA6BN,GAAiC,CAClEpB,EAAsB,EAAK,EAC3BmB,EAAqBC,CAAa,EAAE,MAAM,IAAM,CAEhD,CAAC,CACH,EAEMO,EAAc,CAClB,GAAI,mBACJ,GAAI,mBACJ,GAAI,kBAAA,EAGAC,EAAiB,CACrB,QAAS,uBACT,QAAS,8BAAA,EAGL5E,EAAY8C,GAAiBW,GAAeR,GAAgB,CAACO,EAEnE,OACEqB,EAAAA,KAAAC,WAAA,CACE,SAAA,CAAAD,EAAAA,KAAC,SAAA,CACC,KAAK,SACL,UAAW,iBAAiBD,EAAenC,CAAO,CAAC,IAAIkC,EAAYjC,CAAI,CAAC,IAAIF,CAAS,GACrF,QAAS+B,EACT,SAAU5B,GAAY3C,EACtB,aAAW,uBAEV,SAAA,CAAAA,EACC+E,EAAAA,IAACC,EAAAA,eAAA,CAAe,KAAK,IAAA,CAAK,EAE1BH,EAAAA,KAAC,MAAA,CACC,UAAU,qBACV,MAAM,KACN,OAAO,KACP,QAAQ,cACR,KAAK,eACL,cAAY,OAEZ,SAAA,CAAAE,EAAAA,IAAC,OAAA,CAAK,EAAE,0JAAA,CAA2J,EACnKA,EAAAA,IAAC,OAAA,CAAK,EAAE,0JAAA,CAA2J,EACnKA,EAAAA,IAAC,OAAA,CAAK,EAAE,2JAAA,CAA4J,CAAA,CAAA,CAAA,EAGxKA,EAAAA,IAAC,QAAK,SAAA,sBAAA,CAAoB,CAAA,CAAA,CAAA,EAI3BhC,GACCgC,EAAAA,IAAC,MAAA,CACC,UAAU,wBACV,QAAS,IAAM/B,EAAsB,EAAK,EAC1C,KAAK,eAEL,SAAA6B,EAAAA,KAAC,MAAA,CACC,UAAU,sCACV,KAAK,SACL,aAAW,OACX,kBAAgB,wBAChB,QAAUI,GAAMA,EAAE,gBAAA,EAElB,SAAA,CAAAJ,EAAAA,KAAC,MAAA,CAAI,UAAU,sBACb,SAAA,CAAAE,MAAC,KAAA,CAAG,GAAG,wBAAwB,UAAU,qBAAqB,SAAA,gBAE9D,EACAA,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,UAAU,qBACV,QAAS,IAAM/B,EAAsB,EAAK,EAC1C,aAAW,QAEX,SAAA+B,EAAAA,IAAC,MAAA,CAAI,MAAM,KAAK,OAAO,KAAK,QAAQ,YAAY,KAAK,OAAO,cAAY,OACtE,SAAAA,EAAAA,IAAC,OAAA,CACC,EAAE,uBACF,OAAO,eACP,YAAY,IACZ,cAAc,OAAA,CAAA,CAChB,CACF,CAAA,CAAA,CACF,EACF,EACAA,EAAAA,IAAC,MAAA,CAAI,UAAU,uBACb,SAAAA,EAAAA,IAAC,MAAA,CAAI,UAAU,qBACZ,SAAAlC,EACGc,EAAiB,IAAKC,GACpBiB,EAAAA,KAAC,SAAA,CAEC,KAAK,SACL,UAAU,uBACV,QAAS,IAAML,EAAmBZ,EAAE,QAAQ,IAAI,EAEhD,SAAA,CAAAmB,EAAAA,IAAC,MAAA,CACC,IAAKnB,EAAE,QAAQ,KACf,IAAI,GACJ,MAAM,KACN,OAAO,KACP,UAAU,oBAAA,CAAA,EAEZmB,EAAAA,IAAC,OAAA,CAAM,SAAAnB,EAAE,QAAQ,IAAA,CAAK,CAAA,CAAA,EAZjBA,EAAE,QAAQ,IAAA,CAclB,EACDL,EAAe,IAAK2B,GAClBL,EAAAA,KAAC,SAAA,CAEC,KAAK,SACL,UAAU,uBACV,QAAS,IAAMH,EAA0BQ,CAAE,EAE3C,SAAA,CAAAH,EAAAA,IAAC,MAAA,CACC,IAAKG,EAAG,KACR,IAAI,GACJ,MAAM,KACN,OAAO,KACP,UAAU,oBAAA,CAAA,EAEZH,EAAAA,IAAC,OAAA,CAAM,SAAAG,EAAG,IAAA,CAAK,CAAA,CAAA,EAZVA,EAAG,GAAA,CAcX,EACP,CAAA,CACF,CAAA,CAAA,CAAA,CACF,CAAA,CACF,EAEJ,CAEJ,CCxUO,SAASC,GAAqBtF,EAAsC,CACzE,GAAI,OAAO,OAAW,IACpB,MAAO,GAGT,GAAI,CAGF,MAAMuF,EAAM,QAAQ,uCAAuC,EAErDC,EAASxF,GAAQ,QAAU,CAAC,gBAAgB,EAE5CyF,EAA8C,CAClD,YAAa,CACX,KAAMzF,GAAQ,KACd,IAAKA,GAAQ,IACb,KAAMA,GAAQ,IAAA,EAEhB,OAAAwF,CAAA,EAIF,OAAI,OAAOD,EAAI,iCAAoC,aACjDE,EAAmB,mBAAqBF,EAAI,gCAAA,GAE1C,OAAOA,EAAI,4BAA+B,aAC5CE,EAAmB,cAAgBF,EAAI,2BAAA,GAErC,OAAOA,EAAI,oCAAuC,aACpDE,EAAmB,iBAAmBF,EAAI,mCAAA,GAG5CA,EAAI,YAAYE,CAAkB,EAC3B,EACT,MAAQ,CAEN,MAAO,EACT,CACF"}
@@ -0,0 +1,387 @@
1
+ import { jsxs as m, Fragment as X, jsx as l } from "react/jsx-runtime";
2
+ import { useState as L, useMemo as ee, useCallback as A, useRef as te, useEffect as U } from "react";
3
+ import { u as ae, A as ne, h as H } from "./useCedrosLogin-_94MmGGq.js";
4
+ import { a as K } from "./validation-B8kMV3BL.js";
5
+ import { L as re } from "./LoadingSpinner-6vml-zwr.js";
6
+ function oe() {
7
+ const { config: e, _internal: t } = ae(), [o, n] = L(!1), [_, d] = L(null), p = ee(
8
+ () => new ne({
9
+ baseUrl: e.serverUrl,
10
+ timeoutMs: e.requestTimeout,
11
+ retryAttempts: e.retryAttempts
12
+ }),
13
+ [e.serverUrl, e.requestTimeout, e.retryAttempts]
14
+ ), r = A(
15
+ async (f) => {
16
+ if (!K(f)) {
17
+ const u = {
18
+ code: "INVALID_PUBLIC_KEY",
19
+ message: "Invalid Solana public key format"
20
+ };
21
+ throw d(u), u;
22
+ }
23
+ n(!0), d(null);
24
+ try {
25
+ return await p.post(
26
+ "/solana/challenge",
27
+ { publicKey: f },
28
+ { credentials: "omit" }
29
+ );
30
+ } catch (u) {
31
+ const i = H(u, "Failed to get challenge");
32
+ throw d(i), i;
33
+ } finally {
34
+ n(!1);
35
+ }
36
+ },
37
+ [p]
38
+ ), y = A(
39
+ async (f, u, i) => {
40
+ if (!K(f)) {
41
+ const s = {
42
+ code: "INVALID_PUBLIC_KEY",
43
+ message: "Invalid Solana public key format"
44
+ };
45
+ throw d(s), s;
46
+ }
47
+ n(!0), d(null);
48
+ try {
49
+ const s = await p.post("/solana", {
50
+ publicKey: f,
51
+ signature: u,
52
+ message: i
53
+ });
54
+ return e.callbacks?.onLoginSuccess?.(s.user, "solana"), t?.handleLoginSuccess(s.user, s.tokens), s;
55
+ } catch (s) {
56
+ const c = H(s, "Solana sign-in failed");
57
+ throw d(c), c;
58
+ } finally {
59
+ n(!1);
60
+ }
61
+ },
62
+ [p, e.callbacks, t]
63
+ ), v = A(() => d(null), []);
64
+ return {
65
+ requestChallenge: r,
66
+ signIn: y,
67
+ isLoading: o,
68
+ error: _,
69
+ clearError: v
70
+ };
71
+ }
72
+ const R = [
73
+ "phantom",
74
+ "solflare",
75
+ "backpack",
76
+ "glow",
77
+ "slope",
78
+ "sollet",
79
+ "coin98",
80
+ "clover",
81
+ "mathWallet",
82
+ "ledger",
83
+ "torus",
84
+ "walletconnect"
85
+ ];
86
+ function I(e) {
87
+ if (!e || typeof e != "object") return !1;
88
+ const t = e;
89
+ return typeof t.connect == "function" || typeof t.signMessage == "function" || typeof t.signTransaction == "function" || "isConnected" in t;
90
+ }
91
+ function le() {
92
+ try {
93
+ const e = window.__wallet_standard__;
94
+ if (e && typeof e == "object" && "get" in e && typeof e.get == "function") {
95
+ const t = e.get();
96
+ return Array.isArray(t) && t.length > 0;
97
+ }
98
+ } catch {
99
+ }
100
+ return !1;
101
+ }
102
+ function me() {
103
+ if (typeof window > "u")
104
+ return !1;
105
+ const e = window;
106
+ for (const t of R) {
107
+ const o = e[t];
108
+ if (o && typeof o == "object" && "solana" in o && I(o.solana))
109
+ return !0;
110
+ }
111
+ return !!(I(e.solana) || le());
112
+ }
113
+ const q = {
114
+ phantom: "Phantom",
115
+ solflare: "Solflare",
116
+ backpack: "Backpack",
117
+ glow: "Glow",
118
+ slope: "Slope",
119
+ sollet: "Sollet",
120
+ coin98: "Coin98",
121
+ clover: "Clover",
122
+ mathWallet: "MathWallet",
123
+ ledger: "Ledger",
124
+ torus: "Torus",
125
+ walletconnect: "WalletConnect",
126
+ solana: "Solana Wallet"
127
+ }, O = "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 24 24' fill='none' stroke='%236366f1' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 12V7H5a2 2 0 0 1 0-4h14v4'/%3E%3Cpath d='M3 5v14a2 2 0 0 0 2 2h16v-5'/%3E%3Cpath d='M18 12a2 2 0 0 0 0 4h4v-4Z'/%3E%3C/svg%3E", se = {
128
+ phantom: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 128 128'%3E%3Crect width='128' height='128' rx='26' fill='%23AB9FF2'/%3E%3Cpath d='M110.5 64.2c-.3-3-3-5.2-6-4.8-13.6 1.6-25 7.1-33.5 15.9-5.3 5.4-9 11.7-11.3 18.5-1.1 3.3.7 6.9 4.1 7.9 3.3 1.1 6.9-.7 7.9-4.1 1.7-5.1 4.5-9.7 8.3-13.6 6.4-6.6 15-10.7 25.5-12 3-.3 5.2-3 4.8-6l.2-1.8zM110.2 43.8c-.3-3-3-5.2-6-4.8-25.2 3-44.1 18-53.5 39.2-1.3 2.9.1 6.3 3.1 7.6s6.3-.1 7.6-3.1c7.9-17.9 23.8-30.5 45.8-33.1 3-.3 5.2-3 4.8-6l-1.8-1.8zM44.8 44.5c2.9-1.5 4.1-5.1 2.5-8-1.5-2.9-5.1-4.1-8-2.5C24.4 42.1 16 57.9 16 75.8c0 3.3 2.7 6 6 6s6-2.7 6-6c0-14 6.5-26.3 16.8-31.3z' fill='%23FFFDF8'/%3E%3C/svg%3E",
129
+ solflare: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 128 128'%3E%3Crect width='128' height='128' rx='26' fill='%23FC7227'/%3E%3Cpath d='M64 28l28 36-28 36-28-36z' fill='%23fff'/%3E%3C/svg%3E",
130
+ backpack: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 128 128'%3E%3Crect width='128' height='128' rx='26' fill='%23E33E3F'/%3E%3Cpath d='M48 42h32v8H48zM40 54h48v36H40z' fill='%23fff'/%3E%3C/svg%3E"
131
+ };
132
+ function ie() {
133
+ if (typeof window > "u") return [];
134
+ const e = window, t = [];
135
+ for (const o of R) {
136
+ const n = e[o];
137
+ n && typeof n == "object" && "solana" in n && I(n.solana) && t.push({
138
+ key: o,
139
+ name: q[o] ?? o,
140
+ icon: se[o] ?? O,
141
+ provider: n.solana
142
+ });
143
+ }
144
+ return t.length === 0 && I(e.solana) && t.push({
145
+ key: "solana",
146
+ name: q.solana,
147
+ icon: O,
148
+ provider: e.solana
149
+ }), t;
150
+ }
151
+ function ce(e) {
152
+ if (e instanceof Uint8Array) return e;
153
+ if (e && typeof e == "object" && "signature" in e && e.signature instanceof Uint8Array)
154
+ return e.signature;
155
+ throw new Error("Wallet returned invalid signature format");
156
+ }
157
+ function pe({
158
+ onSuccess: e,
159
+ onError: t,
160
+ className: o = "",
161
+ variant: n = "default",
162
+ size: _ = "md",
163
+ disabled: d = !1,
164
+ hideIfNoWallet: p = !0,
165
+ walletContext: r
166
+ }) {
167
+ const { requestChallenge: y, signIn: v, isLoading: f } = oe(), [u, i] = L(!1), [s, c] = L(!1), [P, M] = L(!1), w = te(!1), [k] = L(
168
+ () => r ? [] : ie()
169
+ ), S = r?.connected ?? !1, N = r?.connecting ?? !1, C = r?.publicKey, E = r?.signMessage, z = r?.wallet, W = (r?.wallets ?? []).filter(
170
+ (a) => a.adapter.readyState === "Installed" || a.adapter.readyState === "Loadable"
171
+ ), V = r ? W.length > 0 : k.length > 0, F = A(async () => {
172
+ if (!w.current) {
173
+ if (!C || !E) {
174
+ t?.(new Error("Wallet not ready"));
175
+ return;
176
+ }
177
+ w.current = !0;
178
+ try {
179
+ const a = C.toBase58(), h = await y(a), g = new TextEncoder().encode(h.message), b = await E(g);
180
+ if (!(b instanceof Uint8Array) || b.length === 0)
181
+ throw new Error("Wallet returned invalid signature");
182
+ let B;
183
+ try {
184
+ B = btoa(String.fromCharCode(...b));
185
+ } catch {
186
+ throw new Error("Failed to encode signature");
187
+ }
188
+ await v(a, B, h.message), e?.();
189
+ } catch (a) {
190
+ const h = a instanceof Error ? a : new Error(String(a));
191
+ t?.(h);
192
+ } finally {
193
+ w.current = !1, c(!1);
194
+ }
195
+ }
196
+ }, [C, E, y, v, e, t]), j = A(
197
+ async (a) => {
198
+ if (!w.current) {
199
+ w.current = !0, c(!0);
200
+ try {
201
+ const g = (await a.provider.connect()).publicKey.toBase58(), b = await y(g), B = new TextEncoder().encode(b.message), Q = await a.provider.signMessage(B), T = ce(Q);
202
+ if (T.length === 0)
203
+ throw new Error("Wallet returned empty signature");
204
+ let x;
205
+ try {
206
+ x = btoa(String.fromCharCode(...T));
207
+ } catch {
208
+ throw new Error("Failed to encode signature");
209
+ }
210
+ await v(g, x, b.message), e?.();
211
+ } catch (h) {
212
+ const g = h instanceof Error ? h : new Error(String(h));
213
+ g.message.includes("User rejected") || g.message.includes("user reject") ? t?.(new Error("Wallet action was cancelled")) : t?.(g);
214
+ } finally {
215
+ w.current = !1, c(!1);
216
+ }
217
+ }
218
+ },
219
+ [y, v, e, t]
220
+ );
221
+ if (U(() => {
222
+ P && z && !S && !N && r?.connect && (M(!1), r.connect().catch((a) => {
223
+ t?.(a instanceof Error ? a : new Error(String(a))), c(!1);
224
+ }));
225
+ }, [P, z, S, N, r, t]), U(() => {
226
+ s && S && C && E && !w.current && F().catch(() => {
227
+ });
228
+ }, [s, S, C, E, F]), p && !V)
229
+ return null;
230
+ const Y = async () => {
231
+ d || f || N || (r ? S && C && E ? (c(!0), await F()) : z ? (c(!0), M(!0)) : W.length === 1 ? (r.select(W[0].adapter.name), c(!0), M(!0)) : W.length > 1 ? i(!0) : t?.(
232
+ new Error("No Solana wallet found. Please install Phantom or another Solana wallet.")
233
+ ) : k.length === 1 ? await j(k[0]) : k.length > 1 ? i(!0) : t?.(
234
+ new Error("No Solana wallet found. Please install Phantom or another Solana wallet.")
235
+ ));
236
+ }, $ = (a) => {
237
+ i(!1), r?.select(a), c(!0), M(!0);
238
+ }, G = (a) => {
239
+ i(!1), j(a).catch(() => {
240
+ });
241
+ }, Z = {
242
+ sm: "cedros-button-sm",
243
+ md: "cedros-button-md",
244
+ lg: "cedros-button-lg"
245
+ }, J = {
246
+ default: "cedros-button-social",
247
+ outline: "cedros-button-social-outline"
248
+ }, D = f || N || s && !S;
249
+ return /* @__PURE__ */ m(X, { children: [
250
+ /* @__PURE__ */ m(
251
+ "button",
252
+ {
253
+ type: "button",
254
+ className: `cedros-button ${J[n]} ${Z[_]} ${o}`,
255
+ onClick: Y,
256
+ disabled: d || D,
257
+ "aria-label": "Continue with Solana",
258
+ children: [
259
+ D ? /* @__PURE__ */ l(re, { size: "sm" }) : /* @__PURE__ */ m(
260
+ "svg",
261
+ {
262
+ className: "cedros-button-icon",
263
+ width: "18",
264
+ height: "18",
265
+ viewBox: "0 0 128 128",
266
+ fill: "currentColor",
267
+ "aria-hidden": "true",
268
+ children: [
269
+ /* @__PURE__ */ l("path", { d: "M25.38 96.04a4.35 4.35 0 0 1 3.07-1.27h91.68c1.93 0 2.9 2.34 1.54 3.7l-17.71 17.72a4.35 4.35 0 0 1-3.07 1.27H9.21c-1.93 0-2.9-2.34-1.54-3.7l17.71-17.72z" }),
270
+ /* @__PURE__ */ l("path", { d: "M25.38 11.81a4.47 4.47 0 0 1 3.07-1.27h91.68c1.93 0 2.9 2.34 1.54 3.7L103.96 31.96a4.35 4.35 0 0 1-3.07 1.27H9.21c-1.93 0-2.9-2.34-1.54-3.7L25.38 11.81z" }),
271
+ /* @__PURE__ */ l("path", { d: "M102.62 53.76a4.35 4.35 0 0 0-3.07-1.27H7.87c-1.93 0-2.9 2.34-1.54 3.7l17.71 17.72a4.35 4.35 0 0 0 3.07 1.27h91.68c1.93 0 2.9-2.34 1.54-3.7L102.62 53.76z" })
272
+ ]
273
+ }
274
+ ),
275
+ /* @__PURE__ */ l("span", { children: "Continue with Solana" })
276
+ ]
277
+ }
278
+ ),
279
+ u && /* @__PURE__ */ l(
280
+ "div",
281
+ {
282
+ className: "cedros-modal-backdrop",
283
+ onClick: () => i(!1),
284
+ role: "presentation",
285
+ children: /* @__PURE__ */ m(
286
+ "div",
287
+ {
288
+ className: "cedros-modal cedros-wallet-selector",
289
+ role: "dialog",
290
+ "aria-modal": "true",
291
+ "aria-labelledby": "wallet-selector-title",
292
+ onClick: (a) => a.stopPropagation(),
293
+ children: [
294
+ /* @__PURE__ */ m("div", { className: "cedros-modal-header", children: [
295
+ /* @__PURE__ */ l("h2", { id: "wallet-selector-title", className: "cedros-modal-title", children: "Select Wallet" }),
296
+ /* @__PURE__ */ l(
297
+ "button",
298
+ {
299
+ type: "button",
300
+ className: "cedros-modal-close",
301
+ onClick: () => i(!1),
302
+ "aria-label": "Close",
303
+ children: /* @__PURE__ */ l("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ l(
304
+ "path",
305
+ {
306
+ d: "M18 6L6 18M6 6l12 12",
307
+ stroke: "currentColor",
308
+ strokeWidth: "2",
309
+ strokeLinecap: "round"
310
+ }
311
+ ) })
312
+ }
313
+ )
314
+ ] }),
315
+ /* @__PURE__ */ l("div", { className: "cedros-modal-content", children: /* @__PURE__ */ l("div", { className: "cedros-wallet-list", children: r ? W.map((a) => /* @__PURE__ */ m(
316
+ "button",
317
+ {
318
+ type: "button",
319
+ className: "cedros-wallet-option",
320
+ onClick: () => $(a.adapter.name),
321
+ children: [
322
+ /* @__PURE__ */ l(
323
+ "img",
324
+ {
325
+ src: a.adapter.icon,
326
+ alt: "",
327
+ width: "32",
328
+ height: "32",
329
+ className: "cedros-wallet-icon"
330
+ }
331
+ ),
332
+ /* @__PURE__ */ l("span", { children: a.adapter.name })
333
+ ]
334
+ },
335
+ a.adapter.name
336
+ )) : k.map((a) => /* @__PURE__ */ m(
337
+ "button",
338
+ {
339
+ type: "button",
340
+ className: "cedros-wallet-option",
341
+ onClick: () => G(a),
342
+ children: [
343
+ /* @__PURE__ */ l(
344
+ "img",
345
+ {
346
+ src: a.icon,
347
+ alt: "",
348
+ width: "32",
349
+ height: "32",
350
+ className: "cedros-wallet-icon"
351
+ }
352
+ ),
353
+ /* @__PURE__ */ l("span", { children: a.name })
354
+ ]
355
+ },
356
+ a.key
357
+ )) }) })
358
+ ]
359
+ }
360
+ )
361
+ }
362
+ )
363
+ ] });
364
+ }
365
+ function ye(e) {
366
+ if (typeof window > "u")
367
+ return !1;
368
+ try {
369
+ const t = require("@solana-mobile/wallet-standard-mobile"), o = e?.chains ?? ["solana:mainnet"], n = {
370
+ appIdentity: {
371
+ name: e?.name,
372
+ uri: e?.uri,
373
+ icon: e?.icon
374
+ },
375
+ chains: o
376
+ };
377
+ return typeof t.createDefaultAuthorizationCache == "function" && (n.authorizationCache = t.createDefaultAuthorizationCache()), typeof t.createDefaultChainSelector == "function" && (n.chainSelector = t.createDefaultChainSelector()), typeof t.createDefaultWalletNotFoundHandler == "function" && (n.onWalletNotFound = t.createDefaultWalletNotFoundHandler()), t.registerMwa(n), !0;
378
+ } catch {
379
+ return !1;
380
+ }
381
+ }
382
+ export {
383
+ pe as S,
384
+ me as d,
385
+ ye as r,
386
+ oe as u
387
+ };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mobileWalletAdapter-CtTXtZlH.js","sources":["../src/hooks/useSolanaAuth.ts","../src/utils/walletDetection.ts","../src/utils/browserWalletAdapter.ts","../src/components/solana/SolanaLoginButton.tsx","../src/utils/mobileWalletAdapter.ts"],"sourcesContent":["import { useState, useCallback, useMemo } from 'react';\nimport { useCedrosLogin } from '../context/useCedrosLogin';\nimport { ApiClient, handleApiError } from '../utils/apiClient';\nimport { validateSolanaPublicKey } from '../utils/validation';\nimport type { AuthResponse, AuthError, ChallengeResponse } from '../types';\n\nexport interface UseSolanaAuthReturn {\n requestChallenge: (publicKey: string) => Promise<ChallengeResponse>;\n signIn: (publicKey: string, signature: string, message: string) => Promise<AuthResponse>;\n isLoading: boolean;\n error: AuthError | null;\n clearError: () => void;\n}\n\n/**\n * Hook for Solana wallet authentication.\n *\n * @example\n * ```tsx\n * function SolanaLogin() {\n * const { requestChallenge, signIn, isLoading } = useSolanaAuth();\n * const { publicKey, signMessage } = useWallet();\n *\n * const handleLogin = async () => {\n * const challenge = await requestChallenge(publicKey.toBase58());\n * const signature = await signMessage(new TextEncoder().encode(challenge.message));\n * const result = await signIn(\n * publicKey.toBase58(),\n * Buffer.from(signature).toString('base64'),\n * challenge.message\n * );\n * };\n * }\n * ```\n */\nexport function useSolanaAuth(): UseSolanaAuthReturn {\n const { config, _internal } = useCedrosLogin();\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<AuthError | null>(null);\n\n const apiClient = useMemo(\n () =>\n new ApiClient({\n baseUrl: config.serverUrl,\n timeoutMs: config.requestTimeout,\n retryAttempts: config.retryAttempts,\n }),\n [config.serverUrl, config.requestTimeout, config.retryAttempts]\n );\n\n const requestChallenge = useCallback(\n async (publicKey: string): Promise<ChallengeResponse> => {\n // Validate public key format before making API call\n if (!validateSolanaPublicKey(publicKey)) {\n const authError: AuthError = {\n code: 'INVALID_PUBLIC_KEY',\n message: 'Invalid Solana public key format',\n };\n setError(authError);\n throw authError;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const data = await apiClient.post<ChallengeResponse>(\n '/solana/challenge',\n { publicKey },\n { credentials: 'omit' }\n );\n return data;\n } catch (err) {\n const authError = handleApiError(err, 'Failed to get challenge');\n setError(authError);\n throw authError;\n } finally {\n setIsLoading(false);\n }\n },\n [apiClient]\n );\n\n const signIn = useCallback(\n async (publicKey: string, signature: string, message: string): Promise<AuthResponse> => {\n // Validate public key format before making API call\n if (!validateSolanaPublicKey(publicKey)) {\n const authError: AuthError = {\n code: 'INVALID_PUBLIC_KEY',\n message: 'Invalid Solana public key format',\n };\n setError(authError);\n throw authError;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const data = await apiClient.post<AuthResponse>('/solana', {\n publicKey,\n signature,\n message,\n });\n config.callbacks?.onLoginSuccess?.(data.user, 'solana');\n _internal?.handleLoginSuccess(data.user, data.tokens);\n return data;\n } catch (err) {\n const authError = handleApiError(err, 'Solana sign-in failed');\n setError(authError);\n throw authError;\n } finally {\n setIsLoading(false);\n }\n },\n [apiClient, config.callbacks, _internal]\n );\n\n const clearError = useCallback(() => setError(null), []);\n\n return {\n requestChallenge,\n signIn,\n isLoading,\n error,\n clearError,\n };\n}\n","/**\n * Wallet detection utilities for Solana browser wallets\n */\n\n/**\n * Type for window with potential Solana wallet extensions\n */\nexport interface WindowWithWallets extends Window {\n phantom?: { solana?: unknown };\n solflare?: { solana?: unknown };\n backpack?: { solana?: unknown };\n glow?: { solana?: unknown };\n slope?: { solana?: unknown };\n sollet?: { solana?: unknown };\n coin98?: { solana?: unknown };\n clover?: { solana?: unknown };\n mathWallet?: { solana?: unknown };\n ledger?: { solana?: unknown };\n torus?: { solana?: unknown };\n walletconnect?: { solana?: unknown };\n solana?: unknown;\n}\n\n/**\n * Known Solana wallet provider names to check for on the window object\n */\ntype WalletProviderName = Exclude<keyof WindowWithWallets, keyof Window>;\n\nexport const WALLET_PROVIDERS: WalletProviderName[] = [\n 'phantom',\n 'solflare',\n 'backpack',\n 'glow',\n 'slope',\n 'sollet',\n 'coin98',\n 'clover',\n 'mathWallet',\n 'ledger',\n 'torus',\n 'walletconnect',\n];\n\n/**\n * UI-9 FIX: Validates that a wallet provider object has expected Solana wallet methods.\n * Prevents spoofed wallet objects from being accepted.\n */\nexport function isValidSolanaProvider(provider: unknown): boolean {\n if (!provider || typeof provider !== 'object') return false;\n const wallet = provider as Record<string, unknown>;\n // Check for at least one expected wallet method/property\n // Real wallets have connect, signMessage, signTransaction, etc.\n return (\n typeof wallet.connect === 'function' ||\n typeof wallet.signMessage === 'function' ||\n typeof wallet.signTransaction === 'function' ||\n 'isConnected' in wallet\n );\n}\n\n/**\n * Check for wallets registered via the Wallet Standard protocol.\n * MWA (via @solana-mobile/wallet-standard-mobile) registers this way.\n */\nfunction hasWalletStandardWallets(): boolean {\n try {\n // The wallet-standard protocol exposes registered wallets via a global\n const walletStandard = (window as unknown as Record<string, unknown>)['__wallet_standard__'];\n if (\n walletStandard &&\n typeof walletStandard === 'object' &&\n 'get' in walletStandard &&\n typeof (walletStandard as Record<string, unknown>).get === 'function'\n ) {\n const wallets = (walletStandard as { get: () => unknown[] }).get();\n return Array.isArray(wallets) && wallets.length > 0;\n }\n } catch {\n // Not available\n }\n return false;\n}\n\n/**\n * Detects if any Solana wallet extensions are installed in the browser.\n * Checks for common wallet adapters like Phantom, Solflare, Backpack, etc.\n *\n * @returns true if at least one Solana wallet is detected\n *\n * @example\n * ```tsx\n * if (detectSolanaWallets()) {\n * // Show Solana login button\n * }\n * ```\n */\nexport function detectSolanaWallets(): boolean {\n if (typeof window === 'undefined') {\n return false;\n }\n\n const win = window as WindowWithWallets;\n\n // Check window object for wallet injections\n // UI-9: Validate wallet has expected methods to reject spoofed providers\n for (const provider of WALLET_PROVIDERS) {\n const walletObj = win[provider];\n if (\n walletObj &&\n typeof walletObj === 'object' &&\n 'solana' in walletObj &&\n isValidSolanaProvider(walletObj.solana)\n ) {\n return true;\n }\n }\n\n // Check for generic Solana provider (e.g., from some mobile wallet browsers)\n // UI-9: Also validate generic provider\n if (isValidSolanaProvider(win.solana)) {\n return true;\n }\n\n // Check for wallet-standard registered wallets (e.g., MWA via registerMwa())\n if (hasWalletStandardWallets()) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Returns list of detected Solana wallet names (for debugging/display)\n *\n * @returns Array of detected wallet provider names\n */\nexport function getDetectedWalletNames(): string[] {\n if (typeof window === 'undefined') {\n return [];\n }\n\n const win = window as WindowWithWallets;\n const detected: string[] = [];\n\n // UI-9: Use validation to reject spoofed providers\n for (const provider of WALLET_PROVIDERS) {\n const walletObj = win[provider];\n if (\n walletObj &&\n typeof walletObj === 'object' &&\n 'solana' in walletObj &&\n isValidSolanaProvider(walletObj.solana)\n ) {\n detected.push(provider);\n }\n }\n\n if (isValidSolanaProvider(win.solana) && detected.length === 0) {\n detected.push('solana');\n }\n\n return detected;\n}\n","/**\n * Direct browser wallet adapter for Solana wallets.\n *\n * Enumerates detected browser wallet extensions and provides a normalized\n * interface for connect + sign, bypassing the need for @solana/wallet-adapter-react.\n */\nimport {\n isValidSolanaProvider,\n WALLET_PROVIDERS,\n type WindowWithWallets,\n} from './walletDetection';\n\n/** Raw Solana wallet provider interface (e.g. window.phantom.solana) */\nexport interface SolanaProvider {\n connect: () => Promise<{ publicKey: { toBase58: () => string } }>;\n signMessage: (message: Uint8Array) => Promise<Uint8Array | { signature: Uint8Array }>;\n disconnect?: () => Promise<void>;\n isConnected?: boolean;\n publicKey?: { toBase58: () => string } | null;\n}\n\n/** A detected browser wallet ready for interaction */\nexport interface BrowserWallet {\n /** Internal key matching WALLET_PROVIDERS or 'solana' for generic */\n key: string;\n /** Human-readable display name */\n name: string;\n /** Data URI icon for rendering */\n icon: string;\n /** The raw provider object */\n provider: SolanaProvider;\n}\n\nconst WALLET_DISPLAY_NAMES: Record<string, string> = {\n phantom: 'Phantom',\n solflare: 'Solflare',\n backpack: 'Backpack',\n glow: 'Glow',\n slope: 'Slope',\n sollet: 'Sollet',\n coin98: 'Coin98',\n clover: 'Clover',\n mathWallet: 'MathWallet',\n ledger: 'Ledger',\n torus: 'Torus',\n walletconnect: 'WalletConnect',\n solana: 'Solana Wallet',\n};\n\n// Generic wallet SVG icon (simple wallet outline) as data URI\nconst GENERIC_WALLET_ICON =\n \"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 24 24' fill='none' stroke='%236366f1' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 12V7H5a2 2 0 0 1 0-4h14v4'/%3E%3Cpath d='M3 5v14a2 2 0 0 0 2 2h16v-5'/%3E%3Cpath d='M18 12a2 2 0 0 0 0 4h4v-4Z'/%3E%3C/svg%3E\";\n\n// Well-known wallet icons (brand-colored SVGs)\nconst WALLET_ICONS: Record<string, string> = {\n phantom:\n \"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 128 128'%3E%3Crect width='128' height='128' rx='26' fill='%23AB9FF2'/%3E%3Cpath d='M110.5 64.2c-.3-3-3-5.2-6-4.8-13.6 1.6-25 7.1-33.5 15.9-5.3 5.4-9 11.7-11.3 18.5-1.1 3.3.7 6.9 4.1 7.9 3.3 1.1 6.9-.7 7.9-4.1 1.7-5.1 4.5-9.7 8.3-13.6 6.4-6.6 15-10.7 25.5-12 3-.3 5.2-3 4.8-6l.2-1.8zM110.2 43.8c-.3-3-3-5.2-6-4.8-25.2 3-44.1 18-53.5 39.2-1.3 2.9.1 6.3 3.1 7.6s6.3-.1 7.6-3.1c7.9-17.9 23.8-30.5 45.8-33.1 3-.3 5.2-3 4.8-6l-1.8-1.8zM44.8 44.5c2.9-1.5 4.1-5.1 2.5-8-1.5-2.9-5.1-4.1-8-2.5C24.4 42.1 16 57.9 16 75.8c0 3.3 2.7 6 6 6s6-2.7 6-6c0-14 6.5-26.3 16.8-31.3z' fill='%23FFFDF8'/%3E%3C/svg%3E\",\n solflare:\n \"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 128 128'%3E%3Crect width='128' height='128' rx='26' fill='%23FC7227'/%3E%3Cpath d='M64 28l28 36-28 36-28-36z' fill='%23fff'/%3E%3C/svg%3E\",\n backpack:\n \"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 128 128'%3E%3Crect width='128' height='128' rx='26' fill='%23E33E3F'/%3E%3Cpath d='M48 42h32v8H48zM40 54h48v36H40z' fill='%23fff'/%3E%3C/svg%3E\",\n};\n\n/**\n * Enumerate detected browser wallets with display info and provider references.\n *\n * @returns Array of BrowserWallet objects for each detected, valid wallet\n */\nexport function getBrowserWallets(): BrowserWallet[] {\n if (typeof window === 'undefined') return [];\n\n const win = window as WindowWithWallets;\n const wallets: BrowserWallet[] = [];\n\n for (const key of WALLET_PROVIDERS) {\n const walletObj = win[key];\n if (\n walletObj &&\n typeof walletObj === 'object' &&\n 'solana' in walletObj &&\n isValidSolanaProvider(walletObj.solana)\n ) {\n wallets.push({\n key,\n name: WALLET_DISPLAY_NAMES[key] ?? key,\n icon: WALLET_ICONS[key] ?? GENERIC_WALLET_ICON,\n provider: walletObj.solana as SolanaProvider,\n });\n }\n }\n\n // Check for generic Solana provider when no named wallets found\n if (wallets.length === 0 && isValidSolanaProvider(win.solana)) {\n wallets.push({\n key: 'solana',\n name: WALLET_DISPLAY_NAMES.solana ?? 'Solana Wallet',\n icon: GENERIC_WALLET_ICON,\n provider: win.solana as SolanaProvider,\n });\n }\n\n return wallets;\n}\n\n/**\n * Normalize wallet signMessage return value.\n *\n * Phantom returns `{ signature: Uint8Array }`, while Solflare/Backpack\n * return raw `Uint8Array`. This handles both formats.\n *\n * @throws Error if result is neither format\n */\nexport function normalizeSignature(result: Uint8Array | { signature: Uint8Array }): Uint8Array {\n if (result instanceof Uint8Array) return result;\n\n if (\n result &&\n typeof result === 'object' &&\n 'signature' in result &&\n result.signature instanceof Uint8Array\n ) {\n return result.signature;\n }\n\n throw new Error('Wallet returned invalid signature format');\n}\n","import { useState, useEffect, useCallback, useRef } from 'react';\nimport { useSolanaAuth } from '../../hooks/useSolanaAuth';\nimport { LoadingSpinner } from '../shared/LoadingSpinner';\nimport {\n getBrowserWallets,\n normalizeSignature,\n type BrowserWallet,\n} from '../../utils/browserWalletAdapter';\n\nexport interface SolanaLoginButtonProps {\n onSuccess?: () => void;\n onError?: (error: Error) => void;\n className?: string;\n variant?: 'default' | 'outline';\n size?: 'sm' | 'md' | 'lg';\n disabled?: boolean;\n /**\n * Hide the button if no Solana wallets are detected.\n * When true (default), button renders nothing if no wallets are installed.\n * When false, button always renders (useful for showing \"install wallet\" prompts).\n * @default true\n */\n hideIfNoWallet?: boolean;\n /**\n * Solana wallet adapter context. Pass this from @solana/wallet-adapter-react's useWallet().\n * The button will handle connection and signing automatically for a one-click experience.\n */\n walletContext?: {\n publicKey: { toBase58: () => string } | null;\n signMessage: ((message: Uint8Array) => Promise<Uint8Array>) | null;\n connected: boolean;\n connecting: boolean;\n connect: () => Promise<void>;\n wallet: { adapter: { name: string } } | null;\n select: (walletName: string) => void;\n wallets: Array<{\n adapter: {\n name: string;\n icon: string;\n readyState: string;\n };\n }>;\n };\n}\n\n/**\n * Solana wallet login button with one-click authentication.\n *\n * Handles wallet connection and message signing automatically.\n * If wallet is already connected, signs immediately.\n * If not connected, connects first then auto-signs.\n */\nexport function SolanaLoginButton({\n onSuccess,\n onError,\n className = '',\n variant = 'default',\n size = 'md',\n disabled = false,\n hideIfNoWallet = true,\n walletContext,\n}: SolanaLoginButtonProps) {\n const { requestChallenge, signIn, isLoading: isAuthLoading } = useSolanaAuth();\n const [showWalletSelector, setShowWalletSelector] = useState(false);\n const [pendingLogin, setPendingLogin] = useState(false);\n const [triggerConnect, setTriggerConnect] = useState(false);\n const isProcessingRef = useRef(false);\n\n // Detect wallets from browser (used when walletContext not provided)\n // Use lazy initializer to avoid re-detecting on every render\n const [browserWallets] = useState<BrowserWallet[]>(() =>\n walletContext ? [] : getBrowserWallets()\n );\n\n const connected = walletContext?.connected ?? false;\n const connecting = walletContext?.connecting ?? false;\n const publicKey = walletContext?.publicKey;\n const signMessage = walletContext?.signMessage;\n const wallet = walletContext?.wallet;\n const wallets = walletContext?.wallets ?? [];\n\n // Get installed/ready wallets from wallet adapter context\n const installedWallets = wallets.filter(\n (w) => w.adapter.readyState === 'Installed' || w.adapter.readyState === 'Loadable'\n );\n\n // Determine if any wallets are available\n // If walletContext is provided, use its wallet list; otherwise use browser detection\n const hasWallets = walletContext ? installedWallets.length > 0 : browserWallets.length > 0;\n\n // Execute the actual sign-in flow\n const executeSignIn = useCallback(async () => {\n if (isProcessingRef.current) return;\n if (!publicKey || !signMessage) {\n onError?.(new Error('Wallet not ready'));\n return;\n }\n\n isProcessingRef.current = true;\n try {\n const pubKeyString = publicKey.toBase58();\n\n // Request challenge from server\n const challenge = await requestChallenge(pubKeyString);\n\n // Sign the message with wallet\n const messageBytes = new TextEncoder().encode(challenge.message);\n const signatureBytes = await signMessage(messageBytes);\n\n // Validate signature\n if (!(signatureBytes instanceof Uint8Array) || signatureBytes.length === 0) {\n throw new Error('Wallet returned invalid signature');\n }\n\n // Encode signature\n let signature: string;\n try {\n signature = btoa(String.fromCharCode(...signatureBytes));\n } catch {\n throw new Error('Failed to encode signature');\n }\n\n // Authenticate with server\n await signIn(pubKeyString, signature, challenge.message);\n\n onSuccess?.();\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n onError?.(error);\n } finally {\n isProcessingRef.current = false;\n setPendingLogin(false);\n }\n }, [publicKey, signMessage, requestChallenge, signIn, onSuccess, onError]);\n\n // Direct browser wallet flow: connect, challenge, sign, authenticate\n const connectAndSignDirect = useCallback(\n async (browserWallet: BrowserWallet) => {\n if (isProcessingRef.current) return;\n isProcessingRef.current = true;\n setPendingLogin(true);\n\n try {\n // Connect to the wallet\n const result = await browserWallet.provider.connect();\n const pubKeyString = result.publicKey.toBase58();\n\n // Request challenge from server\n const challenge = await requestChallenge(pubKeyString);\n\n // Sign the message\n const messageBytes = new TextEncoder().encode(challenge.message);\n const rawSignature = await browserWallet.provider.signMessage(messageBytes);\n const signatureBytes = normalizeSignature(rawSignature);\n\n if (signatureBytes.length === 0) {\n throw new Error('Wallet returned empty signature');\n }\n\n // Encode signature to base64\n let signature: string;\n try {\n signature = btoa(String.fromCharCode(...signatureBytes));\n } catch {\n throw new Error('Failed to encode signature');\n }\n\n // Authenticate with server\n await signIn(pubKeyString, signature, challenge.message);\n onSuccess?.();\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n // Gracefully handle user rejection\n if (error.message.includes('User rejected') || error.message.includes('user reject')) {\n onError?.(new Error('Wallet action was cancelled'));\n } else {\n onError?.(error);\n }\n } finally {\n isProcessingRef.current = false;\n setPendingLogin(false);\n }\n },\n [requestChallenge, signIn, onSuccess, onError]\n );\n\n // Auto-connect when wallet is selected and triggerConnect is set\n useEffect(() => {\n if (triggerConnect && wallet && !connected && !connecting && walletContext?.connect) {\n setTriggerConnect(false);\n walletContext.connect().catch((err) => {\n onError?.(err instanceof Error ? err : new Error(String(err)));\n setPendingLogin(false);\n });\n }\n }, [triggerConnect, wallet, connected, connecting, walletContext, onError]);\n\n // Auto-execute sign-in when connected with pending login\n // COMP-04: Catch unhandled rejections from executeSignIn (defensive - errors already\n // handled internally, but .catch() prevents unhandledrejection events)\n useEffect(() => {\n if (pendingLogin && connected && publicKey && signMessage && !isProcessingRef.current) {\n executeSignIn().catch(() => {\n /* Errors already passed to onError callback inside executeSignIn */\n });\n }\n }, [pendingLogin, connected, publicKey, signMessage, executeSignIn]);\n\n // Hide button if no wallets detected and hideIfNoWallet is true\n // Note: This must come after all hooks to satisfy React rules of hooks\n if (hideIfNoWallet && !hasWallets) {\n return null;\n }\n\n const handleClick = async () => {\n if (disabled || isAuthLoading || connecting) return;\n\n if (walletContext) {\n // Wallet adapter mode (walletContext provided by host)\n if (connected && publicKey && signMessage) {\n setPendingLogin(true);\n await executeSignIn();\n } else if (wallet) {\n setPendingLogin(true);\n setTriggerConnect(true);\n } else if (installedWallets.length === 1) {\n walletContext.select(installedWallets[0].adapter.name);\n setPendingLogin(true);\n setTriggerConnect(true);\n } else if (installedWallets.length > 1) {\n setShowWalletSelector(true);\n } else {\n onError?.(\n new Error('No Solana wallet found. Please install Phantom or another Solana wallet.')\n );\n }\n } else {\n // Direct browser wallet mode (no walletContext)\n if (browserWallets.length === 1) {\n await connectAndSignDirect(browserWallets[0]);\n } else if (browserWallets.length > 1) {\n setShowWalletSelector(true);\n } else {\n onError?.(\n new Error('No Solana wallet found. Please install Phantom or another Solana wallet.')\n );\n }\n }\n };\n\n const handleSelectWallet = (walletName: string) => {\n setShowWalletSelector(false);\n walletContext?.select(walletName);\n setPendingLogin(true);\n setTriggerConnect(true);\n };\n\n const handleSelectBrowserWallet = (browserWallet: BrowserWallet) => {\n setShowWalletSelector(false);\n connectAndSignDirect(browserWallet).catch(() => {\n /* Errors already passed to onError callback inside connectAndSignDirect */\n });\n };\n\n const sizeClasses = {\n sm: 'cedros-button-sm',\n md: 'cedros-button-md',\n lg: 'cedros-button-lg',\n };\n\n const variantClasses = {\n default: 'cedros-button-social',\n outline: 'cedros-button-social-outline',\n };\n\n const isLoading = isAuthLoading || connecting || (pendingLogin && !connected);\n\n return (\n <>\n <button\n type=\"button\"\n className={`cedros-button ${variantClasses[variant]} ${sizeClasses[size]} ${className}`}\n onClick={handleClick}\n disabled={disabled || isLoading}\n aria-label=\"Continue with Solana\"\n >\n {isLoading ? (\n <LoadingSpinner size=\"sm\" />\n ) : (\n <svg\n className=\"cedros-button-icon\"\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 128 128\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path d=\"M25.38 96.04a4.35 4.35 0 0 1 3.07-1.27h91.68c1.93 0 2.9 2.34 1.54 3.7l-17.71 17.72a4.35 4.35 0 0 1-3.07 1.27H9.21c-1.93 0-2.9-2.34-1.54-3.7l17.71-17.72z\" />\n <path d=\"M25.38 11.81a4.47 4.47 0 0 1 3.07-1.27h91.68c1.93 0 2.9 2.34 1.54 3.7L103.96 31.96a4.35 4.35 0 0 1-3.07 1.27H9.21c-1.93 0-2.9-2.34-1.54-3.7L25.38 11.81z\" />\n <path d=\"M102.62 53.76a4.35 4.35 0 0 0-3.07-1.27H7.87c-1.93 0-2.9 2.34-1.54 3.7l17.71 17.72a4.35 4.35 0 0 0 3.07 1.27h91.68c1.93 0 2.9-2.34 1.54-3.7L102.62 53.76z\" />\n </svg>\n )}\n <span>Continue with Solana</span>\n </button>\n\n {/* Wallet Selector Modal */}\n {showWalletSelector && (\n <div\n className=\"cedros-modal-backdrop\"\n onClick={() => setShowWalletSelector(false)}\n role=\"presentation\"\n >\n <div\n className=\"cedros-modal cedros-wallet-selector\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"wallet-selector-title\"\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"cedros-modal-header\">\n <h2 id=\"wallet-selector-title\" className=\"cedros-modal-title\">\n Select Wallet\n </h2>\n <button\n type=\"button\"\n className=\"cedros-modal-close\"\n onClick={() => setShowWalletSelector(false)}\n aria-label=\"Close\"\n >\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M18 6L6 18M6 6l12 12\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n </button>\n </div>\n <div className=\"cedros-modal-content\">\n <div className=\"cedros-wallet-list\">\n {walletContext\n ? installedWallets.map((w) => (\n <button\n key={w.adapter.name}\n type=\"button\"\n className=\"cedros-wallet-option\"\n onClick={() => handleSelectWallet(w.adapter.name)}\n >\n <img\n src={w.adapter.icon}\n alt=\"\"\n width=\"32\"\n height=\"32\"\n className=\"cedros-wallet-icon\"\n />\n <span>{w.adapter.name}</span>\n </button>\n ))\n : browserWallets.map((bw) => (\n <button\n key={bw.key}\n type=\"button\"\n className=\"cedros-wallet-option\"\n onClick={() => handleSelectBrowserWallet(bw)}\n >\n <img\n src={bw.icon}\n alt=\"\"\n width=\"32\"\n height=\"32\"\n className=\"cedros-wallet-icon\"\n />\n <span>{bw.name}</span>\n </button>\n ))}\n </div>\n </div>\n </div>\n </div>\n )}\n </>\n );\n}\n","/**\n * Mobile Wallet Adapter (MWA) registration for web.\n *\n * On Android Chrome, MWA lets users authenticate with their installed Solana\n * wallet app (e.g., Phantom, Solflare) via Android Intents — no browser\n * extension needed.\n *\n * Once registered, MWA appears as a wallet option in the wallet adapter's\n * wallet list (alongside browser extension wallets). Users see it as\n * \"Use Installed Wallet\" in the wallet selector.\n *\n * Requires the optional peer dependency: @solana-mobile/wallet-standard-mobile\n *\n * @see https://docs.solanamobile.com/get-started/web/installation\n */\n\nexport interface MobileWalletConfig {\n /** App name shown in the wallet's authorization dialog */\n name?: string;\n /** App URI for identity verification */\n uri?: string;\n /** App icon path/URL shown in the wallet dialog */\n icon?: string;\n /** Solana cluster(s) to support. Default: ['solana:mainnet'] */\n chains?: string[];\n}\n\n/**\n * Register Mobile Wallet Adapter as a wallet-standard wallet.\n *\n * Call this once at your application root (before rendering). After registration,\n * MWA automatically appears as \"Use Installed Wallet\" for users browsing on\n * Android Chrome with a Solana wallet app installed.\n *\n * Must be called in a non-SSR context (browser only). For Next.js, call in a\n * Client Component with `'use client'`.\n *\n * @example\n * ```tsx\n * import { registerMobileWallet, CedrosLoginProvider } from '@cedros/login-react';\n *\n * // Register before provider mounts\n * registerMobileWallet({ name: 'My App', uri: 'https://myapp.com' });\n *\n * function App() {\n * return (\n * <CedrosLoginProvider config={{ serverUrl: '...' }}>\n * <LoginForm />\n * </CedrosLoginProvider>\n * );\n * }\n * ```\n *\n * @returns true if registration succeeded, false if package not installed or SSR\n */\nexport function registerMobileWallet(config?: MobileWalletConfig): boolean {\n if (typeof window === 'undefined') {\n return false;\n }\n\n try {\n // Dynamic import to avoid bundling the optional peer dep\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const mwa = require('@solana-mobile/wallet-standard-mobile');\n\n const chains = config?.chains ?? ['solana:mainnet'];\n\n const registrationConfig: Record<string, unknown> = {\n appIdentity: {\n name: config?.name,\n uri: config?.uri,\n icon: config?.icon,\n },\n chains,\n };\n\n // Use built-in defaults for optional config if available\n if (typeof mwa.createDefaultAuthorizationCache === 'function') {\n registrationConfig.authorizationCache = mwa.createDefaultAuthorizationCache();\n }\n if (typeof mwa.createDefaultChainSelector === 'function') {\n registrationConfig.chainSelector = mwa.createDefaultChainSelector();\n }\n if (typeof mwa.createDefaultWalletNotFoundHandler === 'function') {\n registrationConfig.onWalletNotFound = mwa.createDefaultWalletNotFoundHandler();\n }\n\n mwa.registerMwa(registrationConfig);\n return true;\n } catch {\n // @solana-mobile/wallet-standard-mobile not installed\n return false;\n }\n}\n"],"names":["useSolanaAuth","config","_internal","useCedrosLogin","isLoading","setIsLoading","useState","error","setError","apiClient","useMemo","ApiClient","requestChallenge","useCallback","publicKey","validateSolanaPublicKey","authError","err","handleApiError","signIn","signature","message","data","clearError","WALLET_PROVIDERS","isValidSolanaProvider","provider","wallet","hasWalletStandardWallets","walletStandard","wallets","detectSolanaWallets","win","walletObj","WALLET_DISPLAY_NAMES","GENERIC_WALLET_ICON","WALLET_ICONS","getBrowserWallets","key","normalizeSignature","result","SolanaLoginButton","onSuccess","onError","className","variant","size","disabled","hideIfNoWallet","walletContext","isAuthLoading","showWalletSelector","setShowWalletSelector","pendingLogin","setPendingLogin","triggerConnect","setTriggerConnect","isProcessingRef","useRef","browserWallets","connected","connecting","signMessage","installedWallets","w","hasWallets","executeSignIn","pubKeyString","challenge","messageBytes","signatureBytes","connectAndSignDirect","browserWallet","rawSignature","useEffect","handleClick","handleSelectWallet","walletName","handleSelectBrowserWallet","sizeClasses","variantClasses","jsxs","Fragment","jsx","LoadingSpinner","e","bw","registerMobileWallet","mwa","chains","registrationConfig"],"mappings":"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"}
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("./useAuth-X6Ds6WW4.cjs"),o=require("./useCedrosLogin-C9MrcZvh.cjs"),e=require("./mobileWalletAdapter-DOdmFAk0.cjs"),n=require("./LoadingSpinner-d6sSxgQN.cjs"),i=require("./ErrorMessage-CHbYbVi2.cjs");exports.CedrosLoginProvider=r.CedrosLoginProvider;exports.useAuth=r.useAuth;exports.useCedrosLogin=o.useCedrosLogin;exports.SolanaLoginButton=e.SolanaLoginButton;exports.registerMobileWallet=e.registerMobileWallet;exports.useSolanaAuth=e.useSolanaAuth;exports.LoadingSpinner=n.LoadingSpinner;exports.ErrorMessage=i.ErrorMessage;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("./useAuth-X6Ds6WW4.cjs"),o=require("./useCedrosLogin-C9MrcZvh.cjs"),e=require("./mobileWalletAdapter-7TOM-TF8.cjs"),n=require("./LoadingSpinner-d6sSxgQN.cjs"),i=require("./ErrorMessage-CHbYbVi2.cjs");exports.CedrosLoginProvider=r.CedrosLoginProvider;exports.useAuth=r.useAuth;exports.useCedrosLogin=o.useCedrosLogin;exports.SolanaLoginButton=e.SolanaLoginButton;exports.registerMobileWallet=e.registerMobileWallet;exports.useSolanaAuth=e.useSolanaAuth;exports.LoadingSpinner=n.LoadingSpinner;exports.ErrorMessage=i.ErrorMessage;
@@ -1,6 +1,6 @@
1
1
  import { C as e, u as s } from "./useAuth-m5Hf89v8.js";
2
2
  import { u as t } from "./useCedrosLogin-_94MmGGq.js";
3
- import { S as u, r as i, u as g } from "./mobileWalletAdapter-BulleEbi.js";
3
+ import { S as u, r as i, u as g } from "./mobileWalletAdapter-CtTXtZlH.js";
4
4
  import { L as f } from "./LoadingSpinner-6vml-zwr.js";
5
5
  import { E as m } from "./ErrorMessage-CcEK0pYO.js";
6
6
  export {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cedros/login-react",
3
- "version": "0.0.19",
3
+ "version": "0.0.20",
4
4
  "description": "React component library for authentication with email/password, Google OAuth, and Solana wallet sign-in",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -1,291 +0,0 @@
1
- import { jsxs as w, Fragment as $, jsx as r } from "react/jsx-runtime";
2
- import { useState as y, useMemo as O, useCallback as N, useRef as Y, useEffect as z } from "react";
3
- import { u as G, A as J, h as B } from "./useCedrosLogin-_94MmGGq.js";
4
- import { a as j } from "./validation-B8kMV3BL.js";
5
- import { L as Q } from "./LoadingSpinner-6vml-zwr.js";
6
- function X() {
7
- const { config: e, _internal: t } = G(), [l, s] = y(!1), [A, c] = y(null), h = O(
8
- () => new J({
9
- baseUrl: e.serverUrl,
10
- timeoutMs: e.requestTimeout,
11
- retryAttempts: e.retryAttempts
12
- }),
13
- [e.serverUrl, e.requestTimeout, e.retryAttempts]
14
- ), n = N(
15
- async (f) => {
16
- if (!j(f)) {
17
- const i = {
18
- code: "INVALID_PUBLIC_KEY",
19
- message: "Invalid Solana public key format"
20
- };
21
- throw c(i), i;
22
- }
23
- s(!0), c(null);
24
- try {
25
- return await h.post(
26
- "/solana/challenge",
27
- { publicKey: f },
28
- { credentials: "omit" }
29
- );
30
- } catch (i) {
31
- const d = B(i, "Failed to get challenge");
32
- throw c(d), d;
33
- } finally {
34
- s(!1);
35
- }
36
- },
37
- [h]
38
- ), S = N(
39
- async (f, i, d) => {
40
- if (!j(f)) {
41
- const o = {
42
- code: "INVALID_PUBLIC_KEY",
43
- message: "Invalid Solana public key format"
44
- };
45
- throw c(o), o;
46
- }
47
- s(!0), c(null);
48
- try {
49
- const o = await h.post("/solana", {
50
- publicKey: f,
51
- signature: i,
52
- message: d
53
- });
54
- return e.callbacks?.onLoginSuccess?.(o.user, "solana"), t?.handleLoginSuccess(o.user, o.tokens), o;
55
- } catch (o) {
56
- const u = B(o, "Solana sign-in failed");
57
- throw c(u), u;
58
- } finally {
59
- s(!1);
60
- }
61
- },
62
- [h, e.callbacks, t]
63
- ), L = N(() => c(null), []);
64
- return {
65
- requestChallenge: n,
66
- signIn: S,
67
- isLoading: l,
68
- error: A,
69
- clearError: L
70
- };
71
- }
72
- const Z = [
73
- "phantom",
74
- "solflare",
75
- "backpack",
76
- "glow",
77
- "slope",
78
- "sollet",
79
- "coin98",
80
- "clover",
81
- "mathWallet",
82
- "ledger",
83
- "torus",
84
- "walletconnect"
85
- ];
86
- function F(e) {
87
- if (!e || typeof e != "object") return !1;
88
- const t = e;
89
- return typeof t.connect == "function" || typeof t.signMessage == "function" || typeof t.signTransaction == "function" || "isConnected" in t;
90
- }
91
- function x() {
92
- try {
93
- const e = window.__wallet_standard__;
94
- if (e && typeof e == "object" && "get" in e && typeof e.get == "function") {
95
- const t = e.get();
96
- return Array.isArray(t) && t.length > 0;
97
- }
98
- } catch {
99
- }
100
- return !1;
101
- }
102
- function ee() {
103
- if (typeof window > "u")
104
- return !1;
105
- const e = window;
106
- for (const t of Z) {
107
- const l = e[t];
108
- if (l && typeof l == "object" && "solana" in l && F(l.solana))
109
- return !0;
110
- }
111
- return !!(F(e.solana) || x());
112
- }
113
- function le({
114
- onSuccess: e,
115
- onError: t,
116
- className: l = "",
117
- variant: s = "default",
118
- size: A = "md",
119
- disabled: c = !1,
120
- hideIfNoWallet: h = !0,
121
- walletContext: n
122
- }) {
123
- const { requestChallenge: S, signIn: L, isLoading: f } = X(), [i, d] = y(!1), [o, u] = y(!1), [_, C] = y(!1), W = Y(!1), [H] = y(() => ee()), g = n?.connected ?? !1, k = n?.connecting ?? !1, m = n?.publicKey, p = n?.signMessage, E = n?.wallet, b = (n?.wallets ?? []).filter(
124
- (a) => a.adapter.readyState === "Installed" || a.adapter.readyState === "Loadable"
125
- ), T = n ? b.length > 0 : H, I = N(async () => {
126
- if (!W.current) {
127
- if (!m || !p) {
128
- t?.(new Error("Wallet not ready"));
129
- return;
130
- }
131
- W.current = !0;
132
- try {
133
- const a = m.toBase58(), v = await S(a), V = new TextEncoder().encode(v.message), M = await p(V);
134
- if (!(M instanceof Uint8Array) || M.length === 0)
135
- throw new Error("Wallet returned invalid signature");
136
- let D;
137
- try {
138
- D = btoa(String.fromCharCode(...M));
139
- } catch {
140
- throw new Error("Failed to encode signature");
141
- }
142
- await L(a, D, v.message), e?.();
143
- } catch (a) {
144
- const v = a instanceof Error ? a : new Error(String(a));
145
- t?.(v);
146
- } finally {
147
- W.current = !1, u(!1);
148
- }
149
- }
150
- }, [m, p, S, L, e, t]);
151
- if (z(() => {
152
- _ && E && !g && !k && n?.connect && (C(!1), n.connect().catch((a) => {
153
- t?.(a instanceof Error ? a : new Error(String(a))), u(!1);
154
- }));
155
- }, [_, E, g, k, n, t]), z(() => {
156
- o && g && m && p && !W.current && I().catch(() => {
157
- });
158
- }, [o, g, m, p, I]), h && !T)
159
- return null;
160
- const U = async () => {
161
- c || f || k || (g && m && p ? (u(!0), await I()) : E ? (u(!0), C(!0)) : b.length === 1 ? (n?.select(b[0].adapter.name), u(!0), C(!0)) : b.length > 1 ? d(!0) : t?.(
162
- new Error("No Solana wallet found. Please install Phantom or another Solana wallet.")
163
- ));
164
- }, q = (a) => {
165
- d(!1), n?.select(a), u(!0), C(!0);
166
- }, K = {
167
- sm: "cedros-button-sm",
168
- md: "cedros-button-md",
169
- lg: "cedros-button-lg"
170
- }, R = {
171
- default: "cedros-button-social",
172
- outline: "cedros-button-social-outline"
173
- }, P = f || k || o && !g;
174
- return /* @__PURE__ */ w($, { children: [
175
- /* @__PURE__ */ w(
176
- "button",
177
- {
178
- type: "button",
179
- className: `cedros-button ${R[s]} ${K[A]} ${l}`,
180
- onClick: U,
181
- disabled: c || P,
182
- "aria-label": "Continue with Solana",
183
- children: [
184
- P ? /* @__PURE__ */ r(Q, { size: "sm" }) : /* @__PURE__ */ w(
185
- "svg",
186
- {
187
- className: "cedros-button-icon",
188
- width: "18",
189
- height: "18",
190
- viewBox: "0 0 128 128",
191
- fill: "currentColor",
192
- "aria-hidden": "true",
193
- children: [
194
- /* @__PURE__ */ r("path", { d: "M25.38 96.04a4.35 4.35 0 0 1 3.07-1.27h91.68c1.93 0 2.9 2.34 1.54 3.7l-17.71 17.72a4.35 4.35 0 0 1-3.07 1.27H9.21c-1.93 0-2.9-2.34-1.54-3.7l17.71-17.72z" }),
195
- /* @__PURE__ */ r("path", { d: "M25.38 11.81a4.47 4.47 0 0 1 3.07-1.27h91.68c1.93 0 2.9 2.34 1.54 3.7L103.96 31.96a4.35 4.35 0 0 1-3.07 1.27H9.21c-1.93 0-2.9-2.34-1.54-3.7L25.38 11.81z" }),
196
- /* @__PURE__ */ r("path", { d: "M102.62 53.76a4.35 4.35 0 0 0-3.07-1.27H7.87c-1.93 0-2.9 2.34-1.54 3.7l17.71 17.72a4.35 4.35 0 0 0 3.07 1.27h91.68c1.93 0 2.9-2.34 1.54-3.7L102.62 53.76z" })
197
- ]
198
- }
199
- ),
200
- /* @__PURE__ */ r("span", { children: "Continue with Solana" })
201
- ]
202
- }
203
- ),
204
- i && /* @__PURE__ */ r(
205
- "div",
206
- {
207
- className: "cedros-modal-backdrop",
208
- onClick: () => d(!1),
209
- role: "presentation",
210
- children: /* @__PURE__ */ w(
211
- "div",
212
- {
213
- className: "cedros-modal cedros-wallet-selector",
214
- role: "dialog",
215
- "aria-modal": "true",
216
- "aria-labelledby": "wallet-selector-title",
217
- onClick: (a) => a.stopPropagation(),
218
- children: [
219
- /* @__PURE__ */ w("div", { className: "cedros-modal-header", children: [
220
- /* @__PURE__ */ r("h2", { id: "wallet-selector-title", className: "cedros-modal-title", children: "Select Wallet" }),
221
- /* @__PURE__ */ r(
222
- "button",
223
- {
224
- type: "button",
225
- className: "cedros-modal-close",
226
- onClick: () => d(!1),
227
- "aria-label": "Close",
228
- children: /* @__PURE__ */ r("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ r(
229
- "path",
230
- {
231
- d: "M18 6L6 18M6 6l12 12",
232
- stroke: "currentColor",
233
- strokeWidth: "2",
234
- strokeLinecap: "round"
235
- }
236
- ) })
237
- }
238
- )
239
- ] }),
240
- /* @__PURE__ */ r("div", { className: "cedros-modal-content", children: /* @__PURE__ */ r("div", { className: "cedros-wallet-list", children: b.map((a) => /* @__PURE__ */ w(
241
- "button",
242
- {
243
- type: "button",
244
- className: "cedros-wallet-option",
245
- onClick: () => q(a.adapter.name),
246
- children: [
247
- /* @__PURE__ */ r(
248
- "img",
249
- {
250
- src: a.adapter.icon,
251
- alt: "",
252
- width: "32",
253
- height: "32",
254
- className: "cedros-wallet-icon"
255
- }
256
- ),
257
- /* @__PURE__ */ r("span", { children: a.adapter.name })
258
- ]
259
- },
260
- a.adapter.name
261
- )) }) })
262
- ]
263
- }
264
- )
265
- }
266
- )
267
- ] });
268
- }
269
- function ce(e) {
270
- if (typeof window > "u")
271
- return !1;
272
- try {
273
- const t = require("@solana-mobile/wallet-standard-mobile"), l = e?.chains ?? ["solana:mainnet"], s = {
274
- appIdentity: {
275
- name: e?.name,
276
- uri: e?.uri,
277
- icon: e?.icon
278
- },
279
- chains: l
280
- };
281
- return typeof t.createDefaultAuthorizationCache == "function" && (s.authorizationCache = t.createDefaultAuthorizationCache()), typeof t.createDefaultChainSelector == "function" && (s.chainSelector = t.createDefaultChainSelector()), typeof t.createDefaultWalletNotFoundHandler == "function" && (s.onWalletNotFound = t.createDefaultWalletNotFoundHandler()), t.registerMwa(s), !0;
282
- } catch {
283
- return !1;
284
- }
285
- }
286
- export {
287
- le as S,
288
- ee as d,
289
- ce as r,
290
- X as u
291
- };
@@ -1 +0,0 @@
1
- {"version":3,"file":"mobileWalletAdapter-BulleEbi.js","sources":["../src/hooks/useSolanaAuth.ts","../src/utils/walletDetection.ts","../src/components/solana/SolanaLoginButton.tsx","../src/utils/mobileWalletAdapter.ts"],"sourcesContent":["import { useState, useCallback, useMemo } from 'react';\nimport { useCedrosLogin } from '../context/useCedrosLogin';\nimport { ApiClient, handleApiError } from '../utils/apiClient';\nimport { validateSolanaPublicKey } from '../utils/validation';\nimport type { AuthResponse, AuthError, ChallengeResponse } from '../types';\n\nexport interface UseSolanaAuthReturn {\n requestChallenge: (publicKey: string) => Promise<ChallengeResponse>;\n signIn: (publicKey: string, signature: string, message: string) => Promise<AuthResponse>;\n isLoading: boolean;\n error: AuthError | null;\n clearError: () => void;\n}\n\n/**\n * Hook for Solana wallet authentication.\n *\n * @example\n * ```tsx\n * function SolanaLogin() {\n * const { requestChallenge, signIn, isLoading } = useSolanaAuth();\n * const { publicKey, signMessage } = useWallet();\n *\n * const handleLogin = async () => {\n * const challenge = await requestChallenge(publicKey.toBase58());\n * const signature = await signMessage(new TextEncoder().encode(challenge.message));\n * const result = await signIn(\n * publicKey.toBase58(),\n * Buffer.from(signature).toString('base64'),\n * challenge.message\n * );\n * };\n * }\n * ```\n */\nexport function useSolanaAuth(): UseSolanaAuthReturn {\n const { config, _internal } = useCedrosLogin();\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<AuthError | null>(null);\n\n const apiClient = useMemo(\n () =>\n new ApiClient({\n baseUrl: config.serverUrl,\n timeoutMs: config.requestTimeout,\n retryAttempts: config.retryAttempts,\n }),\n [config.serverUrl, config.requestTimeout, config.retryAttempts]\n );\n\n const requestChallenge = useCallback(\n async (publicKey: string): Promise<ChallengeResponse> => {\n // Validate public key format before making API call\n if (!validateSolanaPublicKey(publicKey)) {\n const authError: AuthError = {\n code: 'INVALID_PUBLIC_KEY',\n message: 'Invalid Solana public key format',\n };\n setError(authError);\n throw authError;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const data = await apiClient.post<ChallengeResponse>(\n '/solana/challenge',\n { publicKey },\n { credentials: 'omit' }\n );\n return data;\n } catch (err) {\n const authError = handleApiError(err, 'Failed to get challenge');\n setError(authError);\n throw authError;\n } finally {\n setIsLoading(false);\n }\n },\n [apiClient]\n );\n\n const signIn = useCallback(\n async (publicKey: string, signature: string, message: string): Promise<AuthResponse> => {\n // Validate public key format before making API call\n if (!validateSolanaPublicKey(publicKey)) {\n const authError: AuthError = {\n code: 'INVALID_PUBLIC_KEY',\n message: 'Invalid Solana public key format',\n };\n setError(authError);\n throw authError;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const data = await apiClient.post<AuthResponse>('/solana', {\n publicKey,\n signature,\n message,\n });\n config.callbacks?.onLoginSuccess?.(data.user, 'solana');\n _internal?.handleLoginSuccess(data.user, data.tokens);\n return data;\n } catch (err) {\n const authError = handleApiError(err, 'Solana sign-in failed');\n setError(authError);\n throw authError;\n } finally {\n setIsLoading(false);\n }\n },\n [apiClient, config.callbacks, _internal]\n );\n\n const clearError = useCallback(() => setError(null), []);\n\n return {\n requestChallenge,\n signIn,\n isLoading,\n error,\n clearError,\n };\n}\n","/**\n * Wallet detection utilities for Solana browser wallets\n */\n\n/**\n * Type for window with potential Solana wallet extensions\n */\ninterface WindowWithWallets extends Window {\n phantom?: { solana?: unknown };\n solflare?: { solana?: unknown };\n backpack?: { solana?: unknown };\n glow?: { solana?: unknown };\n slope?: { solana?: unknown };\n sollet?: { solana?: unknown };\n coin98?: { solana?: unknown };\n clover?: { solana?: unknown };\n mathWallet?: { solana?: unknown };\n ledger?: { solana?: unknown };\n torus?: { solana?: unknown };\n walletconnect?: { solana?: unknown };\n solana?: unknown;\n}\n\n/**\n * Known Solana wallet provider names to check for on the window object\n */\ntype WalletProviderName = Exclude<keyof WindowWithWallets, keyof Window>;\n\nconst WALLET_PROVIDERS: WalletProviderName[] = [\n 'phantom',\n 'solflare',\n 'backpack',\n 'glow',\n 'slope',\n 'sollet',\n 'coin98',\n 'clover',\n 'mathWallet',\n 'ledger',\n 'torus',\n 'walletconnect',\n];\n\n/**\n * UI-9 FIX: Validates that a wallet provider object has expected Solana wallet methods.\n * Prevents spoofed wallet objects from being accepted.\n */\nfunction isValidSolanaProvider(provider: unknown): boolean {\n if (!provider || typeof provider !== 'object') return false;\n const wallet = provider as Record<string, unknown>;\n // Check for at least one expected wallet method/property\n // Real wallets have connect, signMessage, signTransaction, etc.\n return (\n typeof wallet.connect === 'function' ||\n typeof wallet.signMessage === 'function' ||\n typeof wallet.signTransaction === 'function' ||\n 'isConnected' in wallet\n );\n}\n\n/**\n * Check for wallets registered via the Wallet Standard protocol.\n * MWA (via @solana-mobile/wallet-standard-mobile) registers this way.\n */\nfunction hasWalletStandardWallets(): boolean {\n try {\n // The wallet-standard protocol exposes registered wallets via a global\n const walletStandard = (window as unknown as Record<string, unknown>)['__wallet_standard__'];\n if (\n walletStandard &&\n typeof walletStandard === 'object' &&\n 'get' in walletStandard &&\n typeof (walletStandard as Record<string, unknown>).get === 'function'\n ) {\n const wallets = (walletStandard as { get: () => unknown[] }).get();\n return Array.isArray(wallets) && wallets.length > 0;\n }\n } catch {\n // Not available\n }\n return false;\n}\n\n/**\n * Detects if any Solana wallet extensions are installed in the browser.\n * Checks for common wallet adapters like Phantom, Solflare, Backpack, etc.\n *\n * @returns true if at least one Solana wallet is detected\n *\n * @example\n * ```tsx\n * if (detectSolanaWallets()) {\n * // Show Solana login button\n * }\n * ```\n */\nexport function detectSolanaWallets(): boolean {\n if (typeof window === 'undefined') {\n return false;\n }\n\n const win = window as WindowWithWallets;\n\n // Check window object for wallet injections\n // UI-9: Validate wallet has expected methods to reject spoofed providers\n for (const provider of WALLET_PROVIDERS) {\n const walletObj = win[provider];\n if (\n walletObj &&\n typeof walletObj === 'object' &&\n 'solana' in walletObj &&\n isValidSolanaProvider(walletObj.solana)\n ) {\n return true;\n }\n }\n\n // Check for generic Solana provider (e.g., from some mobile wallet browsers)\n // UI-9: Also validate generic provider\n if (isValidSolanaProvider(win.solana)) {\n return true;\n }\n\n // Check for wallet-standard registered wallets (e.g., MWA via registerMwa())\n if (hasWalletStandardWallets()) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Returns list of detected Solana wallet names (for debugging/display)\n *\n * @returns Array of detected wallet provider names\n */\nexport function getDetectedWalletNames(): string[] {\n if (typeof window === 'undefined') {\n return [];\n }\n\n const win = window as WindowWithWallets;\n const detected: string[] = [];\n\n // UI-9: Use validation to reject spoofed providers\n for (const provider of WALLET_PROVIDERS) {\n const walletObj = win[provider];\n if (\n walletObj &&\n typeof walletObj === 'object' &&\n 'solana' in walletObj &&\n isValidSolanaProvider(walletObj.solana)\n ) {\n detected.push(provider);\n }\n }\n\n if (isValidSolanaProvider(win.solana) && detected.length === 0) {\n detected.push('solana');\n }\n\n return detected;\n}\n","import { useState, useEffect, useCallback, useRef } from 'react';\nimport { useSolanaAuth } from '../../hooks/useSolanaAuth';\nimport { LoadingSpinner } from '../shared/LoadingSpinner';\nimport { detectSolanaWallets } from '../../utils/walletDetection';\n\nexport interface SolanaLoginButtonProps {\n onSuccess?: () => void;\n onError?: (error: Error) => void;\n className?: string;\n variant?: 'default' | 'outline';\n size?: 'sm' | 'md' | 'lg';\n disabled?: boolean;\n /**\n * Hide the button if no Solana wallets are detected.\n * When true (default), button renders nothing if no wallets are installed.\n * When false, button always renders (useful for showing \"install wallet\" prompts).\n * @default true\n */\n hideIfNoWallet?: boolean;\n /**\n * Solana wallet adapter context. Pass this from @solana/wallet-adapter-react's useWallet().\n * The button will handle connection and signing automatically for a one-click experience.\n */\n walletContext?: {\n publicKey: { toBase58: () => string } | null;\n signMessage: ((message: Uint8Array) => Promise<Uint8Array>) | null;\n connected: boolean;\n connecting: boolean;\n connect: () => Promise<void>;\n wallet: { adapter: { name: string } } | null;\n select: (walletName: string) => void;\n wallets: Array<{\n adapter: {\n name: string;\n icon: string;\n readyState: string;\n };\n }>;\n };\n}\n\n/**\n * Solana wallet login button with one-click authentication.\n *\n * Handles wallet connection and message signing automatically.\n * If wallet is already connected, signs immediately.\n * If not connected, connects first then auto-signs.\n */\nexport function SolanaLoginButton({\n onSuccess,\n onError,\n className = '',\n variant = 'default',\n size = 'md',\n disabled = false,\n hideIfNoWallet = true,\n walletContext,\n}: SolanaLoginButtonProps) {\n const { requestChallenge, signIn, isLoading: isAuthLoading } = useSolanaAuth();\n const [showWalletSelector, setShowWalletSelector] = useState(false);\n const [pendingLogin, setPendingLogin] = useState(false);\n const [triggerConnect, setTriggerConnect] = useState(false);\n const isProcessingRef = useRef(false);\n\n // Detect wallets from browser (used when walletContext not provided)\n // Use lazy initializer to avoid re-detecting on every render\n const [browserHasWallets] = useState(() => detectSolanaWallets());\n\n const connected = walletContext?.connected ?? false;\n const connecting = walletContext?.connecting ?? false;\n const publicKey = walletContext?.publicKey;\n const signMessage = walletContext?.signMessage;\n const wallet = walletContext?.wallet;\n const wallets = walletContext?.wallets ?? [];\n\n // Get installed/ready wallets from wallet adapter context\n const installedWallets = wallets.filter(\n (w) => w.adapter.readyState === 'Installed' || w.adapter.readyState === 'Loadable'\n );\n\n // Determine if any wallets are available\n // If walletContext is provided, use its wallet list; otherwise use browser detection\n const hasWallets = walletContext ? installedWallets.length > 0 : browserHasWallets;\n\n // Execute the actual sign-in flow\n const executeSignIn = useCallback(async () => {\n if (isProcessingRef.current) return;\n if (!publicKey || !signMessage) {\n onError?.(new Error('Wallet not ready'));\n return;\n }\n\n isProcessingRef.current = true;\n try {\n const pubKeyString = publicKey.toBase58();\n\n // Request challenge from server\n const challenge = await requestChallenge(pubKeyString);\n\n // Sign the message with wallet\n const messageBytes = new TextEncoder().encode(challenge.message);\n const signatureBytes = await signMessage(messageBytes);\n\n // Validate signature\n if (!(signatureBytes instanceof Uint8Array) || signatureBytes.length === 0) {\n throw new Error('Wallet returned invalid signature');\n }\n\n // Encode signature\n let signature: string;\n try {\n signature = btoa(String.fromCharCode(...signatureBytes));\n } catch {\n throw new Error('Failed to encode signature');\n }\n\n // Authenticate with server\n await signIn(pubKeyString, signature, challenge.message);\n\n onSuccess?.();\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n onError?.(error);\n } finally {\n isProcessingRef.current = false;\n setPendingLogin(false);\n }\n }, [publicKey, signMessage, requestChallenge, signIn, onSuccess, onError]);\n\n // Auto-connect when wallet is selected and triggerConnect is set\n useEffect(() => {\n if (triggerConnect && wallet && !connected && !connecting && walletContext?.connect) {\n setTriggerConnect(false);\n walletContext.connect().catch((err) => {\n onError?.(err instanceof Error ? err : new Error(String(err)));\n setPendingLogin(false);\n });\n }\n }, [triggerConnect, wallet, connected, connecting, walletContext, onError]);\n\n // Auto-execute sign-in when connected with pending login\n // COMP-04: Catch unhandled rejections from executeSignIn (defensive - errors already\n // handled internally, but .catch() prevents unhandledrejection events)\n useEffect(() => {\n if (pendingLogin && connected && publicKey && signMessage && !isProcessingRef.current) {\n executeSignIn().catch(() => {\n /* Errors already passed to onError callback inside executeSignIn */\n });\n }\n }, [pendingLogin, connected, publicKey, signMessage, executeSignIn]);\n\n // Hide button if no wallets detected and hideIfNoWallet is true\n // Note: This must come after all hooks to satisfy React rules of hooks\n if (hideIfNoWallet && !hasWallets) {\n return null;\n }\n\n const handleClick = async () => {\n if (disabled || isAuthLoading || connecting) return;\n\n if (connected && publicKey && signMessage) {\n // Already connected - sign immediately\n setPendingLogin(true);\n await executeSignIn();\n } else if (wallet) {\n // Wallet selected but not connected - connect and queue login\n setPendingLogin(true);\n setTriggerConnect(true);\n } else if (installedWallets.length === 1) {\n // Only one wallet installed - auto-select it\n walletContext?.select(installedWallets[0].adapter.name);\n setPendingLogin(true);\n setTriggerConnect(true);\n } else if (installedWallets.length > 1) {\n // Multiple wallets - show selector\n setShowWalletSelector(true);\n } else {\n // No wallets - show error\n onError?.(\n new Error('No Solana wallet found. Please install Phantom or another Solana wallet.')\n );\n }\n };\n\n const handleSelectWallet = (walletName: string) => {\n setShowWalletSelector(false);\n walletContext?.select(walletName);\n setPendingLogin(true);\n setTriggerConnect(true);\n };\n\n const sizeClasses = {\n sm: 'cedros-button-sm',\n md: 'cedros-button-md',\n lg: 'cedros-button-lg',\n };\n\n const variantClasses = {\n default: 'cedros-button-social',\n outline: 'cedros-button-social-outline',\n };\n\n const isLoading = isAuthLoading || connecting || (pendingLogin && !connected);\n\n return (\n <>\n <button\n type=\"button\"\n className={`cedros-button ${variantClasses[variant]} ${sizeClasses[size]} ${className}`}\n onClick={handleClick}\n disabled={disabled || isLoading}\n aria-label=\"Continue with Solana\"\n >\n {isLoading ? (\n <LoadingSpinner size=\"sm\" />\n ) : (\n <svg\n className=\"cedros-button-icon\"\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 128 128\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path d=\"M25.38 96.04a4.35 4.35 0 0 1 3.07-1.27h91.68c1.93 0 2.9 2.34 1.54 3.7l-17.71 17.72a4.35 4.35 0 0 1-3.07 1.27H9.21c-1.93 0-2.9-2.34-1.54-3.7l17.71-17.72z\" />\n <path d=\"M25.38 11.81a4.47 4.47 0 0 1 3.07-1.27h91.68c1.93 0 2.9 2.34 1.54 3.7L103.96 31.96a4.35 4.35 0 0 1-3.07 1.27H9.21c-1.93 0-2.9-2.34-1.54-3.7L25.38 11.81z\" />\n <path d=\"M102.62 53.76a4.35 4.35 0 0 0-3.07-1.27H7.87c-1.93 0-2.9 2.34-1.54 3.7l17.71 17.72a4.35 4.35 0 0 0 3.07 1.27h91.68c1.93 0 2.9-2.34 1.54-3.7L102.62 53.76z\" />\n </svg>\n )}\n <span>Continue with Solana</span>\n </button>\n\n {/* Wallet Selector Modal */}\n {showWalletSelector && (\n <div\n className=\"cedros-modal-backdrop\"\n onClick={() => setShowWalletSelector(false)}\n role=\"presentation\"\n >\n <div\n className=\"cedros-modal cedros-wallet-selector\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"wallet-selector-title\"\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"cedros-modal-header\">\n <h2 id=\"wallet-selector-title\" className=\"cedros-modal-title\">\n Select Wallet\n </h2>\n <button\n type=\"button\"\n className=\"cedros-modal-close\"\n onClick={() => setShowWalletSelector(false)}\n aria-label=\"Close\"\n >\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M18 6L6 18M6 6l12 12\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n </button>\n </div>\n <div className=\"cedros-modal-content\">\n <div className=\"cedros-wallet-list\">\n {installedWallets.map((w) => (\n <button\n key={w.adapter.name}\n type=\"button\"\n className=\"cedros-wallet-option\"\n onClick={() => handleSelectWallet(w.adapter.name)}\n >\n <img\n src={w.adapter.icon}\n alt=\"\"\n width=\"32\"\n height=\"32\"\n className=\"cedros-wallet-icon\"\n />\n <span>{w.adapter.name}</span>\n </button>\n ))}\n </div>\n </div>\n </div>\n </div>\n )}\n </>\n );\n}\n","/**\n * Mobile Wallet Adapter (MWA) registration for web.\n *\n * On Android Chrome, MWA lets users authenticate with their installed Solana\n * wallet app (e.g., Phantom, Solflare) via Android Intents — no browser\n * extension needed.\n *\n * Once registered, MWA appears as a wallet option in the wallet adapter's\n * wallet list (alongside browser extension wallets). Users see it as\n * \"Use Installed Wallet\" in the wallet selector.\n *\n * Requires the optional peer dependency: @solana-mobile/wallet-standard-mobile\n *\n * @see https://docs.solanamobile.com/get-started/web/installation\n */\n\nexport interface MobileWalletConfig {\n /** App name shown in the wallet's authorization dialog */\n name?: string;\n /** App URI for identity verification */\n uri?: string;\n /** App icon path/URL shown in the wallet dialog */\n icon?: string;\n /** Solana cluster(s) to support. Default: ['solana:mainnet'] */\n chains?: string[];\n}\n\n/**\n * Register Mobile Wallet Adapter as a wallet-standard wallet.\n *\n * Call this once at your application root (before rendering). After registration,\n * MWA automatically appears as \"Use Installed Wallet\" for users browsing on\n * Android Chrome with a Solana wallet app installed.\n *\n * Must be called in a non-SSR context (browser only). For Next.js, call in a\n * Client Component with `'use client'`.\n *\n * @example\n * ```tsx\n * import { registerMobileWallet, CedrosLoginProvider } from '@cedros/login-react';\n *\n * // Register before provider mounts\n * registerMobileWallet({ name: 'My App', uri: 'https://myapp.com' });\n *\n * function App() {\n * return (\n * <CedrosLoginProvider config={{ serverUrl: '...' }}>\n * <LoginForm />\n * </CedrosLoginProvider>\n * );\n * }\n * ```\n *\n * @returns true if registration succeeded, false if package not installed or SSR\n */\nexport function registerMobileWallet(config?: MobileWalletConfig): boolean {\n if (typeof window === 'undefined') {\n return false;\n }\n\n try {\n // Dynamic import to avoid bundling the optional peer dep\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const mwa = require('@solana-mobile/wallet-standard-mobile');\n\n const chains = config?.chains ?? ['solana:mainnet'];\n\n const registrationConfig: Record<string, unknown> = {\n appIdentity: {\n name: config?.name,\n uri: config?.uri,\n icon: config?.icon,\n },\n chains,\n };\n\n // Use built-in defaults for optional config if available\n if (typeof mwa.createDefaultAuthorizationCache === 'function') {\n registrationConfig.authorizationCache = mwa.createDefaultAuthorizationCache();\n }\n if (typeof mwa.createDefaultChainSelector === 'function') {\n registrationConfig.chainSelector = mwa.createDefaultChainSelector();\n }\n if (typeof mwa.createDefaultWalletNotFoundHandler === 'function') {\n registrationConfig.onWalletNotFound = mwa.createDefaultWalletNotFoundHandler();\n }\n\n mwa.registerMwa(registrationConfig);\n return true;\n } catch {\n // @solana-mobile/wallet-standard-mobile not installed\n return false;\n }\n}\n"],"names":["useSolanaAuth","config","_internal","useCedrosLogin","isLoading","setIsLoading","useState","error","setError","apiClient","useMemo","ApiClient","requestChallenge","useCallback","publicKey","validateSolanaPublicKey","authError","err","handleApiError","signIn","signature","message","data","clearError","WALLET_PROVIDERS","isValidSolanaProvider","provider","wallet","hasWalletStandardWallets","walletStandard","wallets","detectSolanaWallets","win","walletObj","SolanaLoginButton","onSuccess","onError","className","variant","size","disabled","hideIfNoWallet","walletContext","isAuthLoading","showWalletSelector","setShowWalletSelector","pendingLogin","setPendingLogin","triggerConnect","setTriggerConnect","isProcessingRef","useRef","browserHasWallets","connected","connecting","signMessage","installedWallets","w","hasWallets","executeSignIn","pubKeyString","challenge","messageBytes","signatureBytes","useEffect","handleClick","handleSelectWallet","walletName","sizeClasses","variantClasses","jsxs","Fragment","jsx","LoadingSpinner","e","registerMobileWallet","mwa","chains","registrationConfig"],"mappings":";;;;;AAmCO,SAASA,IAAqC;AACnD,QAAM,EAAE,QAAAC,GAAQ,WAAAC,EAAA,IAAcC,EAAA,GACxB,CAACC,GAAWC,CAAY,IAAIC,EAAS,EAAK,GAC1C,CAACC,GAAOC,CAAQ,IAAIF,EAA2B,IAAI,GAEnDG,IAAYC;AAAA,IAChB,MACE,IAAIC,EAAU;AAAA,MACZ,SAASV,EAAO;AAAA,MAChB,WAAWA,EAAO;AAAA,MAClB,eAAeA,EAAO;AAAA,IAAA,CACvB;AAAA,IACH,CAACA,EAAO,WAAWA,EAAO,gBAAgBA,EAAO,aAAa;AAAA,EAAA,GAG1DW,IAAmBC;AAAA,IACvB,OAAOC,MAAkD;AAEvD,UAAI,CAACC,EAAwBD,CAAS,GAAG;AACvC,cAAME,IAAuB;AAAA,UAC3B,MAAM;AAAA,UACN,SAAS;AAAA,QAAA;AAEX,cAAAR,EAASQ,CAAS,GACZA;AAAA,MACR;AAEA,MAAAX,EAAa,EAAI,GACjBG,EAAS,IAAI;AAEb,UAAI;AAMF,eALa,MAAMC,EAAU;AAAA,UAC3B;AAAA,UACA,EAAE,WAAAK,EAAA;AAAA,UACF,EAAE,aAAa,OAAA;AAAA,QAAO;AAAA,MAG1B,SAASG,GAAK;AACZ,cAAMD,IAAYE,EAAeD,GAAK,yBAAyB;AAC/D,cAAAT,EAASQ,CAAS,GACZA;AAAA,MACR,UAAA;AACE,QAAAX,EAAa,EAAK;AAAA,MACpB;AAAA,IACF;AAAA,IACA,CAACI,CAAS;AAAA,EAAA,GAGNU,IAASN;AAAA,IACb,OAAOC,GAAmBM,GAAmBC,MAA2C;AAEtF,UAAI,CAACN,EAAwBD,CAAS,GAAG;AACvC,cAAME,IAAuB;AAAA,UAC3B,MAAM;AAAA,UACN,SAAS;AAAA,QAAA;AAEX,cAAAR,EAASQ,CAAS,GACZA;AAAA,MACR;AAEA,MAAAX,EAAa,EAAI,GACjBG,EAAS,IAAI;AAEb,UAAI;AACF,cAAMc,IAAO,MAAMb,EAAU,KAAmB,WAAW;AAAA,UACzD,WAAAK;AAAA,UACA,WAAAM;AAAA,UACA,SAAAC;AAAA,QAAA,CACD;AACD,eAAApB,EAAO,WAAW,iBAAiBqB,EAAK,MAAM,QAAQ,GACtDpB,GAAW,mBAAmBoB,EAAK,MAAMA,EAAK,MAAM,GAC7CA;AAAA,MACT,SAASL,GAAK;AACZ,cAAMD,IAAYE,EAAeD,GAAK,uBAAuB;AAC7D,cAAAT,EAASQ,CAAS,GACZA;AAAA,MACR,UAAA;AACE,QAAAX,EAAa,EAAK;AAAA,MACpB;AAAA,IACF;AAAA,IACA,CAACI,GAAWR,EAAO,WAAWC,CAAS;AAAA,EAAA,GAGnCqB,IAAaV,EAAY,MAAML,EAAS,IAAI,GAAG,CAAA,CAAE;AAEvD,SAAO;AAAA,IACL,kBAAAI;AAAA,IACA,QAAAO;AAAA,IACA,WAAAf;AAAA,IACA,OAAAG;AAAA,IACA,YAAAgB;AAAA,EAAA;AAEJ;ACnGA,MAAMC,IAAyC;AAAA,EAC7C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAMA,SAASC,EAAsBC,GAA4B;AACzD,MAAI,CAACA,KAAY,OAAOA,KAAa,SAAU,QAAO;AACtD,QAAMC,IAASD;AAGf,SACE,OAAOC,EAAO,WAAY,cAC1B,OAAOA,EAAO,eAAgB,cAC9B,OAAOA,EAAO,mBAAoB,cAClC,iBAAiBA;AAErB;AAMA,SAASC,IAAoC;AAC3C,MAAI;AAEF,UAAMC,IAAkB,OAA8C;AACtE,QACEA,KACA,OAAOA,KAAmB,YAC1B,SAASA,KACT,OAAQA,EAA2C,OAAQ,YAC3D;AACA,YAAMC,IAAWD,EAA4C,IAAA;AAC7D,aAAO,MAAM,QAAQC,CAAO,KAAKA,EAAQ,SAAS;AAAA,IACpD;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAeO,SAASC,KAA+B;AAC7C,MAAI,OAAO,SAAW;AACpB,WAAO;AAGT,QAAMC,IAAM;AAIZ,aAAWN,KAAYF,GAAkB;AACvC,UAAMS,IAAYD,EAAIN,CAAQ;AAC9B,QACEO,KACA,OAAOA,KAAc,YACrB,YAAYA,KACZR,EAAsBQ,EAAU,MAAM;AAEtC,aAAO;AAAA,EAEX;AASA,SALI,GAAAR,EAAsBO,EAAI,MAAM,KAKhCJ;AAKN;ACjFO,SAASM,GAAkB;AAAA,EAChC,WAAAC;AAAA,EACA,SAAAC;AAAA,EACA,WAAAC,IAAY;AAAA,EACZ,SAAAC,IAAU;AAAA,EACV,MAAAC,IAAO;AAAA,EACP,UAAAC,IAAW;AAAA,EACX,gBAAAC,IAAiB;AAAA,EACjB,eAAAC;AACF,GAA2B;AACzB,QAAM,EAAE,kBAAA9B,GAAkB,QAAAO,GAAQ,WAAWwB,EAAA,IAAkB3C,EAAA,GACzD,CAAC4C,GAAoBC,CAAqB,IAAIvC,EAAS,EAAK,GAC5D,CAACwC,GAAcC,CAAe,IAAIzC,EAAS,EAAK,GAChD,CAAC0C,GAAgBC,CAAiB,IAAI3C,EAAS,EAAK,GACpD4C,IAAkBC,EAAO,EAAK,GAI9B,CAACC,CAAiB,IAAI9C,EAAS,MAAMyB,IAAqB,GAE1DsB,IAAYX,GAAe,aAAa,IACxCY,IAAaZ,GAAe,cAAc,IAC1C5B,IAAY4B,GAAe,WAC3Ba,IAAcb,GAAe,aAC7Bf,IAASe,GAAe,QAIxBc,KAHUd,GAAe,WAAW,CAAA,GAGT;AAAA,IAC/B,CAACe,MAAMA,EAAE,QAAQ,eAAe,eAAeA,EAAE,QAAQ,eAAe;AAAA,EAAA,GAKpEC,IAAahB,IAAgBc,EAAiB,SAAS,IAAIJ,GAG3DO,IAAgB9C,EAAY,YAAY;AAC5C,QAAI,CAAAqC,EAAgB,SACpB;AAAA,UAAI,CAACpC,KAAa,CAACyC,GAAa;AAC9B,QAAAnB,IAAU,IAAI,MAAM,kBAAkB,CAAC;AACvC;AAAA,MACF;AAEA,MAAAc,EAAgB,UAAU;AAC1B,UAAI;AACF,cAAMU,IAAe9C,EAAU,SAAA,GAGzB+C,IAAY,MAAMjD,EAAiBgD,CAAY,GAG/CE,IAAe,IAAI,YAAA,EAAc,OAAOD,EAAU,OAAO,GACzDE,IAAiB,MAAMR,EAAYO,CAAY;AAGrD,YAAI,EAAEC,aAA0B,eAAeA,EAAe,WAAW;AACvE,gBAAM,IAAI,MAAM,mCAAmC;AAIrD,YAAI3C;AACJ,YAAI;AACF,UAAAA,IAAY,KAAK,OAAO,aAAa,GAAG2C,CAAc,CAAC;AAAA,QACzD,QAAQ;AACN,gBAAM,IAAI,MAAM,4BAA4B;AAAA,QAC9C;AAGA,cAAM5C,EAAOyC,GAAcxC,GAAWyC,EAAU,OAAO,GAEvD1B,IAAA;AAAA,MACF,SAASlB,GAAK;AACZ,cAAMV,IAAQU,aAAe,QAAQA,IAAM,IAAI,MAAM,OAAOA,CAAG,CAAC;AAChE,QAAAmB,IAAU7B,CAAK;AAAA,MACjB,UAAA;AACE,QAAA2C,EAAgB,UAAU,IAC1BH,EAAgB,EAAK;AAAA,MACvB;AAAA;AAAA,EACF,GAAG,CAACjC,GAAWyC,GAAa3C,GAAkBO,GAAQgB,GAAWC,CAAO,CAAC;AA0BzE,MAvBA4B,EAAU,MAAM;AACd,IAAIhB,KAAkBrB,KAAU,CAAC0B,KAAa,CAACC,KAAcZ,GAAe,YAC1EO,EAAkB,EAAK,GACvBP,EAAc,QAAA,EAAU,MAAM,CAACzB,MAAQ;AACrC,MAAAmB,IAAUnB,aAAe,QAAQA,IAAM,IAAI,MAAM,OAAOA,CAAG,CAAC,CAAC,GAC7D8B,EAAgB,EAAK;AAAA,IACvB,CAAC;AAAA,EAEL,GAAG,CAACC,GAAgBrB,GAAQ0B,GAAWC,GAAYZ,GAAeN,CAAO,CAAC,GAK1E4B,EAAU,MAAM;AACd,IAAIlB,KAAgBO,KAAavC,KAAayC,KAAe,CAACL,EAAgB,WAC5ES,EAAA,EAAgB,MAAM,MAAM;AAAA,IAE5B,CAAC;AAAA,EAEL,GAAG,CAACb,GAAcO,GAAWvC,GAAWyC,GAAaI,CAAa,CAAC,GAI/DlB,KAAkB,CAACiB;AACrB,WAAO;AAGT,QAAMO,IAAc,YAAY;AAC9B,IAAIzB,KAAYG,KAAiBW,MAE7BD,KAAavC,KAAayC,KAE5BR,EAAgB,EAAI,GACpB,MAAMY,EAAA,KACGhC,KAEToB,EAAgB,EAAI,GACpBE,EAAkB,EAAI,KACbO,EAAiB,WAAW,KAErCd,GAAe,OAAOc,EAAiB,CAAC,EAAE,QAAQ,IAAI,GACtDT,EAAgB,EAAI,GACpBE,EAAkB,EAAI,KACbO,EAAiB,SAAS,IAEnCX,EAAsB,EAAI,IAG1BT;AAAA,MACE,IAAI,MAAM,0EAA0E;AAAA,IAAA;AAAA,EAG1F,GAEM8B,IAAqB,CAACC,MAAuB;AACjD,IAAAtB,EAAsB,EAAK,GAC3BH,GAAe,OAAOyB,CAAU,GAChCpB,EAAgB,EAAI,GACpBE,EAAkB,EAAI;AAAA,EACxB,GAEMmB,IAAc;AAAA,IAClB,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,EAAA,GAGAC,IAAiB;AAAA,IACrB,SAAS;AAAA,IACT,SAAS;AAAA,EAAA,GAGLjE,IAAYuC,KAAiBW,KAAeR,KAAgB,CAACO;AAEnE,SACE,gBAAAiB,EAAAC,GAAA,EACE,UAAA;AAAA,IAAA,gBAAAD;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAW,iBAAiBD,EAAe/B,CAAO,CAAC,IAAI8B,EAAY7B,CAAI,CAAC,IAAIF,CAAS;AAAA,QACrF,SAAS4B;AAAA,QACT,UAAUzB,KAAYpC;AAAA,QACtB,cAAW;AAAA,QAEV,UAAA;AAAA,UAAAA,IACC,gBAAAoE,EAACC,GAAA,EAAe,MAAK,KAAA,CAAK,IAE1B,gBAAAH;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAU;AAAA,cACV,OAAM;AAAA,cACN,QAAO;AAAA,cACP,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,eAAY;AAAA,cAEZ,UAAA;AAAA,gBAAA,gBAAAE,EAAC,QAAA,EAAK,GAAE,2JAAA,CAA2J;AAAA,gBACnK,gBAAAA,EAAC,QAAA,EAAK,GAAE,2JAAA,CAA2J;AAAA,gBACnK,gBAAAA,EAAC,QAAA,EAAK,GAAE,4JAAA,CAA4J;AAAA,cAAA;AAAA,YAAA;AAAA,UAAA;AAAA,UAGxK,gBAAAA,EAAC,UAAK,UAAA,uBAAA,CAAoB;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,IAI3B5B,KACC,gBAAA4B;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAU;AAAA,QACV,SAAS,MAAM3B,EAAsB,EAAK;AAAA,QAC1C,MAAK;AAAA,QAEL,UAAA,gBAAAyB;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAU;AAAA,YACV,MAAK;AAAA,YACL,cAAW;AAAA,YACX,mBAAgB;AAAA,YAChB,SAAS,CAACI,MAAMA,EAAE,gBAAA;AAAA,YAElB,UAAA;AAAA,cAAA,gBAAAJ,EAAC,OAAA,EAAI,WAAU,uBACb,UAAA;AAAA,gBAAA,gBAAAE,EAAC,MAAA,EAAG,IAAG,yBAAwB,WAAU,sBAAqB,UAAA,iBAE9D;AAAA,gBACA,gBAAAA;AAAA,kBAAC;AAAA,kBAAA;AAAA,oBACC,MAAK;AAAA,oBACL,WAAU;AAAA,oBACV,SAAS,MAAM3B,EAAsB,EAAK;AAAA,oBAC1C,cAAW;AAAA,oBAEX,UAAA,gBAAA2B,EAAC,OAAA,EAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,eAAY,QACtE,UAAA,gBAAAA;AAAA,sBAAC;AAAA,sBAAA;AAAA,wBACC,GAAE;AAAA,wBACF,QAAO;AAAA,wBACP,aAAY;AAAA,wBACZ,eAAc;AAAA,sBAAA;AAAA,oBAAA,EAChB,CACF;AAAA,kBAAA;AAAA,gBAAA;AAAA,cACF,GACF;AAAA,cACA,gBAAAA,EAAC,OAAA,EAAI,WAAU,wBACb,UAAA,gBAAAA,EAAC,OAAA,EAAI,WAAU,sBACZ,UAAAhB,EAAiB,IAAI,CAACC,MACrB,gBAAAa;AAAA,gBAAC;AAAA,gBAAA;AAAA,kBAEC,MAAK;AAAA,kBACL,WAAU;AAAA,kBACV,SAAS,MAAMJ,EAAmBT,EAAE,QAAQ,IAAI;AAAA,kBAEhD,UAAA;AAAA,oBAAA,gBAAAe;AAAA,sBAAC;AAAA,sBAAA;AAAA,wBACC,KAAKf,EAAE,QAAQ;AAAA,wBACf,KAAI;AAAA,wBACJ,OAAM;AAAA,wBACN,QAAO;AAAA,wBACP,WAAU;AAAA,sBAAA;AAAA,oBAAA;AAAA,oBAEZ,gBAAAe,EAAC,QAAA,EAAM,UAAAf,EAAE,QAAQ,KAAA,CAAK;AAAA,kBAAA;AAAA,gBAAA;AAAA,gBAZjBA,EAAE,QAAQ;AAAA,cAAA,CAclB,GACH,EAAA,CACF;AAAA,YAAA;AAAA,UAAA;AAAA,QAAA;AAAA,MACF;AAAA,IAAA;AAAA,EACF,GAEJ;AAEJ;AC7OO,SAASkB,GAAqB1E,GAAsC;AACzE,MAAI,OAAO,SAAW;AACpB,WAAO;AAGT,MAAI;AAGF,UAAM2E,IAAM,QAAQ,uCAAuC,GAErDC,IAAS5E,GAAQ,UAAU,CAAC,gBAAgB,GAE5C6E,IAA8C;AAAA,MAClD,aAAa;AAAA,QACX,MAAM7E,GAAQ;AAAA,QACd,KAAKA,GAAQ;AAAA,QACb,MAAMA,GAAQ;AAAA,MAAA;AAAA,MAEhB,QAAA4E;AAAA,IAAA;AAIF,WAAI,OAAOD,EAAI,mCAAoC,eACjDE,EAAmB,qBAAqBF,EAAI,gCAAA,IAE1C,OAAOA,EAAI,8BAA+B,eAC5CE,EAAmB,gBAAgBF,EAAI,2BAAA,IAErC,OAAOA,EAAI,sCAAuC,eACpDE,EAAmB,mBAAmBF,EAAI,mCAAA,IAG5CA,EAAI,YAAYE,CAAkB,GAC3B;AAAA,EACT,QAAQ;AAEN,WAAO;AAAA,EACT;AACF;"}
@@ -1 +0,0 @@
1
- "use strict";const n=require("react/jsx-runtime"),r=require("react"),W=require("./useCedrosLogin-C9MrcZvh.cjs"),P=require("./validation-BuGQrA-K.cjs"),R=require("./LoadingSpinner-d6sSxgQN.cjs");function q(){const{config:e,_internal:t}=W.useCedrosLogin(),[c,o]=r.useState(!1),[v,i]=r.useState(null),g=r.useMemo(()=>new W.ApiClient({baseUrl:e.serverUrl,timeoutMs:e.requestTimeout,retryAttempts:e.retryAttempts}),[e.serverUrl,e.requestTimeout,e.retryAttempts]),s=r.useCallback(async h=>{if(!P.validateSolanaPublicKey(h)){const u={code:"INVALID_PUBLIC_KEY",message:"Invalid Solana public key format"};throw i(u),u}o(!0),i(null);try{return await g.post("/solana/challenge",{publicKey:h},{credentials:"omit"})}catch(u){const d=W.handleApiError(u,"Failed to get challenge");throw i(d),d}finally{o(!1)}},[g]),S=r.useCallback(async(h,u,d)=>{if(!P.validateSolanaPublicKey(h)){const l={code:"INVALID_PUBLIC_KEY",message:"Invalid Solana public key format"};throw i(l),l}o(!0),i(null);try{const l=await g.post("/solana",{publicKey:h,signature:u,message:d});return e.callbacks?.onLoginSuccess?.(l.user,"solana"),t?.handleLoginSuccess(l.user,l.tokens),l}catch(l){const f=W.handleApiError(l,"Solana sign-in failed");throw i(f),f}finally{o(!1)}},[g,e.callbacks,t]),b=r.useCallback(()=>i(null),[]);return{requestChallenge:s,signIn:S,isLoading:c,error:v,clearError:b}}const V=["phantom","solflare","backpack","glow","slope","sollet","coin98","clover","mathWallet","ledger","torus","walletconnect"];function _(e){if(!e||typeof e!="object")return!1;const t=e;return typeof t.connect=="function"||typeof t.signMessage=="function"||typeof t.signTransaction=="function"||"isConnected"in t}function $(){try{const e=window.__wallet_standard__;if(e&&typeof e=="object"&&"get"in e&&typeof e.get=="function"){const t=e.get();return Array.isArray(t)&&t.length>0}}catch{}return!1}function B(){if(typeof window>"u")return!1;const e=window;for(const t of V){const c=e[t];if(c&&typeof c=="object"&&"solana"in c&&_(c.solana))return!0}return!!(_(e.solana)||$())}function O({onSuccess:e,onError:t,className:c="",variant:o="default",size:v="md",disabled:i=!1,hideIfNoWallet:g=!0,walletContext:s}){const{requestChallenge:S,signIn:b,isLoading:h}=q(),[u,d]=r.useState(!1),[l,f]=r.useState(!1),[I,L]=r.useState(!1),j=r.useRef(!1),[D]=r.useState(()=>B()),m=s?.connected??!1,C=s?.connecting??!1,p=s?.publicKey,w=s?.signMessage,E=s?.wallet,y=(s?.wallets??[]).filter(a=>a.adapter.readyState==="Installed"||a.adapter.readyState==="Loadable"),z=s?y.length>0:D,A=r.useCallback(async()=>{if(!j.current){if(!p||!w){t?.(new Error("Wallet not ready"));return}j.current=!0;try{const a=p.toBase58(),k=await S(a),K=new TextEncoder().encode(k.message),N=await w(K);if(!(N instanceof Uint8Array)||N.length===0)throw new Error("Wallet returned invalid signature");let M;try{M=btoa(String.fromCharCode(...N))}catch{throw new Error("Failed to encode signature")}await b(a,M,k.message),e?.()}catch(a){const k=a instanceof Error?a:new Error(String(a));t?.(k)}finally{j.current=!1,f(!1)}}},[p,w,S,b,e,t]);if(r.useEffect(()=>{I&&E&&!m&&!C&&s?.connect&&(L(!1),s.connect().catch(a=>{t?.(a instanceof Error?a:new Error(String(a))),f(!1)}))},[I,E,m,C,s,t]),r.useEffect(()=>{l&&m&&p&&w&&!j.current&&A().catch(()=>{})},[l,m,p,w,A]),g&&!z)return null;const F=async()=>{i||h||C||(m&&p&&w?(f(!0),await A()):E?(f(!0),L(!0)):y.length===1?(s?.select(y[0].adapter.name),f(!0),L(!0)):y.length>1?d(!0):t?.(new Error("No Solana wallet found. Please install Phantom or another Solana wallet.")))},H=a=>{d(!1),s?.select(a),f(!0),L(!0)},T={sm:"cedros-button-sm",md:"cedros-button-md",lg:"cedros-button-lg"},U={default:"cedros-button-social",outline:"cedros-button-social-outline"},x=h||C||l&&!m;return n.jsxs(n.Fragment,{children:[n.jsxs("button",{type:"button",className:`cedros-button ${U[o]} ${T[v]} ${c}`,onClick:F,disabled:i||x,"aria-label":"Continue with Solana",children:[x?n.jsx(R.LoadingSpinner,{size:"sm"}):n.jsxs("svg",{className:"cedros-button-icon",width:"18",height:"18",viewBox:"0 0 128 128",fill:"currentColor","aria-hidden":"true",children:[n.jsx("path",{d:"M25.38 96.04a4.35 4.35 0 0 1 3.07-1.27h91.68c1.93 0 2.9 2.34 1.54 3.7l-17.71 17.72a4.35 4.35 0 0 1-3.07 1.27H9.21c-1.93 0-2.9-2.34-1.54-3.7l17.71-17.72z"}),n.jsx("path",{d:"M25.38 11.81a4.47 4.47 0 0 1 3.07-1.27h91.68c1.93 0 2.9 2.34 1.54 3.7L103.96 31.96a4.35 4.35 0 0 1-3.07 1.27H9.21c-1.93 0-2.9-2.34-1.54-3.7L25.38 11.81z"}),n.jsx("path",{d:"M102.62 53.76a4.35 4.35 0 0 0-3.07-1.27H7.87c-1.93 0-2.9 2.34-1.54 3.7l17.71 17.72a4.35 4.35 0 0 0 3.07 1.27h91.68c1.93 0 2.9-2.34 1.54-3.7L102.62 53.76z"})]}),n.jsx("span",{children:"Continue with Solana"})]}),u&&n.jsx("div",{className:"cedros-modal-backdrop",onClick:()=>d(!1),role:"presentation",children:n.jsxs("div",{className:"cedros-modal cedros-wallet-selector",role:"dialog","aria-modal":"true","aria-labelledby":"wallet-selector-title",onClick:a=>a.stopPropagation(),children:[n.jsxs("div",{className:"cedros-modal-header",children:[n.jsx("h2",{id:"wallet-selector-title",className:"cedros-modal-title",children:"Select Wallet"}),n.jsx("button",{type:"button",className:"cedros-modal-close",onClick:()=>d(!1),"aria-label":"Close",children:n.jsx("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none","aria-hidden":"true",children:n.jsx("path",{d:"M18 6L6 18M6 6l12 12",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round"})})})]}),n.jsx("div",{className:"cedros-modal-content",children:n.jsx("div",{className:"cedros-wallet-list",children:y.map(a=>n.jsxs("button",{type:"button",className:"cedros-wallet-option",onClick:()=>H(a.adapter.name),children:[n.jsx("img",{src:a.adapter.icon,alt:"",width:"32",height:"32",className:"cedros-wallet-icon"}),n.jsx("span",{children:a.adapter.name})]},a.adapter.name))})})]})})]})}function Y(e){if(typeof window>"u")return!1;try{const t=require("@solana-mobile/wallet-standard-mobile"),c=e?.chains??["solana:mainnet"],o={appIdentity:{name:e?.name,uri:e?.uri,icon:e?.icon},chains:c};return typeof t.createDefaultAuthorizationCache=="function"&&(o.authorizationCache=t.createDefaultAuthorizationCache()),typeof t.createDefaultChainSelector=="function"&&(o.chainSelector=t.createDefaultChainSelector()),typeof t.createDefaultWalletNotFoundHandler=="function"&&(o.onWalletNotFound=t.createDefaultWalletNotFoundHandler()),t.registerMwa(o),!0}catch{return!1}}exports.SolanaLoginButton=O;exports.detectSolanaWallets=B;exports.registerMobileWallet=Y;exports.useSolanaAuth=q;
@@ -1 +0,0 @@
1
- {"version":3,"file":"mobileWalletAdapter-DOdmFAk0.cjs","sources":["../src/hooks/useSolanaAuth.ts","../src/utils/walletDetection.ts","../src/components/solana/SolanaLoginButton.tsx","../src/utils/mobileWalletAdapter.ts"],"sourcesContent":["import { useState, useCallback, useMemo } from 'react';\nimport { useCedrosLogin } from '../context/useCedrosLogin';\nimport { ApiClient, handleApiError } from '../utils/apiClient';\nimport { validateSolanaPublicKey } from '../utils/validation';\nimport type { AuthResponse, AuthError, ChallengeResponse } from '../types';\n\nexport interface UseSolanaAuthReturn {\n requestChallenge: (publicKey: string) => Promise<ChallengeResponse>;\n signIn: (publicKey: string, signature: string, message: string) => Promise<AuthResponse>;\n isLoading: boolean;\n error: AuthError | null;\n clearError: () => void;\n}\n\n/**\n * Hook for Solana wallet authentication.\n *\n * @example\n * ```tsx\n * function SolanaLogin() {\n * const { requestChallenge, signIn, isLoading } = useSolanaAuth();\n * const { publicKey, signMessage } = useWallet();\n *\n * const handleLogin = async () => {\n * const challenge = await requestChallenge(publicKey.toBase58());\n * const signature = await signMessage(new TextEncoder().encode(challenge.message));\n * const result = await signIn(\n * publicKey.toBase58(),\n * Buffer.from(signature).toString('base64'),\n * challenge.message\n * );\n * };\n * }\n * ```\n */\nexport function useSolanaAuth(): UseSolanaAuthReturn {\n const { config, _internal } = useCedrosLogin();\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<AuthError | null>(null);\n\n const apiClient = useMemo(\n () =>\n new ApiClient({\n baseUrl: config.serverUrl,\n timeoutMs: config.requestTimeout,\n retryAttempts: config.retryAttempts,\n }),\n [config.serverUrl, config.requestTimeout, config.retryAttempts]\n );\n\n const requestChallenge = useCallback(\n async (publicKey: string): Promise<ChallengeResponse> => {\n // Validate public key format before making API call\n if (!validateSolanaPublicKey(publicKey)) {\n const authError: AuthError = {\n code: 'INVALID_PUBLIC_KEY',\n message: 'Invalid Solana public key format',\n };\n setError(authError);\n throw authError;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const data = await apiClient.post<ChallengeResponse>(\n '/solana/challenge',\n { publicKey },\n { credentials: 'omit' }\n );\n return data;\n } catch (err) {\n const authError = handleApiError(err, 'Failed to get challenge');\n setError(authError);\n throw authError;\n } finally {\n setIsLoading(false);\n }\n },\n [apiClient]\n );\n\n const signIn = useCallback(\n async (publicKey: string, signature: string, message: string): Promise<AuthResponse> => {\n // Validate public key format before making API call\n if (!validateSolanaPublicKey(publicKey)) {\n const authError: AuthError = {\n code: 'INVALID_PUBLIC_KEY',\n message: 'Invalid Solana public key format',\n };\n setError(authError);\n throw authError;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const data = await apiClient.post<AuthResponse>('/solana', {\n publicKey,\n signature,\n message,\n });\n config.callbacks?.onLoginSuccess?.(data.user, 'solana');\n _internal?.handleLoginSuccess(data.user, data.tokens);\n return data;\n } catch (err) {\n const authError = handleApiError(err, 'Solana sign-in failed');\n setError(authError);\n throw authError;\n } finally {\n setIsLoading(false);\n }\n },\n [apiClient, config.callbacks, _internal]\n );\n\n const clearError = useCallback(() => setError(null), []);\n\n return {\n requestChallenge,\n signIn,\n isLoading,\n error,\n clearError,\n };\n}\n","/**\n * Wallet detection utilities for Solana browser wallets\n */\n\n/**\n * Type for window with potential Solana wallet extensions\n */\ninterface WindowWithWallets extends Window {\n phantom?: { solana?: unknown };\n solflare?: { solana?: unknown };\n backpack?: { solana?: unknown };\n glow?: { solana?: unknown };\n slope?: { solana?: unknown };\n sollet?: { solana?: unknown };\n coin98?: { solana?: unknown };\n clover?: { solana?: unknown };\n mathWallet?: { solana?: unknown };\n ledger?: { solana?: unknown };\n torus?: { solana?: unknown };\n walletconnect?: { solana?: unknown };\n solana?: unknown;\n}\n\n/**\n * Known Solana wallet provider names to check for on the window object\n */\ntype WalletProviderName = Exclude<keyof WindowWithWallets, keyof Window>;\n\nconst WALLET_PROVIDERS: WalletProviderName[] = [\n 'phantom',\n 'solflare',\n 'backpack',\n 'glow',\n 'slope',\n 'sollet',\n 'coin98',\n 'clover',\n 'mathWallet',\n 'ledger',\n 'torus',\n 'walletconnect',\n];\n\n/**\n * UI-9 FIX: Validates that a wallet provider object has expected Solana wallet methods.\n * Prevents spoofed wallet objects from being accepted.\n */\nfunction isValidSolanaProvider(provider: unknown): boolean {\n if (!provider || typeof provider !== 'object') return false;\n const wallet = provider as Record<string, unknown>;\n // Check for at least one expected wallet method/property\n // Real wallets have connect, signMessage, signTransaction, etc.\n return (\n typeof wallet.connect === 'function' ||\n typeof wallet.signMessage === 'function' ||\n typeof wallet.signTransaction === 'function' ||\n 'isConnected' in wallet\n );\n}\n\n/**\n * Check for wallets registered via the Wallet Standard protocol.\n * MWA (via @solana-mobile/wallet-standard-mobile) registers this way.\n */\nfunction hasWalletStandardWallets(): boolean {\n try {\n // The wallet-standard protocol exposes registered wallets via a global\n const walletStandard = (window as unknown as Record<string, unknown>)['__wallet_standard__'];\n if (\n walletStandard &&\n typeof walletStandard === 'object' &&\n 'get' in walletStandard &&\n typeof (walletStandard as Record<string, unknown>).get === 'function'\n ) {\n const wallets = (walletStandard as { get: () => unknown[] }).get();\n return Array.isArray(wallets) && wallets.length > 0;\n }\n } catch {\n // Not available\n }\n return false;\n}\n\n/**\n * Detects if any Solana wallet extensions are installed in the browser.\n * Checks for common wallet adapters like Phantom, Solflare, Backpack, etc.\n *\n * @returns true if at least one Solana wallet is detected\n *\n * @example\n * ```tsx\n * if (detectSolanaWallets()) {\n * // Show Solana login button\n * }\n * ```\n */\nexport function detectSolanaWallets(): boolean {\n if (typeof window === 'undefined') {\n return false;\n }\n\n const win = window as WindowWithWallets;\n\n // Check window object for wallet injections\n // UI-9: Validate wallet has expected methods to reject spoofed providers\n for (const provider of WALLET_PROVIDERS) {\n const walletObj = win[provider];\n if (\n walletObj &&\n typeof walletObj === 'object' &&\n 'solana' in walletObj &&\n isValidSolanaProvider(walletObj.solana)\n ) {\n return true;\n }\n }\n\n // Check for generic Solana provider (e.g., from some mobile wallet browsers)\n // UI-9: Also validate generic provider\n if (isValidSolanaProvider(win.solana)) {\n return true;\n }\n\n // Check for wallet-standard registered wallets (e.g., MWA via registerMwa())\n if (hasWalletStandardWallets()) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Returns list of detected Solana wallet names (for debugging/display)\n *\n * @returns Array of detected wallet provider names\n */\nexport function getDetectedWalletNames(): string[] {\n if (typeof window === 'undefined') {\n return [];\n }\n\n const win = window as WindowWithWallets;\n const detected: string[] = [];\n\n // UI-9: Use validation to reject spoofed providers\n for (const provider of WALLET_PROVIDERS) {\n const walletObj = win[provider];\n if (\n walletObj &&\n typeof walletObj === 'object' &&\n 'solana' in walletObj &&\n isValidSolanaProvider(walletObj.solana)\n ) {\n detected.push(provider);\n }\n }\n\n if (isValidSolanaProvider(win.solana) && detected.length === 0) {\n detected.push('solana');\n }\n\n return detected;\n}\n","import { useState, useEffect, useCallback, useRef } from 'react';\nimport { useSolanaAuth } from '../../hooks/useSolanaAuth';\nimport { LoadingSpinner } from '../shared/LoadingSpinner';\nimport { detectSolanaWallets } from '../../utils/walletDetection';\n\nexport interface SolanaLoginButtonProps {\n onSuccess?: () => void;\n onError?: (error: Error) => void;\n className?: string;\n variant?: 'default' | 'outline';\n size?: 'sm' | 'md' | 'lg';\n disabled?: boolean;\n /**\n * Hide the button if no Solana wallets are detected.\n * When true (default), button renders nothing if no wallets are installed.\n * When false, button always renders (useful for showing \"install wallet\" prompts).\n * @default true\n */\n hideIfNoWallet?: boolean;\n /**\n * Solana wallet adapter context. Pass this from @solana/wallet-adapter-react's useWallet().\n * The button will handle connection and signing automatically for a one-click experience.\n */\n walletContext?: {\n publicKey: { toBase58: () => string } | null;\n signMessage: ((message: Uint8Array) => Promise<Uint8Array>) | null;\n connected: boolean;\n connecting: boolean;\n connect: () => Promise<void>;\n wallet: { adapter: { name: string } } | null;\n select: (walletName: string) => void;\n wallets: Array<{\n adapter: {\n name: string;\n icon: string;\n readyState: string;\n };\n }>;\n };\n}\n\n/**\n * Solana wallet login button with one-click authentication.\n *\n * Handles wallet connection and message signing automatically.\n * If wallet is already connected, signs immediately.\n * If not connected, connects first then auto-signs.\n */\nexport function SolanaLoginButton({\n onSuccess,\n onError,\n className = '',\n variant = 'default',\n size = 'md',\n disabled = false,\n hideIfNoWallet = true,\n walletContext,\n}: SolanaLoginButtonProps) {\n const { requestChallenge, signIn, isLoading: isAuthLoading } = useSolanaAuth();\n const [showWalletSelector, setShowWalletSelector] = useState(false);\n const [pendingLogin, setPendingLogin] = useState(false);\n const [triggerConnect, setTriggerConnect] = useState(false);\n const isProcessingRef = useRef(false);\n\n // Detect wallets from browser (used when walletContext not provided)\n // Use lazy initializer to avoid re-detecting on every render\n const [browserHasWallets] = useState(() => detectSolanaWallets());\n\n const connected = walletContext?.connected ?? false;\n const connecting = walletContext?.connecting ?? false;\n const publicKey = walletContext?.publicKey;\n const signMessage = walletContext?.signMessage;\n const wallet = walletContext?.wallet;\n const wallets = walletContext?.wallets ?? [];\n\n // Get installed/ready wallets from wallet adapter context\n const installedWallets = wallets.filter(\n (w) => w.adapter.readyState === 'Installed' || w.adapter.readyState === 'Loadable'\n );\n\n // Determine if any wallets are available\n // If walletContext is provided, use its wallet list; otherwise use browser detection\n const hasWallets = walletContext ? installedWallets.length > 0 : browserHasWallets;\n\n // Execute the actual sign-in flow\n const executeSignIn = useCallback(async () => {\n if (isProcessingRef.current) return;\n if (!publicKey || !signMessage) {\n onError?.(new Error('Wallet not ready'));\n return;\n }\n\n isProcessingRef.current = true;\n try {\n const pubKeyString = publicKey.toBase58();\n\n // Request challenge from server\n const challenge = await requestChallenge(pubKeyString);\n\n // Sign the message with wallet\n const messageBytes = new TextEncoder().encode(challenge.message);\n const signatureBytes = await signMessage(messageBytes);\n\n // Validate signature\n if (!(signatureBytes instanceof Uint8Array) || signatureBytes.length === 0) {\n throw new Error('Wallet returned invalid signature');\n }\n\n // Encode signature\n let signature: string;\n try {\n signature = btoa(String.fromCharCode(...signatureBytes));\n } catch {\n throw new Error('Failed to encode signature');\n }\n\n // Authenticate with server\n await signIn(pubKeyString, signature, challenge.message);\n\n onSuccess?.();\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n onError?.(error);\n } finally {\n isProcessingRef.current = false;\n setPendingLogin(false);\n }\n }, [publicKey, signMessage, requestChallenge, signIn, onSuccess, onError]);\n\n // Auto-connect when wallet is selected and triggerConnect is set\n useEffect(() => {\n if (triggerConnect && wallet && !connected && !connecting && walletContext?.connect) {\n setTriggerConnect(false);\n walletContext.connect().catch((err) => {\n onError?.(err instanceof Error ? err : new Error(String(err)));\n setPendingLogin(false);\n });\n }\n }, [triggerConnect, wallet, connected, connecting, walletContext, onError]);\n\n // Auto-execute sign-in when connected with pending login\n // COMP-04: Catch unhandled rejections from executeSignIn (defensive - errors already\n // handled internally, but .catch() prevents unhandledrejection events)\n useEffect(() => {\n if (pendingLogin && connected && publicKey && signMessage && !isProcessingRef.current) {\n executeSignIn().catch(() => {\n /* Errors already passed to onError callback inside executeSignIn */\n });\n }\n }, [pendingLogin, connected, publicKey, signMessage, executeSignIn]);\n\n // Hide button if no wallets detected and hideIfNoWallet is true\n // Note: This must come after all hooks to satisfy React rules of hooks\n if (hideIfNoWallet && !hasWallets) {\n return null;\n }\n\n const handleClick = async () => {\n if (disabled || isAuthLoading || connecting) return;\n\n if (connected && publicKey && signMessage) {\n // Already connected - sign immediately\n setPendingLogin(true);\n await executeSignIn();\n } else if (wallet) {\n // Wallet selected but not connected - connect and queue login\n setPendingLogin(true);\n setTriggerConnect(true);\n } else if (installedWallets.length === 1) {\n // Only one wallet installed - auto-select it\n walletContext?.select(installedWallets[0].adapter.name);\n setPendingLogin(true);\n setTriggerConnect(true);\n } else if (installedWallets.length > 1) {\n // Multiple wallets - show selector\n setShowWalletSelector(true);\n } else {\n // No wallets - show error\n onError?.(\n new Error('No Solana wallet found. Please install Phantom or another Solana wallet.')\n );\n }\n };\n\n const handleSelectWallet = (walletName: string) => {\n setShowWalletSelector(false);\n walletContext?.select(walletName);\n setPendingLogin(true);\n setTriggerConnect(true);\n };\n\n const sizeClasses = {\n sm: 'cedros-button-sm',\n md: 'cedros-button-md',\n lg: 'cedros-button-lg',\n };\n\n const variantClasses = {\n default: 'cedros-button-social',\n outline: 'cedros-button-social-outline',\n };\n\n const isLoading = isAuthLoading || connecting || (pendingLogin && !connected);\n\n return (\n <>\n <button\n type=\"button\"\n className={`cedros-button ${variantClasses[variant]} ${sizeClasses[size]} ${className}`}\n onClick={handleClick}\n disabled={disabled || isLoading}\n aria-label=\"Continue with Solana\"\n >\n {isLoading ? (\n <LoadingSpinner size=\"sm\" />\n ) : (\n <svg\n className=\"cedros-button-icon\"\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 128 128\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path d=\"M25.38 96.04a4.35 4.35 0 0 1 3.07-1.27h91.68c1.93 0 2.9 2.34 1.54 3.7l-17.71 17.72a4.35 4.35 0 0 1-3.07 1.27H9.21c-1.93 0-2.9-2.34-1.54-3.7l17.71-17.72z\" />\n <path d=\"M25.38 11.81a4.47 4.47 0 0 1 3.07-1.27h91.68c1.93 0 2.9 2.34 1.54 3.7L103.96 31.96a4.35 4.35 0 0 1-3.07 1.27H9.21c-1.93 0-2.9-2.34-1.54-3.7L25.38 11.81z\" />\n <path d=\"M102.62 53.76a4.35 4.35 0 0 0-3.07-1.27H7.87c-1.93 0-2.9 2.34-1.54 3.7l17.71 17.72a4.35 4.35 0 0 0 3.07 1.27h91.68c1.93 0 2.9-2.34 1.54-3.7L102.62 53.76z\" />\n </svg>\n )}\n <span>Continue with Solana</span>\n </button>\n\n {/* Wallet Selector Modal */}\n {showWalletSelector && (\n <div\n className=\"cedros-modal-backdrop\"\n onClick={() => setShowWalletSelector(false)}\n role=\"presentation\"\n >\n <div\n className=\"cedros-modal cedros-wallet-selector\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"wallet-selector-title\"\n onClick={(e) => e.stopPropagation()}\n >\n <div className=\"cedros-modal-header\">\n <h2 id=\"wallet-selector-title\" className=\"cedros-modal-title\">\n Select Wallet\n </h2>\n <button\n type=\"button\"\n className=\"cedros-modal-close\"\n onClick={() => setShowWalletSelector(false)}\n aria-label=\"Close\"\n >\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n <path\n d=\"M18 6L6 18M6 6l12 12\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n </button>\n </div>\n <div className=\"cedros-modal-content\">\n <div className=\"cedros-wallet-list\">\n {installedWallets.map((w) => (\n <button\n key={w.adapter.name}\n type=\"button\"\n className=\"cedros-wallet-option\"\n onClick={() => handleSelectWallet(w.adapter.name)}\n >\n <img\n src={w.adapter.icon}\n alt=\"\"\n width=\"32\"\n height=\"32\"\n className=\"cedros-wallet-icon\"\n />\n <span>{w.adapter.name}</span>\n </button>\n ))}\n </div>\n </div>\n </div>\n </div>\n )}\n </>\n );\n}\n","/**\n * Mobile Wallet Adapter (MWA) registration for web.\n *\n * On Android Chrome, MWA lets users authenticate with their installed Solana\n * wallet app (e.g., Phantom, Solflare) via Android Intents — no browser\n * extension needed.\n *\n * Once registered, MWA appears as a wallet option in the wallet adapter's\n * wallet list (alongside browser extension wallets). Users see it as\n * \"Use Installed Wallet\" in the wallet selector.\n *\n * Requires the optional peer dependency: @solana-mobile/wallet-standard-mobile\n *\n * @see https://docs.solanamobile.com/get-started/web/installation\n */\n\nexport interface MobileWalletConfig {\n /** App name shown in the wallet's authorization dialog */\n name?: string;\n /** App URI for identity verification */\n uri?: string;\n /** App icon path/URL shown in the wallet dialog */\n icon?: string;\n /** Solana cluster(s) to support. Default: ['solana:mainnet'] */\n chains?: string[];\n}\n\n/**\n * Register Mobile Wallet Adapter as a wallet-standard wallet.\n *\n * Call this once at your application root (before rendering). After registration,\n * MWA automatically appears as \"Use Installed Wallet\" for users browsing on\n * Android Chrome with a Solana wallet app installed.\n *\n * Must be called in a non-SSR context (browser only). For Next.js, call in a\n * Client Component with `'use client'`.\n *\n * @example\n * ```tsx\n * import { registerMobileWallet, CedrosLoginProvider } from '@cedros/login-react';\n *\n * // Register before provider mounts\n * registerMobileWallet({ name: 'My App', uri: 'https://myapp.com' });\n *\n * function App() {\n * return (\n * <CedrosLoginProvider config={{ serverUrl: '...' }}>\n * <LoginForm />\n * </CedrosLoginProvider>\n * );\n * }\n * ```\n *\n * @returns true if registration succeeded, false if package not installed or SSR\n */\nexport function registerMobileWallet(config?: MobileWalletConfig): boolean {\n if (typeof window === 'undefined') {\n return false;\n }\n\n try {\n // Dynamic import to avoid bundling the optional peer dep\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const mwa = require('@solana-mobile/wallet-standard-mobile');\n\n const chains = config?.chains ?? ['solana:mainnet'];\n\n const registrationConfig: Record<string, unknown> = {\n appIdentity: {\n name: config?.name,\n uri: config?.uri,\n icon: config?.icon,\n },\n chains,\n };\n\n // Use built-in defaults for optional config if available\n if (typeof mwa.createDefaultAuthorizationCache === 'function') {\n registrationConfig.authorizationCache = mwa.createDefaultAuthorizationCache();\n }\n if (typeof mwa.createDefaultChainSelector === 'function') {\n registrationConfig.chainSelector = mwa.createDefaultChainSelector();\n }\n if (typeof mwa.createDefaultWalletNotFoundHandler === 'function') {\n registrationConfig.onWalletNotFound = mwa.createDefaultWalletNotFoundHandler();\n }\n\n mwa.registerMwa(registrationConfig);\n return true;\n } catch {\n // @solana-mobile/wallet-standard-mobile not installed\n return false;\n }\n}\n"],"names":["useSolanaAuth","config","_internal","useCedrosLogin","isLoading","setIsLoading","useState","error","setError","apiClient","useMemo","ApiClient","requestChallenge","useCallback","publicKey","validateSolanaPublicKey","authError","err","handleApiError","signIn","signature","message","data","clearError","WALLET_PROVIDERS","isValidSolanaProvider","provider","wallet","hasWalletStandardWallets","walletStandard","wallets","detectSolanaWallets","win","walletObj","SolanaLoginButton","onSuccess","onError","className","variant","size","disabled","hideIfNoWallet","walletContext","isAuthLoading","showWalletSelector","setShowWalletSelector","pendingLogin","setPendingLogin","triggerConnect","setTriggerConnect","isProcessingRef","useRef","browserHasWallets","connected","connecting","signMessage","installedWallets","w","hasWallets","executeSignIn","pubKeyString","challenge","messageBytes","signatureBytes","useEffect","handleClick","handleSelectWallet","walletName","sizeClasses","variantClasses","jsxs","Fragment","jsx","LoadingSpinner","e","registerMobileWallet","mwa","chains","registrationConfig"],"mappings":"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"}