@cedros/login-react 0.0.12 → 0.0.14

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.
Files changed (435) hide show
  1. package/README.md +68 -0
  2. package/dist/AdminDepositList-CyT4VBH8.js +311 -0
  3. package/dist/AdminDepositList-CyT4VBH8.js.map +1 -0
  4. package/dist/AdminDepositList-b2AXtLg0.cjs +1 -0
  5. package/dist/AdminDepositList-b2AXtLg0.cjs.map +1 -0
  6. package/dist/AdminWithdrawalHistory-Cud-yuWy.js +916 -0
  7. package/dist/AdminWithdrawalHistory-Cud-yuWy.js.map +1 -0
  8. package/dist/AdminWithdrawalHistory-DL9zbu2b.cjs +1 -0
  9. package/dist/AdminWithdrawalHistory-DL9zbu2b.cjs.map +1 -0
  10. package/dist/AuthenticationSettings-D739nNul.cjs +1 -0
  11. package/dist/AuthenticationSettings-D739nNul.cjs.map +1 -0
  12. package/dist/AuthenticationSettings-DtLoxQ2z.cjs +1 -0
  13. package/dist/AuthenticationSettings-DtLoxQ2z.cjs.map +1 -0
  14. package/dist/AuthenticationSettings-Dx3JCI3m.js +9 -0
  15. package/dist/AuthenticationSettings-Dx3JCI3m.js.map +1 -0
  16. package/dist/AuthenticationSettings-vowmQPXz.js +525 -0
  17. package/dist/AuthenticationSettings-vowmQPXz.js.map +1 -0
  18. package/dist/AutosaveStatus-CCrZszKA.cjs +1 -0
  19. package/dist/AutosaveStatus-CCrZszKA.cjs.map +1 -0
  20. package/dist/AutosaveStatus-Ciyt350A.js +1497 -0
  21. package/dist/AutosaveStatus-Ciyt350A.js.map +1 -0
  22. package/dist/CreditSystemSettings-BQ3h4CyM.js +210 -0
  23. package/dist/CreditSystemSettings-BQ3h4CyM.js.map +1 -0
  24. package/dist/CreditSystemSettings-C6dUsu72.cjs +1 -0
  25. package/dist/CreditSystemSettings-C6dUsu72.cjs.map +1 -0
  26. package/dist/CreditSystemSettings-CBot8EPW.cjs +1 -0
  27. package/dist/CreditSystemSettings-CBot8EPW.cjs.map +1 -0
  28. package/dist/CreditSystemSettings-bVuNLsqp.js +9 -0
  29. package/dist/CreditSystemSettings-bVuNLsqp.js.map +1 -0
  30. package/dist/DepositsSection-BkKUS4vk.cjs +1 -0
  31. package/dist/DepositsSection-BkKUS4vk.cjs.map +1 -0
  32. package/dist/{DepositsSection-0Hqr0yDm.js → DepositsSection-DD9MKUFt.js} +20 -14
  33. package/dist/DepositsSection-DD9MKUFt.js.map +1 -0
  34. package/dist/EmailRegisterForm-Pvm3I8GP.cjs +1 -0
  35. package/dist/EmailRegisterForm-Pvm3I8GP.cjs.map +1 -0
  36. package/dist/EmailRegisterForm-nI0BOIxR.js +927 -0
  37. package/dist/EmailRegisterForm-nI0BOIxR.js.map +1 -0
  38. package/dist/EmailSettings-B9qwPSiM.cjs +1 -0
  39. package/dist/EmailSettings-B9qwPSiM.cjs.map +1 -0
  40. package/dist/EmailSettings-CCA8dNCi.js +17 -0
  41. package/dist/EmailSettings-CCA8dNCi.js.map +1 -0
  42. package/dist/EmailSettings-RbgAq9FB.cjs +1 -0
  43. package/dist/EmailSettings-RbgAq9FB.cjs.map +1 -0
  44. package/dist/{AuthenticationSettings-BSoIQ58T.js → EmailSettings-mxlKNcPl.js} +3 -3
  45. package/dist/EmailSettings-mxlKNcPl.js.map +1 -0
  46. package/dist/EmbeddedWalletSettings-B4h-8rxB.cjs +1 -0
  47. package/dist/EmbeddedWalletSettings-B4h-8rxB.cjs.map +1 -0
  48. package/dist/EmbeddedWalletSettings-BInZvFZf.js +79 -0
  49. package/dist/EmbeddedWalletSettings-BInZvFZf.js.map +1 -0
  50. package/dist/{EmbeddedWalletSettings-iVf_3pn3.js → EmbeddedWalletSettings-CXlZFFDw.js} +3 -3
  51. package/dist/EmbeddedWalletSettings-CXlZFFDw.js.map +1 -0
  52. package/dist/EmbeddedWalletSettings-D5JXae1L.cjs +1 -0
  53. package/dist/EmbeddedWalletSettings-D5JXae1L.cjs.map +1 -0
  54. package/dist/ErrorMessage-CHbYbVi2.cjs +1 -0
  55. package/dist/ErrorMessage-CHbYbVi2.cjs.map +1 -0
  56. package/dist/ErrorMessage-CcEK0pYO.js +64 -0
  57. package/dist/ErrorMessage-CcEK0pYO.js.map +1 -0
  58. package/dist/{GoogleLoginButton-BzHr545L.js → GoogleLoginButton-CXwp4LsQ.js} +4 -3
  59. package/dist/{GoogleLoginButton-BzHr545L.js.map → GoogleLoginButton-CXwp4LsQ.js.map} +1 -1
  60. package/dist/GoogleLoginButton-zS_69-KV.cjs +1 -0
  61. package/dist/{GoogleLoginButton-DoAdOqb3.cjs.map → GoogleLoginButton-zS_69-KV.cjs.map} +1 -1
  62. package/dist/LoadingSpinner-6vml-zwr.js +79 -0
  63. package/dist/LoadingSpinner-6vml-zwr.js.map +1 -0
  64. package/dist/LoadingSpinner-d6sSxgQN.cjs +1 -0
  65. package/dist/LoadingSpinner-d6sSxgQN.cjs.map +1 -0
  66. package/dist/PermissionsSection-BPbE-hNx.cjs +1 -0
  67. package/dist/PermissionsSection-BPbE-hNx.cjs.map +1 -0
  68. package/dist/PermissionsSection-CighC1p6.js +1026 -0
  69. package/dist/PermissionsSection-CighC1p6.js.map +1 -0
  70. package/dist/ServerSettings-BE8fsE5k.js +84 -0
  71. package/dist/ServerSettings-BE8fsE5k.js.map +1 -0
  72. package/dist/ServerSettings-CYTlQ2xy.cjs +1 -0
  73. package/dist/ServerSettings-CYTlQ2xy.cjs.map +1 -0
  74. package/dist/ServerSettings-DFs9jQ3f.cjs +1 -0
  75. package/dist/ServerSettings-DFs9jQ3f.cjs.map +1 -0
  76. package/dist/{ServerSettings-C_osdbiX.js → ServerSettings-pSmWDC1d.js} +3 -3
  77. package/dist/ServerSettings-pSmWDC1d.js.map +1 -0
  78. package/dist/SettingsPageLayout--GZ_iHLc.js +50 -0
  79. package/dist/SettingsPageLayout--GZ_iHLc.js.map +1 -0
  80. package/dist/SettingsPageLayout-j5lMjEID.cjs +1 -0
  81. package/dist/SettingsPageLayout-j5lMjEID.cjs.map +1 -0
  82. package/dist/SolanaLoginButton-BjOxpE1C.cjs +1 -0
  83. package/dist/{SolanaLoginButton-CPzms0kf.cjs.map → SolanaLoginButton-BjOxpE1C.cjs.map} +1 -1
  84. package/dist/{SolanaLoginButton-C-CfZxAZ.js → SolanaLoginButton-P22QjBaO.js} +5 -4
  85. package/dist/{SolanaLoginButton-C-CfZxAZ.js.map → SolanaLoginButton-P22QjBaO.js.map} +1 -1
  86. package/dist/StatsBar-BX-hHtTq.js +66 -0
  87. package/dist/StatsBar-BX-hHtTq.js.map +1 -0
  88. package/dist/StatsBar-DTUZCwDD.cjs +1 -0
  89. package/dist/StatsBar-DTUZCwDD.cjs.map +1 -0
  90. package/dist/{TeamSection-Bjt72upx.js → TeamSection-BIECkp7g.js} +27 -26
  91. package/dist/TeamSection-BIECkp7g.js.map +1 -0
  92. package/dist/TeamSection-BOH9pv_E.cjs +1 -0
  93. package/dist/TeamSection-BOH9pv_E.cjs.map +1 -0
  94. package/dist/UsersSection-e6q7FHzx.cjs +1 -0
  95. package/dist/UsersSection-e6q7FHzx.cjs.map +1 -0
  96. package/dist/UsersSection-t-zm0jZW.js +33 -0
  97. package/dist/UsersSection-t-zm0jZW.js.map +1 -0
  98. package/dist/{WebhookSettings-IyhyTFes.js → WebhookSettings-Bb70MbFj.js} +4 -4
  99. package/dist/WebhookSettings-Bb70MbFj.js.map +1 -0
  100. package/dist/WebhookSettings-C-gvNAW1.cjs +1 -0
  101. package/dist/WebhookSettings-C-gvNAW1.cjs.map +1 -0
  102. package/dist/WebhookSettings-CGyDKjrm.cjs +1 -0
  103. package/dist/WebhookSettings-CGyDKjrm.cjs.map +1 -0
  104. package/dist/WebhookSettings-kIstSjZi.js +17 -0
  105. package/dist/WebhookSettings-kIstSjZi.js.map +1 -0
  106. package/dist/WithdrawalsSection-sljIyeaz.cjs +1 -0
  107. package/dist/WithdrawalsSection-sljIyeaz.cjs.map +1 -0
  108. package/dist/WithdrawalsSection-yRDTVFsb.js +27 -0
  109. package/dist/WithdrawalsSection-yRDTVFsb.js.map +1 -0
  110. package/dist/admin-only.cjs +1 -0
  111. package/dist/admin-only.cjs.map +1 -0
  112. package/dist/{admin/types.d.ts → admin-only.d.ts} +228 -167
  113. package/dist/admin-only.js +8 -0
  114. package/dist/admin-only.js.map +1 -0
  115. package/dist/assets/argon2Worker-Bi5TuQvD.js.map +1 -1
  116. package/dist/email-only.cjs +1 -1
  117. package/dist/email-only.d.ts +645 -16
  118. package/dist/email-only.js +16 -13
  119. package/dist/email-only.js.map +1 -1
  120. package/dist/google-only.cjs +1 -1
  121. package/dist/google-only.d.ts +554 -13
  122. package/dist/google-only.js +11 -8
  123. package/dist/google-only.js.map +1 -1
  124. package/dist/index.cjs +2061 -1
  125. package/dist/index.cjs.map +1 -1
  126. package/dist/index.d.ts +5030 -144
  127. package/dist/index.js +13482 -117
  128. package/dist/index.js.map +1 -1
  129. package/dist/login-react.css +1 -1
  130. package/dist/plugin-8_dpq7tC.cjs +1 -0
  131. package/dist/plugin-8_dpq7tC.cjs.map +1 -0
  132. package/dist/plugin-D1NdppqC.js +596 -0
  133. package/dist/plugin-D1NdppqC.js.map +1 -0
  134. package/dist/sanitization-Bo_tn-L2.cjs +1 -0
  135. package/dist/sanitization-Bo_tn-L2.cjs.map +1 -0
  136. package/dist/sanitization-CQ-H1MSg.js +39 -0
  137. package/dist/sanitization-CQ-H1MSg.js.map +1 -0
  138. package/dist/shamir-4DyQMJCk.cjs +1 -0
  139. package/dist/shamir-4DyQMJCk.cjs.map +1 -0
  140. package/dist/{solanaKeypair-BlXol3nh.js → shamir-L-s-Tp1Z.js} +765 -757
  141. package/dist/shamir-L-s-Tp1Z.js.map +1 -0
  142. package/dist/silentWalletEnroll-BgTb4H5I.cjs +1 -0
  143. package/dist/silentWalletEnroll-BgTb4H5I.cjs.map +1 -0
  144. package/dist/silentWalletEnroll-DWt6Pr3B.js +41 -0
  145. package/dist/silentWalletEnroll-DWt6Pr3B.js.map +1 -0
  146. package/dist/solana-only.cjs +1 -1
  147. package/dist/solana-only.d.ts +605 -13
  148. package/dist/solana-only.js +12 -9
  149. package/dist/solana-only.js.map +1 -1
  150. package/dist/style.d.ts +1 -0
  151. package/dist/useAdminDeposits-BTSyeAfg.js +151 -0
  152. package/dist/useAdminDeposits-BTSyeAfg.js.map +1 -0
  153. package/dist/useAdminDeposits-BkkCwHWp.cjs +1 -0
  154. package/dist/useAdminDeposits-BkkCwHWp.cjs.map +1 -0
  155. package/dist/{ErrorMessage-DU2VBb85.js → useAuth-C3dpk0po.js} +1005 -1241
  156. package/dist/useAuth-C3dpk0po.js.map +1 -0
  157. package/dist/useAuth-D3Pk_H3z.cjs +1 -0
  158. package/dist/useAuth-D3Pk_H3z.cjs.map +1 -0
  159. package/dist/useCedrosLogin-C9MrcZvh.cjs +1 -0
  160. package/dist/useCedrosLogin-C9MrcZvh.cjs.map +1 -0
  161. package/dist/useCedrosLogin-_94MmGGq.js +216 -0
  162. package/dist/useCedrosLogin-_94MmGGq.js.map +1 -0
  163. package/dist/useOrgs-C3pzMA9h.js +215 -0
  164. package/dist/useOrgs-C3pzMA9h.js.map +1 -0
  165. package/dist/useOrgs-DDVRCaVi.cjs +1 -0
  166. package/dist/useOrgs-DDVRCaVi.cjs.map +1 -0
  167. package/dist/useSystemSettings-DBlAMjFi.js +97 -0
  168. package/dist/useSystemSettings-DBlAMjFi.js.map +1 -0
  169. package/dist/useSystemSettings-DRrreszl.cjs +1 -0
  170. package/dist/useSystemSettings-DRrreszl.cjs.map +1 -0
  171. package/dist/useUsersStatsSummary-8qY7iP4G.cjs +1 -0
  172. package/dist/useUsersStatsSummary-8qY7iP4G.cjs.map +1 -0
  173. package/dist/useUsersStatsSummary-NjEFvWuz.js +1246 -0
  174. package/dist/useUsersStatsSummary-NjEFvWuz.js.map +1 -0
  175. package/dist/{validation-BebL7hMF.js → validation-B8kMV3BL.js} +1 -1
  176. package/dist/{validation-BebL7hMF.js.map → validation-B8kMV3BL.js.map} +1 -1
  177. package/dist/{validation-BeXIfuHB.cjs → validation-BuGQrA-K.cjs} +1 -1
  178. package/dist/{validation-BeXIfuHB.cjs.map → validation-BuGQrA-K.cjs.map} +1 -1
  179. package/package.json +11 -1
  180. package/dist/AuthenticationSettings-BSoIQ58T.js.map +0 -1
  181. package/dist/AuthenticationSettings-CNmWEPFV.cjs +0 -1
  182. package/dist/AuthenticationSettings-CNmWEPFV.cjs.map +0 -1
  183. package/dist/CreditSystemSettings-BYxoFwaP.js +0 -9
  184. package/dist/CreditSystemSettings-BYxoFwaP.js.map +0 -1
  185. package/dist/CreditSystemSettings-D2fLorNx.cjs +0 -1
  186. package/dist/CreditSystemSettings-D2fLorNx.cjs.map +0 -1
  187. package/dist/DepositsSection-0Hqr0yDm.js.map +0 -1
  188. package/dist/DepositsSection-CGKCzM-H.cjs +0 -1
  189. package/dist/DepositsSection-CGKCzM-H.cjs.map +0 -1
  190. package/dist/EmailRegisterForm-C0PStlj5.js +0 -961
  191. package/dist/EmailRegisterForm-C0PStlj5.js.map +0 -1
  192. package/dist/EmailRegisterForm-DaPLGws2.cjs +0 -1
  193. package/dist/EmailRegisterForm-DaPLGws2.cjs.map +0 -1
  194. package/dist/EmailSettings-CiLDwzNb.cjs +0 -1
  195. package/dist/EmailSettings-CiLDwzNb.cjs.map +0 -1
  196. package/dist/EmailSettings-DTjpO65J.js +0 -9
  197. package/dist/EmailSettings-DTjpO65J.js.map +0 -1
  198. package/dist/EmbeddedWalletSettings-CX7sYiPy.cjs +0 -1
  199. package/dist/EmbeddedWalletSettings-CX7sYiPy.cjs.map +0 -1
  200. package/dist/EmbeddedWalletSettings-iVf_3pn3.js.map +0 -1
  201. package/dist/ErrorMessage-BXHiYibN.cjs +0 -1
  202. package/dist/ErrorMessage-BXHiYibN.cjs.map +0 -1
  203. package/dist/ErrorMessage-DU2VBb85.js.map +0 -1
  204. package/dist/GoogleLoginButton-DoAdOqb3.cjs +0 -1
  205. package/dist/ServerSettings-C_osdbiX.js.map +0 -1
  206. package/dist/ServerSettings-HqSb_VDj.cjs +0 -1
  207. package/dist/ServerSettings-HqSb_VDj.cjs.map +0 -1
  208. package/dist/SolanaLoginButton-CPzms0kf.cjs +0 -1
  209. package/dist/TeamSection-Bjt72upx.js.map +0 -1
  210. package/dist/TeamSection-DZeWHkLd.cjs +0 -1
  211. package/dist/TeamSection-DZeWHkLd.cjs.map +0 -1
  212. package/dist/UsersSection-DU86czWP.cjs +0 -1
  213. package/dist/UsersSection-DU86czWP.cjs.map +0 -1
  214. package/dist/UsersSection-hAcyfSZk.js +0 -81
  215. package/dist/UsersSection-hAcyfSZk.js.map +0 -1
  216. package/dist/WebhookSettings-Br9bakAL.cjs +0 -1
  217. package/dist/WebhookSettings-Br9bakAL.cjs.map +0 -1
  218. package/dist/WebhookSettings-IyhyTFes.js.map +0 -1
  219. package/dist/WithdrawalsSection-B1415d-G.js +0 -20
  220. package/dist/WithdrawalsSection-B1415d-G.js.map +0 -1
  221. package/dist/WithdrawalsSection-iZJBuZ7O.cjs +0 -1
  222. package/dist/WithdrawalsSection-iZJBuZ7O.cjs.map +0 -1
  223. package/dist/admin/AdminShell.d.ts +0 -38
  224. package/dist/admin/icons.d.ts +0 -2
  225. package/dist/admin/index.d.ts +0 -10
  226. package/dist/admin/plugin.d.ts +0 -3
  227. package/dist/admin/sections/AuthenticationSettings.d.ts +0 -3
  228. package/dist/admin/sections/CreditSystemSettings.d.ts +0 -3
  229. package/dist/admin/sections/DepositsSection.d.ts +0 -3
  230. package/dist/admin/sections/EmailSettings.d.ts +0 -3
  231. package/dist/admin/sections/EmbeddedWalletSettings.d.ts +0 -3
  232. package/dist/admin/sections/FeatureSettings.d.ts +0 -3
  233. package/dist/admin/sections/InvitesSection.d.ts +0 -3
  234. package/dist/admin/sections/MembersSection.d.ts +0 -3
  235. package/dist/admin/sections/ServerSettings.d.ts +0 -3
  236. package/dist/admin/sections/SettingsSections.d.ts +0 -7
  237. package/dist/admin/sections/TeamSection.d.ts +0 -3
  238. package/dist/admin/sections/UsersSection.d.ts +0 -3
  239. package/dist/admin/sections/WebhookSettings.d.ts +0 -3
  240. package/dist/admin/sections/WithdrawalsSection.d.ts +0 -3
  241. package/dist/components/LoginButton.d.ts +0 -23
  242. package/dist/components/LoginForm.d.ts +0 -9
  243. package/dist/components/LoginModal.d.ts +0 -9
  244. package/dist/components/admin/AdminUserDetail.d.ts +0 -23
  245. package/dist/components/admin/AdminUserList.d.ts +0 -21
  246. package/dist/components/admin/CedrosAdminDashboard.d.ts +0 -52
  247. package/dist/components/admin/PermissionsSection.d.ts +0 -7
  248. package/dist/components/admin/ProfileDropdown.d.ts +0 -34
  249. package/dist/components/admin/SetupWizard.d.ts +0 -30
  250. package/dist/components/admin/StatsBar.d.ts +0 -17
  251. package/dist/components/admin/SystemSettings.d.ts +0 -19
  252. package/dist/components/admin/settings/AuthenticationSettings.d.ts +0 -4
  253. package/dist/components/admin/settings/AutosaveStatus.d.ts +0 -6
  254. package/dist/components/admin/settings/CreditSystemSettings.d.ts +0 -6
  255. package/dist/components/admin/settings/EmailSettings.d.ts +0 -4
  256. package/dist/components/admin/settings/EmbeddedWalletSettings.d.ts +0 -4
  257. package/dist/components/admin/settings/FeatureSettings.d.ts +0 -4
  258. package/dist/components/admin/settings/MessagingSettings.d.ts +0 -4
  259. package/dist/components/admin/settings/SecuritySettings.d.ts +0 -4
  260. package/dist/components/admin/settings/ServerSettings.d.ts +0 -4
  261. package/dist/components/admin/settings/SettingsPageLayout.d.ts +0 -16
  262. package/dist/components/admin/settings/SsoProvidersSettings.d.ts +0 -4
  263. package/dist/components/admin/settings/WebhookSettings.d.ts +0 -4
  264. package/dist/components/admin/settings/index.d.ts +0 -31
  265. package/dist/components/admin/settings/settingsInputs.d.ts +0 -79
  266. package/dist/components/admin/settings/settingsMetadata.d.ts +0 -18
  267. package/dist/components/apple/AppleLoginButton.d.ts +0 -29
  268. package/dist/components/deposit/CreditBalance.d.ts +0 -19
  269. package/dist/components/deposit/DepositFlow.d.ts +0 -118
  270. package/dist/components/deposit/FeeConfigDisplay.d.ts +0 -15
  271. package/dist/components/deposit/History.d.ts +0 -21
  272. package/dist/components/deposit/TieredAmountSlider.d.ts +0 -19
  273. package/dist/components/deposit/TokenSelector.d.ts +0 -23
  274. package/dist/components/deposit/admin/AdminDepositList.d.ts +0 -21
  275. package/dist/components/deposit/admin/AdminDepositStats.d.ts +0 -15
  276. package/dist/components/deposit/admin/AdminPrivacyPeriodDeposits.d.ts +0 -19
  277. package/dist/components/deposit/admin/AdminWithdrawalHistory.d.ts +0 -19
  278. package/dist/components/deposit/admin/AdminWithdrawalQueue.d.ts +0 -23
  279. package/dist/components/deposit/admin/AdminWithdrawalStats.d.ts +0 -10
  280. package/dist/components/deposit/admin/FeatureDisabledMessage.d.ts +0 -15
  281. package/dist/components/deposit/admin/PrivacySystemStatus.d.ts +0 -15
  282. package/dist/components/deposit/admin/featureDisabled.d.ts +0 -14
  283. package/dist/components/deposit/admin/index.d.ts +0 -22
  284. package/dist/components/deposit/index.d.ts +0 -12
  285. package/dist/components/deposit/tierUtils.d.ts +0 -8
  286. package/dist/components/deposit/tokens.d.ts +0 -19
  287. package/dist/components/email/EmailLoginForm.d.ts +0 -11
  288. package/dist/components/email/EmailRegisterForm.d.ts +0 -14
  289. package/dist/components/email/ForgotPasswordForm.d.ts +0 -17
  290. package/dist/components/email/PasswordInput.d.ts +0 -14
  291. package/dist/components/email/ResetPasswordForm.d.ts +0 -22
  292. package/dist/components/google/GoogleLoginButton.d.ts +0 -12
  293. package/dist/components/invites/InviteForm.d.ts +0 -38
  294. package/dist/components/invites/InviteList.d.ts +0 -40
  295. package/dist/components/members/MemberList.d.ts +0 -47
  296. package/dist/components/org/CreateOrgForm.d.ts +0 -7
  297. package/dist/components/org/OrgAvatar.d.ts +0 -7
  298. package/dist/components/org/OrgListView.d.ts +0 -9
  299. package/dist/components/org/OrgSelector.d.ts +0 -52
  300. package/dist/components/org/OrgSwitcher.d.ts +0 -47
  301. package/dist/components/org/icons.d.ts +0 -8
  302. package/dist/components/profile/UserProfileSettings.d.ts +0 -35
  303. package/dist/components/profile/index.d.ts +0 -2
  304. package/dist/components/sessions/SessionList.d.ts +0 -33
  305. package/dist/components/shared/ErrorBoundary.d.ts +0 -38
  306. package/dist/components/shared/ErrorMessage.d.ts +0 -14
  307. package/dist/components/shared/LoadingSpinner.d.ts +0 -16
  308. package/dist/components/solana/SolanaLoginButton.d.ts +0 -49
  309. package/dist/components/templates/FullPageLayout.d.ts +0 -40
  310. package/dist/components/templates/SplitPageLayout.d.ts +0 -44
  311. package/dist/components/templates/index.d.ts +0 -4
  312. package/dist/components/totp/OtpInput.d.ts +0 -32
  313. package/dist/components/totp/QrCode.d.ts +0 -21
  314. package/dist/components/totp/TotpSettings.d.ts +0 -38
  315. package/dist/components/totp/TotpSetup.d.ts +0 -23
  316. package/dist/components/totp/TotpVerify.d.ts +0 -25
  317. package/dist/components/totp/index.d.ts +0 -10
  318. package/dist/components/wallet/CapabilityWarning.d.ts +0 -11
  319. package/dist/components/wallet/PasskeyPrompt.d.ts +0 -34
  320. package/dist/components/wallet/RecoveryPhraseDisplay.d.ts +0 -18
  321. package/dist/components/wallet/RecoveryPhraseInput.d.ts +0 -21
  322. package/dist/components/wallet/WalletAddressRow.d.ts +0 -10
  323. package/dist/components/wallet/WalletEnrollment.d.ts +0 -15
  324. package/dist/components/wallet/WalletManager.d.ts +0 -9
  325. package/dist/components/wallet/WalletRecovery.d.ts +0 -19
  326. package/dist/components/wallet/WalletStatus.d.ts +0 -28
  327. package/dist/components/wallet/WalletUnlock.d.ts +0 -23
  328. package/dist/components/wallet/index.d.ts +0 -23
  329. package/dist/components/webauthn/PasskeyLoginButton.d.ts +0 -8
  330. package/dist/context/CedrosLoginContext.d.ts +0 -24
  331. package/dist/context/CedrosLoginProvider.d.ts +0 -17
  332. package/dist/context/EmbeddedWalletExposure.d.ts +0 -19
  333. package/dist/context/useCedrosLogin.d.ts +0 -12
  334. package/dist/crypto/aesGcm.d.ts +0 -89
  335. package/dist/crypto/argon2.d.ts +0 -65
  336. package/dist/crypto/argon2Worker.d.ts +0 -1
  337. package/dist/crypto/argon2WorkerClient.d.ts +0 -28
  338. package/dist/crypto/bip39.d.ts +0 -106
  339. package/dist/crypto/capabilities.d.ts +0 -35
  340. package/dist/crypto/entropy.d.ts +0 -56
  341. package/dist/crypto/hkdf.d.ts +0 -38
  342. package/dist/crypto/index.d.ts +0 -30
  343. package/dist/crypto/secureWipe.d.ts +0 -71
  344. package/dist/crypto/shamir.d.ts +0 -52
  345. package/dist/crypto/solanaKeypair.d.ts +0 -63
  346. package/dist/crypto/types.d.ts +0 -134
  347. package/dist/crypto/webauthnPrf.d.ts +0 -108
  348. package/dist/hooks/useAdminDeposits.d.ts +0 -10
  349. package/dist/hooks/useAdminUsers.d.ts +0 -28
  350. package/dist/hooks/useAppleAuth.d.ts +0 -52
  351. package/dist/hooks/useAuth.d.ts +0 -34
  352. package/dist/hooks/useAuthSession.d.ts +0 -19
  353. package/dist/hooks/useAuthorize.d.ts +0 -62
  354. package/dist/hooks/useCredits.d.ts +0 -11
  355. package/dist/hooks/useDashboardPermissions.d.ts +0 -45
  356. package/dist/hooks/useDeposit.d.ts +0 -16
  357. package/dist/hooks/useEmailAuth.d.ts +0 -60
  358. package/dist/hooks/useGoogleAuth.d.ts +0 -67
  359. package/dist/hooks/useInstantLink.d.ts +0 -42
  360. package/dist/hooks/useInvites.d.ts +0 -57
  361. package/dist/hooks/useMembers.d.ts +0 -52
  362. package/dist/hooks/useOrgs.d.ts +0 -49
  363. package/dist/hooks/usePasswordReset.d.ts +0 -32
  364. package/dist/hooks/usePendingRecovery.d.ts +0 -34
  365. package/dist/hooks/useProfile.d.ts +0 -35
  366. package/dist/hooks/useRateLimiter.d.ts +0 -58
  367. package/dist/hooks/useServerFeatures.d.ts +0 -55
  368. package/dist/hooks/useSessions.d.ts +0 -45
  369. package/dist/hooks/useSettingsAutosave.d.ts +0 -29
  370. package/dist/hooks/useSetup.d.ts +0 -25
  371. package/dist/hooks/useSolanaAuth.d.ts +0 -30
  372. package/dist/hooks/useSsoProviders.d.ts +0 -52
  373. package/dist/hooks/useSystemSettings.d.ts +0 -47
  374. package/dist/hooks/useThemeManager.d.ts +0 -11
  375. package/dist/hooks/useTotp.d.ts +0 -52
  376. package/dist/hooks/useTotpVerify.d.ts +0 -38
  377. package/dist/hooks/useTransactionSigning.d.ts +0 -45
  378. package/dist/hooks/useWallet.d.ts +0 -10
  379. package/dist/hooks/useWalletDiscovery.d.ts +0 -24
  380. package/dist/hooks/useWalletEnrollment.d.ts +0 -9
  381. package/dist/hooks/useWalletMaterial.d.ts +0 -10
  382. package/dist/hooks/useWalletRecovery.d.ts +0 -9
  383. package/dist/hooks/useWalletSigning.d.ts +0 -31
  384. package/dist/hooks/useWebAuthn.d.ts +0 -25
  385. package/dist/i18n/I18nProvider.d.ts +0 -16
  386. package/dist/i18n/context.d.ts +0 -6
  387. package/dist/i18n/index.d.ts +0 -5
  388. package/dist/i18n/translations.d.ts +0 -66
  389. package/dist/i18n/useI18n.d.ts +0 -9
  390. package/dist/index-ZS9AwAal.cjs +0 -2061
  391. package/dist/index-ZS9AwAal.cjs.map +0 -1
  392. package/dist/index-dgg5tlO7.js +0 -19650
  393. package/dist/index-dgg5tlO7.js.map +0 -1
  394. package/dist/silentWalletEnroll-C3JRAD9_.js +0 -42
  395. package/dist/silentWalletEnroll-C3JRAD9_.js.map +0 -1
  396. package/dist/silentWalletEnroll-DRYQAQfg.cjs +0 -1
  397. package/dist/silentWalletEnroll-DRYQAQfg.cjs.map +0 -1
  398. package/dist/solanaKeypair-BlXol3nh.js.map +0 -1
  399. package/dist/solanaKeypair-C-lIR1JY.cjs +0 -1
  400. package/dist/solanaKeypair-C-lIR1JY.cjs.map +0 -1
  401. package/dist/types/adminUser.d.ts +0 -168
  402. package/dist/types/auth.d.ts +0 -122
  403. package/dist/types/config.d.ts +0 -266
  404. package/dist/types/deposit.d.ts +0 -490
  405. package/dist/types/index.d.ts +0 -13
  406. package/dist/types/invite.d.ts +0 -71
  407. package/dist/types/member.d.ts +0 -45
  408. package/dist/types/org.d.ts +0 -133
  409. package/dist/types/profile.d.ts +0 -56
  410. package/dist/types/session.d.ts +0 -28
  411. package/dist/types/setup.d.ts +0 -47
  412. package/dist/types/systemSettings.d.ts +0 -85
  413. package/dist/types/totp.d.ts +0 -52
  414. package/dist/types/wallet.d.ts +0 -309
  415. package/dist/utils/adminUserApi.d.ts +0 -60
  416. package/dist/utils/apiClient.d.ts +0 -78
  417. package/dist/utils/cryptoShim.d.ts +0 -17
  418. package/dist/utils/csrf.d.ts +0 -1
  419. package/dist/utils/deviceDetection.d.ts +0 -17
  420. package/dist/utils/embeddedWallet.d.ts +0 -75
  421. package/dist/utils/inviteApi.d.ts +0 -31
  422. package/dist/utils/memberApi.d.ts +0 -23
  423. package/dist/utils/orgApi.d.ts +0 -36
  424. package/dist/utils/profileApi.d.ts +0 -26
  425. package/dist/utils/sanitization.d.ts +0 -66
  426. package/dist/utils/sessionApi.d.ts +0 -16
  427. package/dist/utils/setupApi.d.ts +0 -21
  428. package/dist/utils/silentWalletEnroll.d.ts +0 -41
  429. package/dist/utils/systemSettingsApi.d.ts +0 -18
  430. package/dist/utils/tabSync.d.ts +0 -46
  431. package/dist/utils/tokenManager.d.ts +0 -107
  432. package/dist/utils/unlockCredential.d.ts +0 -5
  433. package/dist/utils/validation.d.ts +0 -48
  434. package/dist/utils/walletDetection.d.ts +0 -23
  435. package/dist/utils/webauthnJson.d.ts +0 -21
