@cedros/login-react 0.0.29 → 0.0.30
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/README.md +2 -0
- package/dist/{AdminDepositList-CyT4VBH8.js → AdminDepositList-BUm_ZcAW.js} +1 -1
- package/dist/{AdminDepositList-CyT4VBH8.js.map → AdminDepositList-BUm_ZcAW.js.map} +1 -1
- package/dist/{AdminDepositList-b2AXtLg0.cjs → AdminDepositList-B_z6x3j5.cjs} +1 -1
- package/dist/{AdminDepositList-b2AXtLg0.cjs.map → AdminDepositList-B_z6x3j5.cjs.map} +1 -1
- package/dist/{AdminWithdrawalHistory-DL9zbu2b.cjs → AdminWithdrawalHistory-B2EY2ZmH.cjs} +1 -1
- package/dist/{AdminWithdrawalHistory-DL9zbu2b.cjs.map → AdminWithdrawalHistory-B2EY2ZmH.cjs.map} +1 -1
- package/dist/{AdminWithdrawalHistory-Cud-yuWy.js → AdminWithdrawalHistory-C76bkbjX.js} +1 -1
- package/dist/{AdminWithdrawalHistory-Cud-yuWy.js.map → AdminWithdrawalHistory-C76bkbjX.js.map} +1 -1
- package/dist/{AuthenticationSettings-D6GvSw3g.cjs → AuthenticationSettings-C-aYDXNH.cjs} +1 -1
- package/dist/{AuthenticationSettings-D6GvSw3g.cjs.map → AuthenticationSettings-C-aYDXNH.cjs.map} +1 -1
- package/dist/AuthenticationSettings-CoTic-d_.cjs +1 -0
- package/dist/AuthenticationSettings-CoTic-d_.cjs.map +1 -0
- package/dist/{AuthenticationSettings-rb4Fksw5.js → AuthenticationSettings-CsPbxwP7.js} +1 -1
- package/dist/{AuthenticationSettings-rb4Fksw5.js.map → AuthenticationSettings-CsPbxwP7.js.map} +1 -1
- package/dist/AuthenticationSettings-DIVk0OP8.js +712 -0
- package/dist/AuthenticationSettings-DIVk0OP8.js.map +1 -0
- package/dist/AutosaveStatus-DGNI4lXn.cjs +1 -0
- package/dist/AutosaveStatus-DGNI4lXn.cjs.map +1 -0
- package/dist/{AutosaveStatus-vkJxtuEw.js → AutosaveStatus-f-jw25Ay.js} +141 -93
- package/dist/AutosaveStatus-f-jw25Ay.js.map +1 -0
- package/dist/{CreditSystemSettings-ChA_lbef.cjs → CreditSystemSettings-BNkvsgsk.cjs} +1 -1
- package/dist/{CreditSystemSettings-ChA_lbef.cjs.map → CreditSystemSettings-BNkvsgsk.cjs.map} +1 -1
- package/dist/{CreditSystemSettings-DsRipb2R.js → CreditSystemSettings-C6ed3yp7.js} +1 -1
- package/dist/{CreditSystemSettings-DsRipb2R.js.map → CreditSystemSettings-C6ed3yp7.js.map} +1 -1
- package/dist/{CreditSystemSettings-r3gnGjiU.cjs → CreditSystemSettings-DM9ep1TF.cjs} +1 -1
- package/dist/{CreditSystemSettings-r3gnGjiU.cjs.map → CreditSystemSettings-DM9ep1TF.cjs.map} +1 -1
- package/dist/{CreditSystemSettings-a31pqSYS.js → CreditSystemSettings-uinhzoha.js} +1 -1
- package/dist/{CreditSystemSettings-a31pqSYS.js.map → CreditSystemSettings-uinhzoha.js.map} +1 -1
- package/dist/{DepositsSection-DD9MKUFt.js → DepositsSection-Bb4ISzvE.js} +1 -1
- package/dist/{DepositsSection-DD9MKUFt.js.map → DepositsSection-Bb4ISzvE.js.map} +1 -1
- package/dist/{DepositsSection-BkKUS4vk.cjs → DepositsSection-uQUdGeVb.cjs} +1 -1
- package/dist/{DepositsSection-BkKUS4vk.cjs.map → DepositsSection-uQUdGeVb.cjs.map} +1 -1
- package/dist/EmailRegisterForm-B_TiJkD6.cjs +1 -0
- package/dist/EmailRegisterForm-B_TiJkD6.cjs.map +1 -0
- package/dist/EmailRegisterForm-CCEuQA-w.js +773 -0
- package/dist/EmailRegisterForm-CCEuQA-w.js.map +1 -0
- package/dist/{EmailSettings-BVJ4vz0Y.js → EmailSettings-BAuQtEfM.js} +1 -1
- package/dist/{EmailSettings-BVJ4vz0Y.js.map → EmailSettings-BAuQtEfM.js.map} +1 -1
- package/dist/{EmailSettings-Dg2SAiHj.cjs → EmailSettings-BC0f1PCI.cjs} +1 -1
- package/dist/{EmailSettings-Dg2SAiHj.cjs.map → EmailSettings-BC0f1PCI.cjs.map} +1 -1
- package/dist/{EmailSettings-CM5l8qqK.cjs → EmailSettings-BF5EiPl9.cjs} +1 -1
- package/dist/{EmailSettings-CM5l8qqK.cjs.map → EmailSettings-BF5EiPl9.cjs.map} +1 -1
- package/dist/{EmailSettings-xtVl4kXD.js → EmailSettings-BKuXy8sc.js} +1 -1
- package/dist/{EmailSettings-xtVl4kXD.js.map → EmailSettings-BKuXy8sc.js.map} +1 -1
- package/dist/{EmbeddedWalletSettings-Bmx8x21f.cjs → EmbeddedWalletSettings-BRjt2PAj.cjs} +1 -1
- package/dist/{EmbeddedWalletSettings-Bmx8x21f.cjs.map → EmbeddedWalletSettings-BRjt2PAj.cjs.map} +1 -1
- package/dist/{EmbeddedWalletSettings-BuDgqv-K.js → EmbeddedWalletSettings-C27X9He2.js} +1 -1
- package/dist/{EmbeddedWalletSettings-BuDgqv-K.js.map → EmbeddedWalletSettings-C27X9He2.js.map} +1 -1
- package/dist/{EmbeddedWalletSettings-BXN9VbNJ.cjs → EmbeddedWalletSettings-CJY39UZN.cjs} +1 -1
- package/dist/{EmbeddedWalletSettings-BXN9VbNJ.cjs.map → EmbeddedWalletSettings-CJY39UZN.cjs.map} +1 -1
- package/dist/{EmbeddedWalletSettings-DY5iJhS0.js → EmbeddedWalletSettings-Dmi-EQ7W.js} +1 -1
- package/dist/{EmbeddedWalletSettings-DY5iJhS0.js.map → EmbeddedWalletSettings-Dmi-EQ7W.js.map} +1 -1
- package/dist/GoogleLoginButton-CjBO3Rf1.cjs +1 -0
- package/dist/GoogleLoginButton-CjBO3Rf1.cjs.map +1 -0
- package/dist/{GoogleLoginButton-B6qnNMZp.js → GoogleLoginButton-DEbiQngr.js} +51 -51
- package/dist/GoogleLoginButton-DEbiQngr.js.map +1 -0
- package/dist/LoadingSpinner-6vml-zwr.js.map +1 -1
- package/dist/LoadingSpinner-d6sSxgQN.cjs.map +1 -1
- package/dist/{PermissionsSection-BPbE-hNx.cjs → PermissionsSection-DEMVp7X3.cjs} +1 -1
- package/dist/PermissionsSection-DEMVp7X3.cjs.map +1 -0
- package/dist/{PermissionsSection-CighC1p6.js → PermissionsSection-DNzOL1xW.js} +27 -25
- package/dist/PermissionsSection-DNzOL1xW.js.map +1 -0
- package/dist/{ServerSettings-BAstMKHS.js → ServerSettings-BT9weFPz.js} +1 -1
- package/dist/{ServerSettings-BAstMKHS.js.map → ServerSettings-BT9weFPz.js.map} +1 -1
- package/dist/{ServerSettings-LIIP5TPz.cjs → ServerSettings-CKfiLfXi.cjs} +1 -1
- package/dist/{ServerSettings-LIIP5TPz.cjs.map → ServerSettings-CKfiLfXi.cjs.map} +1 -1
- package/dist/{ServerSettings-9Q091f3o.js → ServerSettings-CZfBdMxG.js} +1 -1
- package/dist/{ServerSettings-9Q091f3o.js.map → ServerSettings-CZfBdMxG.js.map} +1 -1
- package/dist/{ServerSettings-PH7T8JKI.cjs → ServerSettings-rHrVN8O8.cjs} +1 -1
- package/dist/{ServerSettings-PH7T8JKI.cjs.map → ServerSettings-rHrVN8O8.cjs.map} +1 -1
- package/dist/SolanaLoginButton-DAV3r4oB.cjs +1 -0
- package/dist/SolanaLoginButton-DAV3r4oB.cjs.map +1 -0
- package/dist/{mobileWalletAdapter-Cm_AUXhg.js → SolanaLoginButton-DFOoLqoj.js} +75 -74
- package/dist/SolanaLoginButton-DFOoLqoj.js.map +1 -0
- package/dist/{TeamSection-BIECkp7g.js → TeamSection-CoMXyFtz.js} +2 -2
- package/dist/{TeamSection-BIECkp7g.js.map → TeamSection-CoMXyFtz.js.map} +1 -1
- package/dist/{TeamSection-BOH9pv_E.cjs → TeamSection-DopbZClq.cjs} +1 -1
- package/dist/{TeamSection-BOH9pv_E.cjs.map → TeamSection-DopbZClq.cjs.map} +1 -1
- package/dist/{UsersSection-t-zm0jZW.js → UsersSection--PAE1XRh.js} +1 -1
- package/dist/{UsersSection-t-zm0jZW.js.map → UsersSection--PAE1XRh.js.map} +1 -1
- package/dist/{UsersSection-e6q7FHzx.cjs → UsersSection-C7aRNkK2.cjs} +1 -1
- package/dist/{UsersSection-e6q7FHzx.cjs.map → UsersSection-C7aRNkK2.cjs.map} +1 -1
- package/dist/{WebhookSettings-D0F8ESlB.js → WebhookSettings-Bgld6D_T.js} +1 -1
- package/dist/{WebhookSettings-D0F8ESlB.js.map → WebhookSettings-Bgld6D_T.js.map} +1 -1
- package/dist/{WebhookSettings-2p9abGm5.cjs → WebhookSettings-DXjnq-c7.cjs} +1 -1
- package/dist/{WebhookSettings-2p9abGm5.cjs.map → WebhookSettings-DXjnq-c7.cjs.map} +1 -1
- package/dist/{WebhookSettings-CdFM7_V-.cjs → WebhookSettings-DnLk97Mr.cjs} +1 -1
- package/dist/{WebhookSettings-CdFM7_V-.cjs.map → WebhookSettings-DnLk97Mr.cjs.map} +1 -1
- package/dist/{WebhookSettings-CXMBju7N.js → WebhookSettings-ufiGTmbG.js} +1 -1
- package/dist/{WebhookSettings-CXMBju7N.js.map → WebhookSettings-ufiGTmbG.js.map} +1 -1
- package/dist/{WithdrawalsSection-yRDTVFsb.js → WithdrawalsSection-BN-FjTEV.js} +1 -1
- package/dist/{WithdrawalsSection-yRDTVFsb.js.map → WithdrawalsSection-BN-FjTEV.js.map} +1 -1
- package/dist/{WithdrawalsSection-sljIyeaz.cjs → WithdrawalsSection-BhuCwFat.cjs} +1 -1
- package/dist/{WithdrawalsSection-sljIyeaz.cjs.map → WithdrawalsSection-BhuCwFat.cjs.map} +1 -1
- package/dist/admin-only.cjs +1 -1
- package/dist/admin-only.js +1 -1
- package/dist/email-only.cjs +1 -1
- package/dist/email-only.d.ts +17 -1
- package/dist/email-only.js +3 -3
- package/dist/google-only.cjs +1 -1
- package/dist/google-only.d.ts +16 -0
- package/dist/google-only.js +3 -3
- package/dist/index.cjs +12 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +246 -10
- package/dist/index.js +3384 -2508
- package/dist/index.js.map +1 -1
- package/dist/login-react.css +1 -1
- package/dist/{plugin-DbkijwEV.js → plugin-BbExid4E.js} +1 -1
- package/dist/{plugin-DbkijwEV.js.map → plugin-BbExid4E.js.map} +1 -1
- package/dist/{plugin-PU2vAozn.cjs → plugin-Xca67fp7.cjs} +1 -1
- package/dist/{plugin-PU2vAozn.cjs.map → plugin-Xca67fp7.cjs.map} +1 -1
- package/dist/{shamir-CiBczzDN.cjs → shamir-DBpHm7WN.cjs} +1 -1
- package/dist/{shamir-CiBczzDN.cjs.map → shamir-DBpHm7WN.cjs.map} +1 -1
- package/dist/{shamir-OAB2zD9Y.js → shamir-R8ddesFt.js} +1 -1
- package/dist/{shamir-OAB2zD9Y.js.map → shamir-R8ddesFt.js.map} +1 -1
- package/dist/{silentWalletEnroll-FqXS7Rvh.js → silentWalletEnroll-Dp1GTeNr.js} +3 -3
- package/dist/{silentWalletEnroll-FqXS7Rvh.js.map → silentWalletEnroll-Dp1GTeNr.js.map} +1 -1
- package/dist/{silentWalletEnroll-wnkcB9HP.cjs → silentWalletEnroll-HPvsbd2J.cjs} +1 -1
- package/dist/{silentWalletEnroll-wnkcB9HP.cjs.map → silentWalletEnroll-HPvsbd2J.cjs.map} +1 -1
- package/dist/solana-only.cjs +1 -1
- package/dist/solana-only.d.ts +16 -0
- package/dist/solana-only.js +3 -3
- package/dist/{useAdminDeposits-BTSyeAfg.js → useAdminDeposits-C76B2Q_8.js} +1 -1
- package/dist/{useAdminDeposits-BTSyeAfg.js.map → useAdminDeposits-C76B2Q_8.js.map} +1 -1
- package/dist/{useAdminDeposits-BkkCwHWp.cjs → useAdminDeposits-CpLd68oP.cjs} +1 -1
- package/dist/{useAdminDeposits-BkkCwHWp.cjs.map → useAdminDeposits-CpLd68oP.cjs.map} +1 -1
- package/dist/{useAuth-m5Hf89v8.js → useAuth-CVLv2oKA.js} +547 -545
- package/dist/useAuth-CVLv2oKA.js.map +1 -0
- package/dist/useAuth-XZaciuLg.cjs +1 -0
- package/dist/useAuth-XZaciuLg.cjs.map +1 -0
- package/dist/useCedrosLogin-CFfID-0i.js +228 -0
- package/dist/useCedrosLogin-CFfID-0i.js.map +1 -0
- package/dist/useCedrosLogin-DtJorrE7.cjs +1 -0
- package/dist/useCedrosLogin-DtJorrE7.cjs.map +1 -0
- package/dist/{useOrgs-C3pzMA9h.js → useOrgs-C90KT9KP.js} +1 -1
- package/dist/{useOrgs-C3pzMA9h.js.map → useOrgs-C90KT9KP.js.map} +1 -1
- package/dist/{useOrgs-DDVRCaVi.cjs → useOrgs-CNqfn-fk.cjs} +1 -1
- package/dist/{useOrgs-DDVRCaVi.cjs.map → useOrgs-CNqfn-fk.cjs.map} +1 -1
- package/dist/{useSystemSettings-DRrreszl.cjs → useSystemSettings-B2jY51ob.cjs} +1 -1
- package/dist/{useSystemSettings-DRrreszl.cjs.map → useSystemSettings-B2jY51ob.cjs.map} +1 -1
- package/dist/{useSystemSettings-DBlAMjFi.js → useSystemSettings-rgskaDqP.js} +1 -1
- package/dist/{useSystemSettings-DBlAMjFi.js.map → useSystemSettings-rgskaDqP.js.map} +1 -1
- package/dist/{useUsersStatsSummary-NjEFvWuz.js → useUsersStatsSummary-5DJwzntC.js} +2 -2
- package/dist/{useUsersStatsSummary-NjEFvWuz.js.map → useUsersStatsSummary-5DJwzntC.js.map} +1 -1
- package/dist/{useUsersStatsSummary-8qY7iP4G.cjs → useUsersStatsSummary-DgKaUIfs.cjs} +1 -1
- package/dist/{useUsersStatsSummary-8qY7iP4G.cjs.map → useUsersStatsSummary-DgKaUIfs.cjs.map} +1 -1
- package/package.json +1 -1
- package/dist/AuthenticationSettings-C9f5MKgj.cjs +0 -1
- package/dist/AuthenticationSettings-C9f5MKgj.cjs.map +0 -1
- package/dist/AuthenticationSettings-DC64o_J6.js +0 -525
- package/dist/AuthenticationSettings-DC64o_J6.js.map +0 -1
- package/dist/AutosaveStatus-BFj5GIab.cjs +0 -1
- package/dist/AutosaveStatus-BFj5GIab.cjs.map +0 -1
- package/dist/AutosaveStatus-vkJxtuEw.js.map +0 -1
- package/dist/EmailRegisterForm-B1DB-bqe.cjs +0 -1
- package/dist/EmailRegisterForm-B1DB-bqe.cjs.map +0 -1
- package/dist/EmailRegisterForm-BAX_uBIt.js +0 -927
- package/dist/EmailRegisterForm-BAX_uBIt.js.map +0 -1
- package/dist/GoogleLoginButton-B6qnNMZp.js.map +0 -1
- package/dist/GoogleLoginButton-D7CoMXLq.cjs +0 -1
- package/dist/GoogleLoginButton-D7CoMXLq.cjs.map +0 -1
- package/dist/PermissionsSection-BPbE-hNx.cjs.map +0 -1
- package/dist/PermissionsSection-CighC1p6.js.map +0 -1
- package/dist/mobileWalletAdapter-B6ELaZp1.cjs +0 -1
- package/dist/mobileWalletAdapter-B6ELaZp1.cjs.map +0 -1
- package/dist/mobileWalletAdapter-Cm_AUXhg.js.map +0 -1
- package/dist/useAuth-X6Ds6WW4.cjs +0 -1
- package/dist/useAuth-X6Ds6WW4.cjs.map +0 -1
- package/dist/useAuth-m5Hf89v8.js.map +0 -1
- package/dist/useCedrosLogin-C9MrcZvh.cjs +0 -1
- package/dist/useCedrosLogin-C9MrcZvh.cjs.map +0 -1
- package/dist/useCedrosLogin-_94MmGGq.js +0 -216
- package/dist/useCedrosLogin-_94MmGGq.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PermissionsSection-CighC1p6.js","sources":["../src/components/members/MemberList.tsx","../src/components/invites/InviteForm.tsx","../src/components/invites/InviteList.tsx","../src/utils/memberApi.ts","../src/hooks/useMembers.ts","../src/utils/inviteApi.ts","../src/hooks/useInvites.ts","../src/hooks/useServerFeatures.ts","../src/types/org.ts","../src/hooks/useDashboardPermissions.ts","../src/components/admin/PermissionsSection.tsx"],"sourcesContent":["import { useState, useCallback, useMemo } from 'react';\nimport type { Member, OrgRole, DisplayError } from '../../types';\nimport { LoadingSpinner } from '../shared/LoadingSpinner';\nimport { ErrorMessage } from '../shared/ErrorMessage';\nimport { sanitizeImageUrl } from '../../utils/sanitization';\n\ntype SortField = 'name' | 'role' | 'joinedAt';\ntype SortOrder = 'asc' | 'desc';\n\nexport interface MemberListProps {\n /** List of members to display */\n members: Member[];\n /** Current user's ID (to prevent self-actions) */\n currentUserId?: string;\n /** Loading state */\n isLoading?: boolean;\n /** Error message */\n error?: DisplayError;\n /** Whether the current user can manage members */\n canManage?: boolean;\n /** Whether the current user can change roles */\n canChangeRoles?: boolean;\n /** Callback when role is updated */\n onUpdateRole?: (userId: string, role: OrgRole) => Promise<void>;\n /** Callback when member is removed */\n onRemove?: (userId: string) => Promise<void>;\n /** Additional CSS class */\n className?: string;\n}\n\nconst ROLE_OPTIONS: OrgRole[] = ['owner', 'admin', 'member'];\n\n/**\n * Display and manage organization members.\n *\n * @example\n * ```tsx\n * function TeamMembers() {\n * const { activeOrg, hasPermission } = useOrgs();\n * const { members, isLoading, error, updateMemberRole, removeMember } = useMembers(activeOrg?.id);\n * const { user } = useAuth();\n *\n * return (\n * <MemberList\n * members={members}\n * currentUserId={user?.id}\n * isLoading={isLoading}\n * error={error?.message}\n * canManage={hasPermission('member:remove')}\n * canChangeRoles={hasPermission('member:role_change')}\n * onUpdateRole={updateMemberRole}\n * onRemove={removeMember}\n * />\n * );\n * }\n * ```\n */\nexport function MemberList({\n members,\n currentUserId,\n isLoading = false,\n error,\n canManage = false,\n canChangeRoles = false,\n onUpdateRole,\n onRemove,\n className = '',\n}: MemberListProps) {\n const [sortField, setSortField] = useState<SortField>('name');\n const [sortOrder, setSortOrder] = useState<SortOrder>('asc');\n\n const toggleSort = (field: SortField) => {\n if (sortField === field) {\n setSortOrder(sortOrder === 'asc' ? 'desc' : 'asc');\n } else {\n setSortField(field);\n setSortOrder('asc');\n }\n };\n\n const sortedMembers = useMemo(() => {\n const roleOrder: Record<OrgRole, number> = { owner: 0, admin: 1, member: 2 };\n return [...members].sort((a, b) => {\n let aVal: string | number;\n let bVal: string | number;\n\n switch (sortField) {\n case 'name':\n aVal = (a.user.name || a.user.email || '').toLowerCase();\n bVal = (b.user.name || b.user.email || '').toLowerCase();\n break;\n case 'role':\n aVal = roleOrder[a.role] ?? 99;\n bVal = roleOrder[b.role] ?? 99;\n break;\n case 'joinedAt':\n aVal = new Date(a.joinedAt).getTime();\n bVal = new Date(b.joinedAt).getTime();\n break;\n default:\n return 0;\n }\n\n if (aVal < bVal) return sortOrder === 'asc' ? -1 : 1;\n if (aVal > bVal) return sortOrder === 'asc' ? 1 : -1;\n return 0;\n });\n }, [members, sortField, sortOrder]);\n\n if (isLoading && members.length === 0) {\n return (\n <div className={`cedros-member-list cedros-member-list-loading ${className}`}>\n <LoadingSpinner />\n <span>Loading members...</span>\n </div>\n );\n }\n\n if (error) {\n return (\n <div className={`cedros-member-list ${className}`}>\n <ErrorMessage error={error} />\n </div>\n );\n }\n\n if (members.length === 0) {\n return (\n <div className={`cedros-member-list cedros-member-list-empty ${className}`}>\n <p>No members found.</p>\n </div>\n );\n }\n\n return (\n <div className={`cedros-member-list ${className}`}>\n <table className=\"cedros-member-table\">\n <thead>\n <tr>\n <th>\n <button\n type=\"button\"\n className={`cedros-admin-sort-button ${sortField === 'name' ? 'cedros-admin-sort-active' : ''}`}\n onClick={() => toggleSort('name')}\n >\n Member{' '}\n <span className=\"cedros-admin-sort-icon\">\n {sortField === 'name' ? (sortOrder === 'asc' ? '↑' : '↓') : '↕'}\n </span>\n </button>\n </th>\n <th>\n <button\n type=\"button\"\n className={`cedros-admin-sort-button ${sortField === 'role' ? 'cedros-admin-sort-active' : ''}`}\n onClick={() => toggleSort('role')}\n >\n Role{' '}\n <span className=\"cedros-admin-sort-icon\">\n {sortField === 'role' ? (sortOrder === 'asc' ? '↑' : '↓') : '↕'}\n </span>\n </button>\n </th>\n <th>\n <button\n type=\"button\"\n className={`cedros-admin-sort-button ${sortField === 'joinedAt' ? 'cedros-admin-sort-active' : ''}`}\n onClick={() => toggleSort('joinedAt')}\n >\n Joined{' '}\n <span className=\"cedros-admin-sort-icon\">\n {sortField === 'joinedAt' ? (sortOrder === 'asc' ? '↑' : '↓') : '↕'}\n </span>\n </button>\n </th>\n {(canManage || canChangeRoles) && <th>Actions</th>}\n </tr>\n </thead>\n <tbody>\n {sortedMembers.map((member) => (\n <MemberRow\n key={member.id}\n member={member}\n isCurrentUser={member.userId === currentUserId}\n canManage={canManage}\n canChangeRoles={canChangeRoles}\n onUpdateRole={onUpdateRole}\n onRemove={onRemove}\n />\n ))}\n </tbody>\n </table>\n </div>\n );\n}\n\n// Member row component\ninterface MemberRowProps {\n member: Member;\n isCurrentUser: boolean;\n canManage: boolean;\n canChangeRoles: boolean;\n onUpdateRole?: (userId: string, role: OrgRole) => Promise<void>;\n onRemove?: (userId: string) => Promise<void>;\n}\n\nfunction MemberRow({\n member,\n isCurrentUser,\n canManage,\n canChangeRoles,\n onUpdateRole,\n onRemove,\n}: MemberRowProps) {\n const [isUpdating, setIsUpdating] = useState(false);\n const [selectedRole, setSelectedRole] = useState<OrgRole>(member.role);\n\n const handleRoleChange = useCallback(\n async (newRole: OrgRole) => {\n if (!onUpdateRole || newRole === member.role) return;\n\n setIsUpdating(true);\n try {\n await onUpdateRole(member.userId, newRole);\n setSelectedRole(newRole);\n } catch {\n // Revert on error\n setSelectedRole(member.role);\n } finally {\n setIsUpdating(false);\n }\n },\n [member.userId, member.role, onUpdateRole]\n );\n\n const handleRemove = useCallback(async () => {\n if (!onRemove) return;\n\n const confirmed = window.confirm(\n `Are you sure you want to remove ${member.user.name || member.user.email} from this organization?`\n );\n if (!confirmed) return;\n\n setIsUpdating(true);\n try {\n await onRemove(member.userId);\n } finally {\n setIsUpdating(false);\n }\n }, [member.userId, member.user.name, member.user.email, onRemove]);\n\n const isOwner = member.role === 'owner';\n const canModify = !isCurrentUser && !isOwner;\n\n return (\n <tr className={`cedros-member-row ${isCurrentUser ? 'cedros-member-row-current' : ''}`}>\n <td className=\"cedros-member-info\">\n <MemberAvatar user={member.user} />\n <div className=\"cedros-member-details\">\n <span className=\"cedros-member-name\">\n {member.user.name || 'Unknown'}\n {isCurrentUser && <span className=\"cedros-member-you\">(you)</span>}\n </span>\n <span className=\"cedros-member-email\">{member.user.email}</span>\n </div>\n </td>\n <td className=\"cedros-member-role\">\n {canChangeRoles && canModify && onUpdateRole ? (\n <select\n value={selectedRole}\n onChange={(e) => handleRoleChange(e.target.value as OrgRole)}\n disabled={isUpdating}\n className=\"cedros-role-select\"\n >\n {ROLE_OPTIONS.map((role) => (\n <option key={role} value={role}>\n {role.charAt(0).toUpperCase() + role.slice(1)}\n </option>\n ))}\n </select>\n ) : (\n <span className={`cedros-role-badge cedros-role-badge-${member.role}`}>\n {member.role.charAt(0).toUpperCase() + member.role.slice(1)}\n </span>\n )}\n </td>\n <td className=\"cedros-member-joined\">{formatDate(member.joinedAt)}</td>\n {(canManage || canChangeRoles) && (\n <td className=\"cedros-member-actions\">\n {canManage && canModify && onRemove && (\n <button\n type=\"button\"\n className=\"cedros-button cedros-button-danger cedros-button-sm\"\n onClick={handleRemove}\n disabled={isUpdating}\n aria-label={`Remove ${member.user.name || member.user.email}`}\n >\n {isUpdating ? <LoadingSpinner size=\"sm\" /> : 'Remove'}\n </button>\n )}\n </td>\n )}\n </tr>\n );\n}\n\n// Helper components\nfunction MemberAvatar({ user }: { user: Member['user'] }) {\n // COMP-06: Cache sanitized URL and verify before use (blocks dangerous protocols)\n const sanitizedPicture = sanitizeImageUrl(user.picture);\n if (sanitizedPicture) {\n return (\n <img\n src={sanitizedPicture}\n alt={user.name || user.email || 'Member'}\n className=\"cedros-member-avatar\"\n referrerPolicy=\"no-referrer\"\n />\n );\n }\n\n const initial = (user.name?.[0] || user.email?.[0] || '?').toUpperCase();\n return <div className=\"cedros-member-avatar-placeholder\">{initial}</div>;\n}\n\nfunction formatDate(dateString: string): string {\n const date = new Date(dateString);\n return date.toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n });\n}\n","import { useState, useCallback, useEffect, useRef } from 'react';\nimport type { OrgRole, DisplayError } from '../../types';\nimport { LoadingSpinner } from '../shared/LoadingSpinner';\nimport { ErrorMessage } from '../shared/ErrorMessage';\nimport { validateEmail } from '../../utils/validation';\n\ntype InviteRole = Exclude<OrgRole, 'owner'>;\n\nexport interface InviteFormProps {\n /** Callback when invite is submitted */\n onSubmit: (email: string, role: InviteRole) => Promise<void>;\n /** Loading state */\n isLoading?: boolean;\n /** Error message */\n error?: DisplayError;\n /** Available roles for invite (default: admin, member) */\n availableRoles?: InviteRole[];\n /** Default role for new invites */\n defaultRole?: InviteRole;\n /** Additional CSS class */\n className?: string;\n}\n\nconst DEFAULT_ROLES: InviteRole[] = ['admin', 'member'];\n\n/**\n * Form for inviting new members to an organization.\n *\n * @example\n * ```tsx\n * function InviteManager() {\n * const { activeOrg } = useOrgs();\n * const { createInvite, isLoading, error } = useInvites(activeOrg?.id);\n *\n * return (\n * <InviteForm\n * onSubmit={createInvite}\n * isLoading={isLoading}\n * error={error?.message}\n * defaultRole=\"member\"\n * />\n * );\n * }\n * ```\n */\nexport function InviteForm({\n onSubmit,\n isLoading = false,\n error,\n availableRoles = DEFAULT_ROLES,\n defaultRole = 'member',\n className = '',\n}: InviteFormProps) {\n const [email, setEmail] = useState('');\n const [role, setRole] = useState<InviteRole>(defaultRole);\n const [formError, setFormError] = useState<string | null>(null);\n const [success, setSuccess] = useState(false);\n const successTimerRef = useRef<number | null>(null);\n // UI-03: Track mounted state to prevent state updates after unmount\n const isMountedRef = useRef(true);\n\n useEffect(() => {\n isMountedRef.current = true;\n return () => {\n isMountedRef.current = false;\n if (successTimerRef.current !== null) {\n window.clearTimeout(successTimerRef.current);\n successTimerRef.current = null;\n }\n };\n }, []);\n\n const handleSubmit = useCallback(\n async (e: React.FormEvent) => {\n e.preventDefault();\n setFormError(null);\n setSuccess(false);\n\n const trimmedEmail = email.trim();\n\n if (!trimmedEmail) {\n setFormError('Email is required');\n return;\n }\n\n if (!validateEmail(trimmedEmail)) {\n setFormError('Please enter a valid email address');\n return;\n }\n\n try {\n await onSubmit(trimmedEmail, role);\n setEmail('');\n setRole(defaultRole);\n setSuccess(true);\n // Clear success message after 3 seconds\n if (successTimerRef.current !== null) {\n window.clearTimeout(successTimerRef.current);\n }\n successTimerRef.current = window.setTimeout(() => {\n // UI-03: Check mounted before state update to prevent memory leak warnings\n if (isMountedRef.current) {\n setSuccess(false);\n }\n successTimerRef.current = null;\n }, 3000);\n } catch {\n // H-05: Error handling is delegated to parent component.\n // Parent's onSubmit throws -> parent catches -> sets error prop -> ErrorMessage displays it.\n // This pattern allows the parent to control error display and retry logic.\n }\n },\n [email, role, defaultRole, onSubmit]\n );\n\n return (\n <form className={`cedros-invite-form ${className}`} onSubmit={handleSubmit}>\n {(error || formError) && <ErrorMessage error={formError ?? error ?? null} />}\n\n {success && (\n <div className=\"cedros-invite-success\" role=\"status\">\n <CheckIcon />\n <span>Invitation sent successfully!</span>\n </div>\n )}\n\n <div className=\"cedros-invite-form-row\">\n <div className=\"cedros-form-group cedros-invite-email-group\">\n <label htmlFor=\"invite-email\" className=\"cedros-form-label\">\n Email Address\n </label>\n <input\n id=\"invite-email\"\n type=\"email\"\n className=\"cedros-form-input\"\n value={email}\n onChange={(e) => setEmail(e.target.value)}\n placeholder=\"colleague@example.com\"\n disabled={isLoading}\n autoComplete=\"email\"\n />\n </div>\n\n <div className=\"cedros-form-group cedros-invite-role-group\">\n <label htmlFor=\"invite-role\" className=\"cedros-form-label\">\n Role\n </label>\n <select\n id=\"invite-role\"\n className=\"cedros-form-select\"\n value={role}\n onChange={(e) => setRole(e.target.value as InviteRole)}\n disabled={isLoading}\n >\n {availableRoles.map((r) => (\n <option key={r} value={r}>\n {r.charAt(0).toUpperCase() + r.slice(1)}\n </option>\n ))}\n </select>\n </div>\n\n <button\n type=\"submit\"\n className=\"cedros-button cedros-button-primary cedros-invite-submit\"\n disabled={isLoading || !email.trim()}\n >\n {isLoading ? <LoadingSpinner size=\"sm\" /> : 'Send Invite'}\n </button>\n </div>\n\n <p className=\"cedros-form-hint\">\n The invited user will receive an email with a link to join your organization.\n </p>\n </form>\n );\n}\n\nfunction CheckIcon() {\n return (\n <svg\n className=\"cedros-invite-check\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M3 8L6 11L13 5\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n );\n}\n","import { useState, useCallback, useEffect, useRef } from 'react';\nimport type { Invite, DisplayError } from '../../types';\nimport { LoadingSpinner } from '../shared/LoadingSpinner';\nimport { ErrorMessage } from '../shared/ErrorMessage';\n\nexport interface InviteListProps {\n /** List of pending invites */\n invites: Invite[];\n /** Loading state */\n isLoading?: boolean;\n /** Error message */\n error?: DisplayError;\n /** Whether the current user can manage invites */\n canManage?: boolean;\n /** Callback when invite is cancelled */\n onCancel?: (inviteId: string) => Promise<void>;\n /** Callback when invite is resent */\n onResend?: (inviteId: string) => Promise<void>;\n /** Additional CSS class */\n className?: string;\n}\n\n/**\n * Display and manage pending organization invites.\n *\n * @example\n * ```tsx\n * function PendingInvites() {\n * const { activeOrg, hasPermission } = useOrgs();\n * const { invites, isLoading, error, cancelInvite, resendInvite } = useInvites(activeOrg?.id);\n *\n * return (\n * <InviteList\n * invites={invites}\n * isLoading={isLoading}\n * error={error?.message}\n * canManage={hasPermission('invite:cancel')}\n * onCancel={cancelInvite}\n * onResend={resendInvite}\n * />\n * );\n * }\n * ```\n */\nexport function InviteList({\n invites,\n isLoading = false,\n error,\n canManage = false,\n onCancel,\n onResend,\n className = '',\n}: InviteListProps) {\n if (isLoading && invites.length === 0) {\n return (\n <div className={`cedros-invite-list cedros-invite-list-loading ${className}`}>\n <LoadingSpinner />\n <span>Loading invites...</span>\n </div>\n );\n }\n\n if (error) {\n return (\n <div className={`cedros-invite-list ${className}`}>\n <ErrorMessage error={error} />\n </div>\n );\n }\n\n if (invites.length === 0) {\n return (\n <div className={`cedros-invite-list cedros-invite-list-empty ${className}`}>\n <p>No pending invites.</p>\n </div>\n );\n }\n\n return (\n <div className={`cedros-invite-list ${className}`}>\n <ul className=\"cedros-invite-items\">\n {invites.map((invite) => (\n <InviteItem\n key={invite.id}\n invite={invite}\n canManage={canManage}\n onCancel={onCancel}\n onResend={onResend}\n />\n ))}\n </ul>\n </div>\n );\n}\n\n// Invite item component\ninterface InviteItemProps {\n invite: Invite;\n canManage: boolean;\n onCancel?: (inviteId: string) => Promise<void>;\n onResend?: (inviteId: string) => Promise<void>;\n}\n\nfunction InviteItem({ invite, canManage, onCancel, onResend }: InviteItemProps) {\n const [isUpdating, setIsUpdating] = useState(false);\n const [resendSuccess, setResendSuccess] = useState(false);\n const resendTimerRef = useRef<number | null>(null);\n\n const isExpired = new Date(invite.expiresAt) < new Date();\n\n const handleCancel = useCallback(async () => {\n if (!onCancel) return;\n\n const confirmed = window.confirm(\n `Are you sure you want to cancel the invite for ${invite.email}?`\n );\n if (!confirmed) return;\n\n setIsUpdating(true);\n try {\n await onCancel(invite.id);\n } finally {\n setIsUpdating(false);\n }\n }, [invite.id, invite.email, onCancel]);\n\n const handleResend = useCallback(async () => {\n if (!onResend) return;\n\n setIsUpdating(true);\n setResendSuccess(false);\n try {\n await onResend(invite.id);\n setResendSuccess(true);\n if (resendTimerRef.current !== null) {\n window.clearTimeout(resendTimerRef.current);\n }\n resendTimerRef.current = window.setTimeout(() => {\n setResendSuccess(false);\n resendTimerRef.current = null;\n }, 3000);\n } finally {\n setIsUpdating(false);\n }\n }, [invite.id, onResend]);\n\n useEffect(() => {\n return () => {\n if (resendTimerRef.current !== null) {\n window.clearTimeout(resendTimerRef.current);\n resendTimerRef.current = null;\n }\n };\n }, []);\n\n return (\n <li className={`cedros-invite-item ${isExpired ? 'cedros-invite-item-expired' : ''}`}>\n <div className=\"cedros-invite-item-info\">\n <div className=\"cedros-invite-item-main\">\n <span className=\"cedros-invite-item-email\">{invite.email}</span>\n <span className={`cedros-role-badge cedros-role-badge-${invite.role}`}>\n {invite.role.charAt(0).toUpperCase() + invite.role.slice(1)}\n </span>\n {isExpired && <span className=\"cedros-invite-expired-badge\">Expired</span>}\n </div>\n <div className=\"cedros-invite-item-meta\">\n <span className=\"cedros-invite-item-date\">\n {/* TYPE-05: invitedByName removed - backend doesn't populate it */}\n Invited {formatDate(invite.createdAt)}\n </span>\n {!isExpired && (\n <span className=\"cedros-invite-item-expires\">\n Expires {formatRelativeTime(invite.expiresAt)}\n </span>\n )}\n </div>\n </div>\n\n {canManage && (\n <div className=\"cedros-invite-item-actions\">\n {resendSuccess && <span className=\"cedros-invite-resend-success\">Sent!</span>}\n {onResend && !isExpired && (\n <button\n type=\"button\"\n className=\"cedros-button cedros-button-outline cedros-button-sm\"\n onClick={handleResend}\n disabled={isUpdating}\n aria-label={`Resend invite to ${invite.email}`}\n >\n {isUpdating ? <LoadingSpinner size=\"sm\" /> : 'Resend'}\n </button>\n )}\n {onCancel && (\n <button\n type=\"button\"\n className=\"cedros-button cedros-button-danger cedros-button-sm\"\n onClick={handleCancel}\n disabled={isUpdating}\n aria-label={`Cancel invite for ${invite.email}`}\n >\n Cancel\n </button>\n )}\n </div>\n )}\n </li>\n );\n}\n\n// Helper functions\nfunction formatDate(dateString: string): string {\n const date = new Date(dateString);\n return date.toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n });\n}\n\nfunction formatRelativeTime(dateString: string): string {\n const date = new Date(dateString);\n const now = new Date();\n const diffMs = date.getTime() - now.getTime();\n const diffDays = Math.ceil(diffMs / (1000 * 60 * 60 * 24));\n\n if (diffDays < 0) {\n return 'expired';\n } else if (diffDays === 0) {\n return 'today';\n } else if (diffDays === 1) {\n return 'tomorrow';\n } else if (diffDays < 7) {\n return `in ${diffDays} days`;\n } else {\n return formatDate(dateString);\n }\n}\n","import type {\n Member,\n MemberApiResponse,\n UpdateMemberRoleRequest,\n ListMembersResponse,\n} from '../types';\nimport { ApiClient, handleApiError } from './apiClient';\n\n/**\n * API client for member operations within an organization\n */\nexport class MemberApiClient {\n private client: ApiClient;\n\n constructor(\n baseUrl: string,\n timeoutMs?: number,\n retryAttempts?: number,\n getAccessToken?: () => string | null\n ) {\n this.client = new ApiClient({ baseUrl, timeoutMs, retryAttempts, getAccessToken });\n }\n\n /**\n * List all members of an organization\n */\n async listMembers(\n orgId: string,\n limit: number = 50,\n offset: number = 0\n ): Promise<{ members: Member[]; total: number }> {\n try {\n const response = await this.client.get<ListMembersResponse>(\n `/orgs/${orgId}/members?limit=${limit}&offset=${offset}`\n );\n return {\n members: response.members.map((member: MemberApiResponse) => ({\n id: member.id,\n userId: member.userId,\n orgId,\n role: member.role,\n joinedAt: member.joinedAt,\n user: {\n id: member.userId,\n email: member.email,\n name: member.name,\n },\n })),\n total: response.total,\n };\n } catch (error) {\n throw handleApiError(error, 'Failed to list members');\n }\n }\n\n /**\n * Update a member's role\n */\n async updateMemberRole(\n orgId: string,\n userId: string,\n data: UpdateMemberRoleRequest\n ): Promise<Member> {\n try {\n return await this.client.patch<Member>(`/orgs/${orgId}/members/${userId}`, data);\n } catch (error) {\n throw handleApiError(error, 'Failed to update member role');\n }\n }\n\n /**\n * Remove a member from the organization\n */\n async removeMember(orgId: string, userId: string): Promise<void> {\n try {\n await this.client.delete<void>(`/orgs/${orgId}/members/${userId}`);\n } catch (error) {\n throw handleApiError(error, 'Failed to remove member');\n }\n }\n}\n","import { useState, useCallback, useMemo, useEffect, useRef } from 'react';\nimport type { Member, OrgRole, AuthError } from '../types';\nimport { useCedrosLogin } from '../context/useCedrosLogin';\nimport { MemberApiClient } from '../utils/memberApi';\n\nexport interface UseMembersReturn {\n /** List of members */\n members: Member[];\n /** Total members available on the server */\n total: number;\n /** Loading state */\n isLoading: boolean;\n /** Error state */\n error: AuthError | null;\n /** Fetch/refresh members list */\n fetchMembers: (options?: { limit?: number; offset?: number }) => Promise<void>;\n /** Update a member's role */\n updateMemberRole: (userId: string, role: OrgRole) => Promise<void>;\n /** Remove a member */\n removeMember: (userId: string) => Promise<void>;\n}\n\n/**\n * Hook for managing organization members.\n *\n * @param orgId - The organization ID to manage members for\n *\n * @example\n * ```tsx\n * function MembersList() {\n * const { activeOrg } = useOrgs();\n * const { members, isLoading, updateMemberRole, removeMember } = useMembers(activeOrg?.id);\n *\n * if (!activeOrg) return null;\n *\n * return (\n * <ul>\n * {members.map(member => (\n * <li key={member.id}>\n * {member.user.name} - {member.role}\n * <button onClick={() => updateMemberRole(member.userId, 'admin')}>\n * Make Admin\n * </button>\n * <button onClick={() => removeMember(member.userId)}>\n * Remove\n * </button>\n * </li>\n * ))}\n * </ul>\n * );\n * }\n * ```\n */\nexport function useMembers(orgId: string | undefined): UseMembersReturn {\n const { config, authState, _internal } = useCedrosLogin();\n\n const [members, setMembers] = useState<Member[]>([]);\n const [total, setTotal] = useState(0);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<AuthError | null>(null);\n // P-12: Track fetched orgId to prevent duplicate fetches on remount\n const fetchedOrgIdRef = useRef<string | undefined>(undefined);\n const requestIdRef = useRef(0);\n\n const apiClient = useMemo(\n () =>\n new MemberApiClient(\n config.serverUrl,\n config.requestTimeout,\n config.retryAttempts,\n _internal?.getAccessToken\n ),\n [config.serverUrl, config.requestTimeout, config.retryAttempts, _internal]\n );\n\n // C-02: Use ref to avoid apiClient in callback dependencies\n // Prevents infinite loop when apiClient identity changes\n const apiClientRef = useRef(apiClient);\n apiClientRef.current = apiClient;\n\n const fetchMembers = useCallback(\n async (options?: { limit?: number; offset?: number }) => {\n if (!orgId || authState !== 'authenticated') {\n setMembers([]);\n setTotal(0);\n return;\n }\n\n setIsLoading(true);\n setError(null);\n const requestId = ++requestIdRef.current;\n\n try {\n const { limit = 50, offset = 0 } = options ?? {};\n const response = await apiClientRef.current.listMembers(orgId, limit, offset);\n if (requestId !== requestIdRef.current) return;\n setMembers(response.members);\n setTotal(response.total);\n } catch (err) {\n if (requestId !== requestIdRef.current) return;\n setError(err as AuthError);\n } finally {\n if (requestId === requestIdRef.current) {\n setIsLoading(false);\n }\n }\n },\n [orgId, authState]\n );\n\n // P-12: Auto-fetch when orgId changes, but not on every remount\n useEffect(() => {\n if (authState !== 'authenticated') {\n fetchedOrgIdRef.current = undefined;\n return;\n }\n\n if (orgId !== fetchedOrgIdRef.current) {\n fetchedOrgIdRef.current = orgId;\n fetchMembers();\n }\n }, [orgId, authState, fetchMembers]);\n\n const updateMemberRole = useCallback(\n async (userId: string, role: OrgRole): Promise<void> => {\n if (!orgId) {\n throw new Error('No organization selected');\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n await apiClientRef.current.updateMemberRole(orgId, userId, { role });\n // Refresh members list\n await fetchMembers();\n } catch (err) {\n setError(err as AuthError);\n throw err;\n } finally {\n setIsLoading(false);\n }\n },\n [orgId, fetchMembers]\n );\n\n const removeMember = useCallback(\n async (userId: string): Promise<void> => {\n if (!orgId) {\n throw new Error('No organization selected');\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n await apiClientRef.current.removeMember(orgId, userId);\n // Refresh members list\n await fetchMembers();\n } catch (err) {\n setError(err as AuthError);\n throw err;\n } finally {\n setIsLoading(false);\n }\n },\n [orgId, fetchMembers]\n );\n\n return {\n members,\n total,\n isLoading,\n error,\n fetchMembers,\n updateMemberRole,\n removeMember,\n };\n}\n","import type {\n Invite,\n InviteApiResponse,\n CreateInviteRequest,\n AcceptInviteRequest,\n ListInvitesResponse,\n CreateInviteResponse,\n AcceptInviteResponse,\n} from '../types';\nimport { ApiClient, handleApiError } from './apiClient';\n\n/**\n * API client for invite operations\n */\nexport class InviteApiClient {\n private client: ApiClient;\n\n constructor(\n baseUrl: string,\n timeoutMs?: number,\n retryAttempts?: number,\n getAccessToken?: () => string | null\n ) {\n this.client = new ApiClient({ baseUrl, timeoutMs, retryAttempts, getAccessToken });\n }\n\n /**\n * List all pending invites for an organization\n */\n async listInvites(\n orgId: string,\n limit: number = 50,\n offset: number = 0\n ): Promise<{ invites: Invite[]; total: number }> {\n try {\n const response = await this.client.get<ListInvitesResponse>(\n `/orgs/${orgId}/invites?limit=${limit}&offset=${offset}`\n );\n return {\n invites: response.invites.map((invite: InviteApiResponse) => ({\n id: invite.id,\n orgId: invite.orgId,\n email: invite.email,\n role: invite.role,\n invitedBy: invite.invitedBy,\n createdAt: invite.createdAt,\n expiresAt: invite.expiresAt,\n })),\n total: response.total,\n };\n } catch (error) {\n throw handleApiError(error, 'Failed to list invites');\n }\n }\n\n /**\n * Create a new invite\n */\n async createInvite(orgId: string, data: CreateInviteRequest): Promise<CreateInviteResponse> {\n try {\n return await this.client.post<CreateInviteResponse>(`/orgs/${orgId}/invites`, data);\n } catch (error) {\n throw handleApiError(error, 'Failed to create invite');\n }\n }\n\n /**\n * Cancel a pending invite\n */\n async cancelInvite(orgId: string, inviteId: string): Promise<void> {\n try {\n await this.client.delete<void>(`/orgs/${orgId}/invites/${inviteId}`);\n } catch (error) {\n throw handleApiError(error, 'Failed to cancel invite');\n }\n }\n\n /**\n * Resend an invite email\n */\n async resendInvite(orgId: string, inviteId: string): Promise<void> {\n try {\n await this.client.post<void>(`/orgs/${orgId}/invites/${inviteId}/resend`, {});\n } catch (error) {\n throw handleApiError(error, 'Failed to resend invite');\n }\n }\n\n /**\n * Accept an invite (public endpoint)\n */\n async acceptInvite(data: AcceptInviteRequest): Promise<AcceptInviteResponse> {\n try {\n return await this.client.post<AcceptInviteResponse>('/invites/accept', data);\n } catch (error) {\n throw handleApiError(error, 'Failed to accept invite');\n }\n }\n}\n","import { useState, useCallback, useMemo, useEffect, useRef } from 'react';\nimport type { Invite, OrgRole, AuthError, AcceptInviteResponse } from '../types';\nimport { useCedrosLogin } from '../context/useCedrosLogin';\nimport { InviteApiClient } from '../utils/inviteApi';\n\nexport interface UseInvitesReturn {\n /** List of pending invites */\n invites: Invite[];\n /** Total pending invites available on the server */\n total: number;\n /** Loading state */\n isLoading: boolean;\n /** Error state */\n error: AuthError | null;\n /** Fetch/refresh invites list */\n fetchInvites: (options?: { limit?: number; offset?: number }) => Promise<void>;\n /** Create a new invite */\n createInvite: (email: string, role?: Exclude<OrgRole, 'owner'>) => Promise<void>;\n /** Cancel a pending invite */\n cancelInvite: (inviteId: string) => Promise<void>;\n /** Resend an invite email */\n resendInvite: (inviteId: string) => Promise<void>;\n /** Accept an invite (public) */\n acceptInvite: (token: string) => Promise<AcceptInviteResponse>;\n}\n\n/**\n * Hook for managing organization invites.\n *\n * @param orgId - The organization ID to manage invites for\n *\n * @example\n * ```tsx\n * function InviteManager() {\n * const { activeOrg } = useOrgs();\n * const { invites, createInvite, cancelInvite, resendInvite } = useInvites(activeOrg?.id);\n *\n * const handleInvite = async (email: string) => {\n * await createInvite(email, 'member');\n * };\n *\n * return (\n * <div>\n * <InviteForm onSubmit={handleInvite} />\n * <ul>\n * {invites.map(invite => (\n * <li key={invite.id}>\n * {invite.email} ({invite.role})\n * <button onClick={() => resendInvite(invite.id)}>Resend</button>\n * <button onClick={() => cancelInvite(invite.id)}>Cancel</button>\n * </li>\n * ))}\n * </ul>\n * </div>\n * );\n * }\n * ```\n */\nexport function useInvites(orgId: string | undefined): UseInvitesReturn {\n const { config, authState, _internal } = useCedrosLogin();\n\n const [invites, setInvites] = useState<Invite[]>([]);\n const [total, setTotal] = useState(0);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<AuthError | null>(null);\n // P-13: Track fetched orgId to prevent duplicate fetches on remount\n const fetchedOrgIdRef = useRef<string | undefined>(undefined);\n const requestIdRef = useRef(0);\n\n const apiClient = useMemo(\n () =>\n new InviteApiClient(\n config.serverUrl,\n config.requestTimeout,\n config.retryAttempts,\n _internal?.getAccessToken\n ),\n [config.serverUrl, config.requestTimeout, config.retryAttempts, _internal]\n );\n\n // H-02: Use ref to avoid apiClient in callback dependencies\n // Prevents infinite loop when apiClient identity changes\n const apiClientRef = useRef(apiClient);\n apiClientRef.current = apiClient;\n\n const fetchInvites = useCallback(\n async (options?: { limit?: number; offset?: number }) => {\n if (!orgId || authState !== 'authenticated') {\n setInvites([]);\n setTotal(0);\n return;\n }\n\n setIsLoading(true);\n setError(null);\n const requestId = ++requestIdRef.current;\n\n try {\n const { limit = 50, offset = 0 } = options ?? {};\n const response = await apiClientRef.current.listInvites(orgId, limit, offset);\n if (requestId !== requestIdRef.current) return;\n setInvites(response.invites);\n setTotal(response.total);\n } catch (err) {\n if (requestId !== requestIdRef.current) return;\n setError(err as AuthError);\n } finally {\n if (requestId === requestIdRef.current) {\n setIsLoading(false);\n }\n }\n },\n [orgId, authState]\n );\n\n // P-13: Auto-fetch when orgId changes, but not on every remount\n useEffect(() => {\n if (authState !== 'authenticated') {\n fetchedOrgIdRef.current = undefined;\n return;\n }\n\n if (orgId !== fetchedOrgIdRef.current) {\n fetchedOrgIdRef.current = orgId;\n fetchInvites();\n }\n }, [orgId, authState, fetchInvites]);\n\n const createInvite = useCallback(\n async (email: string, role: Exclude<OrgRole, 'owner'> = 'member'): Promise<void> => {\n if (!orgId) {\n throw new Error('No organization selected');\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n await apiClientRef.current.createInvite(orgId, { email, role });\n // Refresh invites list\n await fetchInvites();\n } catch (err) {\n setError(err as AuthError);\n throw err;\n } finally {\n setIsLoading(false);\n }\n },\n [orgId, fetchInvites]\n );\n\n const cancelInvite = useCallback(\n async (inviteId: string): Promise<void> => {\n if (!orgId) {\n throw new Error('No organization selected');\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n await apiClientRef.current.cancelInvite(orgId, inviteId);\n // Refresh invites list\n await fetchInvites();\n } catch (err) {\n setError(err as AuthError);\n throw err;\n } finally {\n setIsLoading(false);\n }\n },\n [orgId, fetchInvites]\n );\n\n const resendInvite = useCallback(\n async (inviteId: string): Promise<void> => {\n if (!orgId) {\n throw new Error('No organization selected');\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n await apiClientRef.current.resendInvite(orgId, inviteId);\n } catch (err) {\n setError(err as AuthError);\n throw err;\n } finally {\n setIsLoading(false);\n }\n },\n [orgId]\n );\n\n const acceptInvite = useCallback(async (token: string): Promise<AcceptInviteResponse> => {\n setIsLoading(true);\n setError(null);\n\n try {\n return await apiClientRef.current.acceptInvite({ token });\n } catch (err) {\n setError(err as AuthError);\n throw err;\n } finally {\n setIsLoading(false);\n }\n }, []);\n\n return {\n invites,\n total,\n isLoading,\n error,\n fetchInvites,\n createInvite,\n cancelInvite,\n resendInvite,\n acceptInvite,\n };\n}\n","import { useState, useEffect, useCallback, useMemo } from 'react';\nimport { useSystemSettings } from './useSystemSettings';\n\n/**\n * Server-side feature flags stored in system settings.\n *\n * These control which features are available in the application.\n * Unlike client-side FeatureFlags (passed to CedrosLoginProvider),\n * these can be toggled at runtime via the admin dashboard.\n *\n * **Cosmetic vs enforced:**\n * Some flags only affect UI visibility (cosmetic) while others are\n * enforced server-side. See per-field docs below.\n *\n * Settings that are enforced per-request by the server (hard 403 if disabled):\n * `auth_email_enabled`, `auth_google_enabled`, `auth_apple_enabled`,\n * `auth_instantlink_enabled`, `feature_user_withdrawals`, `privacy_period_secs`,\n * withdrawal worker settings, and deposit fee settings.\n *\n * Settings applied at server startup (take effect after restart):\n * `security_cors_origins`, `rate_limit_*`, `auth_webauthn_*`, `webhook_*`.\n */\nexport interface ServerFeatures {\n /**\n * Enable multi-tenant organizations. Controls: Team, Invites sections.\n *\n * **Cosmetic** — org endpoints are always reachable server-side.\n * This flag only controls admin dashboard section visibility.\n */\n organizations: boolean;\n /** Enable Enterprise SSO for organizations. Startup-config enforced. */\n sso: boolean;\n /**\n * Enable two-factor authentication (TOTP).\n *\n * **Cosmetic** — MFA is actually gated by whether the user has TOTP\n * enrolled (`has_mfa_enabled()`), not by this flag. This controls\n * admin dashboard visibility only.\n */\n mfa: boolean;\n /** Enable embedded wallet for transaction signing. Startup-config enforced. */\n walletSigning: boolean;\n /**\n * Enable deposits and credits system.\n * Controls: Deposits, Withdrawals, Credit System admin sections.\n * Deposit/withdrawal endpoints are enforced server-side.\n */\n credits: boolean;\n /**\n * Enable user withdrawals from embedded wallet to external addresses.\n * **Enforced** — server returns 403 on withdrawal endpoints when disabled.\n */\n userWithdrawals: boolean;\n /**\n * Enable Cedros Pay integration.\n * Controls: Products, Transactions, Refunds admin sections.\n *\n * **Cosmetic** — only controls admin dashboard tab visibility.\n */\n cedrosPay: boolean;\n}\n\n/**\n * Default feature values when settings haven't loaded yet.\n * All features disabled by default for safety.\n */\nconst DEFAULT_FEATURES: ServerFeatures = {\n organizations: false,\n sso: false,\n mfa: false,\n walletSigning: false,\n credits: false,\n userWithdrawals: false,\n cedrosPay: false,\n};\n\nexport interface UseServerFeaturesReturn {\n /** Current feature flag states */\n features: ServerFeatures;\n /** Whether settings are still loading */\n isLoading: boolean;\n /** Error if settings failed to load */\n error: Error | null;\n /** Refresh feature flags from server */\n refetch: () => Promise<void>;\n /** Check if a specific feature is enabled */\n isEnabled: (feature: keyof ServerFeatures) => boolean;\n}\n\n/**\n * Hook for reading server-side feature flags from system settings.\n *\n * Use this to conditionally show/hide features based on admin settings.\n *\n * @example\n * ```tsx\n * function AdminDashboard() {\n * const { features, isLoading, isEnabled } = useServerFeatures();\n *\n * if (isLoading) return <LoadingSpinner />;\n *\n * return (\n * <nav>\n * {isEnabled('organizations') && <NavItem>Team</NavItem>}\n * {isEnabled('credits') && <NavItem>Deposits</NavItem>}\n * </nav>\n * );\n * }\n * ```\n */\nexport function useServerFeatures(): UseServerFeaturesReturn {\n const { settings, isLoading, error, fetchSettings, getValue } = useSystemSettings();\n const [hasFetched, setHasFetched] = useState(false);\n\n // Fetch settings on mount\n useEffect(() => {\n if (!hasFetched) {\n fetchSettings();\n setHasFetched(true);\n }\n }, [fetchSettings, hasFetched]);\n\n // Parse boolean value from string setting\n const parseBoolean = useCallback((value: string | undefined): boolean => {\n if (value === undefined) return false;\n return value === 'true' || value === '1';\n }, []);\n\n // Derive features from settings\n const features = useMemo<ServerFeatures>(() => {\n // If no settings loaded yet, return defaults\n if (Object.keys(settings).length === 0) {\n return DEFAULT_FEATURES;\n }\n\n return {\n organizations: parseBoolean(getValue('feature_organizations')),\n sso: parseBoolean(getValue('feature_sso')),\n mfa: parseBoolean(getValue('feature_mfa')),\n walletSigning: parseBoolean(getValue('feature_wallet_signing')),\n credits: parseBoolean(getValue('feature_credits')),\n userWithdrawals: parseBoolean(getValue('feature_user_withdrawals')),\n cedrosPay: parseBoolean(getValue('feature_cedros_pay')),\n };\n }, [settings, getValue, parseBoolean]);\n\n const refetch = useCallback(async () => {\n await fetchSettings();\n }, [fetchSettings]);\n\n const isEnabled = useCallback(\n (feature: keyof ServerFeatures): boolean => {\n return features[feature];\n },\n [features]\n );\n\n return {\n features,\n isLoading,\n error,\n refetch,\n isEnabled,\n };\n}\n","/**\n * Organization role in RBAC hierarchy\n * owner > admin > member\n */\nexport type OrgRole = 'owner' | 'admin' | 'member';\n\n/**\n * Organization entity\n */\nexport interface Organization {\n id: string;\n name: string;\n slug: string;\n logoUrl?: string;\n isPersonal: boolean;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Membership - user's relationship to an organization\n */\nexport interface Membership {\n id?: string;\n userId?: string;\n orgId?: string;\n role: OrgRole;\n joinedAt?: string;\n}\n\n/**\n * Organization with membership details for the current user\n */\nexport interface OrgWithMembership extends Organization {\n membership: Membership;\n}\n\n/**\n * Permission types for RBAC\n */\nexport type Permission =\n | 'org:delete'\n | 'org:update'\n | 'org:read'\n | 'member:invite'\n | 'member:remove'\n | 'member:role_change'\n | 'member:read'\n | 'invite:create'\n | 'invite:cancel'\n | 'invite:read'\n | 'audit:read';\n\n/**\n * Create organization request\n */\nexport interface CreateOrgRequest {\n name: string;\n slug?: string;\n}\n\n/**\n * Update organization request\n */\nexport interface UpdateOrgRequest {\n name?: string;\n slug?: string;\n logoUrl?: string;\n}\n\n/**\n * List organizations response\n */\nexport interface ListOrgsResponse {\n orgs: Array<Organization & { role: OrgRole }>;\n total?: number;\n limit?: number;\n offset?: number;\n}\n\n/**\n * Authorization check request\n */\nexport interface AuthorizeRequest {\n orgId: string;\n action: string;\n resource?: string;\n resourceId?: string;\n}\n\n/**\n * Authorization check response\n */\nexport interface AuthorizeResponse {\n allowed: boolean;\n reason?: string;\n}\n\n/**\n * Permissions response\n */\nexport interface PermissionsResponse {\n permissions: Permission[];\n role: OrgRole;\n}\n\n/**\n * Organization state for context\n */\nexport interface OrgState {\n /** Currently active organization */\n activeOrg: OrgWithMembership | null;\n /** All organizations the user belongs to */\n orgs: OrgWithMembership[];\n /** User's permissions in the active org */\n permissions: Permission[];\n /** User's role in the active org */\n role: OrgRole | null;\n /** Loading state for org operations */\n isLoading: boolean;\n}\n\n// =============================================================================\n// DASHBOARD PERMISSIONS\n// =============================================================================\n\n/**\n * Admin dashboard sections that can be permission-controlled\n */\nexport type DashboardSection =\n // Cedros Login sections\n | 'users'\n | 'team'\n | 'deposits'\n | 'withdrawals'\n | 'settings-wallet'\n | 'settings-auth'\n | 'settings-messaging'\n | 'settings-credits'\n | 'settings-server'\n // Cedros Pay sections\n | 'pay-products'\n | 'pay-subscriptions'\n | 'pay-transactions'\n | 'pay-coupons'\n | 'pay-refunds'\n | 'pay-storefront'\n | 'pay-ai'\n | 'pay-payment'\n | 'pay-messaging'\n | 'pay-settings';\n\n/**\n * Cedros Login dashboard sections\n */\nexport const LOGIN_DASHBOARD_SECTIONS: DashboardSection[] = [\n 'users',\n 'team',\n 'deposits',\n 'withdrawals',\n 'settings-wallet',\n 'settings-auth',\n 'settings-messaging',\n 'settings-credits',\n 'settings-server',\n];\n\n/**\n * Cedros Pay dashboard sections\n */\nexport const PAY_DASHBOARD_SECTIONS: DashboardSection[] = [\n 'pay-products',\n 'pay-subscriptions',\n 'pay-transactions',\n 'pay-coupons',\n 'pay-refunds',\n 'pay-storefront',\n 'pay-ai',\n 'pay-payment',\n 'pay-messaging',\n 'pay-settings',\n];\n\n/**\n * All available dashboard sections\n */\nexport const ALL_DASHBOARD_SECTIONS: DashboardSection[] = [\n ...LOGIN_DASHBOARD_SECTIONS,\n ...PAY_DASHBOARD_SECTIONS,\n];\n\n/**\n * Human-readable labels for dashboard sections\n */\nexport const DASHBOARD_SECTION_LABELS: Record<DashboardSection, string> = {\n // Cedros Login\n users: 'Users',\n team: 'Team',\n deposits: 'Deposits',\n withdrawals: 'Withdrawals',\n 'settings-wallet': 'Wallet Settings',\n 'settings-auth': 'Auth Settings',\n 'settings-messaging': 'Messages Settings',\n 'settings-credits': 'Credits Settings',\n 'settings-server': 'Server Settings',\n // Cedros Pay\n 'pay-products': 'Products',\n 'pay-subscriptions': 'Subscriptions',\n 'pay-transactions': 'Transactions',\n 'pay-coupons': 'Coupons',\n 'pay-refunds': 'Refunds',\n 'pay-storefront': 'Storefront',\n 'pay-ai': 'Store AI',\n 'pay-payment': 'Payment Options',\n 'pay-messaging': 'Store Messages',\n 'pay-settings': 'Store Server',\n};\n\n/**\n * Dashboard permissions per role\n * Only admin and member are configurable - owner always has full access\n */\nexport interface DashboardPermissions {\n admin: Record<DashboardSection, boolean>;\n member: Record<DashboardSection, boolean>;\n}\n\n/**\n * Default dashboard permissions for new orgs\n */\nexport const DEFAULT_DASHBOARD_PERMISSIONS: DashboardPermissions = {\n admin: {\n // Cedros Login\n users: true,\n team: true,\n deposits: true,\n withdrawals: true,\n 'settings-wallet': true,\n 'settings-auth': true,\n 'settings-messaging': true,\n 'settings-credits': true,\n 'settings-server': true,\n // Cedros Pay\n 'pay-products': true,\n 'pay-subscriptions': true,\n 'pay-transactions': true,\n 'pay-coupons': true,\n 'pay-refunds': true,\n 'pay-storefront': true,\n 'pay-ai': true,\n 'pay-payment': true,\n 'pay-messaging': true,\n 'pay-settings': true,\n },\n member: {\n // Cedros Login\n users: false,\n team: true,\n deposits: false,\n withdrawals: false,\n 'settings-wallet': false,\n 'settings-auth': false,\n 'settings-messaging': false,\n 'settings-credits': false,\n 'settings-server': false,\n // Cedros Pay\n 'pay-products': false,\n 'pay-subscriptions': false,\n 'pay-transactions': false,\n 'pay-coupons': false,\n 'pay-refunds': false,\n 'pay-storefront': false,\n 'pay-ai': false,\n 'pay-payment': false,\n 'pay-messaging': false,\n 'pay-settings': false,\n },\n};\n","import { useState, useCallback, useMemo, useRef, useEffect } from 'react';\nimport type { DashboardSection, DashboardPermissions, AuthError } from '../types';\nimport { DEFAULT_DASHBOARD_PERMISSIONS } from '../types/org';\nimport { useCedrosLogin } from '../context/useCedrosLogin';\nimport { useOrgs } from './useOrgs';\nimport { ApiClient } from '../utils/apiClient';\n\nexport interface UseDashboardPermissionsReturn {\n /** Current dashboard permissions config */\n permissions: DashboardPermissions;\n /** Whether the current user can access a specific section */\n canAccess: (section: DashboardSection) => boolean;\n /** Update permissions (owner only) */\n updatePermissions: (permissions: DashboardPermissions) => Promise<void>;\n /** Loading state */\n isLoading: boolean;\n /** Updating state */\n isUpdating: boolean;\n /** Error state */\n error: AuthError | null;\n /** Refresh permissions from server */\n fetchPermissions: () => Promise<void>;\n}\n\n/**\n * Hook for managing dashboard permissions per role.\n *\n * Allows org owners to configure which dashboard sections each role can access.\n * - Owner always has full access (not configurable)\n * - Admin and Member roles are configurable\n *\n * @example\n * ```tsx\n * function AdminDashboard() {\n * const { canAccess, permissions, updatePermissions } = useDashboardPermissions();\n *\n * // Check if current user can access a section\n * if (!canAccess('deposits')) {\n * return <div>You don't have access to deposits</div>;\n * }\n *\n * // Update permissions (owner only)\n * const toggleMemberDeposits = () => {\n * updatePermissions({\n * ...permissions,\n * member: { ...permissions.member, deposits: !permissions.member.deposits },\n * });\n * };\n * }\n * ```\n */\nexport function useDashboardPermissions(): UseDashboardPermissionsReturn {\n const { config, authState, _internal } = useCedrosLogin();\n const { activeOrg, role } = useOrgs();\n\n const [permissions, setPermissions] = useState<DashboardPermissions>(\n DEFAULT_DASHBOARD_PERMISSIONS\n );\n const [isLoading, setIsLoading] = useState(false);\n const [isUpdating, setIsUpdating] = useState(false);\n const [error, setError] = useState<AuthError | null>(null);\n const requestIdRef = useRef(0);\n\n const apiClient = useMemo(\n () =>\n new ApiClient({\n baseUrl: config.serverUrl,\n timeoutMs: config.requestTimeout,\n retryAttempts: config.retryAttempts,\n getAccessToken: _internal?.getAccessToken,\n }),\n [config.serverUrl, config.requestTimeout, config.retryAttempts, _internal]\n );\n\n // Use ref to avoid apiClient in callback dependencies\n const apiClientRef = useRef(apiClient);\n apiClientRef.current = apiClient;\n\n const fetchPermissions = useCallback(async () => {\n if (authState !== 'authenticated' || !activeOrg) {\n setPermissions(DEFAULT_DASHBOARD_PERMISSIONS);\n return;\n }\n\n setIsLoading(true);\n setError(null);\n const requestId = ++requestIdRef.current;\n\n try {\n const response = await apiClientRef.current.get<{ permissions: DashboardPermissions }>(\n '/admin/dashboard-permissions'\n );\n if (requestId !== requestIdRef.current) return;\n setPermissions(response.permissions);\n } catch (err) {\n if (requestId !== requestIdRef.current) return;\n // If 404, use defaults (permissions not configured yet)\n if (err instanceof Error && err.message.includes('404')) {\n setPermissions(DEFAULT_DASHBOARD_PERMISSIONS);\n } else {\n const message = err instanceof Error ? err.message : 'Failed to fetch permissions';\n setError({ code: 'NETWORK_ERROR', message } as AuthError);\n // Fall back to defaults on error\n setPermissions(DEFAULT_DASHBOARD_PERMISSIONS);\n }\n } finally {\n if (requestId === requestIdRef.current) {\n setIsLoading(false);\n }\n }\n }, [authState, activeOrg]);\n\n const updatePermissions = useCallback(\n async (newPermissions: DashboardPermissions): Promise<void> => {\n if (authState !== 'authenticated' || !activeOrg) {\n throw new Error('Not authenticated');\n }\n\n if (role !== 'owner') {\n throw new Error('Only owners can modify dashboard permissions');\n }\n\n setIsUpdating(true);\n setError(null);\n\n try {\n await apiClientRef.current.request<{ permissions: DashboardPermissions }>({\n method: 'PUT',\n path: '/admin/dashboard-permissions',\n body: newPermissions,\n });\n setPermissions(newPermissions);\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Failed to update permissions';\n const authError = { code: 'NETWORK_ERROR', message } as AuthError;\n setError(authError);\n throw new Error(message);\n } finally {\n setIsUpdating(false);\n }\n },\n [authState, activeOrg, role]\n );\n\n /**\n * Check if the current user can access a dashboard section\n * - No org context (system admin): full access (permissions are org-scoped)\n * - Owner: always has full access\n * - Admin: check permissions.admin[section]\n * - Member: check permissions.member[section]\n */\n const canAccess = useCallback(\n (section: DashboardSection): boolean => {\n // No org context = system admin level, allow all\n // (dashboard permissions are org-scoped, not system-scoped)\n if (!activeOrg || !role) {\n return true;\n }\n\n // Owner always has full access\n if (role === 'owner') {\n return true;\n }\n\n // Admin and member: check configured permissions\n const rolePermissions = permissions[role as 'admin' | 'member'];\n return rolePermissions?.[section] ?? false;\n },\n [activeOrg, role, permissions]\n );\n\n // Fetch permissions when org changes\n useEffect(() => {\n if (activeOrg?.id) {\n fetchPermissions();\n }\n }, [activeOrg?.id, fetchPermissions]);\n\n return {\n permissions,\n canAccess,\n updatePermissions,\n isLoading,\n isUpdating,\n error,\n fetchPermissions,\n };\n}\n","/**\n * PermissionsSection - Dashboard permissions matrix for role configuration\n *\n * Allows org owners to configure which dashboard sections each role can access.\n */\n\nimport React, { useCallback, useRef, useEffect } from 'react';\nimport { useDashboardPermissions } from '../../hooks/useDashboardPermissions';\nimport { useServerFeatures } from '../../hooks/useServerFeatures';\nimport {\n LOGIN_DASHBOARD_SECTIONS,\n PAY_DASHBOARD_SECTIONS,\n DASHBOARD_SECTION_LABELS,\n type DashboardSection,\n type DashboardPermissions,\n type OrgRole,\n} from '../../types/org';\n\ninterface PermissionToggleProps {\n checked: boolean;\n onChange: (checked: boolean) => void;\n disabled?: boolean;\n label: string;\n}\n\nfunction PermissionToggle({ checked, onChange, disabled, label }: PermissionToggleProps) {\n return (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={checked}\n aria-label={label}\n disabled={disabled}\n className={`cedros-toggle cedros-toggle-sm ${checked ? 'cedros-toggle-on' : 'cedros-toggle-off'} ${disabled ? 'cedros-toggle-disabled' : ''}`}\n onClick={() => !disabled && onChange(!checked)}\n >\n <span className=\"cedros-toggle-track\">\n <span className=\"cedros-toggle-thumb\" />\n </span>\n </button>\n );\n}\n\nexport interface PermissionsSectionProps {\n /** Current user's role in the org */\n userRole?: OrgRole | null;\n}\n\nexport function PermissionsSection({ userRole }: PermissionsSectionProps): React.JSX.Element {\n const { permissions, updatePermissions, isLoading, isUpdating, error } =\n useDashboardPermissions();\n const { features, isLoading: featuresLoading } = useServerFeatures();\n const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const pendingPermissions = useRef<DashboardPermissions | null>(null);\n\n const isOwner = userRole === 'owner';\n const cedrosPayEnabled = features.cedrosPay;\n\n // Debounced save - batch rapid changes\n const debouncedSave = useCallback(\n (newPermissions: DashboardPermissions) => {\n pendingPermissions.current = newPermissions;\n if (debounceRef.current) {\n clearTimeout(debounceRef.current);\n }\n debounceRef.current = setTimeout(() => {\n if (pendingPermissions.current) {\n updatePermissions(pendingPermissions.current).catch(() => {\n // Error is already set in state by the hook\n });\n pendingPermissions.current = null;\n }\n }, 500);\n },\n [updatePermissions]\n );\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n if (debounceRef.current) {\n clearTimeout(debounceRef.current);\n }\n };\n }, []);\n\n const handleToggle = useCallback(\n (role: 'admin' | 'member', section: DashboardSection, enabled: boolean) => {\n const newPermissions: DashboardPermissions = {\n ...permissions,\n [role]: {\n ...permissions[role],\n [section]: enabled,\n },\n };\n debouncedSave(newPermissions);\n },\n [permissions, debouncedSave]\n );\n\n if (isLoading || featuresLoading) {\n return (\n <div className=\"cedros-dashboard__section\">\n <div className=\"cedros-dashboard__loading\">Loading permissions...</div>\n </div>\n );\n }\n\n if (!isOwner) {\n return (\n <div className=\"cedros-dashboard__section\">\n <div className=\"cedros-dashboard__empty\">\n Only organization owners can configure dashboard permissions.\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"cedros-dashboard__section cedros-permissions-section\">\n <div className=\"cedros-permissions-header\">\n <p className=\"cedros-permissions-description\">\n Configure which dashboard sections each role can access. Owners always have full access.\n </p>\n {error && <div className=\"cedros-permissions-error\">{error.message}</div>}\n {isUpdating && <span className=\"cedros-permissions-saving\">Saving...</span>}\n </div>\n\n <div className=\"cedros-permissions-matrix\">\n <table className=\"cedros-permissions-table\">\n <tbody>\n {/* Cedros Login Sections */}\n <tr className=\"cedros-permissions-group-header\">\n <th className=\"cedros-permissions-section-header\">Cedros Login</th>\n <th className=\"cedros-permissions-role-header\">Admin</th>\n <th className=\"cedros-permissions-role-header\">Member</th>\n </tr>\n {LOGIN_DASHBOARD_SECTIONS.map((section) => (\n <tr key={section} className=\"cedros-permissions-row\">\n <td className=\"cedros-permissions-section-label\">\n {DASHBOARD_SECTION_LABELS[section]}\n </td>\n <td className=\"cedros-permissions-toggle-cell\">\n <PermissionToggle\n checked={permissions.admin[section] ?? false}\n onChange={(enabled) => handleToggle('admin', section, enabled)}\n disabled={isUpdating}\n label={`Admin access to ${DASHBOARD_SECTION_LABELS[section]}`}\n />\n </td>\n <td className=\"cedros-permissions-toggle-cell\">\n <PermissionToggle\n checked={permissions.member[section] ?? false}\n onChange={(enabled) => handleToggle('member', section, enabled)}\n disabled={isUpdating}\n label={`Member access to ${DASHBOARD_SECTION_LABELS[section]}`}\n />\n </td>\n </tr>\n ))}\n\n {/* Cedros Pay Sections (only when cedrosPay feature is enabled) */}\n {cedrosPayEnabled && (\n <>\n <tr className=\"cedros-permissions-group-header\">\n <th className=\"cedros-permissions-section-header\">Cedros Pay</th>\n <th className=\"cedros-permissions-role-header\">Admin</th>\n <th className=\"cedros-permissions-role-header\">Member</th>\n </tr>\n {PAY_DASHBOARD_SECTIONS.map((section) => (\n <tr key={section} className=\"cedros-permissions-row\">\n <td className=\"cedros-permissions-section-label\">\n {DASHBOARD_SECTION_LABELS[section]}\n </td>\n <td className=\"cedros-permissions-toggle-cell\">\n <PermissionToggle\n checked={permissions.admin[section] ?? false}\n onChange={(enabled) => handleToggle('admin', section, enabled)}\n disabled={isUpdating}\n label={`Admin access to ${DASHBOARD_SECTION_LABELS[section]}`}\n />\n </td>\n <td className=\"cedros-permissions-toggle-cell\">\n <PermissionToggle\n checked={permissions.member[section] ?? false}\n onChange={(enabled) => handleToggle('member', section, enabled)}\n disabled={isUpdating}\n label={`Member access to ${DASHBOARD_SECTION_LABELS[section]}`}\n />\n </td>\n </tr>\n ))}\n </>\n )}\n </tbody>\n </table>\n </div>\n </div>\n );\n}\n"],"names":["ROLE_OPTIONS","MemberList","members","currentUserId","isLoading","error","canManage","canChangeRoles","onUpdateRole","onRemove","className","sortField","setSortField","useState","sortOrder","setSortOrder","toggleSort","field","sortedMembers","useMemo","roleOrder","a","b","aVal","bVal","jsxs","jsx","LoadingSpinner","ErrorMessage","member","MemberRow","isCurrentUser","isUpdating","setIsUpdating","selectedRole","setSelectedRole","handleRoleChange","useCallback","newRole","handleRemove","isOwner","canModify","MemberAvatar","e","role","formatDate","user","sanitizedPicture","sanitizeImageUrl","initial","dateString","DEFAULT_ROLES","InviteForm","onSubmit","availableRoles","defaultRole","email","setEmail","setRole","formError","setFormError","success","setSuccess","successTimerRef","useRef","isMountedRef","useEffect","handleSubmit","trimmedEmail","validateEmail","CheckIcon","r","InviteList","invites","onCancel","onResend","invite","InviteItem","resendSuccess","setResendSuccess","resendTimerRef","isExpired","handleCancel","handleResend","formatRelativeTime","date","now","diffMs","diffDays","MemberApiClient","baseUrl","timeoutMs","retryAttempts","getAccessToken","ApiClient","orgId","limit","offset","response","handleApiError","userId","data","useMembers","config","authState","_internal","useCedrosLogin","setMembers","total","setTotal","setIsLoading","setError","fetchedOrgIdRef","requestIdRef","apiClient","apiClientRef","fetchMembers","options","requestId","err","updateMemberRole","removeMember","InviteApiClient","inviteId","useInvites","setInvites","fetchInvites","createInvite","cancelInvite","resendInvite","acceptInvite","token","DEFAULT_FEATURES","useServerFeatures","settings","fetchSettings","getValue","useSystemSettings","hasFetched","setHasFetched","parseBoolean","value","features","refetch","isEnabled","feature","LOGIN_DASHBOARD_SECTIONS","PAY_DASHBOARD_SECTIONS","DASHBOARD_SECTION_LABELS","DEFAULT_DASHBOARD_PERMISSIONS","useDashboardPermissions","activeOrg","useOrgs","permissions","setPermissions","fetchPermissions","message","updatePermissions","newPermissions","canAccess","section","PermissionToggle","checked","onChange","disabled","label","PermissionsSection","userRole","featuresLoading","debounceRef","pendingPermissions","cedrosPayEnabled","debouncedSave","handleToggle","enabled","Fragment"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";const l=require("react/jsx-runtime"),n=require("react"),T=require("@solana/wallet-adapter-react"),D=require("@solana/wallet-adapter-react-ui"),W=require("./useCedrosLogin-C9MrcZvh.cjs"),K=require("./validation-BuGQrA-K.cjs"),G=require("./LoadingSpinner-d6sSxgQN.cjs");function _(){const{config:e,_internal:t}=W.useCedrosLogin(),[w,o]=n.useState(!1),[j,i]=n.useState(null),g=n.useMemo(()=>new W.ApiClient({baseUrl:e.serverUrl,timeoutMs:e.requestTimeout,retryAttempts:e.retryAttempts}),[e.serverUrl,e.requestTimeout,e.retryAttempts]),L=n.useCallback(async f=>{if(!K.validateSolanaPublicKey(f)){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:f},{credentials:"omit"})}catch(u){const r=W.handleApiError(u,"Failed to get challenge");throw i(r),r}finally{o(!1)}},[g]),c=n.useCallback(async(f,u,r)=>{if(!K.validateSolanaPublicKey(f)){const s={code:"INVALID_PUBLIC_KEY",message:"Invalid Solana public key format"};throw i(s),s}o(!0),i(null);try{const s=await g.post("/solana",{publicKey:f,signature:u,message:r});return e.callbacks?.onLoginSuccess?.(s.user,"solana"),t?.handleLoginSuccess(s.user,s.tokens),s}catch(s){const E=W.handleApiError(s,"Solana sign-in failed");throw i(E),E}finally{o(!1)}},[g,e.callbacks,t]),C=n.useCallback(()=>i(null),[]);return{requestChallenge:L,signIn:c,isLoading:w,error:j,clearError:C}}const J=[];function Q(e){return e.walletContext?l.jsx(D.WalletModalProvider,{children:l.jsx(U,{...e})}):l.jsx(T.WalletProvider,{wallets:J,localStorageKey:"cedros-walletName",children:l.jsx(D.WalletModalProvider,{children:l.jsx(U,{...e})})})}function U({onSuccess:e,onError:t,className:w="",variant:o="default",size:j="md",disabled:i=!1,hideIfNoWallet:g=!0,onLoadingChange:L,walletContext:c}){const{requestChallenge:C,signIn:f,isLoading:u}=_(),r=T.useWallet(),{visible:s,setVisible:E}=D.useWalletModal(),[h,y]=n.useState(!1),[z,q]=n.useState(!1),A=n.useRef(!1),k=n.useRef(!1),M=n.useRef(!1),d=c?.connected??r.connected,m=c?.connecting??r.connecting,b=c?.publicKey??r.publicKey,S=c?.signMessage??r.signMessage,p=c?.wallet??r.wallet,F=c?.wallets??r.wallets,H=c?c.select:a=>r.select(a),B=c?.connect??r.connect,P=F.filter(a=>a.adapter.readyState==="Installed"||a.adapter.readyState==="Loadable"),R=n.useCallback(async()=>{if(!A.current){if(!b||!S){t?.(new Error("Wallet not ready"));return}A.current=!0;try{const a=b.toBase58(),I=await C(a),O=new TextEncoder().encode(I.message),x=await S(O);if(!(x instanceof Uint8Array)||x.length===0)throw new Error("Wallet returned invalid signature");let N;try{N=btoa(String.fromCharCode(...x))}catch{throw new Error("Failed to encode signature")}await f(a,N,I.message),M.current=!1,e?.()}catch(a){const I=a instanceof Error?a:new Error(String(a));M.current=!0,t?.(I)}finally{A.current=!1,y(!1)}}},[b,S,C,f,e,t]);if(n.useEffect(()=>{z&&p&&!d&&!m&&(q(!1),B().catch(a=>{t?.(a instanceof Error?a:new Error(String(a))),y(!1)}))},[z,p,d,m,B,t]),n.useEffect(()=>{h&&d&&b&&S&&!A.current&&R().catch(()=>{})},[h,d,b,S,R]),n.useEffect(()=>{s?k.current=!0:k.current&&(k.current=!1,h&&!d&&p&&!m?q(!0):h&&!d&&y(!1))},[s,h,d,p,m]),g&&P.length===0)return null;const V=async()=>{i||u||m||(d&&b&&S&&!M.current?(y(!0),await R()):P.length===1&&!p?(H(P[0].adapter.name),y(!0),q(!0)):(M.current=!1,p&&r.select(null),E(!0),y(!0)))},Y={sm:"cedros-button-sm",md:"cedros-button-md",lg:"cedros-button-lg"},$={default:"cedros-button-social",outline:"cedros-button-social-outline"},v=u||m||h&&!d;return n.useEffect(()=>{L?.(v)},[v,L]),l.jsxs("button",{type:"button",className:`cedros-button ${$[o]} ${Y[j]} ${w}`,onClick:V,disabled:i||v,"aria-label":"Continue with Solana",children:[v?l.jsx(G.LoadingSpinner,{size:"sm"}):l.jsxs("svg",{className:"cedros-button-icon",width:"18",height:"18",viewBox:"0 0 128 128",fill:"currentColor","aria-hidden":"true",children:[l.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"}),l.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"}),l.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"})]}),l.jsx("span",{children:"Continue with Solana"})]})}function X(e){if(typeof window>"u")return!1;try{const t=require("@solana-mobile/wallet-standard-mobile"),w=e?.chains??["solana:mainnet"],o={appIdentity:{name:e?.name,uri:e?.uri,icon:e?.icon},chains:w};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=Q;exports.registerMobileWallet=X;exports.useSolanaAuth=_;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mobileWalletAdapter-B6ELaZp1.cjs","sources":["../src/hooks/useSolanaAuth.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","import { useState, useEffect, useCallback, useRef } from 'react';\nimport { WalletProvider, useWallet } from '@solana/wallet-adapter-react';\nimport { WalletModalProvider, useWalletModal } from '@solana/wallet-adapter-react-ui';\nimport type { WalletName } from '@solana/wallet-adapter-base';\nimport { useSolanaAuth } from '../../hooks/useSolanaAuth';\nimport { LoadingSpinner } from '../shared/LoadingSpinner';\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 /** Called when the button's loading state changes (connecting, signing, etc.). */\n onLoadingChange?: (loading: boolean) => void;\n /**\n * Solana wallet adapter context. Pass this from @solana/wallet-adapter-react's useWallet().\n * When provided, the component assumes a WalletProvider exists in the React tree and\n * uses the consumer's wallet context for wallet discovery and connection.\n * When omitted, the component provides its own WalletProvider with wallet-standard discovery.\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/** Stable empty array to avoid re-renders in self-contained WalletProvider. */\nconst EMPTY_ADAPTERS: [] = [];\n\n/**\n * Solana wallet login button with one-click authentication.\n *\n * Uses the standard wallet adapter modal for wallet selection, which provides\n * real brand icons and discovers all wallet-standard-compliant wallets.\n *\n * When `walletContext` is provided, assumes a WalletProvider exists in the tree.\n * Otherwise, wraps itself with WalletProvider for self-contained operation.\n */\nexport function SolanaLoginButton(props: SolanaLoginButtonProps) {\n if (props.walletContext) {\n // Consumer has their own WalletProvider; just add modal capability\n return (\n <WalletModalProvider>\n <SolanaLoginInner {...props} />\n </WalletModalProvider>\n );\n }\n\n // Self-contained: provide wallet-standard discovery + modal\n return (\n <WalletProvider wallets={EMPTY_ADAPTERS} localStorageKey=\"cedros-walletName\">\n <WalletModalProvider>\n <SolanaLoginInner {...props} />\n </WalletModalProvider>\n </WalletProvider>\n );\n}\n\nfunction SolanaLoginInner({\n onSuccess,\n onError,\n className = '',\n variant = 'default',\n size = 'md',\n disabled = false,\n hideIfNoWallet = true,\n onLoadingChange,\n walletContext,\n}: SolanaLoginButtonProps) {\n const { requestChallenge, signIn, isLoading: isAuthLoading } = useSolanaAuth();\n const adapterWallet = useWallet();\n const { visible: modalVisible, setVisible: setModalVisible } = useWalletModal();\n const [pendingLogin, setPendingLogin] = useState(false);\n const [triggerConnect, setTriggerConnect] = useState(false);\n const isProcessingRef = useRef(false);\n const modalWasOpen = useRef(false);\n const signRejectedRef = useRef(false);\n\n // Use walletContext if provided, otherwise use adapter's useWallet()\n const connected = walletContext?.connected ?? adapterWallet.connected;\n const connecting = walletContext?.connecting ?? adapterWallet.connecting;\n const publicKey = walletContext?.publicKey ?? adapterWallet.publicKey;\n const signMessage = walletContext?.signMessage ?? adapterWallet.signMessage;\n const wallet = walletContext?.wallet ?? adapterWallet.wallet;\n const wallets = walletContext?.wallets ?? adapterWallet.wallets;\n const select = walletContext\n ? walletContext.select\n : (name: string) => adapterWallet.select(name as WalletName);\n const connect = walletContext?.connect ?? adapterWallet.connect;\n\n // Get installed/ready wallets\n const installedWallets = wallets.filter(\n (w) => w.adapter.readyState === 'Installed' || w.adapter.readyState === 'Loadable'\n );\n\n // Execute the sign-in flow (challenge → sign → verify)\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 const challenge = await requestChallenge(pubKeyString);\n\n const messageBytes = new TextEncoder().encode(challenge.message);\n const signatureBytes = await signMessage(messageBytes);\n\n if (!(signatureBytes instanceof Uint8Array) || signatureBytes.length === 0) {\n throw new Error('Wallet returned invalid signature');\n }\n\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 await signIn(pubKeyString, signature, challenge.message);\n signRejectedRef.current = false;\n onSuccess?.();\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n signRejectedRef.current = true;\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) {\n setTriggerConnect(false);\n connect().catch((err) => {\n onError?.(err instanceof Error ? err : new Error(String(err)));\n setPendingLogin(false);\n });\n }\n }, [triggerConnect, wallet, connected, connecting, connect, onError]);\n\n // Auto-execute sign-in when connected with pending login\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 // When modal closes: connect if a wallet was selected, else reset.\n // Wallet is always deselected before opening, so any non-null wallet = user chose one.\n useEffect(() => {\n if (modalVisible) {\n modalWasOpen.current = true;\n } else if (modalWasOpen.current) {\n modalWasOpen.current = false;\n if (pendingLogin && !connected && wallet && !connecting) {\n setTriggerConnect(true);\n } else if (pendingLogin && !connected) {\n setPendingLogin(false);\n }\n }\n }, [modalVisible, pendingLogin, connected, wallet, connecting]);\n\n // Hide button if no wallets detected\n if (hideIfNoWallet && installedWallets.length === 0) {\n return null;\n }\n\n const handleClick = async () => {\n if (disabled || isAuthLoading || connecting) return;\n\n if (connected && publicKey && signMessage && !signRejectedRef.current) {\n // Already connected, previous attempt wasn't rejected — sign immediately\n setPendingLogin(true);\n await executeSignIn();\n } else if (installedWallets.length === 1 && !wallet) {\n // Single installed wallet, nothing remembered — auto-select + connect\n select(installedWallets[0].adapter.name);\n setPendingLogin(true);\n setTriggerConnect(true);\n } else {\n // Show wallet picker — deselect any remembered wallet first so that\n // every selection in the modal registers as \"new\" and dismissing\n // leaves wallet as null (no accidental auto-connect).\n signRejectedRef.current = false;\n if (wallet) {\n adapterWallet.select(null as unknown as WalletName);\n }\n setModalVisible(true);\n setPendingLogin(true);\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 // Notify parent of loading state changes\n useEffect(() => {\n onLoadingChange?.(isLoading);\n }, [isLoading, onLoadingChange]);\n\n return (\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}\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","EMPTY_ADAPTERS","SolanaLoginButton","props","WalletModalProvider","jsx","SolanaLoginInner","WalletProvider","onSuccess","onError","className","variant","size","disabled","hideIfNoWallet","onLoadingChange","walletContext","isAuthLoading","adapterWallet","useWallet","modalVisible","setModalVisible","useWalletModal","pendingLogin","setPendingLogin","triggerConnect","setTriggerConnect","isProcessingRef","useRef","modalWasOpen","signRejectedRef","connected","connecting","signMessage","wallet","wallets","select","name","connect","installedWallets","w","executeSignIn","pubKeyString","challenge","messageBytes","signatureBytes","useEffect","handleClick","sizeClasses","variantClasses","jsxs","LoadingSpinner","registerMobileWallet","mwa","chains","registrationConfig"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mobileWalletAdapter-Cm_AUXhg.js","sources":["../src/hooks/useSolanaAuth.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","import { useState, useEffect, useCallback, useRef } from 'react';\nimport { WalletProvider, useWallet } from '@solana/wallet-adapter-react';\nimport { WalletModalProvider, useWalletModal } from '@solana/wallet-adapter-react-ui';\nimport type { WalletName } from '@solana/wallet-adapter-base';\nimport { useSolanaAuth } from '../../hooks/useSolanaAuth';\nimport { LoadingSpinner } from '../shared/LoadingSpinner';\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 /** Called when the button's loading state changes (connecting, signing, etc.). */\n onLoadingChange?: (loading: boolean) => void;\n /**\n * Solana wallet adapter context. Pass this from @solana/wallet-adapter-react's useWallet().\n * When provided, the component assumes a WalletProvider exists in the React tree and\n * uses the consumer's wallet context for wallet discovery and connection.\n * When omitted, the component provides its own WalletProvider with wallet-standard discovery.\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/** Stable empty array to avoid re-renders in self-contained WalletProvider. */\nconst EMPTY_ADAPTERS: [] = [];\n\n/**\n * Solana wallet login button with one-click authentication.\n *\n * Uses the standard wallet adapter modal for wallet selection, which provides\n * real brand icons and discovers all wallet-standard-compliant wallets.\n *\n * When `walletContext` is provided, assumes a WalletProvider exists in the tree.\n * Otherwise, wraps itself with WalletProvider for self-contained operation.\n */\nexport function SolanaLoginButton(props: SolanaLoginButtonProps) {\n if (props.walletContext) {\n // Consumer has their own WalletProvider; just add modal capability\n return (\n <WalletModalProvider>\n <SolanaLoginInner {...props} />\n </WalletModalProvider>\n );\n }\n\n // Self-contained: provide wallet-standard discovery + modal\n return (\n <WalletProvider wallets={EMPTY_ADAPTERS} localStorageKey=\"cedros-walletName\">\n <WalletModalProvider>\n <SolanaLoginInner {...props} />\n </WalletModalProvider>\n </WalletProvider>\n );\n}\n\nfunction SolanaLoginInner({\n onSuccess,\n onError,\n className = '',\n variant = 'default',\n size = 'md',\n disabled = false,\n hideIfNoWallet = true,\n onLoadingChange,\n walletContext,\n}: SolanaLoginButtonProps) {\n const { requestChallenge, signIn, isLoading: isAuthLoading } = useSolanaAuth();\n const adapterWallet = useWallet();\n const { visible: modalVisible, setVisible: setModalVisible } = useWalletModal();\n const [pendingLogin, setPendingLogin] = useState(false);\n const [triggerConnect, setTriggerConnect] = useState(false);\n const isProcessingRef = useRef(false);\n const modalWasOpen = useRef(false);\n const signRejectedRef = useRef(false);\n\n // Use walletContext if provided, otherwise use adapter's useWallet()\n const connected = walletContext?.connected ?? adapterWallet.connected;\n const connecting = walletContext?.connecting ?? adapterWallet.connecting;\n const publicKey = walletContext?.publicKey ?? adapterWallet.publicKey;\n const signMessage = walletContext?.signMessage ?? adapterWallet.signMessage;\n const wallet = walletContext?.wallet ?? adapterWallet.wallet;\n const wallets = walletContext?.wallets ?? adapterWallet.wallets;\n const select = walletContext\n ? walletContext.select\n : (name: string) => adapterWallet.select(name as WalletName);\n const connect = walletContext?.connect ?? adapterWallet.connect;\n\n // Get installed/ready wallets\n const installedWallets = wallets.filter(\n (w) => w.adapter.readyState === 'Installed' || w.adapter.readyState === 'Loadable'\n );\n\n // Execute the sign-in flow (challenge → sign → verify)\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 const challenge = await requestChallenge(pubKeyString);\n\n const messageBytes = new TextEncoder().encode(challenge.message);\n const signatureBytes = await signMessage(messageBytes);\n\n if (!(signatureBytes instanceof Uint8Array) || signatureBytes.length === 0) {\n throw new Error('Wallet returned invalid signature');\n }\n\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 await signIn(pubKeyString, signature, challenge.message);\n signRejectedRef.current = false;\n onSuccess?.();\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n signRejectedRef.current = true;\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) {\n setTriggerConnect(false);\n connect().catch((err) => {\n onError?.(err instanceof Error ? err : new Error(String(err)));\n setPendingLogin(false);\n });\n }\n }, [triggerConnect, wallet, connected, connecting, connect, onError]);\n\n // Auto-execute sign-in when connected with pending login\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 // When modal closes: connect if a wallet was selected, else reset.\n // Wallet is always deselected before opening, so any non-null wallet = user chose one.\n useEffect(() => {\n if (modalVisible) {\n modalWasOpen.current = true;\n } else if (modalWasOpen.current) {\n modalWasOpen.current = false;\n if (pendingLogin && !connected && wallet && !connecting) {\n setTriggerConnect(true);\n } else if (pendingLogin && !connected) {\n setPendingLogin(false);\n }\n }\n }, [modalVisible, pendingLogin, connected, wallet, connecting]);\n\n // Hide button if no wallets detected\n if (hideIfNoWallet && installedWallets.length === 0) {\n return null;\n }\n\n const handleClick = async () => {\n if (disabled || isAuthLoading || connecting) return;\n\n if (connected && publicKey && signMessage && !signRejectedRef.current) {\n // Already connected, previous attempt wasn't rejected — sign immediately\n setPendingLogin(true);\n await executeSignIn();\n } else if (installedWallets.length === 1 && !wallet) {\n // Single installed wallet, nothing remembered — auto-select + connect\n select(installedWallets[0].adapter.name);\n setPendingLogin(true);\n setTriggerConnect(true);\n } else {\n // Show wallet picker — deselect any remembered wallet first so that\n // every selection in the modal registers as \"new\" and dismissing\n // leaves wallet as null (no accidental auto-connect).\n signRejectedRef.current = false;\n if (wallet) {\n adapterWallet.select(null as unknown as WalletName);\n }\n setModalVisible(true);\n setPendingLogin(true);\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 // Notify parent of loading state changes\n useEffect(() => {\n onLoadingChange?.(isLoading);\n }, [isLoading, onLoadingChange]);\n\n return (\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}\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","EMPTY_ADAPTERS","SolanaLoginButton","props","WalletModalProvider","jsx","SolanaLoginInner","WalletProvider","onSuccess","onError","className","variant","size","disabled","hideIfNoWallet","onLoadingChange","walletContext","isAuthLoading","adapterWallet","useWallet","modalVisible","setModalVisible","useWalletModal","pendingLogin","setPendingLogin","triggerConnect","setTriggerConnect","isProcessingRef","useRef","modalWasOpen","signRejectedRef","connected","connecting","signMessage","wallet","wallets","select","name","connect","installedWallets","w","executeSignIn","pubKeyString","challenge","messageBytes","signatureBytes","useEffect","handleClick","sizeClasses","variantClasses","jsxs","LoadingSpinner","registerMobileWallet","mwa","chains","registrationConfig"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";const X=require("react/jsx-runtime"),o=require("react"),Ae=require("./LoadingSpinner-d6sSxgQN.cjs"),b=require("./useCedrosLogin-C9MrcZvh.cjs");let W=0;function He({theme:e,themeOverrides:t}){o.useEffect(()=>{if(typeof document>"u"||typeof window>"u")return;const A=document.documentElement;let i=!1;e==="dark"?i=!0:e==="light"?i=!1:i=window.matchMedia("(prefers-color-scheme: dark)").matches;let r=!1;i?(W++,r=!0,A.classList.add("cedros-dark")):W===0&&A.classList.remove("cedros-dark");const n=new Map;return t&&Object.entries(t).forEach(([s,g])=>{if(g){const C=A.style.getPropertyValue(s);n.set(s,C),A.style.setProperty(s,g)}}),()=>{r&&(W--,W===0&&A.classList.remove("cedros-dark")),n.forEach((s,g)=>{s?A.style.setProperty(g,s):A.style.removeProperty(g)})}},[e,t])}const Je={email:!0,google:!0,apple:!0,solana:!0,webauthn:!0,instantLink:!0};function Me(e,t,A){const[i,r]=o.useState(null),[n,s]=o.useState(),[g,C]=o.useState(),[I,y]=o.useState(t),p=o.useRef(!1);return o.useEffect(()=>{if(!t||p.current)return;p.current=!0,new b.ApiClient({baseUrl:e,timeoutMs:A??5e3,retryAttempts:1}).get("/features",{credentials:"omit"}).then(u=>{r({email:u.email,google:u.google,apple:u.apple,solana:u.solana,webauthn:u.webauthn,instantLink:u.instantLink}),s(u.googleClientId),C(u.appleClientId)}).catch(()=>{r(Je)}).finally(()=>{y(!1)})},[t,e,A]),{features:i,googleClientId:n,appleClientId:g,isLoading:I}}const Pe="cedros_tokens",Ve=6e4;class Ne{storage;requestedStorage;storageKey;tokens=null;expiresAt=0;refreshTimer=null;onRefreshNeeded=null;onSessionExpired=null;onRefreshError=null;isDestroyed=!1;sessionExpiredFired=!1;allowWebStorage;constructor(t="cookie",A=Pe,i={}){this.requestedStorage=t,this.storage=t,this.storageKey=A,this.allowWebStorage=i.allowWebStorage??!1,this.warnIfLocalStorage(),!this.allowWebStorage&&(this.requestedStorage==="localStorage"||this.requestedStorage==="sessionStorage")&&(this.storage="memory"),this.loadFromStorage()}warnIfLocalStorage(){if((this.requestedStorage==="localStorage"||this.requestedStorage==="sessionStorage")&&typeof console<"u"){const t=this.allowWebStorage?"":" (web storage disabled by default; set allowWebStorage=true to enable)";console.warn("[cedros-login] SECURITY: Using web storage for token storage. Tokens are vulnerable to XSS attacks."+t+" PRODUCTION RECOMMENDATIONS: (1) Use httpOnly cookie storage instead, (2) If web storage required: implement strict Content-Security-Policy, sanitize all input/output, audit third-party scripts. See https://owasp.org/www-community/attacks/xss/")}}setRefreshCallback(t){this.onRefreshNeeded=t,this.scheduleRefresh()}setSessionExpiredCallback(t){this.onSessionExpired=t}setRefreshErrorCallback(t){this.onRefreshError=t}setTokens(t){this.tokens=t,this.expiresAt=Date.now()+t.expiresIn*1e3,this.sessionExpiredFired=!1,this.saveToStorage(),this.scheduleRefresh()}getAccessToken(){if(this.isDestroyed)return null;const t=this.tokens?.accessToken;return t?Date.now()>=this.expiresAt?(this.clear(),this.fireSessionExpired(),null):t:null}getRefreshToken(){return this.tokens?.refreshToken??null}clear(){this.tokens=null,this.expiresAt=0,this.cancelRefresh(),this.clearStorage()}hasTokens(){return this.tokens!==null&&Date.now()<this.expiresAt}destroy(){this.isDestroyed=!0,this.cancelRefresh(),this.clearStorage(),this.onRefreshNeeded=null,this.onSessionExpired=null,this.onRefreshError=null,this.tokens=null}getTimeUntilExpiry(){return this.tokens?Math.max(0,this.expiresAt-Date.now()):0}fireSessionExpired(){this.sessionExpiredFired||(this.sessionExpiredFired=!0,this.onSessionExpired?.())}scheduleRefresh(){if(this.cancelRefresh(),!this.tokens||!this.onRefreshNeeded)return;const t=this.getTimeUntilExpiry(),A=Math.max(0,t-Ve);if(A<=0){if(this.isDestroyed)return;this.onRefreshNeeded().catch(i=>{if(this.isDestroyed)return;const r=i instanceof Error?i:new Error("Token refresh failed");this.onRefreshError?.(r),this.clear(),this.fireSessionExpired()});return}this.refreshTimer=setTimeout(()=>{this.isDestroyed||this.onRefreshNeeded?.().catch(i=>{if(this.isDestroyed)return;const r=i instanceof Error?i:new Error("Token refresh failed");this.onRefreshError?.(r),this.clear(),this.fireSessionExpired()})},A)}cancelRefresh(){this.refreshTimer&&(clearTimeout(this.refreshTimer),this.refreshTimer=null)}loadFromStorage(){if(this.storage!=="memory"&&!(typeof window>"u")&&!(!this.allowWebStorage&&(this.storage==="localStorage"||this.storage==="sessionStorage")))try{if(this.storage==="localStorage"||this.storage==="sessionStorage"){const t=this.storage==="localStorage"?localStorage:sessionStorage,A=t.getItem(this.storageKey);if(A){const i=JSON.parse(A);this.isValidStoredTokenData(i)?i.expiresAt>Date.now()?(this.tokens=i.tokens,this.expiresAt=i.expiresAt):t.removeItem(this.storageKey):t.removeItem(this.storageKey)}}}catch{if(this.storage==="localStorage"||this.storage==="sessionStorage"){const t=this.storage==="localStorage"?localStorage:sessionStorage;try{t.removeItem(this.storageKey)}catch{}}}}isValidStoredTokenData(t){if(typeof t!="object"||t===null)return!1;const A=t;if(typeof A.expiresAt!="number"||typeof A.tokens!="object"||A.tokens===null)return!1;const i=A.tokens;return!(typeof i.accessToken!="string"||typeof i.refreshToken!="string"||typeof i.expiresIn!="number")}saveToStorage(){if(!(this.storage==="memory"||!this.tokens)&&!(typeof window>"u")&&!(!this.allowWebStorage&&(this.storage==="localStorage"||this.storage==="sessionStorage")))try{if(this.storage==="localStorage"||this.storage==="sessionStorage"){const t=this.storage==="localStorage"?localStorage:sessionStorage,A={tokens:this.tokens,expiresAt:this.expiresAt};t.setItem(this.storageKey,JSON.stringify(A))}}catch{}}clearStorage(){if(this.storage!=="memory"&&!(typeof window>"u")&&!(!this.allowWebStorage&&(this.storage==="localStorage"||this.storage==="sessionStorage")))try{(this.storage==="localStorage"||this.storage==="sessionStorage")&&(this.storage==="localStorage"?localStorage:sessionStorage).removeItem(this.storageKey)}catch{}}}const Ye="cedros_auth_sync";class xe{channel=null;callback=null;boundHandler=null;constructor(){typeof window<"u"&&"BroadcastChannel"in window&&(this.channel=new BroadcastChannel(Ye),this.boundHandler=this.handleMessage.bind(this),this.channel.addEventListener("message",this.boundHandler))}handleMessage(t){const A=t.data;if(!(!A||typeof A!="object"||typeof A.type!="string")&&["login","logout","refresh"].includes(A.type)){if(A.type==="login"){const i=A;if(typeof i.user!="object"||i.user===null||typeof i.user.id!="string")return}this.callback?.(A)}}setCallback(t){this.callback=t}broadcastLogin(t){this.channel?.postMessage({type:"login",user:t})}broadcastLogout(){this.channel?.postMessage({type:"logout"})}broadcastRefresh(){this.channel?.postMessage({type:"refresh"})}close(){this.channel&&(this.boundHandler&&(this.channel.removeEventListener("message",this.boundHandler),this.boundHandler=null),this.channel.close(),this.channel=null),this.callback=null}}function j(e){if(typeof e!="object"||e===null)return!1;const t=e;if(typeof t.user!="object"||t.user===null)return!1;const A=t.user;return typeof A.id=="string"&&A.id.length>0}function Oe(e){if(typeof e!="object"||e===null)return!1;const t=e;return typeof t.accessToken=="string"&&t.accessToken.length>0&&typeof t.refreshToken=="string"&&t.refreshToken.length>0&&typeof t.expiresIn=="number"&&t.expiresIn>0}function ve({serverUrl:e,session:t,callbacks:A,requestTimeoutMs:i}){const[r,n]=o.useState(null),[s,g]=o.useState("idle"),C=o.useRef(null),I=o.useRef(null),y=o.useRef(A),p=o.useRef(!0),Q=o.useRef(null),u=o.useRef(()=>Promise.resolve()),m=o.useRef(()=>{});o.useEffect(()=>{y.current=A},[A]),o.useEffect(()=>(p.current=!0,()=>{p.current=!1}),[]);const B=o.useCallback(h=>{p.current&&n(h)},[]),d=o.useCallback(h=>{p.current&&g(h)},[]),f=o.useMemo(()=>({storage:t?.storage??"cookie",autoRefresh:t?.autoRefresh??!0,syncTabs:t?.syncTabs??!0,persistKey:t?.persistKey,allowWebStorage:t?.allowWebStorage??!1}),[t?.storage,t?.autoRefresh,t?.syncTabs,t?.persistKey,t?.allowWebStorage]);o.useEffect(()=>{const h=new Ne(f.storage,f.persistKey,{allowWebStorage:f.allowWebStorage});return C.current=h,f.autoRefresh&&h.setRefreshCallback(()=>u.current()),h.setSessionExpiredCallback(()=>m.current()),f.syncTabs&&(I.current=new xe),()=>{h.destroy(),C.current=null,I.current?.close()}},[f.storage,f.syncTabs,f.persistKey,f.allowWebStorage,f.autoRefresh]);const F=o.useCallback(async()=>{if(Q.current)return Q.current;const h=C.current?.getRefreshToken(),S=!!h,K=b.getCsrfToken(),H={};S&&(H["Content-Type"]="application/json"),K&&(H["X-CSRF-Token"]=K);let G,M;const J=new Promise((L,ee)=>{G=L,M=ee});Q.current=J,(async()=>{const L=new AbortController,ee=i??1e4,Ke=window.setTimeout(()=>L.abort(),ee);try{const O=await fetch(`${e}/refresh`,{method:"POST",headers:Object.keys(H).length>0?H:void 0,credentials:"include",body:S?JSON.stringify({refreshToken:h}):void 0,signal:L.signal});if(!O.ok)throw new Error("Token refresh failed");const te=await O.json();if(te.tokens){if(!Oe(te.tokens))throw new Error("Invalid token response structure");C.current?.setTokens(te.tokens)}else if(f.storage!=="cookie")throw new Error("Token refresh failed");I.current?.broadcastRefresh(),G()}catch(O){throw M(O),O}finally{window.clearTimeout(Ke)}})().catch(()=>{});try{await J}finally{Q.current=null}},[e,f.storage,i]),k=o.useCallback(()=>{if(f.storage==="cookie")return;const h=C.current?.getAccessToken();if(h)return{Authorization:`Bearer ${h}`}},[f.storage]),U=o.useCallback(()=>{C.current?.clear(),B(null),d("unauthenticated"),y.current?.onSessionExpired?.()},[d,B]);u.current=F,m.current=U;const E=o.useCallback(h=>{const S=new AbortController,K=i??1e4,H=window.setTimeout(()=>S.abort(),K),G={},M=k();M&&Object.assign(G,M);const J=b.getCsrfToken();return J&&(G["X-CSRF-Token"]=J),{promise:fetch(h,{credentials:"include",headers:Object.keys(G).length>0?G:void 0,signal:S.signal}),cleanup:()=>window.clearTimeout(H)}},[k,i]),l=o.useCallback(async()=>{const h=E(`${e}/user`);try{const S=await h.promise;if(S.ok){const K=await S.json();if(j(K)){B(K.user),d("authenticated");return}}if(S.status===401&&f.autoRefresh){try{await F()}catch{U();return}const K=E(`${e}/user`);try{const H=await K.promise;if(H.ok){const G=await H.json();if(j(G)){B(G.user),d("authenticated");return}}}finally{K.cleanup()}}B(null),d("unauthenticated")}catch{B(null),d("unauthenticated")}finally{h.cleanup()}},[e,f.autoRefresh,F,E,U,d,B]);o.useEffect(()=>{!I.current||!f.syncTabs||I.current.setCallback(h=>{switch(h.type){case"login":B(h.user),d("authenticated");break;case"logout":B(null),d("unauthenticated"),C.current?.clear();break;case"refresh":l();break;default:console.warn("[Cedros Login] Unhandled tab sync event:",h)}})},[f.syncTabs,l,d,B]),o.useEffect(()=>{const h=new AbortController,S=i??1e4,K=window.setTimeout(()=>h.abort(),S);return(async()=>{d("loading");try{const G=await fetch(`${e}/user`,{credentials:"include",headers:k(),signal:h.signal});if(G.ok){const M=await G.json();if(j(M)){B(M.user),d("authenticated");return}}if(G.status===401&&f.autoRefresh){try{await F()}catch{U();return}const M=await fetch(`${e}/user`,{credentials:"include",headers:k(),signal:h.signal});if(M.ok){const J=await M.json();if(j(J)){B(J.user),d("authenticated");return}}}B(null),d("unauthenticated")}catch{B(null),d("unauthenticated")}})(),()=>{window.clearTimeout(K),h.abort()}},[e,f.autoRefresh,F,k,U,d,B,i]);const a=o.useCallback((h,S)=>{B(h),d("authenticated"),S&&C.current?.setTokens(S),p.current&&I.current?.broadcastLogin(h)},[B,d]),c=o.useCallback(async()=>{const h=b.getCsrfToken(),S=new AbortController,K=i??1e4,H=window.setTimeout(()=>S.abort(),K);try{await fetch(`${e}/logout`,{method:"POST",headers:{...h?{"X-CSRF-Token":h}:{},...k()??{}},credentials:"include",signal:S.signal})}catch{}finally{window.clearTimeout(H),B(null),d("unauthenticated"),C.current?.clear(),I.current?.broadcastLogout(),y.current?.onLogout?.()}},[e,k,B,d,i]),w=o.useCallback(()=>C.current?.getAccessToken()??null,[]);return{user:r,authState:s,handleLoginSuccess:a,logout:c,refreshUser:l,getAccessToken:w}}const Be={mCost:19456,tCost:2,pCost:1};function Re(e){return e.length===16}function Te(e){if(e.length===16)return!0;if(e.length<18)return!1;const t=e[0];return t===0||t===1||t===128||t===8}function Le(e){return e.length===32}function Xe(e){return e.length===12}function We(e){return e.length>=16}function je(e){return e.length===32}function de(e){if(!Re(e))throw new Error(`Invalid seed length: expected 16, got ${e.length}`);return e}function Ze(e){if(!Te(e))throw new Error(`Invalid share length: expected >=16, got ${e.length}`);return e}function ce(e){if(!Le(e))throw new Error(`Invalid key length: expected 32, got ${e.length}`);return e}function qe(e){if(!Xe(e))throw new Error(`Invalid nonce length: expected 12, got ${e.length}`);return e}function _e(e){if(!We(e))throw new Error(`Invalid salt length: expected >=16, got ${e.length}`);return e}function $e(e){if(!je(e))throw new Error(`Invalid PRF salt length: expected 32, got ${e.length}`);return e}function Y(e){return new Uint8Array(e)}function _(e){if(typeof crypto>"u"||!crypto.getRandomValues)throw new Error("WebCrypto API not available. Secure random generation requires a modern browser.");const t=new Uint8Array(e);return crypto.getRandomValues(t),t}function ze(){return de(_(16))}function et(){return qe(_(12))}function tt(){return _e(_(16))}function Ee(){return $e(_(32))}function Ce(e){if(!(!e||e.length===0)){if(typeof globalThis.crypto?.getRandomValues=="function")globalThis.crypto.getRandomValues(e);else for(let t=0;t<e.length;t++)e[t]=t*90&255;e.fill(0)}}function At(...e){for(const t of e)t&&Ce(t)}async function it(e){return crypto.subtle.importKey("raw",Y(e),{name:"AES-GCM",length:256},!1,["encrypt","decrypt"])}async function rt(e,t,A){const i=A??et(),r=await it(t),n=await crypto.subtle.encrypt({name:"AES-GCM",iv:Y(i)},r,Y(e));return{ciphertext:new Uint8Array(n),nonce:i}}async function nt(e,t){const A=await rt(e,t);return{ciphertext:T(A.ciphertext),nonce:T(A.nonce)}}function T(e){const A=[];for(let i=0;i<e.length;i+=32768){const r=e.subarray(i,Math.min(i+32768,e.length));A.push(String.fromCharCode(...r))}return btoa(A.join(""))}function pe(e){let t;try{t=atob(e)}catch{throw new Error("Invalid base64 string: input is malformed or contains invalid characters")}const A=new Uint8Array(t.length);for(let i=0;i<t.length;i++)A[i]=t.charCodeAt(i);return A}async function ot(e,t,A,i=32){const r=await crypto.subtle.importKey("raw",Y(e),"HKDF",!1,["deriveBits"]),n=new TextEncoder().encode(A),s=await crypto.subtle.deriveBits({name:"HKDF",hash:"SHA-256",salt:Y(t??new Uint8Array(32)),info:Y(n)},r,i*8);return new Uint8Array(s)}async function st(e,t){const A=await ot(e,t,"cedros-wallet-share-b-encryption",32);return ce(A)}async function It(){try{const e=await crypto.subtle.importKey("raw",new Uint8Array(32),"HKDF",!1,["deriveBits"]);return await crypto.subtle.deriveBits({name:"HKDF",hash:"SHA-256",salt:new Uint8Array(32),info:new Uint8Array(0)},e,256),!0}catch{return!1}}function x(e,t,A,i){function r(n){return n instanceof A?n:new A(function(s){s(n)})}return new(A||(A=Promise))(function(n,s){function g(y){try{I(i.next(y))}catch(p){s(p)}}function C(y){try{I(i.throw(y))}catch(p){s(p)}}function I(y){y.done?n(y.value):r(y.value).then(g,C)}I((i=i.apply(e,[])).next())})}class D{constructor(){this.mutex=Promise.resolve()}lock(){let t=()=>{};return this.mutex=this.mutex.then(()=>new Promise(t)),new Promise(A=>{t=A})}dispatch(t){return x(this,void 0,void 0,function*(){const A=yield this.lock();try{return yield Promise.resolve(t())}finally{A()}})}}var ie;function at(){return typeof globalThis<"u"?globalThis:typeof self<"u"?self:typeof window<"u"?window:global}const ae=at(),re=(ie=ae.Buffer)!==null&&ie!==void 0?ie:null,gt=ae.TextEncoder?new ae.TextEncoder:null;function ye(e,t){return(e&15)+(e>>6|e>>3&8)<<4|(t&15)+(t>>6|t>>3&8)}function ke(e,t){const A=t.length>>1;for(let i=0;i<A;i++){const r=i<<1;e[i]=ye(t.charCodeAt(r),t.charCodeAt(r+1))}}function lt(e,t){if(e.length!==t.length*2)return!1;for(let A=0;A<t.length;A++){const i=A<<1;if(t[A]!==ye(e.charCodeAt(i),e.charCodeAt(i+1)))return!1}return!0}const he=87,ue=48;function ge(e,t,A){let i=0;for(let r=0;r<A;r++){let n=t[r]>>>4;e[i++]=n>9?n+he:n+ue,n=t[r]&15,e[i++]=n>9?n+he:n+ue}return String.fromCharCode.apply(null,e)}const N=re!==null?e=>{if(typeof e=="string"){const t=re.from(e,"utf8");return new Uint8Array(t.buffer,t.byteOffset,t.length)}if(re.isBuffer(e))return new Uint8Array(e.buffer,e.byteOffset,e.length);if(ArrayBuffer.isView(e))return new Uint8Array(e.buffer,e.byteOffset,e.byteLength);throw new Error("Invalid data type!")}:e=>{if(typeof e=="string")return gt.encode(e);if(ArrayBuffer.isView(e))return new Uint8Array(e.buffer,e.byteOffset,e.byteLength);throw new Error("Invalid data type!")},P="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",R=new Uint8Array(256);for(let e=0;e<P.length;e++)R[P.charCodeAt(e)]=e;function fe(e,t=!0){const A=e.length,i=A%3,r=[],n=A-i;for(let s=0;s<n;s+=3){const g=(e[s]<<16&16711680)+(e[s+1]<<8&65280)+(e[s+2]&255),C=P.charAt(g>>18&63)+P.charAt(g>>12&63)+P.charAt(g>>6&63)+P.charAt(g&63);r.push(C)}if(i===1){const s=e[A-1],g=P.charAt(s>>2),C=P.charAt(s<<4&63);r.push(`${g}${C}`),t&&r.push("==")}else if(i===2){const s=(e[A-2]<<8)+e[A-1],g=P.charAt(s>>10),C=P.charAt(s>>4&63),I=P.charAt(s<<2&63);r.push(`${g}${C}${I}`),t&&r.push("=")}return r.join("")}function ct(e){let t=Math.floor(e.length*.75);const A=e.length;return e[A-1]==="="&&(t-=1,e[A-2]==="="&&(t-=1)),t}function Ct(e){const t=ct(e),A=e.length,i=new Uint8Array(t);let r=0;for(let n=0;n<A;n+=4){const s=R[e.charCodeAt(n)],g=R[e.charCodeAt(n+1)],C=R[e.charCodeAt(n+2)],I=R[e.charCodeAt(n+3)];i[r]=s<<2|g>>4,r+=1,i[r]=(g&15)<<4|C>>2,r+=1,i[r]=(C&3)<<6|I&63,r+=1}return i}const Z=16*1024,v=4,ht=new D,ne=new Map;function Se(e,t){return x(this,void 0,void 0,function*(){let A=null,i=null,r=!1;if(typeof WebAssembly>"u")throw new Error("WebAssembly is not supported in this environment!");const n=(l,a=0)=>{i.set(l,a)},s=()=>i,g=()=>A.exports,C=l=>{A.exports.Hash_SetMemorySize(l);const a=A.exports.Hash_GetBuffer(),c=A.exports.memory.buffer;i=new Uint8Array(c,a,l)},I=()=>new DataView(A.exports.memory.buffer).getUint32(A.exports.STATE_SIZE,!0),y=ht.dispatch(()=>x(this,void 0,void 0,function*(){if(!ne.has(e.name)){const a=Ct(e.data),c=WebAssembly.compile(a);ne.set(e.name,c)}const l=yield ne.get(e.name);A=yield WebAssembly.instantiate(l,{})})),p=()=>x(this,void 0,void 0,function*(){A||(yield y);const l=A.exports.Hash_GetBuffer(),a=A.exports.memory.buffer;i=new Uint8Array(a,l,Z)}),Q=(l=null)=>{r=!0,A.exports.Hash_Init(l)},u=l=>{let a=0;for(;a<l.length;){const c=l.subarray(a,a+Z);a+=c.length,i.set(c),A.exports.Hash_Update(c.length)}},m=l=>{if(!r)throw new Error("update() called before init()");const a=N(l);u(a)},B=new Uint8Array(t*2),d=(l,a=null)=>{if(!r)throw new Error("digest() called before init()");return r=!1,A.exports.Hash_Final(a),l==="binary"?i.slice(0,t):ge(B,i,t)},f=()=>{if(!r)throw new Error("save() can only be called after init() and before digest()");const l=A.exports.Hash_GetState(),a=I(),c=A.exports.memory.buffer,w=new Uint8Array(c,l,a),h=new Uint8Array(v+a);return ke(h,e.hash),h.set(w,v),h},F=l=>{if(!(l instanceof Uint8Array))throw new Error("load() expects an Uint8Array generated by save()");const a=A.exports.Hash_GetState(),c=I(),w=v+c,h=A.exports.memory.buffer;if(l.length!==w)throw new Error(`Bad state length (expected ${w} bytes, got ${l.length})`);if(!lt(e.hash,l.subarray(0,v)))throw new Error("This state was written by an incompatible hash implementation");const S=l.subarray(v);new Uint8Array(h,a,c).set(S),r=!0},k=l=>typeof l=="string"?l.length<Z/4:l.byteLength<Z;let U=k;switch(e.name){case"argon2":case"scrypt":U=()=>!0;break;case"blake2b":case"blake2s":U=(l,a)=>a<=512&&k(l);break;case"blake3":U=(l,a)=>a===0&&k(l);break;case"xxhash64":case"xxhash3":case"xxhash128":case"crc64":U=()=>!1;break}const E=(l,a=null,c=null)=>{if(!U(l,a))return Q(a),m(l),d("hex",c);const w=N(l);return i.set(w),A.exports.Hash_Calculate(w.length,a,c),ge(B,i,t)};return yield p(),{getMemory:s,writeMemory:n,getExports:g,setMemorySize:C,init:Q,update:m,digest:d,save:f,load:F,calculate:E,hashLength:t}})}new D;var ut="argon2",ft="AGFzbQEAAAABKQVgAX8Bf2AAAX9gEH9/f39/f39/f39/f39/f38AYAR/f39/AGACf38AAwYFAAECAwQFBgEBAoCAAgYIAX8BQZCoBAsHQQQGbWVtb3J5AgASSGFzaF9TZXRNZW1vcnlTaXplAAAOSGFzaF9HZXRCdWZmZXIAAQ5IYXNoX0NhbGN1bGF0ZQAECvEyBVgBAn9BACEBAkAgAEEAKAKICCICRg0AAkAgACACayIAQRB2IABBgIB8cSAASWoiAEAAQX9HDQBB/wHADwtBACEBQQBBACkDiAggAEEQdK18NwOICAsgAcALcAECfwJAQQAoAoAIIgANAEEAPwBBEHQiADYCgAhBACgCiAgiAUGAgCBGDQACQEGAgCAgAWsiAEEQdiAAQYCAfHEgAElqIgBAAEF/Rw0AQQAPC0EAQQApA4gIIABBEHStfDcDiAhBACgCgAghAAsgAAvcDgECfiAAIAQpAwAiECAAKQMAIhF8IBFCAYZC/v///x+DIBBC/////w+DfnwiEDcDACAMIBAgDCkDAIVCIIkiEDcDACAIIBAgCCkDACIRfCARQgGGQv7///8fgyAQQv////8Pg358IhA3AwAgBCAQIAQpAwCFQiiJIhA3AwAgACAQIAApAwAiEXwgEEL/////D4MgEUIBhkL+////H4N+fCIQNwMAIAwgECAMKQMAhUIwiSIQNwMAIAggECAIKQMAIhF8IBBC/////w+DIBFCAYZC/v///x+DfnwiEDcDACAEIBAgBCkDAIVCAYk3AwAgASAFKQMAIhAgASkDACIRfCARQgGGQv7///8fgyAQQv////8Pg358IhA3AwAgDSAQIA0pAwCFQiCJIhA3AwAgCSAQIAkpAwAiEXwgEUIBhkL+////H4MgEEL/////D4N+fCIQNwMAIAUgECAFKQMAhUIoiSIQNwMAIAEgECABKQMAIhF8IBBC/////w+DIBFCAYZC/v///x+DfnwiEDcDACANIBAgDSkDAIVCMIkiEDcDACAJIBAgCSkDACIRfCAQQv////8PgyARQgGGQv7///8fg358IhA3AwAgBSAQIAUpAwCFQgGJNwMAIAIgBikDACIQIAIpAwAiEXwgEUIBhkL+////H4MgEEL/////D4N+fCIQNwMAIA4gECAOKQMAhUIgiSIQNwMAIAogECAKKQMAIhF8IBFCAYZC/v///x+DIBBC/////w+DfnwiEDcDACAGIBAgBikDAIVCKIkiEDcDACACIBAgAikDACIRfCAQQv////8PgyARQgGGQv7///8fg358IhA3AwAgDiAQIA4pAwCFQjCJIhA3AwAgCiAQIAopAwAiEXwgEEL/////D4MgEUIBhkL+////H4N+fCIQNwMAIAYgECAGKQMAhUIBiTcDACADIAcpAwAiECADKQMAIhF8IBFCAYZC/v///x+DIBBC/////w+DfnwiEDcDACAPIBAgDykDAIVCIIkiEDcDACALIBAgCykDACIRfCARQgGGQv7///8fgyAQQv////8Pg358IhA3AwAgByAQIAcpAwCFQiiJIhA3AwAgAyAQIAMpAwAiEXwgEEL/////D4MgEUIBhkL+////H4N+fCIQNwMAIA8gECAPKQMAhUIwiSIQNwMAIAsgECALKQMAIhF8IBBC/////w+DIBFCAYZC/v///x+DfnwiEDcDACAHIBAgBykDAIVCAYk3AwAgACAFKQMAIhAgACkDACIRfCARQgGGQv7///8fgyAQQv////8Pg358IhA3AwAgDyAQIA8pAwCFQiCJIhA3AwAgCiAQIAopAwAiEXwgEUIBhkL+////H4MgEEL/////D4N+fCIQNwMAIAUgECAFKQMAhUIoiSIQNwMAIAAgECAAKQMAIhF8IBBC/////w+DIBFCAYZC/v///x+DfnwiEDcDACAPIBAgDykDAIVCMIkiEDcDACAKIBAgCikDACIRfCAQQv////8PgyARQgGGQv7///8fg358IhA3AwAgBSAQIAUpAwCFQgGJNwMAIAEgBikDACIQIAEpAwAiEXwgEUIBhkL+////H4MgEEL/////D4N+fCIQNwMAIAwgECAMKQMAhUIgiSIQNwMAIAsgECALKQMAIhF8IBFCAYZC/v///x+DIBBC/////w+DfnwiEDcDACAGIBAgBikDAIVCKIkiEDcDACABIBAgASkDACIRfCAQQv////8PgyARQgGGQv7///8fg358IhA3AwAgDCAQIAwpAwCFQjCJIhA3AwAgCyAQIAspAwAiEXwgEEL/////D4MgEUIBhkL+////H4N+fCIQNwMAIAYgECAGKQMAhUIBiTcDACACIAcpAwAiECACKQMAIhF8IBFCAYZC/v///x+DIBBC/////w+DfnwiEDcDACANIBAgDSkDAIVCIIkiEDcDACAIIBAgCCkDACIRfCARQgGGQv7///8fgyAQQv////8Pg358IhA3AwAgByAQIAcpAwCFQiiJIhA3AwAgAiAQIAIpAwAiEXwgEEL/////D4MgEUIBhkL+////H4N+fCIQNwMAIA0gECANKQMAhUIwiSIQNwMAIAggECAIKQMAIhF8IBBC/////w+DIBFCAYZC/v///x+DfnwiEDcDACAHIBAgBykDAIVCAYk3AwAgAyAEKQMAIhAgAykDACIRfCARQgGGQv7///8fgyAQQv////8Pg358IhA3AwAgDiAQIA4pAwCFQiCJIhA3AwAgCSAQIAkpAwAiEXwgEUIBhkL+////H4MgEEL/////D4N+fCIQNwMAIAQgECAEKQMAhUIoiSIQNwMAIAMgECADKQMAIhF8IBBC/////w+DIBFCAYZC/v///x+DfnwiEDcDACAOIBAgDikDAIVCMIkiEDcDACAJIBAgCSkDACIRfCAQQv////8PgyARQgGGQv7///8fg358IhA3AwAgBCAQIAQpAwCFQgGJNwMAC98aAQN/QQAhBEEAIAIpAwAgASkDAIU3A5AIQQAgAikDCCABKQMIhTcDmAhBACACKQMQIAEpAxCFNwOgCEEAIAIpAxggASkDGIU3A6gIQQAgAikDICABKQMghTcDsAhBACACKQMoIAEpAyiFNwO4CEEAIAIpAzAgASkDMIU3A8AIQQAgAikDOCABKQM4hTcDyAhBACACKQNAIAEpA0CFNwPQCEEAIAIpA0ggASkDSIU3A9gIQQAgAikDUCABKQNQhTcD4AhBACACKQNYIAEpA1iFNwPoCEEAIAIpA2AgASkDYIU3A/AIQQAgAikDaCABKQNohTcD+AhBACACKQNwIAEpA3CFNwOACUEAIAIpA3ggASkDeIU3A4gJQQAgAikDgAEgASkDgAGFNwOQCUEAIAIpA4gBIAEpA4gBhTcDmAlBACACKQOQASABKQOQAYU3A6AJQQAgAikDmAEgASkDmAGFNwOoCUEAIAIpA6ABIAEpA6ABhTcDsAlBACACKQOoASABKQOoAYU3A7gJQQAgAikDsAEgASkDsAGFNwPACUEAIAIpA7gBIAEpA7gBhTcDyAlBACACKQPAASABKQPAAYU3A9AJQQAgAikDyAEgASkD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",wt="e4cdc523",Qt={name:ut,data:ft,hash:wt},Bt="blake2b",dt="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",Et="c6f286e6",pt={name:Bt,data:dt,hash:Et};new D;function we(e){return!Number.isInteger(e)||e<8||e>512||e%8!==0?new Error("Invalid variant! Valid values: 8, 16, ..., 512"):null}function yt(e,t){return e|t<<16}function le(e=512,t=null){if(we(e))return Promise.reject(we(e));let A=null,i=e;if(t!==null){if(A=N(t),A.length>64)return Promise.reject(new Error("Max key length is 64 bytes"));i=yt(e,A.length)}const r=e/8;return Se(pt,r).then(n=>{i>512&&n.writeMemory(A),n.init(i);const s={init:i>512?()=>(n.writeMemory(A),n.init(i),s):()=>(n.init(i),s),update:g=>(n.update(g),s),digest:g=>n.digest(g),save:()=>n.save(),load:g=>(n.load(g),s),blockSize:128,digestSize:r};return s})}function kt(e,t,A){const i=[`m=${t.memorySize}`,`t=${t.iterations}`,`p=${t.parallelism}`].join(",");return`$argon2${t.hashType}$v=19$${i}$${fe(e,!1)}$${fe(A,!1)}`}const Qe=new DataView(new ArrayBuffer(4));function V(e){return Qe.setInt32(0,e,!0),new Uint8Array(Qe.buffer)}function oe(e,t,A){return x(this,void 0,void 0,function*(){if(A<=64){const C=yield le(A*8);return C.update(V(A)),C.update(t),C.digest("binary")}const i=Math.ceil(A/32)-2,r=new Uint8Array(A);e.init(),e.update(V(A)),e.update(t);let n=e.digest("binary");r.set(n.subarray(0,32),0);for(let C=1;C<i;C++)e.init(),e.update(n),n=e.digest("binary"),r.set(n.subarray(0,32),C*32);const s=A-32*i;let g;return s===64?(g=e,g.init()):g=yield le(s*8),g.update(n),n=g.digest("binary"),r.set(n.subarray(0,s),i*32),r})}function St(e){switch(e){case"d":return 0;case"i":return 1;default:return 2}}function Dt(e){return x(this,void 0,void 0,function*(){var t;const{parallelism:A,iterations:i,hashLength:r}=e,n=N(e.password),s=N(e.salt),g=19,C=St(e.hashType),{memorySize:I}=e,y=N((t=e.secret)!==null&&t!==void 0?t:""),[p,Q]=yield Promise.all([Se(Qt,1024),le(512)]);p.setMemorySize(I*1024+1024);const u=new Uint8Array(24),m=new DataView(u.buffer);m.setInt32(0,A,!0),m.setInt32(4,r,!0),m.setInt32(8,I,!0),m.setInt32(12,i,!0),m.setInt32(16,g,!0),m.setInt32(20,C,!0),p.writeMemory(u,I*1024),Q.init(),Q.update(u),Q.update(V(n.length)),Q.update(n),Q.update(V(s.length)),Q.update(s),Q.update(V(y.length)),Q.update(y),Q.update(V(0));const d=Math.floor(I/(A*4))*4,f=new Uint8Array(72),F=Q.digest("binary");f.set(F);for(let E=0;E<A;E++){f.set(V(0),64),f.set(V(E),68);let l=E*d,a=yield oe(Q,f,1024);p.writeMemory(a,l*1024),l+=1,f.set(V(1),64),a=yield oe(Q,f,1024),p.writeMemory(a,l*1024)}const k=new Uint8Array(1024);ke(k,p.calculate(new Uint8Array([]),I));const U=yield oe(Q,k,r);if(e.outputType==="hex"){const E=new Uint8Array(r*2);return ge(E,U,r)}return e.outputType==="encoded"?kt(s,e,U):U})}const Ft=e=>{var t;if(!e||typeof e!="object")throw new Error("Invalid options parameter. It requires an object.");if(!e.password)throw new Error("Password must be specified");if(e.password=N(e.password),e.password.length<1)throw new Error("Password must be specified");if(!e.salt)throw new Error("Salt must be specified");if(e.salt=N(e.salt),e.salt.length<8)throw new Error("Salt should be at least 8 bytes long");if(e.secret=N((t=e.secret)!==null&&t!==void 0?t:""),!Number.isInteger(e.iterations)||e.iterations<1)throw new Error("Iterations should be a positive number");if(!Number.isInteger(e.parallelism)||e.parallelism<1)throw new Error("Parallelism should be a positive number");if(!Number.isInteger(e.hashLength)||e.hashLength<4)throw new Error("Hash length should be at least 4 bytes.");if(!Number.isInteger(e.memorySize))throw new Error("Memory size should be specified.");if(e.memorySize<8*e.parallelism)throw new Error("Memory size should be at least 8 * parallelism.");if(e.outputType===void 0&&(e.outputType="hex"),!["hex","binary","encoded"].includes(e.outputType))throw new Error(`Insupported output type ${e.outputType}. Valid values: ['hex', 'binary', 'encoded']`)};function De(e){return x(this,void 0,void 0,function*(){return Ft(e),Dt(Object.assign(Object.assign({},e),{hashType:"id"}))})}new D;new D;new D;new D;new D;new D;new D;new D;new D;new D;new D;new D;new D;new D;new D;new D;new D;new D;new D;new D;const Ut=32;async function bt(e,t,A=Be){Fe(A);try{const i=await De({password:e,salt:t,iterations:A.tCost,memorySize:A.mCost,parallelism:A.pCost,hashLength:Ut,outputType:"binary"});return ce(i)}catch{throw new Error("Key derivation failed")}}function Fe(e){if(e.mCost<16384)throw new Error("KDF memory cost too low (minimum 16 MiB)");if(e.mCost>1048576)throw new Error("KDF memory cost too high (maximum 1 GiB)");if(e.tCost<1)throw new Error("KDF time cost must be at least 1");if(e.tCost>10)throw new Error("KDF time cost too high (maximum 10)");if(e.pCost<1)throw new Error("KDF parallelism must be at least 1");if(e.pCost>4)throw new Error("KDF parallelism too high (maximum 4)")}async function mt(){try{const e=await De({password:"test",salt:new Uint8Array(16),iterations:1,memorySize:1024,parallelism:1,hashLength:32,outputType:"binary"});return e.length!==32?!1:(Ce(e),!0)}catch{return!1}}function Gt(e){return e==="localhost"||e==="127.0.0.1"||e.endsWith(".localhost")}function Ue(e){if(typeof window>"u")return;const t=window.location.hostname;if(!Gt(t))throw new Error("[Cedros] WebAuthn RP domain validation is not configured. Set wallet.allowedRpDomains to a non-empty list of allowed domains.")}function $(){return typeof window<"u"&&typeof window.PublicKeyCredential<"u"&&typeof navigator.credentials<"u"}async function Kt(){if(!$())return!1;try{if(!await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable())return!1;if("getClientCapabilities"in PublicKeyCredential&&typeof PublicKeyCredential.getClientCapabilities=="function"){const t=await PublicKeyCredential.getClientCapabilities();if(t&&"prf"in t)return t.prf===!0}return!0}catch{return!1}}async function Ht(e,t,A,i,r){if(!$())throw new Error("WebAuthn is not available in this browser");Ue();const n=i??Ee(),s=await navigator.credentials.create({publicKey:{challenge:crypto.getRandomValues(new Uint8Array(32)),rp:{name:"Cedros Wallet",id:window.location.hostname},user:{id:Y(e),name:t,displayName:A},pubKeyCredParams:[{type:"public-key",alg:-7},{type:"public-key",alg:-257}],authenticatorSelection:{authenticatorAttachment:"platform",userVerification:"required",residentKey:"required"},timeout:6e4,attestation:"none",extensions:{prf:{eval:{first:n}}}}});if(!s)throw new Error("Passkey registration was cancelled");const g=s.getClientExtensionResults();if(!g.prf?.enabled||!g.prf?.results?.first)throw new Error("PRF extension is not supported by this authenticator. Please use a device with a compatible platform authenticator.");const C=g.prf?.results?.first;if(!C)throw new Error("PRF extension did not return a result");const I=new Uint8Array(C);if(I.length!==32)throw new Error(`Unexpected PRF output length: expected 32 bytes, got ${I.length}. The authenticator may not be compatible.`);return{credentialId:T(new Uint8Array(s.rawId)),prfSalt:T(n),prfOutput:I}}async function Jt(e,t){if(!$())throw new Error("WebAuthn is not available in this browser");Ue();const A=pe(e),i=await navigator.credentials.get({publicKey:{challenge:crypto.getRandomValues(new Uint8Array(32)),rpId:window.location.hostname,allowCredentials:[],userVerification:"required",timeout:6e4,extensions:{prf:{eval:{first:A}}}}});if(!i)throw new Error("Passkey authentication was cancelled");const n=i.getClientExtensionResults().prf?.results?.first;if(!n)throw new Error("PRF extension did not return a result during authentication");const s=new Uint8Array(n);if(s.length!==32)throw new Error(`Unexpected PRF output length: expected 32 bytes, got ${s.length}. The authenticator may not be compatible.`);return{prfOutput:s}}async function Mt(){const[e,t,A,i,r,n,s]=await Promise.all([Pt(),Vt(),It(),Nt(),Promise.resolve($()),Kt(),mt()]);return{webCrypto:e,aesGcm:t,hkdf:A,ed25519:i,webAuthn:r,webAuthnPrf:n,argon2:s,allSupported:e&&t&&A&&r&&n&&s}}async function Pt(){try{return typeof crypto<"u"&&typeof crypto.subtle<"u"&&typeof crypto.getRandomValues=="function"}catch{return!1}}async function Vt(){try{const e=await crypto.subtle.generateKey({name:"AES-GCM",length:256},!1,["encrypt","decrypt"]),t=new Uint8Array([1,2,3,4]),A=crypto.getRandomValues(new Uint8Array(12)),i=await crypto.subtle.encrypt({name:"AES-GCM",iv:A},e,t),r=await crypto.subtle.decrypt({name:"AES-GCM",iv:A},e,i),n=new Uint8Array(r);return n.length===t.length&&n.every((s,g)=>s===t[g])}catch{return!1}}async function Nt(){try{return await crypto.subtle.generateKey("Ed25519",!1,["sign","verify"]),!0}catch{return!1}}function Yt(e){if(e.allSupported)return null;const t=[];return e.webCrypto||t.push("Web Crypto API"),e.aesGcm||t.push("AES-GCM encryption"),e.hkdf||t.push("HKDF key derivation"),e.webAuthn||t.push("WebAuthn/Passkeys"),e.webAuthnPrf||t.push("WebAuthn PRF extension (requires platform authenticator)"),e.argon2||t.push("Argon2 password hashing"),t.length===0?null:`Your browser or device is missing required features: ${t.join(", ")}. Please use a modern browser with a platform authenticator (e.g., Touch ID, Face ID, Windows Hello).`}function xt(){const e=typeof navigator<"u"?navigator.userAgent:"",t=e.match(/Chrome\/(\d+)/);if(t){const n=parseInt(t[1],10);return{browser:"Chrome",version:t[1],likelySupported:n>=116}}const A=e.match(/Version\/(\d+)/);if(A&&e.includes("Safari")&&!e.includes("Chrome")){const n=parseInt(A[1],10);return{browser:"Safari",version:A[1],likelySupported:n>=17}}const i=e.match(/Firefox\/(\d+)/);if(i)return{browser:"Firefox",version:i[1],likelySupported:!1};const r=e.match(/Edg\/(\d+)/);if(r){const n=parseInt(r[1],10);return{browser:"Edge",version:r[1],likelySupported:n>=116}}return{browser:"Unknown",version:"Unknown",likelySupported:!1}}let q=null,se=null;const Ot=6e4;async function vt(e=!1){const t=Date.now(),A=se===null||t-se>Ot;return!e&&!(typeof window>"u")&&!A&&q!==null||(q=await Mt(),se=Date.now()),q}function be(e){switch(e.type){case"password":return{password:e.password};case"prfOutput":return{prfOutput:e.prfOutput}}}function me(){const e=b.useCedrosLoginOptional(),[t,A]=o.useState(!1),[i,r]=o.useState(null),n=e?.config.serverUrl,s=e?.config.requestTimeout,g=e?.config.retryAttempts,C=e?._internal?.getAccessToken,I=o.useMemo(()=>e?new b.ApiClient({baseUrl:n,timeoutMs:s,retryAttempts:g,getAccessToken:C}):null,[e,n,s,g,C]),y=o.useCallback(async()=>{if(!I)throw new Error("useWalletMaterial must be used within a CedrosLoginProvider");A(!0),r(null);try{return await I.get("/wallet/status")}catch(a){const c=b.handleApiError(a,"Failed to fetch wallet status");throw r(c.message),c}finally{A(!1)}},[I]),p=o.useCallback(async()=>{if(!I)throw new Error("useWalletMaterial must be used within a CedrosLoginProvider");A(!0),r(null);try{return await I.get("/wallet/material")}catch(a){const c=b.handleApiError(a,"Failed to fetch wallet material");if(c.code==="NOT_FOUND")return null;throw r(c.message),c}finally{A(!1)}},[I]),Q=o.useCallback(async a=>{if(!I)throw new Error("useWalletMaterial must be used within a CedrosLoginProvider");A(!0),r(null);try{await I.post("/wallet/enroll",a)}catch(c){const w=b.handleApiError(c,"Failed to enroll wallet");throw r(w.message),w}finally{A(!1)}},[I]),u=o.useCallback(async a=>{if(!I)throw new Error("useWalletMaterial must be used within a CedrosLoginProvider");A(!0),r(null);try{await I.post("/wallet/recover",a)}catch(c){const w=b.handleApiError(c,"Failed to recover wallet");throw r(w.message),w}finally{A(!1)}},[I]),m=o.useCallback(async a=>{if(!I)throw new Error("useWalletMaterial must be used within a CedrosLoginProvider");A(!0),r(null);try{return await I.post("/wallet/sign",a)}catch(c){const w=b.handleApiError(c,"Failed to sign transaction");throw r(w.message),w}finally{A(!1)}},[I]),B=o.useCallback(async a=>{if(!I)throw new Error("useWalletMaterial must be used within a CedrosLoginProvider");A(!0),r(null);try{await I.post("/wallet/rotate-user-secret",a)}catch(c){const w=b.handleApiError(c,"Failed to rotate user secret");throw r(w.message),w}finally{A(!1)}},[I]),d=o.useCallback(async a=>{if(!I)throw new Error("useWalletMaterial must be used within a CedrosLoginProvider");A(!0),r(null);try{return await I.post("/wallet/unlock",be(a))}catch(c){const w=b.handleApiError(c,"Failed to unlock wallet");throw r(w.message),w}finally{A(!1)}},[I]),f=o.useCallback(async()=>{if(!I)throw new Error("useWalletMaterial must be used within a CedrosLoginProvider");A(!0),r(null);try{await I.post("/wallet/lock",{})}catch(a){const c=b.handleApiError(a,"Failed to lock wallet");throw r(c.message),c}finally{A(!1)}},[I]),F=o.useCallback(async a=>{if(!I)throw new Error("useWalletMaterial must be used within a CedrosLoginProvider");A(!0),r(null);try{return await I.post("/wallet/share-b",a)}catch(c){const w=b.handleApiError(c,"Failed to get Share B for recovery");throw r(w.message),w}finally{A(!1)}},[I]),k=o.useCallback(async a=>{if(!I)throw new Error("useWalletMaterial must be used within a CedrosLoginProvider");A(!0),r(null);try{return await I.post("/wallet/derived",a)}catch(c){const w=b.handleApiError(c,"Failed to create derived wallet");throw r(w.message),w}finally{A(!1)}},[I]),U=o.useCallback(async()=>{if(!I)throw new Error("useWalletMaterial must be used within a CedrosLoginProvider");A(!0),r(null);try{return await I.get("/wallet/derived")}catch(a){const c=b.handleApiError(a,"Failed to list wallets");throw r(c.message),c}finally{A(!1)}},[I]),E=o.useCallback(async a=>{if(!I)throw new Error("useWalletMaterial must be used within a CedrosLoginProvider");A(!0),r(null);try{await I.delete(`/wallet/derived/${a}`)}catch(c){const w=b.handleApiError(c,"Failed to delete derived wallet");throw r(w.message),w}finally{A(!1)}},[I]),l=o.useCallback(()=>r(null),[]);return{getStatus:y,getMaterial:p,enroll:Q,recover:u,signTransaction:m,rotateUserSecret:B,unlock:d,lock:f,getShareBForRecovery:F,createDerivedWallet:k,listAllWallets:U,deleteDerivedWallet:E,isLoading:t,error:i,clearError:l}}const Rt={status:"not_enrolled",solanaPubkey:null,authMethod:null,hasExternalWallet:!1,isUnlocked:!1,capabilities:null,isSupported:!1,error:null,refresh:async()=>{},clearError:()=>{}};function Ge(){const t=b.useCedrosLoginOptional()!==null,[A,i]=o.useState("loading"),[r,n]=o.useState(null),[s,g]=o.useState(null),[C,I]=o.useState(!1),[y,p]=o.useState(!1),[Q,u]=o.useState(null),[m,B]=o.useState(null),{getStatus:d,isLoading:f}=me(),F=o.useRef(!1);o.useEffect(()=>{if(!t)return;let E=!1;return(async()=>{try{const a=await vt();if(E)return;u(a),a.allSupported||(i("error"),B("Your browser or device does not support all required features. Please use a modern browser with a platform authenticator."))}catch{if(E)return;u(null),i("error"),B("Failed to check crypto capabilities")}})(),()=>{E=!0}},[t]);const k=o.useCallback(async()=>{if(!(!t||!Q?.allSupported)){i("loading"),B(null);try{const E=await d();n(E.solanaPubkey??null),g(E.authMethod??null),I(E.hasExternalWallet),p(E.unlocked),E.hasExternalWallet?i("enrolled_unlocked"):E.enrolled?i(E.unlocked?"enrolled_unlocked":"enrolled_locked"):i("not_enrolled")}catch(E){i("error"),B(E instanceof Error?E.message:"Failed to fetch wallet status")}}},[t,Q?.allSupported,d]);o.useEffect(()=>{t&&Q?.allSupported&&!f&&!F.current&&(F.current=!0,k())},[t,Q?.allSupported,f,k]);const U=o.useCallback(()=>B(null),[]);return t?{status:A,solanaPubkey:r,authMethod:s,hasExternalWallet:C,isUnlocked:y,capabilities:Q,isSupported:Q?.allSupported??!1,error:m,refresh:k,clearError:U}:Rt}const z="__CEDROS_EMBEDDED_WALLET__";function Tt(e){typeof window<"u"&&(window[z]=e)}function Ie(){typeof window<"u"&&delete window[z]}function Lt(){return typeof window>"u"?!1:window[z]?.available??!1}function Xt(){return typeof window>"u"?null:window[z]??null}function Wt(){const{config:e,user:t}=b.useCedrosLogin(),{status:A,solanaPubkey:i,hasExternalWallet:r}=Ge(),n=e.wallet?.exposeAvailability??!1,s=e.wallet?.exposePublicKey??!1;return o.useEffect(()=>{if(!n||!t){Ie();return}if(r){Ie();return}if(A==="loading")return;const g=A==="enrolled_locked"||A==="enrolled_unlocked";return Tt({available:g,publicKey:s&&g?i:null}),()=>{Ie()}},[n,s,t,A,i,r]),null}function jt({config:e,children:t}){const[A,i]=o.useState(null),[r,n]=o.useState(!1),s=o.useRef(e.callbacks);s.current=e.callbacks;const g=o.useRef({onLoginSuccess:(...J)=>s.current?.onLoginSuccess?.(...J),onLoginError:(...J)=>s.current?.onLoginError?.(...J),onLogout:()=>s.current?.onLogout?.(),onSessionExpired:()=>s.current?.onSessionExpired?.()}),C=e.features==="auto",{features:I,googleClientId:y,appleClientId:p,isLoading:Q}=Me(e.serverUrl,C,e.requestTimeout),u=o.useMemo(()=>!C||!I?e:{...e,features:I,googleClientId:e.googleClientId??y,appleClientId:e.appleClientId??p},[e,C,I,y,p]),m=o.useMemo(()=>JSON.stringify(u.themeOverrides??null),[u.themeOverrides]),B=o.useMemo(()=>JSON.stringify(u.session??null),[u.session]),d=o.useMemo(()=>JSON.stringify(u.features??null),[u.features]),f=o.useMemo(()=>JSON.stringify(u.forms??null),[u.forms]),F=o.useMemo(()=>u,[u.serverUrl,u.googleClientId,u.appleClientId,u.requestTimeout,u.retryAttempts,u.theme,m,B,d,f]);He({theme:F.theme,themeOverrides:F.themeOverrides});const{user:k,authState:U,handleLoginSuccess:E,logout:l,refreshUser:a,getAccessToken:c}=ve({serverUrl:F.serverUrl,session:F.session,callbacks:g.current,requestTimeoutMs:F.requestTimeout}),w=o.useCallback(async()=>{i(null),await l()},[l]),h=o.useCallback((...J)=>{i(null),E(...J)},[E]),S=o.useCallback(()=>n(!0),[]),K=o.useCallback(()=>n(!1),[]),H=o.useMemo(()=>({config:F,user:k,authState:U,logout:w,refreshUser:a,_internal:{handleLoginSuccess:h,getAccessToken:c}}),[F,k,U,w,a,h,c]),G=o.useMemo(()=>({error:A,isModalOpen:r,openModal:S,closeModal:K}),[A,r,S,K]),M=o.useMemo(()=>({...H,...G}),[H,G]);return C&&Q?null:X.jsx(Ae.AuthStateContext.Provider,{value:H,children:X.jsx(Ae.AuthUIContext.Provider,{value:G,children:X.jsxs(Ae.CedrosLoginContext.Provider,{value:M,children:[X.jsx(Wt,{}),t]})})})}function Zt(){const{user:e,authState:t,error:A,logout:i,refreshUser:r,openModal:n,closeModal:s}=b.useCedrosLogin();return{user:e,authState:t,error:A,isAuthenticated:t==="authenticated"&&e!==null,isLoading:t==="loading",logout:i,refreshUser:r,openLoginModal:n,closeLoginModal:s}}exports.CedrosLoginProvider=jt;exports.DEFAULT_KDF_PARAMS=Be;exports.aesGcmEncryptToBase64=nt;exports.argon2Derive=bt;exports.authenticateWithDiscoverablePrf=Jt;exports.base64ToUint8Array=pe;exports.deriveKeyFromPrf=st;exports.generateArgon2Salt=tt;exports.generatePrfSalt=Ee;exports.generateSeed=ze;exports.getBrowserSupportInfo=xt;exports.getEmbeddedWalletInfo=Xt;exports.getMissingCapabilitiesMessage=Yt;exports.isEmbeddedWalletAvailable=Lt;exports.registerPasskeyWithPrf=Ht;exports.toCredentialRequest=be;exports.toEncryptionKey=ce;exports.toSeed=de;exports.toShamirShare=Ze;exports.uint8ArrayToBase64=T;exports.useAuth=Zt;exports.useWallet=Ge;exports.useWalletMaterial=me;exports.validateKdfParams=Fe;exports.wipeAll=At;exports.wipeBytes=Ce;
|