@@ -1 +1 @@
1
- {"version":3,"file":"GoogleLoginButton-BzHr545L.js","sources":["../src/hooks/useGoogleAuth.ts","../src/components/google/GoogleLoginButton.tsx"],"sourcesContent":["import { useState, useCallback, useEffect, useRef, useMemo } from 'react';\nimport { useCedrosLogin } from '../context/useCedrosLogin';\nimport { ApiClient, handleApiError } from '../utils/apiClient';\nimport type { AuthResponse, AuthError } from '../types';\n\n/**\n * Module-level singleton for Google script loading (P-01)\n *\n * Prevents race conditions when multiple components mount simultaneously.\n * Uses a promise queue pattern to ensure the script is only loaded once.\n *\n * ## SSR Limitations (F-08)\n *\n * This singleton persists across the module lifecycle. In SSR environments:\n * - Module state persists between requests (potential cross-request leakage)\n * - Google Sign-In requires browser APIs (document, window)\n * - The hook guards against SSR with `googleClientId` checks\n *\n * For SSR frameworks (Next.js, Remix), ensure this hook is only used\n * in client-side components.\n *\n * ## Test Isolation\n *\n * For test isolation, call `scriptLoader._reset()` in test setup/teardown.\n *\n * @internal\n */\nconst scriptLoader = {\n loading: false,\n loaded: false,\n error: null as Error | null,\n callbacks: [] as Array<{ resolve: () => void; reject: (err: Error) => void }>,\n\n load(): Promise<void> {\n // SSR guard: avoid touching browser globals when running in Node/SSR.\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n return Promise.reject(new Error('Google Sign-In script loader cannot run in SSR'));\n }\n\n // Already loaded\n if (this.loaded) {\n return Promise.resolve();\n }\n\n // Loading in progress - queue callback\n if (this.loading) {\n return new Promise((resolve, reject) => {\n this.callbacks.push({ resolve, reject });\n });\n }\n\n // Start loading\n this.loading = true;\n return new Promise((resolve, reject) => {\n this.callbacks.push({ resolve, reject });\n\n // Check if script already exists (from previous session or SSR)\n const existingScript = document.getElementById('google-gsi-script');\n if (existingScript) {\n if (window.google?.accounts?.id) {\n this.loaded = true;\n this.loading = false;\n this.callbacks.forEach((cb) => cb.resolve());\n this.callbacks = [];\n } else {\n existingScript.addEventListener('load', () => {\n this.loaded = true;\n this.loading = false;\n this.callbacks.forEach((cb) => cb.resolve());\n this.callbacks = [];\n });\n }\n return;\n }\n\n const script = document.createElement('script');\n script.src = 'https://accounts.google.com/gsi/client';\n script.async = true;\n script.defer = true;\n script.id = 'google-gsi-script';\n\n script.onload = () => {\n this.loaded = true;\n this.loading = false;\n this.callbacks.forEach((cb) => cb.resolve());\n this.callbacks = [];\n };\n\n script.onerror = () => {\n this.loading = false;\n // M-02: Remove failed script from DOM to allow retry on next load() call.\n // Without removal, retry finds existingScript and waits for a load event\n // that will never fire on an already-failed script.\n script.remove();\n const error = new Error('Failed to load Google Sign-In script');\n this.callbacks.forEach((cb) => cb.reject(error));\n this.callbacks = [];\n };\n\n document.head.appendChild(script);\n });\n },\n\n /**\n * Reset singleton state for test isolation (F-08)\n * @internal - Only use in test setup/teardown\n */\n _reset(): void {\n this.loading = false;\n this.loaded = false;\n this.error = null;\n this.callbacks = [];\n },\n};\n\n/** @internal */\nexport const _internalGoogleScriptLoader = scriptLoader;\n\nexport interface UseGoogleAuthReturn {\n signIn: () => Promise<AuthResponse>;\n isLoading: boolean;\n isInitialized: boolean;\n error: AuthError | null;\n clearError: () => void;\n}\n\ninterface PromiseCallbacks {\n resolve: (value: AuthResponse) => void;\n reject: (error: AuthError) => void;\n}\n\n/**\n * Hook for Google OAuth authentication.\n *\n * @example\n * ```tsx\n * function GoogleButton() {\n * const { signIn, isLoading, isInitialized, error } = useGoogleAuth();\n *\n * return (\n * <button onClick={signIn} disabled={!isInitialized || isLoading}>\n * {isLoading ? 'Signing in...' : 'Sign in with Google'}\n * </button>\n * );\n * }\n * ```\n */\nexport function useGoogleAuth(): UseGoogleAuthReturn {\n const { config, _internal } = useCedrosLogin();\n const [isLoading, setIsLoading] = useState(false);\n const [isInitialized, setIsInitialized] = useState(false);\n const [error, setError] = useState<AuthError | null>(null);\n\n const promiseCallbacksRef = useRef<PromiseCallbacks | null>(null);\n const configRef = useRef(config);\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 // Keep config ref in sync\n useEffect(() => {\n configRef.current = config;\n }, [config]);\n\n // Handle credential response from Google\n const handleCredentialResponse = useCallback(\n async (response: { credential: string }) => {\n const callbacks = promiseCallbacksRef.current;\n if (!callbacks) return;\n\n try {\n const data = await apiClient.post<AuthResponse>('/google', {\n idToken: response.credential,\n });\n configRef.current.callbacks?.onLoginSuccess?.(data.user, 'google');\n _internal?.handleLoginSuccess(data.user, data.tokens);\n setIsLoading(false);\n callbacks.resolve(data);\n } catch (err) {\n const authError = handleApiError(err, 'Google sign-in failed');\n setError(authError);\n setIsLoading(false);\n callbacks.reject(authError);\n } finally {\n promiseCallbacksRef.current = null;\n }\n },\n [apiClient, _internal]\n );\n\n // P-01: Initialize Google Sign-In SDK using singleton loader\n useEffect(() => {\n // Early return if Google auth is not enabled\n if (!config.googleClientId) {\n return;\n }\n\n // Track mounted state to prevent state updates after unmount\n let isMounted = true;\n\n const initializeGoogleSignIn = () => {\n if (!isMounted) return;\n\n window.google?.accounts?.id?.initialize({\n client_id: config.googleClientId!,\n callback: handleCredentialResponse,\n auto_select: false,\n cancel_on_tap_outside: true,\n });\n\n if (isMounted) {\n setIsInitialized(true);\n }\n };\n\n // Use singleton loader to handle script loading\n scriptLoader\n .load()\n .then(() => {\n if (isMounted) {\n initializeGoogleSignIn();\n }\n })\n .catch(() => {\n if (isMounted) {\n setError({\n code: 'SERVER_ERROR',\n message: 'Failed to load Google Sign-In',\n });\n }\n });\n\n return () => {\n isMounted = false;\n };\n }, [config.googleClientId, handleCredentialResponse]);\n\n const signIn = useCallback(async (): Promise<AuthResponse> => {\n if (!config.googleClientId) {\n const err: AuthError = {\n code: 'VALIDATION_ERROR',\n message: 'Google Client ID not configured',\n };\n setError(err);\n throw err;\n }\n\n if (!isInitialized) {\n const err: AuthError = {\n code: 'VALIDATION_ERROR',\n message: 'Google Sign-In not initialized',\n };\n setError(err);\n throw err;\n }\n\n if (promiseCallbacksRef.current) {\n const err: AuthError = {\n code: 'VALIDATION_ERROR',\n message: 'Google Sign-In already in progress',\n };\n setError(err);\n throw err;\n }\n\n setIsLoading(true);\n setError(null);\n\n return new Promise<AuthResponse>((resolve, reject) => {\n promiseCallbacksRef.current = { resolve, reject };\n\n // Show Google One Tap prompt\n window.google?.accounts?.id?.prompt((notification) => {\n if (notification.isNotDisplayed()) {\n const err: AuthError = {\n code: 'SERVER_ERROR',\n message: 'Google Sign-In popup was blocked. Please allow popups or try again.',\n };\n setError(err);\n setIsLoading(false);\n promiseCallbacksRef.current = null;\n reject(err);\n } else if (notification.isSkippedMoment()) {\n const err: AuthError = {\n code: 'SERVER_ERROR',\n message: 'Google Sign-In was cancelled',\n };\n setError(err);\n setIsLoading(false);\n promiseCallbacksRef.current = null;\n reject(err);\n } else if (notification.isDismissedMoment()) {\n const err: AuthError = {\n code: 'SERVER_ERROR',\n message: 'Google Sign-In was cancelled',\n };\n setError(err);\n setIsLoading(false);\n promiseCallbacksRef.current = null;\n reject(err);\n }\n });\n });\n }, [config.googleClientId, isInitialized]);\n\n const clearError = useCallback(() => setError(null), []);\n\n return {\n signIn,\n isLoading,\n isInitialized,\n error,\n clearError,\n };\n}\n\n// Type declaration for Google Identity Services\ndeclare global {\n interface Window {\n google?: {\n accounts?: {\n id?: {\n initialize: (config: {\n client_id: string;\n callback: (response: { credential: string }) => void;\n auto_select?: boolean;\n cancel_on_tap_outside?: boolean;\n }) => void;\n prompt: (\n callback: (notification: {\n isNotDisplayed: () => boolean;\n isSkippedMoment: () => boolean;\n isDismissedMoment: () => boolean;\n getMomentType: () => string;\n }) => void\n ) => void;\n renderButton: (element: HTMLElement, config: object) => void;\n disableAutoSelect: () => void;\n };\n };\n };\n }\n}\n","import { useGoogleAuth } from '../../hooks/useGoogleAuth';\nimport { LoadingSpinner } from '../shared/LoadingSpinner';\n\nexport interface GoogleLoginButtonProps {\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\n/**\n * Google OAuth login button\n */\nexport function GoogleLoginButton({\n onSuccess,\n onError,\n className = '',\n variant = 'default',\n size = 'md',\n disabled = false,\n}: GoogleLoginButtonProps) {\n const { signIn, isLoading, isInitialized } = useGoogleAuth();\n\n const handleClick = async () => {\n try {\n await signIn();\n onSuccess?.();\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n onError?.(error);\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-google',\n outline: 'cedros-button-google-outline',\n };\n\n return (\n <button\n type=\"button\"\n className={`cedros-button ${variantClasses[variant]} ${sizeClasses[size]} ${className}`}\n onClick={handleClick}\n disabled={disabled || !isInitialized || isLoading}\n aria-label=\"Sign in with Google\"\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 18 18\"\n fill=\"none\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844c-.209 1.125-.843 2.078-1.796 2.717v2.258h2.908c1.702-1.567 2.684-3.874 2.684-6.615z\"\n fill=\"#4285F4\"\n />\n <path\n d=\"M9.003 18c2.43 0 4.467-.806 5.956-2.18l-2.909-2.26c-.806.54-1.836.86-3.047.86-2.344 0-4.328-1.584-5.036-3.711H.96v2.332A8.997 8.997 0 0 0 9.003 18z\"\n fill=\"#34A853\"\n />\n <path\n d=\"M3.964 10.712A5.41 5.41 0 0 1 3.682 9c0-.593.102-1.17.282-1.71V4.958H.96A8.996 8.996 0 0 0 0 9c0 1.452.348 2.827.96 4.042l3.004-2.33z\"\n fill=\"#FBBC05\"\n />\n <path\n d=\"M9.003 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.464.891 11.428 0 9.002 0A8.997 8.997 0 0 0 .96 4.958l3.005 2.332c.708-2.127 2.692-3.71 5.036-3.71z\"\n fill=\"#EA4335\"\n />\n </svg>\n )}\n <span>Continue with Google</span>\n </button>\n );\n}\n"],"names":["scriptLoader","resolve","reject","existingScript","cb","script","error","useGoogleAuth","config","_internal","useCedrosLogin","isLoading","setIsLoading","useState","isInitialized","setIsInitialized","setError","promiseCallbacksRef","useRef","configRef","apiClient","useMemo","ApiClient","useEffect","handleCredentialResponse","useCallback","response","callbacks","data","err","authError","handleApiError","isMounted","initializeGoogleSignIn","signIn","notification","clearError","GoogleLoginButton","onSuccess","onError","className","variant","size","disabled","handleClick","sizeClasses","jsxs","jsx","LoadingSpinner"],"mappings":"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"}
1
+ {"version":3,"file":"GoogleLoginButton-CXwp4LsQ.js","sources":["../src/hooks/useGoogleAuth.ts","../src/components/google/GoogleLoginButton.tsx"],"sourcesContent":["import { useState, useCallback, useEffect, useRef, useMemo } from 'react';\nimport { useCedrosLogin } from '../context/useCedrosLogin';\nimport { ApiClient, handleApiError } from '../utils/apiClient';\nimport type { AuthResponse, AuthError } from '../types';\n\n/**\n * Module-level singleton for Google script loading (P-01)\n *\n * Prevents race conditions when multiple components mount simultaneously.\n * Uses a promise queue pattern to ensure the script is only loaded once.\n *\n * ## SSR Limitations (F-08)\n *\n * This singleton persists across the module lifecycle. In SSR environments:\n * - Module state persists between requests (potential cross-request leakage)\n * - Google Sign-In requires browser APIs (document, window)\n * - The hook guards against SSR with `googleClientId` checks\n *\n * For SSR frameworks (Next.js, Remix), ensure this hook is only used\n * in client-side components.\n *\n * ## Test Isolation\n *\n * For test isolation, call `scriptLoader._reset()` in test setup/teardown.\n *\n * @internal\n */\nconst scriptLoader = {\n loading: false,\n loaded: false,\n error: null as Error | null,\n callbacks: [] as Array<{ resolve: () => void; reject: (err: Error) => void }>,\n\n load(): Promise<void> {\n // SSR guard: avoid touching browser globals when running in Node/SSR.\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n return Promise.reject(new Error('Google Sign-In script loader cannot run in SSR'));\n }\n\n // Already loaded\n if (this.loaded) {\n return Promise.resolve();\n }\n\n // Loading in progress - queue callback\n if (this.loading) {\n return new Promise((resolve, reject) => {\n this.callbacks.push({ resolve, reject });\n });\n }\n\n // Start loading\n this.loading = true;\n return new Promise((resolve, reject) => {\n this.callbacks.push({ resolve, reject });\n\n // Check if script already exists (from previous session or SSR)\n const existingScript = document.getElementById('google-gsi-script');\n if (existingScript) {\n if (window.google?.accounts?.id) {\n this.loaded = true;\n this.loading = false;\n this.callbacks.forEach((cb) => cb.resolve());\n this.callbacks = [];\n } else {\n existingScript.addEventListener('load', () => {\n this.loaded = true;\n this.loading = false;\n this.callbacks.forEach((cb) => cb.resolve());\n this.callbacks = [];\n });\n }\n return;\n }\n\n const script = document.createElement('script');\n script.src = 'https://accounts.google.com/gsi/client';\n script.async = true;\n script.defer = true;\n script.id = 'google-gsi-script';\n\n script.onload = () => {\n this.loaded = true;\n this.loading = false;\n this.callbacks.forEach((cb) => cb.resolve());\n this.callbacks = [];\n };\n\n script.onerror = () => {\n this.loading = false;\n // M-02: Remove failed script from DOM to allow retry on next load() call.\n // Without removal, retry finds existingScript and waits for a load event\n // that will never fire on an already-failed script.\n script.remove();\n const error = new Error('Failed to load Google Sign-In script');\n this.callbacks.forEach((cb) => cb.reject(error));\n this.callbacks = [];\n };\n\n document.head.appendChild(script);\n });\n },\n\n /**\n * Reset singleton state for test isolation (F-08)\n * @internal - Only use in test setup/teardown\n */\n _reset(): void {\n this.loading = false;\n this.loaded = false;\n this.error = null;\n this.callbacks = [];\n },\n};\n\n/** @internal */\nexport const _internalGoogleScriptLoader = scriptLoader;\n\nexport interface UseGoogleAuthReturn {\n signIn: () => Promise<AuthResponse>;\n isLoading: boolean;\n isInitialized: boolean;\n error: AuthError | null;\n clearError: () => void;\n}\n\ninterface PromiseCallbacks {\n resolve: (value: AuthResponse) => void;\n reject: (error: AuthError) => void;\n}\n\n/**\n * Hook for Google OAuth authentication.\n *\n * @example\n * ```tsx\n * function GoogleButton() {\n * const { signIn, isLoading, isInitialized, error } = useGoogleAuth();\n *\n * return (\n * <button onClick={signIn} disabled={!isInitialized || isLoading}>\n * {isLoading ? 'Signing in...' : 'Sign in with Google'}\n * </button>\n * );\n * }\n * ```\n */\nexport function useGoogleAuth(): UseGoogleAuthReturn {\n const { config, _internal } = useCedrosLogin();\n const [isLoading, setIsLoading] = useState(false);\n const [isInitialized, setIsInitialized] = useState(false);\n const [error, setError] = useState<AuthError | null>(null);\n\n const promiseCallbacksRef = useRef<PromiseCallbacks | null>(null);\n const configRef = useRef(config);\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 // Keep config ref in sync\n useEffect(() => {\n configRef.current = config;\n }, [config]);\n\n // Handle credential response from Google\n const handleCredentialResponse = useCallback(\n async (response: { credential: string }) => {\n const callbacks = promiseCallbacksRef.current;\n if (!callbacks) return;\n\n try {\n const data = await apiClient.post<AuthResponse>('/google', {\n idToken: response.credential,\n });\n configRef.current.callbacks?.onLoginSuccess?.(data.user, 'google');\n _internal?.handleLoginSuccess(data.user, data.tokens);\n setIsLoading(false);\n callbacks.resolve(data);\n } catch (err) {\n const authError = handleApiError(err, 'Google sign-in failed');\n setError(authError);\n setIsLoading(false);\n callbacks.reject(authError);\n } finally {\n promiseCallbacksRef.current = null;\n }\n },\n [apiClient, _internal]\n );\n\n // P-01: Initialize Google Sign-In SDK using singleton loader\n useEffect(() => {\n // Early return if Google auth is not enabled\n if (!config.googleClientId) {\n return;\n }\n\n // Track mounted state to prevent state updates after unmount\n let isMounted = true;\n\n const initializeGoogleSignIn = () => {\n if (!isMounted) return;\n\n window.google?.accounts?.id?.initialize({\n client_id: config.googleClientId!,\n callback: handleCredentialResponse,\n auto_select: false,\n cancel_on_tap_outside: true,\n });\n\n if (isMounted) {\n setIsInitialized(true);\n }\n };\n\n // Use singleton loader to handle script loading\n scriptLoader\n .load()\n .then(() => {\n if (isMounted) {\n initializeGoogleSignIn();\n }\n })\n .catch(() => {\n if (isMounted) {\n setError({\n code: 'SERVER_ERROR',\n message: 'Failed to load Google Sign-In',\n });\n }\n });\n\n return () => {\n isMounted = false;\n };\n }, [config.googleClientId, handleCredentialResponse]);\n\n const signIn = useCallback(async (): Promise<AuthResponse> => {\n if (!config.googleClientId) {\n const err: AuthError = {\n code: 'VALIDATION_ERROR',\n message: 'Google Client ID not configured',\n };\n setError(err);\n throw err;\n }\n\n if (!isInitialized) {\n const err: AuthError = {\n code: 'VALIDATION_ERROR',\n message: 'Google Sign-In not initialized',\n };\n setError(err);\n throw err;\n }\n\n if (promiseCallbacksRef.current) {\n const err: AuthError = {\n code: 'VALIDATION_ERROR',\n message: 'Google Sign-In already in progress',\n };\n setError(err);\n throw err;\n }\n\n setIsLoading(true);\n setError(null);\n\n return new Promise<AuthResponse>((resolve, reject) => {\n promiseCallbacksRef.current = { resolve, reject };\n\n // Show Google One Tap prompt\n window.google?.accounts?.id?.prompt((notification) => {\n if (notification.isNotDisplayed()) {\n const err: AuthError = {\n code: 'SERVER_ERROR',\n message: 'Google Sign-In popup was blocked. Please allow popups or try again.',\n };\n setError(err);\n setIsLoading(false);\n promiseCallbacksRef.current = null;\n reject(err);\n } else if (notification.isSkippedMoment()) {\n const err: AuthError = {\n code: 'SERVER_ERROR',\n message: 'Google Sign-In was cancelled',\n };\n setError(err);\n setIsLoading(false);\n promiseCallbacksRef.current = null;\n reject(err);\n } else if (notification.isDismissedMoment()) {\n const err: AuthError = {\n code: 'SERVER_ERROR',\n message: 'Google Sign-In was cancelled',\n };\n setError(err);\n setIsLoading(false);\n promiseCallbacksRef.current = null;\n reject(err);\n }\n });\n });\n }, [config.googleClientId, isInitialized]);\n\n const clearError = useCallback(() => setError(null), []);\n\n return {\n signIn,\n isLoading,\n isInitialized,\n error,\n clearError,\n };\n}\n\n// Type declaration for Google Identity Services\ndeclare global {\n interface Window {\n google?: {\n accounts?: {\n id?: {\n initialize: (config: {\n client_id: string;\n callback: (response: { credential: string }) => void;\n auto_select?: boolean;\n cancel_on_tap_outside?: boolean;\n }) => void;\n prompt: (\n callback: (notification: {\n isNotDisplayed: () => boolean;\n isSkippedMoment: () => boolean;\n isDismissedMoment: () => boolean;\n getMomentType: () => string;\n }) => void\n ) => void;\n renderButton: (element: HTMLElement, config: object) => void;\n disableAutoSelect: () => void;\n };\n };\n };\n }\n}\n","import { useGoogleAuth } from '../../hooks/useGoogleAuth';\nimport { LoadingSpinner } from '../shared/LoadingSpinner';\n\nexport interface GoogleLoginButtonProps {\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\n/**\n * Google OAuth login button\n */\nexport function GoogleLoginButton({\n onSuccess,\n onError,\n className = '',\n variant = 'default',\n size = 'md',\n disabled = false,\n}: GoogleLoginButtonProps) {\n const { signIn, isLoading, isInitialized } = useGoogleAuth();\n\n const handleClick = async () => {\n try {\n await signIn();\n onSuccess?.();\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n onError?.(error);\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-google',\n outline: 'cedros-button-google-outline',\n };\n\n return (\n <button\n type=\"button\"\n className={`cedros-button ${variantClasses[variant]} ${sizeClasses[size]} ${className}`}\n onClick={handleClick}\n disabled={disabled || !isInitialized || isLoading}\n aria-label=\"Sign in with Google\"\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 18 18\"\n fill=\"none\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844c-.209 1.125-.843 2.078-1.796 2.717v2.258h2.908c1.702-1.567 2.684-3.874 2.684-6.615z\"\n fill=\"#4285F4\"\n />\n <path\n d=\"M9.003 18c2.43 0 4.467-.806 5.956-2.18l-2.909-2.26c-.806.54-1.836.86-3.047.86-2.344 0-4.328-1.584-5.036-3.711H.96v2.332A8.997 8.997 0 0 0 9.003 18z\"\n fill=\"#34A853\"\n />\n <path\n d=\"M3.964 10.712A5.41 5.41 0 0 1 3.682 9c0-.593.102-1.17.282-1.71V4.958H.96A8.996 8.996 0 0 0 0 9c0 1.452.348 2.827.96 4.042l3.004-2.33z\"\n fill=\"#FBBC05\"\n />\n <path\n d=\"M9.003 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.464.891 11.428 0 9.002 0A8.997 8.997 0 0 0 .96 4.958l3.005 2.332c.708-2.127 2.692-3.71 5.036-3.71z\"\n fill=\"#EA4335\"\n />\n </svg>\n )}\n <span>Continue with Google</span>\n </button>\n );\n}\n"],"names":["scriptLoader","resolve","reject","existingScript","cb","script","error","useGoogleAuth","config","_internal","useCedrosLogin","isLoading","setIsLoading","useState","isInitialized","setIsInitialized","setError","promiseCallbacksRef","useRef","configRef","apiClient","useMemo","ApiClient","useEffect","handleCredentialResponse","useCallback","response","callbacks","data","err","authError","handleApiError","isMounted","initializeGoogleSignIn","signIn","notification","clearError","GoogleLoginButton","onSuccess","onError","className","variant","size","disabled","handleClick","sizeClasses","jsxs","jsx","LoadingSpinner"],"mappings":"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"}
@@ -0,0 +1 @@
1
+ "use strict";const u=require("react/jsx-runtime"),i=require("react"),I=require("./useCedrosLogin-C9MrcZvh.cjs"),S=require("./LoadingSpinner-d6sSxgQN.cjs"),k={loading:!1,loaded:!1,error:null,callbacks:[],load(){return typeof window>"u"||typeof document>"u"?Promise.reject(new Error("Google Sign-In script loader cannot run in SSR")):this.loaded?Promise.resolve():this.loading?new Promise((e,d)=>{this.callbacks.push({resolve:e,reject:d})}):(this.loading=!0,new Promise((e,d)=>{this.callbacks.push({resolve:e,reject:d});const g=document.getElementById("google-gsi-script");if(g){window.google?.accounts?.id?(this.loaded=!0,this.loading=!1,this.callbacks.forEach(t=>t.resolve()),this.callbacks=[]):g.addEventListener("load",()=>{this.loaded=!0,this.loading=!1,this.callbacks.forEach(t=>t.resolve()),this.callbacks=[]});return}const o=document.createElement("script");o.src="https://accounts.google.com/gsi/client",o.async=!0,o.defer=!0,o.id="google-gsi-script",o.onload=()=>{this.loaded=!0,this.loading=!1,this.callbacks.forEach(t=>t.resolve()),this.callbacks=[]},o.onerror=()=>{this.loading=!1,o.remove();const t=new Error("Failed to load Google Sign-In script");this.callbacks.forEach(f=>f.reject(t)),this.callbacks=[]},document.head.appendChild(o)}))},_reset(){this.loading=!1,this.loaded=!1,this.error=null,this.callbacks=[]}};function w(){const{config:e,_internal:d}=I.useCedrosLogin(),[g,o]=i.useState(!1),[t,f]=i.useState(!1),[E,n]=i.useState(null),c=i.useRef(null),p=i.useRef(e),m=i.useMemo(()=>new I.ApiClient({baseUrl:e.serverUrl,timeoutMs:e.requestTimeout,retryAttempts:e.retryAttempts}),[e.serverUrl,e.requestTimeout,e.retryAttempts]);i.useEffect(()=>{p.current=e},[e]);const R=i.useCallback(async s=>{const r=c.current;if(r)try{const a=await m.post("/google",{idToken:s.credential});p.current.callbacks?.onLoginSuccess?.(a.user,"google"),d?.handleLoginSuccess(a.user,a.tokens),o(!1),r.resolve(a)}catch(a){const l=I.handleApiError(a,"Google sign-in failed");n(l),o(!1),r.reject(l)}finally{c.current=null}},[m,d]);i.useEffect(()=>{if(!e.googleClientId)return;let s=!0;const r=()=>{s&&(window.google?.accounts?.id?.initialize({client_id:e.googleClientId,callback:R,auto_select:!1,cancel_on_tap_outside:!0}),s&&f(!0))};return k.load().then(()=>{s&&r()}).catch(()=>{s&&n({code:"SERVER_ERROR",message:"Failed to load Google Sign-In"})}),()=>{s=!1}},[e.googleClientId,R]);const h=i.useCallback(async()=>{if(!e.googleClientId){const s={code:"VALIDATION_ERROR",message:"Google Client ID not configured"};throw n(s),s}if(!t){const s={code:"VALIDATION_ERROR",message:"Google Sign-In not initialized"};throw n(s),s}if(c.current){const s={code:"VALIDATION_ERROR",message:"Google Sign-In already in progress"};throw n(s),s}return o(!0),n(null),new Promise((s,r)=>{c.current={resolve:s,reject:r},window.google?.accounts?.id?.prompt(a=>{if(a.isNotDisplayed()){const l={code:"SERVER_ERROR",message:"Google Sign-In popup was blocked. Please allow popups or try again."};n(l),o(!1),c.current=null,r(l)}else if(a.isSkippedMoment()){const l={code:"SERVER_ERROR",message:"Google Sign-In was cancelled"};n(l),o(!1),c.current=null,r(l)}else if(a.isDismissedMoment()){const l={code:"SERVER_ERROR",message:"Google Sign-In was cancelled"};n(l),o(!1),c.current=null,r(l)}})})},[e.googleClientId,t]),b=i.useCallback(()=>n(null),[]);return{signIn:h,isLoading:g,isInitialized:t,error:E,clearError:b}}function C({onSuccess:e,onError:d,className:g="",variant:o="default",size:t="md",disabled:f=!1}){const{signIn:E,isLoading:n,isInitialized:c}=w(),p=async()=>{try{await E(),e?.()}catch(h){const b=h instanceof Error?h:new Error(String(h));d?.(b)}},m={sm:"cedros-button-sm",md:"cedros-button-md",lg:"cedros-button-lg"},R={default:"cedros-button-google",outline:"cedros-button-google-outline"};return u.jsxs("button",{type:"button",className:`cedros-button ${R[o]} ${m[t]} ${g}`,onClick:p,disabled:f||!c||n,"aria-label":"Sign in with Google",children:[n?u.jsx(S.LoadingSpinner,{size:"sm"}):u.jsxs("svg",{className:"cedros-button-icon",width:"18",height:"18",viewBox:"0 0 18 18",fill:"none","aria-hidden":"true",children:[u.jsx("path",{d:"M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844c-.209 1.125-.843 2.078-1.796 2.717v2.258h2.908c1.702-1.567 2.684-3.874 2.684-6.615z",fill:"#4285F4"}),u.jsx("path",{d:"M9.003 18c2.43 0 4.467-.806 5.956-2.18l-2.909-2.26c-.806.54-1.836.86-3.047.86-2.344 0-4.328-1.584-5.036-3.711H.96v2.332A8.997 8.997 0 0 0 9.003 18z",fill:"#34A853"}),u.jsx("path",{d:"M3.964 10.712A5.41 5.41 0 0 1 3.682 9c0-.593.102-1.17.282-1.71V4.958H.96A8.996 8.996 0 0 0 0 9c0 1.452.348 2.827.96 4.042l3.004-2.33z",fill:"#FBBC05"}),u.jsx("path",{d:"M9.003 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.464.891 11.428 0 9.002 0A8.997 8.997 0 0 0 .96 4.958l3.005 2.332c.708-2.127 2.692-3.71 5.036-3.71z",fill:"#EA4335"})]}),u.jsx("span",{children:"Continue with Google"})]})}exports.GoogleLoginButton=C;exports.useGoogleAuth=w;
@@ -1 +1 @@
1
- {"version":3,"file":"GoogleLoginButton-DoAdOqb3.cjs","sources":["../src/hooks/useGoogleAuth.ts","../src/components/google/GoogleLoginButton.tsx"],"sourcesContent":["import { useState, useCallback, useEffect, useRef, useMemo } from 'react';\nimport { useCedrosLogin } from '../context/useCedrosLogin';\nimport { ApiClient, handleApiError } from '../utils/apiClient';\nimport type { AuthResponse, AuthError } from '../types';\n\n/**\n * Module-level singleton for Google script loading (P-01)\n *\n * Prevents race conditions when multiple components mount simultaneously.\n * Uses a promise queue pattern to ensure the script is only loaded once.\n *\n * ## SSR Limitations (F-08)\n *\n * This singleton persists across the module lifecycle. In SSR environments:\n * - Module state persists between requests (potential cross-request leakage)\n * - Google Sign-In requires browser APIs (document, window)\n * - The hook guards against SSR with `googleClientId` checks\n *\n * For SSR frameworks (Next.js, Remix), ensure this hook is only used\n * in client-side components.\n *\n * ## Test Isolation\n *\n * For test isolation, call `scriptLoader._reset()` in test setup/teardown.\n *\n * @internal\n */\nconst scriptLoader = {\n loading: false,\n loaded: false,\n error: null as Error | null,\n callbacks: [] as Array<{ resolve: () => void; reject: (err: Error) => void }>,\n\n load(): Promise<void> {\n // SSR guard: avoid touching browser globals when running in Node/SSR.\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n return Promise.reject(new Error('Google Sign-In script loader cannot run in SSR'));\n }\n\n // Already loaded\n if (this.loaded) {\n return Promise.resolve();\n }\n\n // Loading in progress - queue callback\n if (this.loading) {\n return new Promise((resolve, reject) => {\n this.callbacks.push({ resolve, reject });\n });\n }\n\n // Start loading\n this.loading = true;\n return new Promise((resolve, reject) => {\n this.callbacks.push({ resolve, reject });\n\n // Check if script already exists (from previous session or SSR)\n const existingScript = document.getElementById('google-gsi-script');\n if (existingScript) {\n if (window.google?.accounts?.id) {\n this.loaded = true;\n this.loading = false;\n this.callbacks.forEach((cb) => cb.resolve());\n this.callbacks = [];\n } else {\n existingScript.addEventListener('load', () => {\n this.loaded = true;\n this.loading = false;\n this.callbacks.forEach((cb) => cb.resolve());\n this.callbacks = [];\n });\n }\n return;\n }\n\n const script = document.createElement('script');\n script.src = 'https://accounts.google.com/gsi/client';\n script.async = true;\n script.defer = true;\n script.id = 'google-gsi-script';\n\n script.onload = () => {\n this.loaded = true;\n this.loading = false;\n this.callbacks.forEach((cb) => cb.resolve());\n this.callbacks = [];\n };\n\n script.onerror = () => {\n this.loading = false;\n // M-02: Remove failed script from DOM to allow retry on next load() call.\n // Without removal, retry finds existingScript and waits for a load event\n // that will never fire on an already-failed script.\n script.remove();\n const error = new Error('Failed to load Google Sign-In script');\n this.callbacks.forEach((cb) => cb.reject(error));\n this.callbacks = [];\n };\n\n document.head.appendChild(script);\n });\n },\n\n /**\n * Reset singleton state for test isolation (F-08)\n * @internal - Only use in test setup/teardown\n */\n _reset(): void {\n this.loading = false;\n this.loaded = false;\n this.error = null;\n this.callbacks = [];\n },\n};\n\n/** @internal */\nexport const _internalGoogleScriptLoader = scriptLoader;\n\nexport interface UseGoogleAuthReturn {\n signIn: () => Promise<AuthResponse>;\n isLoading: boolean;\n isInitialized: boolean;\n error: AuthError | null;\n clearError: () => void;\n}\n\ninterface PromiseCallbacks {\n resolve: (value: AuthResponse) => void;\n reject: (error: AuthError) => void;\n}\n\n/**\n * Hook for Google OAuth authentication.\n *\n * @example\n * ```tsx\n * function GoogleButton() {\n * const { signIn, isLoading, isInitialized, error } = useGoogleAuth();\n *\n * return (\n * <button onClick={signIn} disabled={!isInitialized || isLoading}>\n * {isLoading ? 'Signing in...' : 'Sign in with Google'}\n * </button>\n * );\n * }\n * ```\n */\nexport function useGoogleAuth(): UseGoogleAuthReturn {\n const { config, _internal } = useCedrosLogin();\n const [isLoading, setIsLoading] = useState(false);\n const [isInitialized, setIsInitialized] = useState(false);\n const [error, setError] = useState<AuthError | null>(null);\n\n const promiseCallbacksRef = useRef<PromiseCallbacks | null>(null);\n const configRef = useRef(config);\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 // Keep config ref in sync\n useEffect(() => {\n configRef.current = config;\n }, [config]);\n\n // Handle credential response from Google\n const handleCredentialResponse = useCallback(\n async (response: { credential: string }) => {\n const callbacks = promiseCallbacksRef.current;\n if (!callbacks) return;\n\n try {\n const data = await apiClient.post<AuthResponse>('/google', {\n idToken: response.credential,\n });\n configRef.current.callbacks?.onLoginSuccess?.(data.user, 'google');\n _internal?.handleLoginSuccess(data.user, data.tokens);\n setIsLoading(false);\n callbacks.resolve(data);\n } catch (err) {\n const authError = handleApiError(err, 'Google sign-in failed');\n setError(authError);\n setIsLoading(false);\n callbacks.reject(authError);\n } finally {\n promiseCallbacksRef.current = null;\n }\n },\n [apiClient, _internal]\n );\n\n // P-01: Initialize Google Sign-In SDK using singleton loader\n useEffect(() => {\n // Early return if Google auth is not enabled\n if (!config.googleClientId) {\n return;\n }\n\n // Track mounted state to prevent state updates after unmount\n let isMounted = true;\n\n const initializeGoogleSignIn = () => {\n if (!isMounted) return;\n\n window.google?.accounts?.id?.initialize({\n client_id: config.googleClientId!,\n callback: handleCredentialResponse,\n auto_select: false,\n cancel_on_tap_outside: true,\n });\n\n if (isMounted) {\n setIsInitialized(true);\n }\n };\n\n // Use singleton loader to handle script loading\n scriptLoader\n .load()\n .then(() => {\n if (isMounted) {\n initializeGoogleSignIn();\n }\n })\n .catch(() => {\n if (isMounted) {\n setError({\n code: 'SERVER_ERROR',\n message: 'Failed to load Google Sign-In',\n });\n }\n });\n\n return () => {\n isMounted = false;\n };\n }, [config.googleClientId, handleCredentialResponse]);\n\n const signIn = useCallback(async (): Promise<AuthResponse> => {\n if (!config.googleClientId) {\n const err: AuthError = {\n code: 'VALIDATION_ERROR',\n message: 'Google Client ID not configured',\n };\n setError(err);\n throw err;\n }\n\n if (!isInitialized) {\n const err: AuthError = {\n code: 'VALIDATION_ERROR',\n message: 'Google Sign-In not initialized',\n };\n setError(err);\n throw err;\n }\n\n if (promiseCallbacksRef.current) {\n const err: AuthError = {\n code: 'VALIDATION_ERROR',\n message: 'Google Sign-In already in progress',\n };\n setError(err);\n throw err;\n }\n\n setIsLoading(true);\n setError(null);\n\n return new Promise<AuthResponse>((resolve, reject) => {\n promiseCallbacksRef.current = { resolve, reject };\n\n // Show Google One Tap prompt\n window.google?.accounts?.id?.prompt((notification) => {\n if (notification.isNotDisplayed()) {\n const err: AuthError = {\n code: 'SERVER_ERROR',\n message: 'Google Sign-In popup was blocked. Please allow popups or try again.',\n };\n setError(err);\n setIsLoading(false);\n promiseCallbacksRef.current = null;\n reject(err);\n } else if (notification.isSkippedMoment()) {\n const err: AuthError = {\n code: 'SERVER_ERROR',\n message: 'Google Sign-In was cancelled',\n };\n setError(err);\n setIsLoading(false);\n promiseCallbacksRef.current = null;\n reject(err);\n } else if (notification.isDismissedMoment()) {\n const err: AuthError = {\n code: 'SERVER_ERROR',\n message: 'Google Sign-In was cancelled',\n };\n setError(err);\n setIsLoading(false);\n promiseCallbacksRef.current = null;\n reject(err);\n }\n });\n });\n }, [config.googleClientId, isInitialized]);\n\n const clearError = useCallback(() => setError(null), []);\n\n return {\n signIn,\n isLoading,\n isInitialized,\n error,\n clearError,\n };\n}\n\n// Type declaration for Google Identity Services\ndeclare global {\n interface Window {\n google?: {\n accounts?: {\n id?: {\n initialize: (config: {\n client_id: string;\n callback: (response: { credential: string }) => void;\n auto_select?: boolean;\n cancel_on_tap_outside?: boolean;\n }) => void;\n prompt: (\n callback: (notification: {\n isNotDisplayed: () => boolean;\n isSkippedMoment: () => boolean;\n isDismissedMoment: () => boolean;\n getMomentType: () => string;\n }) => void\n ) => void;\n renderButton: (element: HTMLElement, config: object) => void;\n disableAutoSelect: () => void;\n };\n };\n };\n }\n}\n","import { useGoogleAuth } from '../../hooks/useGoogleAuth';\nimport { LoadingSpinner } from '../shared/LoadingSpinner';\n\nexport interface GoogleLoginButtonProps {\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\n/**\n * Google OAuth login button\n */\nexport function GoogleLoginButton({\n onSuccess,\n onError,\n className = '',\n variant = 'default',\n size = 'md',\n disabled = false,\n}: GoogleLoginButtonProps) {\n const { signIn, isLoading, isInitialized } = useGoogleAuth();\n\n const handleClick = async () => {\n try {\n await signIn();\n onSuccess?.();\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n onError?.(error);\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-google',\n outline: 'cedros-button-google-outline',\n };\n\n return (\n <button\n type=\"button\"\n className={`cedros-button ${variantClasses[variant]} ${sizeClasses[size]} ${className}`}\n onClick={handleClick}\n disabled={disabled || !isInitialized || isLoading}\n aria-label=\"Sign in with Google\"\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 18 18\"\n fill=\"none\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844c-.209 1.125-.843 2.078-1.796 2.717v2.258h2.908c1.702-1.567 2.684-3.874 2.684-6.615z\"\n fill=\"#4285F4\"\n />\n <path\n d=\"M9.003 18c2.43 0 4.467-.806 5.956-2.18l-2.909-2.26c-.806.54-1.836.86-3.047.86-2.344 0-4.328-1.584-5.036-3.711H.96v2.332A8.997 8.997 0 0 0 9.003 18z\"\n fill=\"#34A853\"\n />\n <path\n d=\"M3.964 10.712A5.41 5.41 0 0 1 3.682 9c0-.593.102-1.17.282-1.71V4.958H.96A8.996 8.996 0 0 0 0 9c0 1.452.348 2.827.96 4.042l3.004-2.33z\"\n fill=\"#FBBC05\"\n />\n <path\n d=\"M9.003 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.464.891 11.428 0 9.002 0A8.997 8.997 0 0 0 .96 4.958l3.005 2.332c.708-2.127 2.692-3.71 5.036-3.71z\"\n fill=\"#EA4335\"\n />\n </svg>\n )}\n <span>Continue with Google</span>\n </button>\n );\n}\n"],"names":["scriptLoader","resolve","reject","existingScript","cb","script","error","useGoogleAuth","config","_internal","useCedrosLogin","isLoading","setIsLoading","useState","isInitialized","setIsInitialized","setError","promiseCallbacksRef","useRef","configRef","apiClient","useMemo","ApiClient","useEffect","handleCredentialResponse","useCallback","response","callbacks","data","err","authError","handleApiError","isMounted","initializeGoogleSignIn","signIn","notification","clearError","GoogleLoginButton","onSuccess","onError","className","variant","size","disabled","handleClick","sizeClasses","variantClasses","jsxs","jsx","LoadingSpinner"],"mappings":"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"}
1
+ {"version":3,"file":"GoogleLoginButton-zS_69-KV.cjs","sources":["../src/hooks/useGoogleAuth.ts","../src/components/google/GoogleLoginButton.tsx"],"sourcesContent":["import { useState, useCallback, useEffect, useRef, useMemo } from 'react';\nimport { useCedrosLogin } from '../context/useCedrosLogin';\nimport { ApiClient, handleApiError } from '../utils/apiClient';\nimport type { AuthResponse, AuthError } from '../types';\n\n/**\n * Module-level singleton for Google script loading (P-01)\n *\n * Prevents race conditions when multiple components mount simultaneously.\n * Uses a promise queue pattern to ensure the script is only loaded once.\n *\n * ## SSR Limitations (F-08)\n *\n * This singleton persists across the module lifecycle. In SSR environments:\n * - Module state persists between requests (potential cross-request leakage)\n * - Google Sign-In requires browser APIs (document, window)\n * - The hook guards against SSR with `googleClientId` checks\n *\n * For SSR frameworks (Next.js, Remix), ensure this hook is only used\n * in client-side components.\n *\n * ## Test Isolation\n *\n * For test isolation, call `scriptLoader._reset()` in test setup/teardown.\n *\n * @internal\n */\nconst scriptLoader = {\n loading: false,\n loaded: false,\n error: null as Error | null,\n callbacks: [] as Array<{ resolve: () => void; reject: (err: Error) => void }>,\n\n load(): Promise<void> {\n // SSR guard: avoid touching browser globals when running in Node/SSR.\n if (typeof window === 'undefined' || typeof document === 'undefined') {\n return Promise.reject(new Error('Google Sign-In script loader cannot run in SSR'));\n }\n\n // Already loaded\n if (this.loaded) {\n return Promise.resolve();\n }\n\n // Loading in progress - queue callback\n if (this.loading) {\n return new Promise((resolve, reject) => {\n this.callbacks.push({ resolve, reject });\n });\n }\n\n // Start loading\n this.loading = true;\n return new Promise((resolve, reject) => {\n this.callbacks.push({ resolve, reject });\n\n // Check if script already exists (from previous session or SSR)\n const existingScript = document.getElementById('google-gsi-script');\n if (existingScript) {\n if (window.google?.accounts?.id) {\n this.loaded = true;\n this.loading = false;\n this.callbacks.forEach((cb) => cb.resolve());\n this.callbacks = [];\n } else {\n existingScript.addEventListener('load', () => {\n this.loaded = true;\n this.loading = false;\n this.callbacks.forEach((cb) => cb.resolve());\n this.callbacks = [];\n });\n }\n return;\n }\n\n const script = document.createElement('script');\n script.src = 'https://accounts.google.com/gsi/client';\n script.async = true;\n script.defer = true;\n script.id = 'google-gsi-script';\n\n script.onload = () => {\n this.loaded = true;\n this.loading = false;\n this.callbacks.forEach((cb) => cb.resolve());\n this.callbacks = [];\n };\n\n script.onerror = () => {\n this.loading = false;\n // M-02: Remove failed script from DOM to allow retry on next load() call.\n // Without removal, retry finds existingScript and waits for a load event\n // that will never fire on an already-failed script.\n script.remove();\n const error = new Error('Failed to load Google Sign-In script');\n this.callbacks.forEach((cb) => cb.reject(error));\n this.callbacks = [];\n };\n\n document.head.appendChild(script);\n });\n },\n\n /**\n * Reset singleton state for test isolation (F-08)\n * @internal - Only use in test setup/teardown\n */\n _reset(): void {\n this.loading = false;\n this.loaded = false;\n this.error = null;\n this.callbacks = [];\n },\n};\n\n/** @internal */\nexport const _internalGoogleScriptLoader = scriptLoader;\n\nexport interface UseGoogleAuthReturn {\n signIn: () => Promise<AuthResponse>;\n isLoading: boolean;\n isInitialized: boolean;\n error: AuthError | null;\n clearError: () => void;\n}\n\ninterface PromiseCallbacks {\n resolve: (value: AuthResponse) => void;\n reject: (error: AuthError) => void;\n}\n\n/**\n * Hook for Google OAuth authentication.\n *\n * @example\n * ```tsx\n * function GoogleButton() {\n * const { signIn, isLoading, isInitialized, error } = useGoogleAuth();\n *\n * return (\n * <button onClick={signIn} disabled={!isInitialized || isLoading}>\n * {isLoading ? 'Signing in...' : 'Sign in with Google'}\n * </button>\n * );\n * }\n * ```\n */\nexport function useGoogleAuth(): UseGoogleAuthReturn {\n const { config, _internal } = useCedrosLogin();\n const [isLoading, setIsLoading] = useState(false);\n const [isInitialized, setIsInitialized] = useState(false);\n const [error, setError] = useState<AuthError | null>(null);\n\n const promiseCallbacksRef = useRef<PromiseCallbacks | null>(null);\n const configRef = useRef(config);\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 // Keep config ref in sync\n useEffect(() => {\n configRef.current = config;\n }, [config]);\n\n // Handle credential response from Google\n const handleCredentialResponse = useCallback(\n async (response: { credential: string }) => {\n const callbacks = promiseCallbacksRef.current;\n if (!callbacks) return;\n\n try {\n const data = await apiClient.post<AuthResponse>('/google', {\n idToken: response.credential,\n });\n configRef.current.callbacks?.onLoginSuccess?.(data.user, 'google');\n _internal?.handleLoginSuccess(data.user, data.tokens);\n setIsLoading(false);\n callbacks.resolve(data);\n } catch (err) {\n const authError = handleApiError(err, 'Google sign-in failed');\n setError(authError);\n setIsLoading(false);\n callbacks.reject(authError);\n } finally {\n promiseCallbacksRef.current = null;\n }\n },\n [apiClient, _internal]\n );\n\n // P-01: Initialize Google Sign-In SDK using singleton loader\n useEffect(() => {\n // Early return if Google auth is not enabled\n if (!config.googleClientId) {\n return;\n }\n\n // Track mounted state to prevent state updates after unmount\n let isMounted = true;\n\n const initializeGoogleSignIn = () => {\n if (!isMounted) return;\n\n window.google?.accounts?.id?.initialize({\n client_id: config.googleClientId!,\n callback: handleCredentialResponse,\n auto_select: false,\n cancel_on_tap_outside: true,\n });\n\n if (isMounted) {\n setIsInitialized(true);\n }\n };\n\n // Use singleton loader to handle script loading\n scriptLoader\n .load()\n .then(() => {\n if (isMounted) {\n initializeGoogleSignIn();\n }\n })\n .catch(() => {\n if (isMounted) {\n setError({\n code: 'SERVER_ERROR',\n message: 'Failed to load Google Sign-In',\n });\n }\n });\n\n return () => {\n isMounted = false;\n };\n }, [config.googleClientId, handleCredentialResponse]);\n\n const signIn = useCallback(async (): Promise<AuthResponse> => {\n if (!config.googleClientId) {\n const err: AuthError = {\n code: 'VALIDATION_ERROR',\n message: 'Google Client ID not configured',\n };\n setError(err);\n throw err;\n }\n\n if (!isInitialized) {\n const err: AuthError = {\n code: 'VALIDATION_ERROR',\n message: 'Google Sign-In not initialized',\n };\n setError(err);\n throw err;\n }\n\n if (promiseCallbacksRef.current) {\n const err: AuthError = {\n code: 'VALIDATION_ERROR',\n message: 'Google Sign-In already in progress',\n };\n setError(err);\n throw err;\n }\n\n setIsLoading(true);\n setError(null);\n\n return new Promise<AuthResponse>((resolve, reject) => {\n promiseCallbacksRef.current = { resolve, reject };\n\n // Show Google One Tap prompt\n window.google?.accounts?.id?.prompt((notification) => {\n if (notification.isNotDisplayed()) {\n const err: AuthError = {\n code: 'SERVER_ERROR',\n message: 'Google Sign-In popup was blocked. Please allow popups or try again.',\n };\n setError(err);\n setIsLoading(false);\n promiseCallbacksRef.current = null;\n reject(err);\n } else if (notification.isSkippedMoment()) {\n const err: AuthError = {\n code: 'SERVER_ERROR',\n message: 'Google Sign-In was cancelled',\n };\n setError(err);\n setIsLoading(false);\n promiseCallbacksRef.current = null;\n reject(err);\n } else if (notification.isDismissedMoment()) {\n const err: AuthError = {\n code: 'SERVER_ERROR',\n message: 'Google Sign-In was cancelled',\n };\n setError(err);\n setIsLoading(false);\n promiseCallbacksRef.current = null;\n reject(err);\n }\n });\n });\n }, [config.googleClientId, isInitialized]);\n\n const clearError = useCallback(() => setError(null), []);\n\n return {\n signIn,\n isLoading,\n isInitialized,\n error,\n clearError,\n };\n}\n\n// Type declaration for Google Identity Services\ndeclare global {\n interface Window {\n google?: {\n accounts?: {\n id?: {\n initialize: (config: {\n client_id: string;\n callback: (response: { credential: string }) => void;\n auto_select?: boolean;\n cancel_on_tap_outside?: boolean;\n }) => void;\n prompt: (\n callback: (notification: {\n isNotDisplayed: () => boolean;\n isSkippedMoment: () => boolean;\n isDismissedMoment: () => boolean;\n getMomentType: () => string;\n }) => void\n ) => void;\n renderButton: (element: HTMLElement, config: object) => void;\n disableAutoSelect: () => void;\n };\n };\n };\n }\n}\n","import { useGoogleAuth } from '../../hooks/useGoogleAuth';\nimport { LoadingSpinner } from '../shared/LoadingSpinner';\n\nexport interface GoogleLoginButtonProps {\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\n/**\n * Google OAuth login button\n */\nexport function GoogleLoginButton({\n onSuccess,\n onError,\n className = '',\n variant = 'default',\n size = 'md',\n disabled = false,\n}: GoogleLoginButtonProps) {\n const { signIn, isLoading, isInitialized } = useGoogleAuth();\n\n const handleClick = async () => {\n try {\n await signIn();\n onSuccess?.();\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n onError?.(error);\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-google',\n outline: 'cedros-button-google-outline',\n };\n\n return (\n <button\n type=\"button\"\n className={`cedros-button ${variantClasses[variant]} ${sizeClasses[size]} ${className}`}\n onClick={handleClick}\n disabled={disabled || !isInitialized || isLoading}\n aria-label=\"Sign in with Google\"\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 18 18\"\n fill=\"none\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844c-.209 1.125-.843 2.078-1.796 2.717v2.258h2.908c1.702-1.567 2.684-3.874 2.684-6.615z\"\n fill=\"#4285F4\"\n />\n <path\n d=\"M9.003 18c2.43 0 4.467-.806 5.956-2.18l-2.909-2.26c-.806.54-1.836.86-3.047.86-2.344 0-4.328-1.584-5.036-3.711H.96v2.332A8.997 8.997 0 0 0 9.003 18z\"\n fill=\"#34A853\"\n />\n <path\n d=\"M3.964 10.712A5.41 5.41 0 0 1 3.682 9c0-.593.102-1.17.282-1.71V4.958H.96A8.996 8.996 0 0 0 0 9c0 1.452.348 2.827.96 4.042l3.004-2.33z\"\n fill=\"#FBBC05\"\n />\n <path\n d=\"M9.003 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.464.891 11.428 0 9.002 0A8.997 8.997 0 0 0 .96 4.958l3.005 2.332c.708-2.127 2.692-3.71 5.036-3.71z\"\n fill=\"#EA4335\"\n />\n </svg>\n )}\n <span>Continue with Google</span>\n </button>\n );\n}\n"],"names":["scriptLoader","resolve","reject","existingScript","cb","script","error","useGoogleAuth","config","_internal","useCedrosLogin","isLoading","setIsLoading","useState","isInitialized","setIsInitialized","setError","promiseCallbacksRef","useRef","configRef","apiClient","useMemo","ApiClient","useEffect","handleCredentialResponse","useCallback","response","callbacks","data","err","authError","handleApiError","isMounted","initializeGoogleSignIn","signIn","notification","clearError","GoogleLoginButton","onSuccess","onError","className","variant","size","disabled","handleClick","sizeClasses","variantClasses","jsxs","jsx","LoadingSpinner"],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ import { createContext as e, memo as d } from "react";
2
+ import { jsxs as a, jsx as r } from "react/jsx-runtime";
3
+ const f = e(null), x = e(null), C = e(null), m = {
4
+ sm: 16,
5
+ md: 24,
6
+ lg: 32,
7
+ xl: 48
8
+ // H-04: Added for WalletUnlock component
9
+ }, k = d(function({
10
+ size: i = "md",
11
+ className: c = "",
12
+ style: l,
13
+ label: t = "Loading",
14
+ announce: n = !1
15
+ }) {
16
+ const s = m[i], o = /* @__PURE__ */ a(
17
+ "svg",
18
+ {
19
+ className: `cedros-spinner ${c}`,
20
+ width: s,
21
+ height: s,
22
+ viewBox: "0 0 24 24",
23
+ fill: "none",
24
+ style: l,
25
+ "aria-label": t,
26
+ role: "status",
27
+ "aria-hidden": n ? "true" : void 0,
28
+ children: [
29
+ /* @__PURE__ */ r(
30
+ "circle",
31
+ {
32
+ className: "cedros-spinner-track",
33
+ cx: "12",
34
+ cy: "12",
35
+ r: "10",
36
+ stroke: "currentColor",
37
+ strokeWidth: "3",
38
+ strokeOpacity: "0.25"
39
+ }
40
+ ),
41
+ /* @__PURE__ */ r(
42
+ "circle",
43
+ {
44
+ className: "cedros-spinner-head",
45
+ cx: "12",
46
+ cy: "12",
47
+ r: "10",
48
+ stroke: "currentColor",
49
+ strokeWidth: "3",
50
+ strokeLinecap: "round",
51
+ strokeDasharray: "31.4 31.4",
52
+ transform: "rotate(-90 12 12)",
53
+ children: /* @__PURE__ */ r(
54
+ "animateTransform",
55
+ {
56
+ attributeName: "transform",
57
+ type: "rotate",
58
+ from: "0 12 12",
59
+ to: "360 12 12",
60
+ dur: "1s",
61
+ repeatCount: "indefinite"
62
+ }
63
+ )
64
+ }
65
+ )
66
+ ]
67
+ }
68
+ );
69
+ return n ? /* @__PURE__ */ a("span", { "aria-live": "polite", "aria-busy": "true", children: [
70
+ o,
71
+ /* @__PURE__ */ r("span", { className: "cedros-sr-only", children: t })
72
+ ] }) : o;
73
+ });
74
+ export {
75
+ f as A,
76
+ C,
77
+ k as L,
78
+ x as a
79
+ };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LoadingSpinner-6vml-zwr.js","sources":["../src/context/CedrosLoginContext.ts","../src/components/shared/LoadingSpinner.tsx"],"sourcesContent":["import { createContext } from 'react';\nimport type { CedrosLoginConfig, AuthUser, AuthState, AuthError, TokenPair } from '../types';\n\n/**\n * Internal helpers for auth hooks (not part of public API)\n */\nexport interface CedrosLoginInternalAPI {\n handleLoginSuccess: (user: AuthUser, tokens?: TokenPair) => void;\n getAccessToken: () => string | null;\n}\n\n/**\n * Auth state context — changes only on login/logout/token refresh.\n *\n * Subscribing to this context alone avoids re-renders from UI state\n * changes (modal open/close, error display).\n */\nexport interface AuthStateContextValue {\n config: CedrosLoginConfig;\n user: AuthUser | null;\n authState: AuthState;\n logout: () => Promise<void>;\n refreshUser: () => Promise<void>;\n _internal?: CedrosLoginInternalAPI;\n}\n\n/**\n * UI state context — changes on modal/error state changes.\n *\n * Subscribing to this context alone avoids re-renders from auth state\n * changes (login, token refresh).\n */\nexport interface AuthUIContextValue {\n error: AuthError | null;\n isModalOpen: boolean;\n openModal: () => void;\n closeModal: () => void;\n}\n\n/**\n * Combined context value (backward-compatible with existing consumers)\n */\nexport interface CedrosLoginContextValue extends AuthStateContextValue, AuthUIContextValue {}\n\nexport const AuthStateContext = createContext<AuthStateContextValue | null>(null);\nexport const AuthUIContext = createContext<AuthUIContextValue | null>(null);\n\n/**\n * @deprecated Use AuthStateContext + AuthUIContext directly for better performance.\n * Kept for backward compatibility with useCedrosLogin.\n */\nexport const CedrosLoginContext = createContext<CedrosLoginContextValue | null>(null);\n","import { memo, type CSSProperties } from 'react';\n\nexport interface LoadingSpinnerProps {\n size?: 'sm' | 'md' | 'lg' | 'xl';\n className?: string;\n style?: CSSProperties;\n /** Custom label for screen readers (default: \"Loading\") */\n label?: string;\n /** If true, announce the loading state to screen readers */\n announce?: boolean;\n}\n\nconst sizeMap = {\n sm: 16,\n md: 24,\n lg: 32,\n xl: 48, // H-04: Added for WalletUnlock component\n};\n\n/**\n * Accessible loading spinner component.\n * Announces loading state to screen readers when announce prop is true.\n * Wrapped with React.memo to prevent unnecessary re-renders.\n */\nexport const LoadingSpinner = memo(function LoadingSpinner({\n size = 'md',\n className = '',\n style,\n label = 'Loading',\n announce = false,\n}: LoadingSpinnerProps) {\n const dimension = sizeMap[size];\n\n const spinner = (\n <svg\n className={`cedros-spinner ${className}`}\n width={dimension}\n height={dimension}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n style={style}\n aria-label={label}\n role=\"status\"\n aria-hidden={announce ? 'true' : undefined}\n >\n <circle\n className=\"cedros-spinner-track\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"3\"\n strokeOpacity=\"0.25\"\n />\n <circle\n className=\"cedros-spinner-head\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"3\"\n strokeLinecap=\"round\"\n strokeDasharray=\"31.4 31.4\"\n transform=\"rotate(-90 12 12)\"\n >\n <animateTransform\n attributeName=\"transform\"\n type=\"rotate\"\n from=\"0 12 12\"\n to=\"360 12 12\"\n dur=\"1s\"\n repeatCount=\"indefinite\"\n />\n </circle>\n </svg>\n );\n\n // Wrap in aria-live region if announce is true\n if (announce) {\n return (\n <span aria-live=\"polite\" aria-busy=\"true\">\n {spinner}\n <span className=\"cedros-sr-only\">{label}</span>\n </span>\n );\n }\n\n return spinner;\n});\n"],"names":["AuthStateContext","createContext","AuthUIContext","CedrosLoginContext","sizeMap","LoadingSpinner","memo","size","className","style","label","announce","dimension","spinner","jsxs","jsx"],"mappings":";;AA4CO,MAAMA,IAAmBC,EAA4C,IAAI,GACnEC,IAAgBD,EAAyC,IAAI,GAM7DE,IAAqBF,EAA8C,IAAI,GCvC9EG,IAAU;AAAA,EACd,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA;AACN,GAOaC,IAAiBC,EAAK,SAAwB;AAAA,EACzD,MAAAC,IAAO;AAAA,EACP,WAAAC,IAAY;AAAA,EACZ,OAAAC;AAAA,EACA,OAAAC,IAAQ;AAAA,EACR,UAAAC,IAAW;AACb,GAAwB;AACtB,QAAMC,IAAYR,EAAQG,CAAI,GAExBM,IACJ,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW,kBAAkBN,CAAS;AAAA,MACtC,OAAOI;AAAA,MACP,QAAQA;AAAA,MACR,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,OAAAH;AAAA,MACA,cAAYC;AAAA,MACZ,MAAK;AAAA,MACL,eAAaC,IAAW,SAAS;AAAA,MAEjC,UAAA;AAAA,QAAA,gBAAAI;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAU;AAAA,YACV,IAAG;AAAA,YACH,IAAG;AAAA,YACH,GAAE;AAAA,YACF,QAAO;AAAA,YACP,aAAY;AAAA,YACZ,eAAc;AAAA,UAAA;AAAA,QAAA;AAAA,QAEhB,gBAAAA;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAU;AAAA,YACV,IAAG;AAAA,YACH,IAAG;AAAA,YACH,GAAE;AAAA,YACF,QAAO;AAAA,YACP,aAAY;AAAA,YACZ,eAAc;AAAA,YACd,iBAAgB;AAAA,YAChB,WAAU;AAAA,YAEV,UAAA,gBAAAA;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,eAAc;AAAA,gBACd,MAAK;AAAA,gBACL,MAAK;AAAA,gBACL,IAAG;AAAA,gBACH,KAAI;AAAA,gBACJ,aAAY;AAAA,cAAA;AAAA,YAAA;AAAA,UACd;AAAA,QAAA;AAAA,MACF;AAAA,IAAA;AAAA,EAAA;AAKJ,SAAIJ,IAEA,gBAAAG,EAAC,QAAA,EAAK,aAAU,UAAS,aAAU,QAChC,UAAA;AAAA,IAAAD;AAAA,IACD,gBAAAE,EAAC,QAAA,EAAK,WAAU,kBAAkB,UAAAL,EAAA,CAAM;AAAA,EAAA,GAC1C,IAIGG;AACT,CAAC;"}
@@ -0,0 +1 @@
1
+ "use strict";const t=require("react"),e=require("react/jsx-runtime"),d=t.createContext(null),l=t.createContext(null),u=t.createContext(null),x={sm:16,md:24,lg:32,xl:48},m=t.memo(function({size:i="md",className:a="",style:c,label:r="Loading",announce:n=!1}){const s=x[i],o=e.jsxs("svg",{className:`cedros-spinner ${a}`,width:s,height:s,viewBox:"0 0 24 24",fill:"none",style:c,"aria-label":r,role:"status","aria-hidden":n?"true":void 0,children:[e.jsx("circle",{className:"cedros-spinner-track",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"3",strokeOpacity:"0.25"}),e.jsx("circle",{className:"cedros-spinner-head",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"3",strokeLinecap:"round",strokeDasharray:"31.4 31.4",transform:"rotate(-90 12 12)",children:e.jsx("animateTransform",{attributeName:"transform",type:"rotate",from:"0 12 12",to:"360 12 12",dur:"1s",repeatCount:"indefinite"})})]});return n?e.jsxs("span",{"aria-live":"polite","aria-busy":"true",children:[o,e.jsx("span",{className:"cedros-sr-only",children:r})]}):o});exports.AuthStateContext=d;exports.AuthUIContext=l;exports.CedrosLoginContext=u;exports.LoadingSpinner=m;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LoadingSpinner-d6sSxgQN.cjs","sources":["../src/context/CedrosLoginContext.ts","../src/components/shared/LoadingSpinner.tsx"],"sourcesContent":["import { createContext } from 'react';\nimport type { CedrosLoginConfig, AuthUser, AuthState, AuthError, TokenPair } from '../types';\n\n/**\n * Internal helpers for auth hooks (not part of public API)\n */\nexport interface CedrosLoginInternalAPI {\n handleLoginSuccess: (user: AuthUser, tokens?: TokenPair) => void;\n getAccessToken: () => string | null;\n}\n\n/**\n * Auth state context — changes only on login/logout/token refresh.\n *\n * Subscribing to this context alone avoids re-renders from UI state\n * changes (modal open/close, error display).\n */\nexport interface AuthStateContextValue {\n config: CedrosLoginConfig;\n user: AuthUser | null;\n authState: AuthState;\n logout: () => Promise<void>;\n refreshUser: () => Promise<void>;\n _internal?: CedrosLoginInternalAPI;\n}\n\n/**\n * UI state context — changes on modal/error state changes.\n *\n * Subscribing to this context alone avoids re-renders from auth state\n * changes (login, token refresh).\n */\nexport interface AuthUIContextValue {\n error: AuthError | null;\n isModalOpen: boolean;\n openModal: () => void;\n closeModal: () => void;\n}\n\n/**\n * Combined context value (backward-compatible with existing consumers)\n */\nexport interface CedrosLoginContextValue extends AuthStateContextValue, AuthUIContextValue {}\n\nexport const AuthStateContext = createContext<AuthStateContextValue | null>(null);\nexport const AuthUIContext = createContext<AuthUIContextValue | null>(null);\n\n/**\n * @deprecated Use AuthStateContext + AuthUIContext directly for better performance.\n * Kept for backward compatibility with useCedrosLogin.\n */\nexport const CedrosLoginContext = createContext<CedrosLoginContextValue | null>(null);\n","import { memo, type CSSProperties } from 'react';\n\nexport interface LoadingSpinnerProps {\n size?: 'sm' | 'md' | 'lg' | 'xl';\n className?: string;\n style?: CSSProperties;\n /** Custom label for screen readers (default: \"Loading\") */\n label?: string;\n /** If true, announce the loading state to screen readers */\n announce?: boolean;\n}\n\nconst sizeMap = {\n sm: 16,\n md: 24,\n lg: 32,\n xl: 48, // H-04: Added for WalletUnlock component\n};\n\n/**\n * Accessible loading spinner component.\n * Announces loading state to screen readers when announce prop is true.\n * Wrapped with React.memo to prevent unnecessary re-renders.\n */\nexport const LoadingSpinner = memo(function LoadingSpinner({\n size = 'md',\n className = '',\n style,\n label = 'Loading',\n announce = false,\n}: LoadingSpinnerProps) {\n const dimension = sizeMap[size];\n\n const spinner = (\n <svg\n className={`cedros-spinner ${className}`}\n width={dimension}\n height={dimension}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n style={style}\n aria-label={label}\n role=\"status\"\n aria-hidden={announce ? 'true' : undefined}\n >\n <circle\n className=\"cedros-spinner-track\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"3\"\n strokeOpacity=\"0.25\"\n />\n <circle\n className=\"cedros-spinner-head\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"3\"\n strokeLinecap=\"round\"\n strokeDasharray=\"31.4 31.4\"\n transform=\"rotate(-90 12 12)\"\n >\n <animateTransform\n attributeName=\"transform\"\n type=\"rotate\"\n from=\"0 12 12\"\n to=\"360 12 12\"\n dur=\"1s\"\n repeatCount=\"indefinite\"\n />\n </circle>\n </svg>\n );\n\n // Wrap in aria-live region if announce is true\n if (announce) {\n return (\n <span aria-live=\"polite\" aria-busy=\"true\">\n {spinner}\n <span className=\"cedros-sr-only\">{label}</span>\n </span>\n );\n }\n\n return spinner;\n});\n"],"names":["AuthStateContext","createContext","AuthUIContext","CedrosLoginContext","sizeMap","LoadingSpinner","memo","size","className","style","label","announce","dimension","spinner","jsxs","jsx"],"mappings":"qEA4CaA,EAAmBC,EAAAA,cAA4C,IAAI,EACnEC,EAAgBD,EAAAA,cAAyC,IAAI,EAM7DE,EAAqBF,EAAAA,cAA8C,IAAI,ECvC9EG,EAAU,CACd,GAAI,GACJ,GAAI,GACJ,GAAI,GACJ,GAAI,EACN,EAOaC,EAAiBC,EAAAA,KAAK,SAAwB,CACzD,KAAAC,EAAO,KACP,UAAAC,EAAY,GACZ,MAAAC,EACA,MAAAC,EAAQ,UACR,SAAAC,EAAW,EACb,EAAwB,CACtB,MAAMC,EAAYR,EAAQG,CAAI,EAExBM,EACJC,EAAAA,KAAC,MAAA,CACC,UAAW,kBAAkBN,CAAS,GACtC,MAAOI,EACP,OAAQA,EACR,QAAQ,YACR,KAAK,OACL,MAAAH,EACA,aAAYC,EACZ,KAAK,SACL,cAAaC,EAAW,OAAS,OAEjC,SAAA,CAAAI,EAAAA,IAAC,SAAA,CACC,UAAU,uBACV,GAAG,KACH,GAAG,KACH,EAAE,KACF,OAAO,eACP,YAAY,IACZ,cAAc,MAAA,CAAA,EAEhBA,EAAAA,IAAC,SAAA,CACC,UAAU,sBACV,GAAG,KACH,GAAG,KACH,EAAE,KACF,OAAO,eACP,YAAY,IACZ,cAAc,QACd,gBAAgB,YAChB,UAAU,oBAEV,SAAAA,EAAAA,IAAC,mBAAA,CACC,cAAc,YACd,KAAK,SACL,KAAK,UACL,GAAG,YACH,IAAI,KACJ,YAAY,YAAA,CAAA,CACd,CAAA,CACF,CAAA,CAAA,EAKJ,OAAIJ,EAEAG,EAAAA,KAAC,OAAA,CAAK,YAAU,SAAS,YAAU,OAChC,SAAA,CAAAD,EACDE,EAAAA,IAAC,OAAA,CAAK,UAAU,iBAAkB,SAAAL,CAAA,CAAM,CAAA,EAC1C,EAIGG,CACT,CAAC"}
@@ -0,0 +1 @@
1
+ "use strict";const e=require("react/jsx-runtime"),r=require("react"),k=require("./LoadingSpinner-d6sSxgQN.cjs"),$=require("./ErrorMessage-CHbYbVi2.cjs"),D=require("./sanitization-Bo_tn-L2.cjs"),F=require("./validation-BuGQrA-K.cjs"),A=require("./useCedrosLogin-C9MrcZvh.cjs"),P=require("./useOrgs-DDVRCaVi.cjs"),q=require("./useSystemSettings-DRrreszl.cjs"),U=["owner","admin","member"];function z({members:s,currentUserId:t,isLoading:a=!1,error:i,canManage:n=!1,canChangeRoles:o=!1,onUpdateRole:f,onRemove:m,className:h=""}){const[l,j]=r.useState("name"),[d,y]=r.useState("asc"),p=u=>{l===u?y(d==="asc"?"desc":"asc"):(j(u),y("asc"))},c=r.useMemo(()=>{const u={owner:0,admin:1,member:2};return[...s].sort((g,b)=>{let S,w;switch(l){case"name":S=(g.user.name||g.user.email||"").toLowerCase(),w=(b.user.name||b.user.email||"").toLowerCase();break;case"role":S=u[g.role]??99,w=u[b.role]??99;break;case"joinedAt":S=new Date(g.joinedAt).getTime(),w=new Date(b.joinedAt).getTime();break;default:return 0}return S<w?d==="asc"?-1:1:S>w?d==="asc"?1:-1:0})},[s,l,d]);return a&&s.length===0?e.jsxs("div",{className:`cedros-member-list cedros-member-list-loading ${h}`,children:[e.jsx(k.LoadingSpinner,{}),e.jsx("span",{children:"Loading members..."})]}):i?e.jsx("div",{className:`cedros-member-list ${h}`,children:e.jsx($.ErrorMessage,{error:i})}):s.length===0?e.jsx("div",{className:`cedros-member-list cedros-member-list-empty ${h}`,children:e.jsx("p",{children:"No members found."})}):e.jsx("div",{className:`cedros-member-list ${h}`,children:e.jsxs("table",{className:"cedros-member-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:e.jsxs("button",{type:"button",className:`cedros-admin-sort-button ${l==="name"?"cedros-admin-sort-active":""}`,onClick:()=>p("name"),children:["Member"," ",e.jsx("span",{className:"cedros-admin-sort-icon",children:l==="name"?d==="asc"?"↑":"↓":"↕"})]})}),e.jsx("th",{children:e.jsxs("button",{type:"button",className:`cedros-admin-sort-button ${l==="role"?"cedros-admin-sort-active":""}`,onClick:()=>p("role"),children:["Role"," ",e.jsx("span",{className:"cedros-admin-sort-icon",children:l==="role"?d==="asc"?"↑":"↓":"↕"})]})}),e.jsx("th",{children:e.jsxs("button",{type:"button",className:`cedros-admin-sort-button ${l==="joinedAt"?"cedros-admin-sort-active":""}`,onClick:()=>p("joinedAt"),children:["Joined"," ",e.jsx("span",{className:"cedros-admin-sort-icon",children:l==="joinedAt"?d==="asc"?"↑":"↓":"↕"})]})}),(n||o)&&e.jsx("th",{children:"Actions"})]})}),e.jsx("tbody",{children:c.map(u=>e.jsx(B,{member:u,isCurrentUser:u.userId===t,canManage:n,canChangeRoles:o,onUpdateRole:f,onRemove:m},u.id))})]})})}function B({member:s,isCurrentUser:t,canManage:a,canChangeRoles:i,onUpdateRole:n,onRemove:o}){const[f,m]=r.useState(!1),[h,l]=r.useState(s.role),j=r.useCallback(async c=>{if(!(!n||c===s.role)){m(!0);try{await n(s.userId,c),l(c)}catch{l(s.role)}finally{m(!1)}}},[s.userId,s.role,n]),d=r.useCallback(async()=>{if(!(!o||!window.confirm(`Are you sure you want to remove ${s.user.name||s.user.email} from this organization?`))){m(!0);try{await o(s.userId)}finally{m(!1)}}},[s.userId,s.user.name,s.user.email,o]),y=s.role==="owner",p=!t&&!y;return e.jsxs("tr",{className:`cedros-member-row ${t?"cedros-member-row-current":""}`,children:[e.jsxs("td",{className:"cedros-member-info",children:[e.jsx(W,{user:s.user}),e.jsxs("div",{className:"cedros-member-details",children:[e.jsxs("span",{className:"cedros-member-name",children:[s.user.name||"Unknown",t&&e.jsx("span",{className:"cedros-member-you",children:"(you)"})]}),e.jsx("span",{className:"cedros-member-email",children:s.user.email})]})]}),e.jsx("td",{className:"cedros-member-role",children:i&&p&&n?e.jsx("select",{value:h,onChange:c=>j(c.target.value),disabled:f,className:"cedros-role-select",children:U.map(c=>e.jsx("option",{value:c,children:c.charAt(0).toUpperCase()+c.slice(1)},c))}):e.jsx("span",{className:`cedros-role-badge cedros-role-badge-${s.role}`,children:s.role.charAt(0).toUpperCase()+s.role.slice(1)})}),e.jsx("td",{className:"cedros-member-joined",children:H(s.joinedAt)}),(a||i)&&e.jsx("td",{className:"cedros-member-actions",children:a&&p&&o&&e.jsx("button",{type:"button",className:"cedros-button cedros-button-danger cedros-button-sm",onClick:d,disabled:f,"aria-label":`Remove ${s.user.name||s.user.email}`,children:f?e.jsx(k.LoadingSpinner,{size:"sm"}):"Remove"})})]})}function W({user:s}){const t=D.sanitizeImageUrl(s.picture);if(t)return e.jsx("img",{src:t,alt:s.name||s.email||"Member",className:"cedros-member-avatar",referrerPolicy:"no-referrer"});const a=(s.name?.[0]||s.email?.[0]||"?").toUpperCase();return e.jsx("div",{className:"cedros-member-avatar-placeholder",children:a})}function H(s){return new Date(s).toLocaleDateString(void 0,{year:"numeric",month:"short",day:"numeric"})}const V=["admin","member"];function K({onSubmit:s,isLoading:t=!1,error:a,availableRoles:i=V,defaultRole:n="member",className:o=""}){const[f,m]=r.useState(""),[h,l]=r.useState(n),[j,d]=r.useState(null),[y,p]=r.useState(!1),c=r.useRef(null),u=r.useRef(!0);r.useEffect(()=>(u.current=!0,()=>{u.current=!1,c.current!==null&&(window.clearTimeout(c.current),c.current=null)}),[]);const g=r.useCallback(async b=>{b.preventDefault(),d(null),p(!1);const S=f.trim();if(!S){d("Email is required");return}if(!F.validateEmail(S)){d("Please enter a valid email address");return}try{await s(S,h),m(""),l(n),p(!0),c.current!==null&&window.clearTimeout(c.current),c.current=window.setTimeout(()=>{u.current&&p(!1),c.current=null},3e3)}catch{}},[f,h,n,s]);return e.jsxs("form",{className:`cedros-invite-form ${o}`,onSubmit:g,children:[(a||j)&&e.jsx($.ErrorMessage,{error:j??a??null}),y&&e.jsxs("div",{className:"cedros-invite-success",role:"status",children:[e.jsx(G,{}),e.jsx("span",{children:"Invitation sent successfully!"})]}),e.jsxs("div",{className:"cedros-invite-form-row",children:[e.jsxs("div",{className:"cedros-form-group cedros-invite-email-group",children:[e.jsx("label",{htmlFor:"invite-email",className:"cedros-form-label",children:"Email Address"}),e.jsx("input",{id:"invite-email",type:"email",className:"cedros-form-input",value:f,onChange:b=>m(b.target.value),placeholder:"colleague@example.com",disabled:t,autoComplete:"email"})]}),e.jsxs("div",{className:"cedros-form-group cedros-invite-role-group",children:[e.jsx("label",{htmlFor:"invite-role",className:"cedros-form-label",children:"Role"}),e.jsx("select",{id:"invite-role",className:"cedros-form-select",value:h,onChange:b=>l(b.target.value),disabled:t,children:i.map(b=>e.jsx("option",{value:b,children:b.charAt(0).toUpperCase()+b.slice(1)},b))})]}),e.jsx("button",{type:"submit",className:"cedros-button cedros-button-primary cedros-invite-submit",disabled:t||!f.trim(),children:t?e.jsx(k.LoadingSpinner,{size:"sm"}):"Send Invite"})]}),e.jsx("p",{className:"cedros-form-hint",children:"The invited user will receive an email with a link to join your organization."})]})}function G(){return e.jsx("svg",{className:"cedros-invite-check",width:"16",height:"16",viewBox:"0 0 16 16",fill:"none",xmlns:"http://www.w3.org/2000/svg",children:e.jsx("path",{d:"M3 8L6 11L13 5",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})}function J({invites:s,isLoading:t=!1,error:a,canManage:i=!1,onCancel:n,onResend:o,className:f=""}){return t&&s.length===0?e.jsxs("div",{className:`cedros-invite-list cedros-invite-list-loading ${f}`,children:[e.jsx(k.LoadingSpinner,{}),e.jsx("span",{children:"Loading invites..."})]}):a?e.jsx("div",{className:`cedros-invite-list ${f}`,children:e.jsx($.ErrorMessage,{error:a})}):s.length===0?e.jsx("div",{className:`cedros-invite-list cedros-invite-list-empty ${f}`,children:e.jsx("p",{children:"No pending invites."})}):e.jsx("div",{className:`cedros-invite-list ${f}`,children:e.jsx("ul",{className:"cedros-invite-items",children:s.map(m=>e.jsx(Y,{invite:m,canManage:i,onCancel:n,onResend:o},m.id))})})}function Y({invite:s,canManage:t,onCancel:a,onResend:i}){const[n,o]=r.useState(!1),[f,m]=r.useState(!1),h=r.useRef(null),l=new Date(s.expiresAt)<new Date,j=r.useCallback(async()=>{if(!(!a||!window.confirm(`Are you sure you want to cancel the invite for ${s.email}?`))){o(!0);try{await a(s.id)}finally{o(!1)}}},[s.id,s.email,a]),d=r.useCallback(async()=>{if(i){o(!0),m(!1);try{await i(s.id),m(!0),h.current!==null&&window.clearTimeout(h.current),h.current=window.setTimeout(()=>{m(!1),h.current=null},3e3)}finally{o(!1)}}},[s.id,i]);return r.useEffect(()=>()=>{h.current!==null&&(window.clearTimeout(h.current),h.current=null)},[]),e.jsxs("li",{className:`cedros-invite-item ${l?"cedros-invite-item-expired":""}`,children:[e.jsxs("div",{className:"cedros-invite-item-info",children:[e.jsxs("div",{className:"cedros-invite-item-main",children:[e.jsx("span",{className:"cedros-invite-item-email",children:s.email}),e.jsx("span",{className:`cedros-role-badge cedros-role-badge-${s.role}`,children:s.role.charAt(0).toUpperCase()+s.role.slice(1)}),l&&e.jsx("span",{className:"cedros-invite-expired-badge",children:"Expired"})]}),e.jsxs("div",{className:"cedros-invite-item-meta",children:[e.jsxs("span",{className:"cedros-invite-item-date",children:["Invited ",M(s.createdAt)]}),!l&&e.jsxs("span",{className:"cedros-invite-item-expires",children:["Expires ",Q(s.expiresAt)]})]})]}),t&&e.jsxs("div",{className:"cedros-invite-item-actions",children:[f&&e.jsx("span",{className:"cedros-invite-resend-success",children:"Sent!"}),i&&!l&&e.jsx("button",{type:"button",className:"cedros-button cedros-button-outline cedros-button-sm",onClick:d,disabled:n,"aria-label":`Resend invite to ${s.email}`,children:n?e.jsx(k.LoadingSpinner,{size:"sm"}):"Resend"}),a&&e.jsx("button",{type:"button",className:"cedros-button cedros-button-danger cedros-button-sm",onClick:j,disabled:n,"aria-label":`Cancel invite for ${s.email}`,children:"Cancel"})]})]})}function M(s){return new Date(s).toLocaleDateString(void 0,{year:"numeric",month:"short",day:"numeric"})}function Q(s){const t=new Date(s),a=new Date,i=t.getTime()-a.getTime(),n=Math.ceil(i/(1e3*60*60*24));return n<0?"expired":n===0?"today":n===1?"tomorrow":n<7?`in ${n} days`:M(s)}class X{client;constructor(t,a,i,n){this.client=new A.ApiClient({baseUrl:t,timeoutMs:a,retryAttempts:i,getAccessToken:n})}async listMembers(t,a=50,i=0){try{const n=await this.client.get(`/orgs/${t}/members?limit=${a}&offset=${i}`);return{members:n.members.map(o=>({id:o.id,userId:o.userId,orgId:t,role:o.role,joinedAt:o.joinedAt,user:{id:o.userId,email:o.email,name:o.name}})),total:n.total}}catch(n){throw A.handleApiError(n,"Failed to list members")}}async updateMemberRole(t,a,i){try{return await this.client.patch(`/orgs/${t}/members/${a}`,i)}catch(n){throw A.handleApiError(n,"Failed to update member role")}}async removeMember(t,a){try{await this.client.delete(`/orgs/${t}/members/${a}`)}catch(i){throw A.handleApiError(i,"Failed to remove member")}}}function Z(s){const{config:t,authState:a,_internal:i}=A.useCedrosLogin(),[n,o]=r.useState([]),[f,m]=r.useState(0),[h,l]=r.useState(!1),[j,d]=r.useState(null),y=r.useRef(void 0),p=r.useRef(0),c=r.useMemo(()=>new X(t.serverUrl,t.requestTimeout,t.retryAttempts,i?.getAccessToken),[t.serverUrl,t.requestTimeout,t.retryAttempts,i]),u=r.useRef(c);u.current=c;const g=r.useCallback(async w=>{if(!s||a!=="authenticated"){o([]),m(0);return}l(!0),d(null);const x=++p.current;try{const{limit:v=50,offset:N=0}=w??{},C=await u.current.listMembers(s,v,N);if(x!==p.current)return;o(C.members),m(C.total)}catch(v){if(x!==p.current)return;d(v)}finally{x===p.current&&l(!1)}},[s,a]);r.useEffect(()=>{if(a!=="authenticated"){y.current=void 0;return}s!==y.current&&(y.current=s,g())},[s,a,g]);const b=r.useCallback(async(w,x)=>{if(!s)throw new Error("No organization selected");l(!0),d(null);try{await u.current.updateMemberRole(s,w,{role:x}),await g()}catch(v){throw d(v),v}finally{l(!1)}},[s,g]),S=r.useCallback(async w=>{if(!s)throw new Error("No organization selected");l(!0),d(null);try{await u.current.removeMember(s,w),await g()}catch(x){throw d(x),x}finally{l(!1)}},[s,g]);return{members:n,total:f,isLoading:h,error:j,fetchMembers:g,updateMemberRole:b,removeMember:S}}class ee{client;constructor(t,a,i,n){this.client=new A.ApiClient({baseUrl:t,timeoutMs:a,retryAttempts:i,getAccessToken:n})}async listInvites(t,a=50,i=0){try{const n=await this.client.get(`/orgs/${t}/invites?limit=${a}&offset=${i}`);return{invites:n.invites.map(o=>({id:o.id,orgId:o.orgId,email:o.email,role:o.role,invitedBy:o.invitedBy,createdAt:o.createdAt,expiresAt:o.expiresAt})),total:n.total}}catch(n){throw A.handleApiError(n,"Failed to list invites")}}async createInvite(t,a){try{return await this.client.post(`/orgs/${t}/invites`,a)}catch(i){throw A.handleApiError(i,"Failed to create invite")}}async cancelInvite(t,a){try{await this.client.delete(`/orgs/${t}/invites/${a}`)}catch(i){throw A.handleApiError(i,"Failed to cancel invite")}}async resendInvite(t,a){try{await this.client.post(`/orgs/${t}/invites/${a}/resend`,{})}catch(i){throw A.handleApiError(i,"Failed to resend invite")}}async acceptInvite(t){try{return await this.client.post("/invites/accept",t)}catch(a){throw A.handleApiError(a,"Failed to accept invite")}}}function se(s){const{config:t,authState:a,_internal:i}=A.useCedrosLogin(),[n,o]=r.useState([]),[f,m]=r.useState(0),[h,l]=r.useState(!1),[j,d]=r.useState(null),y=r.useRef(void 0),p=r.useRef(0),c=r.useMemo(()=>new ee(t.serverUrl,t.requestTimeout,t.retryAttempts,i?.getAccessToken),[t.serverUrl,t.requestTimeout,t.retryAttempts,i]),u=r.useRef(c);u.current=c;const g=r.useCallback(async v=>{if(!s||a!=="authenticated"){o([]),m(0);return}l(!0),d(null);const N=++p.current;try{const{limit:C=50,offset:O=0}=v??{},L=await u.current.listInvites(s,C,O);if(N!==p.current)return;o(L.invites),m(L.total)}catch(C){if(N!==p.current)return;d(C)}finally{N===p.current&&l(!1)}},[s,a]);r.useEffect(()=>{if(a!=="authenticated"){y.current=void 0;return}s!==y.current&&(y.current=s,g())},[s,a,g]);const b=r.useCallback(async(v,N="member")=>{if(!s)throw new Error("No organization selected");l(!0),d(null);try{await u.current.createInvite(s,{email:v,role:N}),await g()}catch(C){throw d(C),C}finally{l(!1)}},[s,g]),S=r.useCallback(async v=>{if(!s)throw new Error("No organization selected");l(!0),d(null);try{await u.current.cancelInvite(s,v),await g()}catch(N){throw d(N),N}finally{l(!1)}},[s,g]),w=r.useCallback(async v=>{if(!s)throw new Error("No organization selected");l(!0),d(null);try{await u.current.resendInvite(s,v)}catch(N){throw d(N),N}finally{l(!1)}},[s]),x=r.useCallback(async v=>{l(!0),d(null);try{return await u.current.acceptInvite({token:v})}catch(N){throw d(N),N}finally{l(!1)}},[]);return{invites:n,total:f,isLoading:h,error:j,fetchInvites:g,createInvite:b,cancelInvite:S,resendInvite:w,acceptInvite:x}}const te={organizations:!1,sso:!1,mfa:!1,walletSigning:!1,credits:!1,userWithdrawals:!1,cedrosPay:!1};function I(){const{settings:s,isLoading:t,error:a,fetchSettings:i,getValue:n}=q.useSystemSettings(),[o,f]=r.useState(!1);r.useEffect(()=>{o||(i(),f(!0))},[i,o]);const m=r.useCallback(d=>d===void 0?!1:d==="true"||d==="1",[]),h=r.useMemo(()=>Object.keys(s).length===0?te:{organizations:m(n("feature_organizations")),sso:m(n("feature_sso")),mfa:m(n("feature_mfa")),walletSigning:m(n("feature_wallet_signing")),credits:m(n("feature_credits")),userWithdrawals:m(n("feature_user_withdrawals")),cedrosPay:m(n("feature_cedros_pay"))},[s,n,m]),l=r.useCallback(async()=>{await i()},[i]),j=r.useCallback(d=>h[d],[h]);return{features:h,isLoading:t,error:a,refetch:l,isEnabled:j}}const re=["users","team","deposits","withdrawals","settings-wallet","settings-auth","settings-messaging","settings-credits","settings-server"],ne=["pay-products","pay-subscriptions","pay-transactions","pay-coupons","pay-refunds","pay-storefront","pay-ai","pay-payment","pay-messaging","pay-settings"],E={users:"Users",team:"Team",deposits:"Deposits",withdrawals:"Withdrawals","settings-wallet":"Wallet Settings","settings-auth":"Auth Settings","settings-messaging":"Messages Settings","settings-credits":"Credits Settings","settings-server":"Server Settings","pay-products":"Products","pay-subscriptions":"Subscriptions","pay-transactions":"Transactions","pay-coupons":"Coupons","pay-refunds":"Refunds","pay-storefront":"Storefront","pay-ai":"Store AI","pay-payment":"Payment Options","pay-messaging":"Store Messages","pay-settings":"Store Server"},R={admin:{users:!0,team:!0,deposits:!0,withdrawals:!0,"settings-wallet":!0,"settings-auth":!0,"settings-messaging":!0,"settings-credits":!0,"settings-server":!0,"pay-products":!0,"pay-subscriptions":!0,"pay-transactions":!0,"pay-coupons":!0,"pay-refunds":!0,"pay-storefront":!0,"pay-ai":!0,"pay-payment":!0,"pay-messaging":!0,"pay-settings":!0},member:{users:!1,team:!0,deposits:!1,withdrawals:!1,"settings-wallet":!1,"settings-auth":!1,"settings-messaging":!1,"settings-credits":!1,"settings-server":!1,"pay-products":!1,"pay-subscriptions":!1,"pay-transactions":!1,"pay-coupons":!1,"pay-refunds":!1,"pay-storefront":!1,"pay-ai":!1,"pay-payment":!1,"pay-messaging":!1,"pay-settings":!1}};function _(){const{config:s,authState:t,_internal:a}=A.useCedrosLogin(),{activeOrg:i,role:n}=P.useOrgs(),[o,f]=r.useState(R),[m,h]=r.useState(!1),[l,j]=r.useState(!1),[d,y]=r.useState(null),p=r.useRef(0),c=r.useMemo(()=>new A.ApiClient({baseUrl:s.serverUrl,timeoutMs:s.requestTimeout,retryAttempts:s.retryAttempts,getAccessToken:a?.getAccessToken}),[s.serverUrl,s.requestTimeout,s.retryAttempts,a]),u=r.useRef(c);u.current=c;const g=r.useCallback(async()=>{if(t!=="authenticated"||!i){f(R);return}h(!0),y(null);const w=++p.current;try{const x=await u.current.get("/admin/dashboard-permissions");if(w!==p.current)return;f(x.permissions)}catch(x){if(w!==p.current)return;if(x instanceof Error&&x.message.includes("404"))f(R);else{const v=x instanceof Error?x.message:"Failed to fetch permissions";y({code:"NETWORK_ERROR",message:v}),f(R)}}finally{w===p.current&&h(!1)}},[t,i]),b=r.useCallback(async w=>{if(t!=="authenticated"||!i)throw new Error("Not authenticated");if(n!=="owner")throw new Error("Only owners can modify dashboard permissions");j(!0),y(null);try{await u.current.request({method:"PUT",path:"/admin/dashboard-permissions",body:w}),f(w)}catch(x){const v=x instanceof Error?x.message:"Failed to update permissions";throw y({code:"NETWORK_ERROR",message:v}),new Error(v)}finally{j(!1)}},[t,i,n]),S=r.useCallback(w=>!i||!n||n==="owner"?!0:o[n]?.[w]??!1,[i,n,o]);return r.useEffect(()=>{i?.id&&g()},[i?.id,g]),{permissions:o,canAccess:S,updatePermissions:b,isLoading:m,isUpdating:l,error:d,fetchPermissions:g}}function T({checked:s,onChange:t,disabled:a,label:i}){return e.jsx("button",{type:"button",role:"switch","aria-checked":s,"aria-label":i,disabled:a,className:`cedros-toggle cedros-toggle-sm ${s?"cedros-toggle-on":"cedros-toggle-off"} ${a?"cedros-toggle-disabled":""}`,onClick:()=>!a&&t(!s),children:e.jsx("span",{className:"cedros-toggle-track",children:e.jsx("span",{className:"cedros-toggle-thumb"})})})}function ae({userRole:s}){const{permissions:t,updatePermissions:a,isLoading:i,isUpdating:n,error:o}=_(),{features:f,isLoading:m}=I(),h=r.useRef(null),l=r.useRef(null),j=s==="owner",d=f.cedrosPay,y=r.useCallback(c=>{l.current=c,h.current&&clearTimeout(h.current),h.current=setTimeout(()=>{l.current&&(a(l.current).catch(()=>{}),l.current=null)},500)},[a]);r.useEffect(()=>()=>{h.current&&clearTimeout(h.current)},[]);const p=r.useCallback((c,u,g)=>{const b={...t,[c]:{...t[c],[u]:g}};y(b)},[t,y]);return i||m?e.jsx("div",{className:"cedros-dashboard__section",children:e.jsx("div",{className:"cedros-dashboard__loading",children:"Loading permissions..."})}):j?e.jsxs("div",{className:"cedros-dashboard__section cedros-permissions-section",children:[e.jsxs("div",{className:"cedros-permissions-header",children:[e.jsx("p",{className:"cedros-permissions-description",children:"Configure which dashboard sections each role can access. Owners always have full access."}),o&&e.jsx("div",{className:"cedros-permissions-error",children:o.message}),n&&e.jsx("span",{className:"cedros-permissions-saving",children:"Saving..."})]}),e.jsx("div",{className:"cedros-permissions-matrix",children:e.jsx("table",{className:"cedros-permissions-table",children:e.jsxs("tbody",{children:[e.jsxs("tr",{className:"cedros-permissions-group-header",children:[e.jsx("th",{className:"cedros-permissions-section-header",children:"Cedros Login"}),e.jsx("th",{className:"cedros-permissions-role-header",children:"Admin"}),e.jsx("th",{className:"cedros-permissions-role-header",children:"Member"})]}),re.map(c=>e.jsxs("tr",{className:"cedros-permissions-row",children:[e.jsx("td",{className:"cedros-permissions-section-label",children:E[c]}),e.jsx("td",{className:"cedros-permissions-toggle-cell",children:e.jsx(T,{checked:t.admin[c]??!1,onChange:u=>p("admin",c,u),disabled:n,label:`Admin access to ${E[c]}`})}),e.jsx("td",{className:"cedros-permissions-toggle-cell",children:e.jsx(T,{checked:t.member[c]??!1,onChange:u=>p("member",c,u),disabled:n,label:`Member access to ${E[c]}`})})]},c)),d&&e.jsxs(e.Fragment,{children:[e.jsxs("tr",{className:"cedros-permissions-group-header",children:[e.jsx("th",{className:"cedros-permissions-section-header",children:"Cedros Pay"}),e.jsx("th",{className:"cedros-permissions-role-header",children:"Admin"}),e.jsx("th",{className:"cedros-permissions-role-header",children:"Member"})]}),ne.map(c=>e.jsxs("tr",{className:"cedros-permissions-row",children:[e.jsx("td",{className:"cedros-permissions-section-label",children:E[c]}),e.jsx("td",{className:"cedros-permissions-toggle-cell",children:e.jsx(T,{checked:t.admin[c]??!1,onChange:u=>p("admin",c,u),disabled:n,label:`Admin access to ${E[c]}`})}),e.jsx("td",{className:"cedros-permissions-toggle-cell",children:e.jsx(T,{checked:t.member[c]??!1,onChange:u=>p("member",c,u),disabled:n,label:`Member access to ${E[c]}`})})]},c))]})]})})})]}):e.jsx("div",{className:"cedros-dashboard__section",children:e.jsx("div",{className:"cedros-dashboard__empty",children:"Only organization owners can configure dashboard permissions."})})}exports.InviteForm=K;exports.InviteList=J;exports.MemberList=z;exports.PermissionsSection=ae;exports.useDashboardPermissions=_;exports.useInvites=se;exports.useMembers=Z;exports.useServerFeatures=I;