@cedros/login-react 0.0.42 → 0.0.43

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 (66) hide show
  1. package/dist/{AuthenticationSettings-DwSxgjbH.js → AuthenticationSettings-CxAubcoz.js} +1 -1
  2. package/dist/{AuthenticationSettings-DwSxgjbH.js.map → AuthenticationSettings-CxAubcoz.js.map} +1 -1
  3. package/dist/{AuthenticationSettings-Dl41GbJL.cjs → AuthenticationSettings-DPr882lj.cjs} +1 -1
  4. package/dist/{AuthenticationSettings-Dl41GbJL.cjs.map → AuthenticationSettings-DPr882lj.cjs.map} +1 -1
  5. package/dist/{AuthenticationSettings-JxHsBst9.cjs → AuthenticationSettings-Y40T1djV.cjs} +1 -1
  6. package/dist/{AuthenticationSettings-JxHsBst9.cjs.map → AuthenticationSettings-Y40T1djV.cjs.map} +1 -1
  7. package/dist/{AuthenticationSettings-CheE3j7w.js → AuthenticationSettings-aVBFKKZ-.js} +1 -1
  8. package/dist/{AuthenticationSettings-CheE3j7w.js.map → AuthenticationSettings-aVBFKKZ-.js.map} +1 -1
  9. package/dist/{AutosaveStatus-BMXjH1XN.cjs → AutosaveStatus-ByD01ENa.cjs} +1 -1
  10. package/dist/AutosaveStatus-ByD01ENa.cjs.map +1 -0
  11. package/dist/{AutosaveStatus-DNuCl59W.js → AutosaveStatus-DtF_58rC.js} +68 -33
  12. package/dist/AutosaveStatus-DtF_58rC.js.map +1 -0
  13. package/dist/{CreditSystemSettings-HSdF2_CY.js → CreditSystemSettings-BQek2Ux2.js} +1 -1
  14. package/dist/{CreditSystemSettings-HSdF2_CY.js.map → CreditSystemSettings-BQek2Ux2.js.map} +1 -1
  15. package/dist/{CreditSystemSettings-BVgl6uUg.cjs → CreditSystemSettings-CbuCce29.cjs} +1 -1
  16. package/dist/{CreditSystemSettings-BVgl6uUg.cjs.map → CreditSystemSettings-CbuCce29.cjs.map} +1 -1
  17. package/dist/{CreditSystemSettings-LvA8rb17.cjs → CreditSystemSettings-DHG_jhz9.cjs} +1 -1
  18. package/dist/{CreditSystemSettings-LvA8rb17.cjs.map → CreditSystemSettings-DHG_jhz9.cjs.map} +1 -1
  19. package/dist/{CreditSystemSettings-C-ksysSx.js → CreditSystemSettings-GDKgYc7I.js} +1 -1
  20. package/dist/{CreditSystemSettings-C-ksysSx.js.map → CreditSystemSettings-GDKgYc7I.js.map} +1 -1
  21. package/dist/{EmailSettings-QBMzpbxv.cjs → EmailSettings-Cg4Z7139.cjs} +1 -1
  22. package/dist/{EmailSettings-QBMzpbxv.cjs.map → EmailSettings-Cg4Z7139.cjs.map} +1 -1
  23. package/dist/{EmailSettings-DC_zT4nI.cjs → EmailSettings-CjxBg0cE.cjs} +1 -1
  24. package/dist/{EmailSettings-DC_zT4nI.cjs.map → EmailSettings-CjxBg0cE.cjs.map} +1 -1
  25. package/dist/{EmailSettings-Cy1cuVUq.js → EmailSettings-Ct6nFslP.js} +1 -1
  26. package/dist/{EmailSettings-Cy1cuVUq.js.map → EmailSettings-Ct6nFslP.js.map} +1 -1
  27. package/dist/{EmailSettings-hIhJzux0.js → EmailSettings-D2pCqTKC.js} +1 -1
  28. package/dist/{EmailSettings-hIhJzux0.js.map → EmailSettings-D2pCqTKC.js.map} +1 -1
  29. package/dist/{EmbeddedWalletSettings-Cwiug0vR.js → EmbeddedWalletSettings-Bus7UyOX.js} +1 -1
  30. package/dist/{EmbeddedWalletSettings-Cwiug0vR.js.map → EmbeddedWalletSettings-Bus7UyOX.js.map} +1 -1
  31. package/dist/{EmbeddedWalletSettings-C81QQMWz.cjs → EmbeddedWalletSettings-CfzvFYnn.cjs} +1 -1
  32. package/dist/{EmbeddedWalletSettings-C81QQMWz.cjs.map → EmbeddedWalletSettings-CfzvFYnn.cjs.map} +1 -1
  33. package/dist/{EmbeddedWalletSettings-CvvTnRvt.js → EmbeddedWalletSettings-PwFgtGmK.js} +1 -1
  34. package/dist/{EmbeddedWalletSettings-CvvTnRvt.js.map → EmbeddedWalletSettings-PwFgtGmK.js.map} +1 -1
  35. package/dist/{EmbeddedWalletSettings-4qC9KBwh.cjs → EmbeddedWalletSettings-t0_5poBu.cjs} +1 -1
  36. package/dist/{EmbeddedWalletSettings-4qC9KBwh.cjs.map → EmbeddedWalletSettings-t0_5poBu.cjs.map} +1 -1
  37. package/dist/{ServerSettings-BV0SipW1.cjs → ServerSettings-BjLFs_sb.cjs} +1 -1
  38. package/dist/{ServerSettings-BV0SipW1.cjs.map → ServerSettings-BjLFs_sb.cjs.map} +1 -1
  39. package/dist/{ServerSettings-Sfr0CG6K.js → ServerSettings-COkhan4u.js} +1 -1
  40. package/dist/{ServerSettings-Sfr0CG6K.js.map → ServerSettings-COkhan4u.js.map} +1 -1
  41. package/dist/{ServerSettings-DPqHtsgV.js → ServerSettings-D7WJDTbZ.js} +1 -1
  42. package/dist/{ServerSettings-DPqHtsgV.js.map → ServerSettings-D7WJDTbZ.js.map} +1 -1
  43. package/dist/{ServerSettings-Bf7gFE8r.cjs → ServerSettings-Dmw2rpFA.cjs} +1 -1
  44. package/dist/{ServerSettings-Bf7gFE8r.cjs.map → ServerSettings-Dmw2rpFA.cjs.map} +1 -1
  45. package/dist/{WebhookSettings-D4mKAWAg.js → WebhookSettings-CpPvGmV7.js} +1 -1
  46. package/dist/{WebhookSettings-D4mKAWAg.js.map → WebhookSettings-CpPvGmV7.js.map} +1 -1
  47. package/dist/{WebhookSettings-CMROMCFT.js → WebhookSettings-DEHV2ptf.js} +1 -1
  48. package/dist/{WebhookSettings-CMROMCFT.js.map → WebhookSettings-DEHV2ptf.js.map} +1 -1
  49. package/dist/{WebhookSettings-Cj-iELGa.cjs → WebhookSettings-DbyPJ8V2.cjs} +1 -1
  50. package/dist/{WebhookSettings-Cj-iELGa.cjs.map → WebhookSettings-DbyPJ8V2.cjs.map} +1 -1
  51. package/dist/{WebhookSettings-BPCKv5Or.cjs → WebhookSettings-Rq_nNJuw.cjs} +1 -1
  52. package/dist/{WebhookSettings-BPCKv5Or.cjs.map → WebhookSettings-Rq_nNJuw.cjs.map} +1 -1
  53. package/dist/admin-only.cjs +1 -1
  54. package/dist/admin-only.js +1 -1
  55. package/dist/index.cjs +13 -13
  56. package/dist/index.cjs.map +1 -1
  57. package/dist/index.d.ts +89 -0
  58. package/dist/index.js +2545 -2215
  59. package/dist/index.js.map +1 -1
  60. package/dist/{plugin-CK2d7aP5.js → plugin-Bwwe7_ZO.js} +1 -1
  61. package/dist/{plugin-CK2d7aP5.js.map → plugin-Bwwe7_ZO.js.map} +1 -1
  62. package/dist/{plugin-BHGg7ius.cjs → plugin-C4bijrSr.cjs} +1 -1
  63. package/dist/{plugin-BHGg7ius.cjs.map → plugin-C4bijrSr.cjs.map} +1 -1
  64. package/package.json +1 -1
  65. package/dist/AutosaveStatus-BMXjH1XN.cjs.map +0 -1
  66. package/dist/AutosaveStatus-DNuCl59W.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AutosaveStatus-ByD01ENa.cjs","sources":["../src/components/admin/settings/settingsMetadata.ts","../src/components/admin/settings/settingsInputs.tsx","../src/hooks/useSettingsAutosave.ts","../src/components/admin/settings/AutosaveStatus.tsx"],"sourcesContent":["/**\n * Settings metadata - rich descriptions and input configuration\n */\nimport type { SettingMeta } from '../../../types';\n\n// =============================================================================\n// DURATION UTILITIES\n// =============================================================================\n\nexport interface DurationParts {\n days: number;\n hours: number;\n minutes: number;\n seconds: number;\n}\n\nexport function secondsToDuration(totalSeconds: number): DurationParts {\n const days = Math.floor(totalSeconds / 86400);\n const hours = Math.floor((totalSeconds % 86400) / 3600);\n const minutes = Math.floor((totalSeconds % 3600) / 60);\n const seconds = totalSeconds % 60;\n return { days, hours, minutes, seconds };\n}\n\nexport function formatDuration(totalSeconds: number): string {\n const { days, hours, minutes } = secondsToDuration(totalSeconds);\n const parts: string[] = [];\n if (days > 0) parts.push(`${days}d`);\n if (hours > 0) parts.push(`${hours}h`);\n if (minutes > 0) parts.push(`${minutes}m`);\n if (parts.length === 0) parts.push(`${totalSeconds}s`);\n return parts.join(' ');\n}\n\n// =============================================================================\n// SETTING METADATA - Rich descriptions and input configuration\n// =============================================================================\n\nexport const SETTING_METADATA: Record<string, SettingMeta> = {\n // ============= Authentication Providers =============\n // Email auth\n auth_email_enabled: {\n key: 'auth_email_enabled',\n label: 'Enable Email Authentication',\n description: 'Allow users to sign up and log in with email/password.',\n inputType: 'boolean',\n },\n auth_email_require_verification: {\n key: 'auth_email_require_verification',\n label: 'Require Email Verification',\n description: 'Users must verify their email address before they can log in.',\n inputType: 'boolean',\n },\n auth_email_block_disposable: {\n key: 'auth_email_block_disposable',\n label: 'Block Disposable Emails',\n description: 'Reject registrations from known disposable email providers.',\n inputType: 'boolean',\n },\n\n // Google OAuth\n auth_google_enabled: {\n key: 'auth_google_enabled',\n label: 'Enable Google Sign-In',\n description:\n 'Allow users to authenticate with their Google account. Configure at <a href=\"https://console.cloud.google.com/apis/credentials\" target=\"_blank\" rel=\"noopener\">Google Cloud Console &gt; Credentials</a>.',\n inputType: 'boolean',\n },\n auth_google_client_id: {\n key: 'auth_google_client_id',\n label: 'Google Client ID',\n description:\n 'OAuth 2.0 client ID from Google Cloud Console. Create a Web application credential and add your frontend URL to Authorized JavaScript origins.',\n inputType: 'text',\n },\n // Apple OAuth\n auth_apple_enabled: {\n key: 'auth_apple_enabled',\n label: 'Enable Sign in with Apple',\n description:\n 'Allow users to authenticate with their Apple ID. Configure at <a href=\"https://developer.apple.com/account/resources/identifiers\" target=\"_blank\" rel=\"noopener\">Apple Developer &gt; Identifiers</a>.',\n inputType: 'boolean',\n },\n auth_apple_client_id: {\n key: 'auth_apple_client_id',\n label: 'Apple Services ID',\n description:\n 'Your Client ID (e.g. com.yourdomain.service). Create at Identifiers &gt; Services IDs, then enable Sign in with Apple and add your frontend URL as a Return URL (e.g. https://yourdomain.com).',\n inputType: 'text',\n placeholder: 'com.yourdomain.service',\n },\n auth_apple_team_id: {\n key: 'auth_apple_team_id',\n label: 'Apple Team ID',\n description:\n 'Identifies your developer account. Found at the top-right of <a href=\"https://developer.apple.com/account\" target=\"_blank\" rel=\"noopener\">Apple Developer</a>.',\n inputType: 'text',\n },\n\n // Solana auth\n auth_solana_enabled: {\n key: 'auth_solana_enabled',\n label: 'Enable Solana Wallet Auth',\n description: 'Allow users to authenticate by signing with their Solana wallet.',\n inputType: 'boolean',\n },\n auth_solana_challenge_expiry: {\n key: 'auth_solana_challenge_expiry',\n label: 'Challenge Expiry',\n description: 'How long a wallet signature challenge is valid.',\n inputType: 'duration',\n min: 60,\n presets: [\n { label: '1 minute', value: '60' },\n { label: '5 minutes', value: '300' },\n { label: '10 minutes', value: '600' },\n ],\n },\n\n // WebAuthn/Passkeys\n auth_webauthn_enabled: {\n key: 'auth_webauthn_enabled',\n label: 'Enable WebAuthn/Passkeys',\n description: 'Allow passwordless authentication with FIDO2/WebAuthn credentials.',\n inputType: 'boolean',\n },\n auth_webauthn_rp_id: {\n key: 'auth_webauthn_rp_id',\n label: 'Relying Party ID',\n description: 'Usually your domain (e.g., example.com). Passkeys are bound to this.',\n inputType: 'text',\n },\n auth_webauthn_rp_name: {\n key: 'auth_webauthn_rp_name',\n label: 'Relying Party Name',\n description: 'Display name shown to users during passkey registration.',\n inputType: 'text',\n },\n auth_webauthn_rp_origin: {\n key: 'auth_webauthn_rp_origin',\n label: 'Allowed Origins',\n description: 'Comma-separated origins allowed for WebAuthn (e.g., https://example.com).',\n inputType: 'text',\n },\n\n // Instant Link (Magic Link)\n auth_instantlink_enabled: {\n key: 'auth_instantlink_enabled',\n label: 'Enable Instant Link',\n description:\n 'When enabled, \"Forgot your password?\" on the sign-in form sends a one-time sign-in link instead of a password reset. This replaces the password reset flow — it is not a separate login button.',\n inputType: 'boolean',\n },\n auth_instantlink_expiry: {\n key: 'auth_instantlink_expiry',\n label: 'Link Expiry',\n description: 'How long the magic link remains valid.',\n inputType: 'duration',\n min: 60,\n presets: [\n { label: '5 minutes', value: '300' },\n { label: '15 minutes', value: '900' },\n { label: '30 minutes', value: '1800' },\n { label: '1 hour', value: '3600' },\n ],\n },\n auth_instantlink_rate_limit: {\n key: 'auth_instantlink_rate_limit',\n label: 'Rate Limit',\n description: 'Maximum instant link requests per email per hour.',\n inputType: 'select',\n presets: [\n { label: '3 per hour', value: '3' },\n { label: '5 per hour', value: '5' },\n { label: '10 per hour', value: '10' },\n ],\n },\n\n // ============= Feature Flags =============\n // Order: organizations, enterprise SSO, 2fa, embedded wallets, credit system\n feature_organizations: {\n key: 'feature_organizations',\n label: 'Organizations',\n description: 'Enable multi-user organizations with role-based access.',\n inputType: 'boolean',\n },\n feature_sso: {\n key: 'feature_sso',\n label: 'Enterprise SSO',\n description: 'Enable SAML/OIDC single sign-on for enterprise customers.',\n inputType: 'boolean',\n },\n feature_mfa: {\n key: 'feature_mfa',\n label: 'Two-Factor Authentication',\n description:\n 'Allow users to enable TOTP-based two-factor authentication for email/password sign-in. ' +\n 'OAuth (Google, Apple) and passkey logins are not affected — those providers handle their own verification.',\n inputType: 'boolean',\n },\n feature_wallet_signing: {\n key: 'feature_wallet_signing',\n label: 'Enable Embedded Wallet',\n description: 'Enable the embedded wallet for transaction signing.',\n inputType: 'boolean',\n },\n wallet_recovery_mode: {\n key: 'wallet_recovery_mode',\n label: 'Recovery Mode',\n description:\n 'Controls whether users can recover their embedded wallet seed. <b>Share C Only</b> lets users export a single key share (cannot reconstruct the full seed). <b>Full Seed</b> lets users export the complete seed phrase. <b>No Recovery</b> prevents any seed export — required when Private Deposits are enabled, because recoverable seeds would let users front-run privacy withdrawals.',\n inputType: 'select',\n presets: [\n { label: 'Share C Only (Recommended)', value: 'share_c_only' },\n { label: 'Full Seed Phrase', value: 'full_seed' },\n { label: 'No Recovery (Required for Private Deposits)', value: 'none' },\n ],\n },\n feature_credits: {\n key: 'feature_credits',\n label: 'Credit System',\n description:\n 'Enable the deposits and credits system. Users can deposit tokens to receive platform credits.',\n inputType: 'boolean',\n },\n feature_user_withdrawals: {\n key: 'feature_user_withdrawals',\n label: 'User Withdrawals',\n description:\n 'Allow users to initiate withdrawals from their embedded wallet to external addresses. This is separate from the automated privacy withdrawal worker, which moves funds from the privacy pool to the treasury.',\n inputType: 'boolean',\n },\n feature_referrals_enabled: {\n key: 'feature_referrals_enabled',\n label: 'Referral System',\n description:\n 'Enable the referral system. Each user gets a unique referral code they can share. ' +\n 'New users can register with a referral code to track who invited them.',\n inputType: 'boolean',\n },\n referral_reward_lamports: {\n key: 'referral_reward_lamports',\n label: 'Referral Reward Amount (lamports)',\n description:\n 'Amount of credits to reward the referrer (in smallest unit: lamports for SOL, micros for USD). ' +\n 'Set to 0 to disable referral rewards. For example, 1000000000 = 1 SOL.',\n inputType: 'text',\n },\n referral_reward_max_per_referrer: {\n key: 'referral_reward_max_per_referrer',\n label: 'Max Reward Per Referrer',\n description:\n 'Maximum total reward amount a single referrer can earn (in smallest unit). ' +\n 'Set to 0 for unlimited. Applies to direct payout mode only.',\n inputType: 'text',\n },\n referral_reward_type: {\n key: 'referral_reward_type',\n label: 'Referral Reward Type',\n description:\n 'How referral rewards are issued. \"Credits\" adds balance to the referrer\\'s in-app credit account. ' +\n '\"Direct payout\" queues an on-chain transfer to the referrer\\'s configured payout wallet address.',\n inputType: 'select',\n presets: [\n { label: 'Credits', value: 'credits' },\n { label: 'Direct payout (on-chain)', value: 'direct_payout' },\n ],\n },\n referral_reward_trigger: {\n key: 'referral_reward_trigger',\n label: 'Referral Reward Trigger',\n description:\n 'When to issue the referral reward to the referrer. ' +\n '\"On signup\" rewards immediately when the referred user registers. ' +\n '\"On first purchase\" rewards only after the referred user makes their first spend. ' +\n '\"On every purchase\" rewards the referrer on each spend by the referred user.',\n inputType: 'select',\n presets: [\n { label: 'On signup', value: 'on_signup' },\n { label: 'On first purchase', value: 'on_first_spend' },\n { label: 'On every purchase', value: 'on_every_spend' },\n ],\n },\n\n // ============= Payout Worker Settings =============\n payout_auto_enabled: {\n key: 'payout_auto_enabled',\n label: 'Auto-Process Payouts',\n description:\n 'Enable the automated payout worker that periodically processes pending referral payouts on-chain. ' +\n 'When disabled, payouts must be processed manually from the admin dashboard.',\n inputType: 'boolean',\n },\n payout_poll_interval_secs: {\n key: 'payout_poll_interval_secs',\n label: 'Payout Poll Interval',\n description:\n 'How often the payout worker checks for pending payouts (in seconds). Default: 3600 (1 hour). ' +\n 'Lower values mean faster payouts but more frequent treasury key decryption.',\n inputType: 'duration',\n unit: 'seconds',\n },\n payout_batch_size: {\n key: 'payout_batch_size',\n label: 'Payout Batch Size',\n description:\n 'Maximum number of referrer groups to process per worker cycle. Default: 50. ' +\n 'Each referrer group aggregates all pending payouts for that referrer into a single transfer.',\n inputType: 'text',\n },\n\n // ============= Security Settings =============\n security_require_mfa: {\n key: 'security_require_mfa',\n label: 'Require Two-Factor Authentication',\n description:\n 'Require users with email/password credentials to set up TOTP two-factor authentication. ' +\n 'Users will be prompted to enroll after their next sign-in. ' +\n 'Does not affect OAuth, passkey, or wallet sign-in methods. ' +\n 'Works independently of the \"Two-Factor Authentication\" feature flag (which controls UI visibility).',\n inputType: 'boolean',\n },\n security_cors_origins: {\n key: 'security_cors_origins',\n label: 'CORS Origins',\n description:\n 'Allowed origins for cross-origin requests (comma-separated). Empty = same origin only.',\n inputType: 'text',\n },\n security_cookie_domain: {\n key: 'security_cookie_domain',\n label: 'Cookie Domain',\n description: 'Domain for auth cookies. Empty uses the request origin.',\n inputType: 'text',\n },\n security_cookie_secure: {\n key: 'security_cookie_secure',\n label: 'Secure Cookies',\n description: 'Require HTTPS for cookies. Disable only for local development.',\n inputType: 'boolean',\n },\n security_cookie_same_site: {\n key: 'security_cookie_same_site',\n label: 'Cookie SameSite',\n description: 'SameSite policy for cookies. Use \"none\" only if needed for cross-site embeds.',\n inputType: 'select',\n presets: [\n { label: 'Strict', value: 'strict' },\n { label: 'Lax (Recommended)', value: 'lax' },\n { label: 'None (cross-site)', value: 'none' },\n ],\n },\n security_session_timeout: {\n key: 'security_session_timeout',\n label: 'Session Timeout',\n description: 'How long sessions remain valid before requiring re-authentication.',\n inputType: 'duration',\n min: 300,\n presets: [\n { label: '1 hour', value: '3600' },\n { label: '24 hours', value: '86400' },\n { label: '7 days', value: '604800' },\n { label: '30 days', value: '2592000' },\n ],\n },\n security_jwt_issuer: {\n key: 'security_jwt_issuer',\n label: 'JWT Issuer',\n description: 'Issuer claim for JWTs. Empty uses the server URL.',\n inputType: 'text',\n },\n security_jwt_audience: {\n key: 'security_jwt_audience',\n label: 'JWT Audience',\n description: 'Audience claim for JWTs. Empty uses default.',\n inputType: 'text',\n },\n\n // ============= Email/SMTP Settings =============\n email_provider: {\n key: 'email_provider',\n label: 'Email Provider',\n description:\n 'Select a provider to auto-configure SMTP host, port, and TLS. Choose Custom SMTP to enter settings manually.',\n inputType: 'select',\n presets: [\n { label: 'Mailgun', value: 'mailgun' },\n { label: 'SendGrid', value: 'sendgrid' },\n { label: 'Postmark', value: 'postmark' },\n { label: 'AWS SES', value: 'ses' },\n { label: 'Resend', value: 'resend' },\n { label: 'Custom SMTP', value: 'custom' },\n ],\n },\n email_smtp_host: {\n key: 'email_smtp_host',\n label: 'SMTP Host',\n description:\n 'SMTP server hostname. Auto-filled when selecting a provider above.',\n inputType: 'text',\n placeholder: 'smtp.example.com',\n },\n email_smtp_port: {\n key: 'email_smtp_port',\n label: 'SMTP Port',\n description: 'SMTP server port. Most providers use 587 (TLS).',\n inputType: 'select',\n presets: [\n { label: '587 (TLS)', value: '587' },\n { label: '465 (SSL)', value: '465' },\n { label: '25 (Plain)', value: '25' },\n ],\n },\n email_smtp_user: {\n key: 'email_smtp_user',\n label: 'SMTP Username',\n description:\n 'Username for SMTP authentication. For SendGrid use \"apikey\", for Postmark use your server API token, for Mailgun use your full Mailgun SMTP login.',\n inputType: 'text',\n },\n email_smtp_password: {\n key: 'email_smtp_password',\n label: 'API Key',\n description:\n 'API key or password for your email provider. For SendGrid this is your API key, for Postmark your server API token, for Mailgun your SMTP password.',\n inputType: 'secret',\n },\n email_smtp_tls: {\n key: 'email_smtp_tls',\n label: 'Use TLS',\n description: 'Enable TLS encryption for SMTP connections. Required by most providers.',\n inputType: 'boolean',\n },\n email_from_address: {\n key: 'email_from_address',\n label: 'From Address',\n description:\n 'Sender email address for verification, password reset, and instant link emails. Must be verified with your provider.',\n inputType: 'text',\n placeholder: 'noreply@yourdomain.com',\n },\n email_from_name: {\n key: 'email_from_name',\n label: 'From Name',\n description: 'Display name shown in the \"From\" field of outbound emails.',\n inputType: 'text',\n placeholder: 'My App',\n },\n\n // ============= Email Subject Customization =============\n email_subject_verification: {\n key: 'email_subject_verification',\n label: 'Verification Email Subject',\n description: 'Custom subject for email verification messages. Leave empty for the default: \"Verify your email address\".',\n inputType: 'text',\n placeholder: 'Verify your email address',\n },\n email_subject_password_reset: {\n key: 'email_subject_password_reset',\n label: 'Password Reset Subject',\n description: 'Custom subject for password reset emails. Leave empty for the default: \"Reset your password\".',\n inputType: 'text',\n placeholder: 'Reset your password',\n },\n email_subject_instant_link: {\n key: 'email_subject_instant_link',\n label: 'Instant Link Subject',\n description: 'Custom subject for instant link sign-in emails. Leave empty for the default: \"Your sign-in link\".',\n inputType: 'text',\n placeholder: 'Your sign-in link',\n },\n email_subject_invite: {\n key: 'email_subject_invite',\n label: 'Invite Email Subject',\n description: 'Custom subject for organization invite emails. Leave empty for the default which includes the org name.',\n inputType: 'text',\n placeholder: \"You've been invited to join...\",\n },\n email_subject_security_alert: {\n key: 'email_subject_security_alert',\n label: 'Security Alert Subject',\n description: 'Custom subject for new device sign-in alerts. Leave empty for the default: \"New sign-in to your account\".',\n inputType: 'text',\n placeholder: 'New sign-in to your account',\n },\n\n // ============= Webhook Settings =============\n webhook_enabled: {\n key: 'webhook_enabled',\n label: 'Enable Webhooks',\n description: 'Send notifications to a Discord or Slack webhook URL.',\n inputType: 'boolean',\n },\n webhook_url: {\n key: 'webhook_url',\n label: 'Webhook URL',\n description: 'Discord or Slack webhook URL to receive notifications.',\n inputType: 'text',\n placeholder: 'https://discord.com/api/webhooks/...',\n },\n webhook_notify_registrations: {\n key: 'webhook_notify_registrations',\n label: 'New Registrations',\n description: 'Notify when a new user registers.',\n inputType: 'boolean',\n },\n webhook_notify_signins: {\n key: 'webhook_notify_signins',\n label: 'Sign-Ins',\n description: 'Notify when a user signs in.',\n inputType: 'boolean',\n },\n webhook_notify_deposits: {\n key: 'webhook_notify_deposits',\n label: 'Deposits',\n description: 'Notify when a user makes a deposit.',\n inputType: 'boolean',\n },\n\n // ============= Server Settings =============\n server_frontend_url: {\n key: 'server_frontend_url',\n label: 'Frontend URL',\n description: 'URL of your frontend app (for redirects and email links).',\n inputType: 'text',\n },\n server_base_path: {\n key: 'server_base_path',\n label: 'Base Path',\n description: 'Base path for auth endpoints (e.g., /auth).',\n inputType: 'text',\n },\n server_trust_proxy: {\n key: 'server_trust_proxy',\n label: 'Trust Proxy',\n description: 'Trust X-Forwarded-For headers. Enable if behind a reverse proxy.',\n inputType: 'boolean',\n },\n feature_cedros_pay: {\n key: 'feature_cedros_pay',\n label: 'Cedros Pay Integration',\n description:\n 'Enable Cedros Pay integration. When enabled, shows the Integrations tab with API key configuration. Not needed for co-located deployments using JWT/JWKS inter-service auth.',\n inputType: 'boolean',\n },\n server_cedros_pay_api_key: {\n key: 'server_cedros_pay_api_key',\n label: 'Cedros Pay API Key',\n description:\n 'API key for Cedros Pay to authenticate with this server. Copy this into your Cedros Pay settings.',\n inputType: 'secret',\n },\n jupiter_api_key: {\n key: 'jupiter_api_key',\n label: 'Jupiter API Key',\n description:\n 'API key for Jupiter Ultra API (gasless swaps). Get a free key at <a href=\"https://portal.jup.ag\" target=\"_blank\" rel=\"noopener\">portal.jup.ag</a>.',\n inputType: 'secret',\n },\n server_metrics_api_key: {\n key: 'server_metrics_api_key',\n label: 'Metrics API Key',\n description:\n 'API key for Prometheus/Grafana to scrape the /metrics endpoint. Use with Authorization: Bearer header.',\n inputType: 'secret',\n },\n server_log_level: {\n key: 'server_log_level',\n label: 'Log Level',\n description: 'Minimum severity level for log output. Lower levels are more verbose.',\n inputType: 'select',\n presets: [\n { label: 'Trace (most verbose)', value: 'trace' },\n { label: 'Debug', value: 'debug' },\n { label: 'Info', value: 'info' },\n { label: 'Warn', value: 'warn' },\n { label: 'Error (least verbose)', value: 'error' },\n ],\n },\n server_log_format: {\n key: 'server_log_format',\n label: 'Log Format',\n description: 'Output format for log messages.',\n inputType: 'select',\n presets: [\n { label: 'JSON (structured)', value: 'json' },\n { label: 'Pretty (human-readable)', value: 'pretty' },\n ],\n },\n server_environment: {\n key: 'server_environment',\n label: 'Environment',\n description: 'Deployment environment. Affects default behaviors and log verbosity.',\n inputType: 'select',\n presets: [\n { label: 'Development', value: 'development' },\n { label: 'Staging', value: 'staging' },\n { label: 'Production', value: 'production' },\n ],\n },\n\n // ============= Privacy Settings (existing) =============\n privacy_period_secs: {\n key: 'privacy_period_secs',\n label: 'Privacy Period',\n description:\n 'How long deposits are held before withdrawal to provide timing privacy. Longer periods provide better privacy but delay user access to funds.',\n inputType: 'duration',\n min: 0,\n presets: [\n { label: 'Disabled', value: '0' },\n { label: '1 hour', value: '3600' },\n { label: '6 hours', value: '21600' },\n { label: '24 hours', value: '86400' },\n { label: '7 days', value: '604800' },\n { label: '14 days', value: '1209600' },\n { label: '30 days', value: '2592000' },\n ],\n warningThreshold: {\n below: 3600,\n message: 'Very short privacy periods may not provide adequate timing protection.',\n },\n },\n\n // Treasury settings\n treasury_wallet_address: {\n key: 'treasury_wallet_address',\n label: 'Treasury Wallet Address',\n description:\n 'Solana wallet address where funds are sent. Used for privacy cash withdrawals, micro payment batches, and direct payments.',\n inputType: 'text',\n placeholder: 'e.g., 7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU',\n },\n\n // Withdrawal worker settings\n withdrawal_poll_interval_secs: {\n key: 'withdrawal_poll_interval_secs',\n label: 'Worker Poll Interval',\n description:\n 'How often the withdrawal worker checks for deposits ready to process. Lower values process faster but increase server load.',\n inputType: 'duration',\n min: 60,\n presets: [\n { label: '1 minute', value: '60' },\n { label: '5 minutes', value: '300' },\n { label: '15 minutes', value: '900' },\n { label: '1 hour', value: '3600' },\n { label: '6 hours', value: '21600' },\n ],\n warningThreshold: {\n below: 60,\n message: 'Polling more than once per minute may cause excessive load.',\n },\n },\n withdrawal_batch_size: {\n key: 'withdrawal_batch_size',\n label: 'Batch Size',\n description:\n 'Maximum number of withdrawals to process in a single batch. Higher values improve throughput but may cause timeouts.',\n inputType: 'select',\n min: 1,\n max: 100,\n presets: [\n { label: '1 (Sequential)', value: '1' },\n { label: '5', value: '5' },\n { label: '10 (Recommended)', value: '10' },\n { label: '25', value: '25' },\n { label: '50', value: '50' },\n { label: '100 (Max)', value: '100' },\n ],\n },\n withdrawal_timeout_secs: {\n key: 'withdrawal_timeout_secs',\n label: 'Transaction Timeout',\n description:\n 'How long to wait for a withdrawal transaction to confirm before considering it failed.',\n inputType: 'duration',\n min: 30,\n presets: [\n { label: '30 seconds', value: '30' },\n { label: '1 minute', value: '60' },\n { label: '2 minutes', value: '120' },\n { label: '5 minutes', value: '300' },\n ],\n warningThreshold: {\n below: 30,\n message: 'Very short timeouts may cause premature failure on slow networks.',\n },\n },\n withdrawal_max_retries: {\n key: 'withdrawal_max_retries',\n label: 'Max Retries',\n description:\n 'Number of times to retry a failed withdrawal before marking it as permanently failed.',\n inputType: 'select',\n min: 0,\n max: 10,\n presets: [\n { label: '0 (No retries)', value: '0' },\n { label: '1', value: '1' },\n { label: '3 (Recommended)', value: '3' },\n { label: '5', value: '5' },\n { label: '10', value: '10' },\n ],\n },\n withdrawal_percentage: {\n key: 'withdrawal_percentage',\n label: 'Withdrawal Percentage',\n description:\n 'Percentage of ready funds to withdraw each cycle. Lower values spread withdrawals over time for better privacy.',\n inputType: 'percentage',\n min: 1,\n max: 100,\n step: 5,\n presets: [\n { label: '25%', value: '25' },\n { label: '50%', value: '50' },\n { label: '75%', value: '75' },\n { label: '100% (All at once)', value: '100' },\n ],\n warningThreshold: {\n above: 75,\n message:\n 'High percentages may reduce timing privacy by processing most withdrawals together.',\n },\n },\n partial_withdrawal_count: {\n key: 'partial_withdrawal_count',\n label: 'Partial Withdrawals',\n description:\n 'Maximum partial withdrawals per batch. Partial withdrawals add noise to timing analysis. Set to 0 to disable.',\n inputType: 'select',\n min: 0,\n presets: [\n { label: 'Disabled', value: '0' },\n { label: '1', value: '1' },\n { label: '3', value: '3' },\n { label: '5', value: '5' },\n { label: '10', value: '10' },\n ],\n },\n partial_withdrawal_min_lamports: {\n key: 'partial_withdrawal_min_lamports',\n label: 'Min Balance for Partial',\n description:\n 'Minimum account balance (in lamports) required before partial withdrawals are considered. 1 SOL = 1,000,000,000 lamports.',\n inputType: 'select',\n min: 0,\n presets: [\n { label: '0.1 SOL', value: '100000000' },\n { label: '0.5 SOL', value: '500000000' },\n { label: '1 SOL', value: '1000000000' },\n { label: '5 SOL', value: '5000000000' },\n { label: '10 SOL', value: '10000000000' },\n ],\n },\n\n // Rate limit settings\n rate_limit_auth: {\n key: 'rate_limit_auth',\n label: 'Auth Request Limit',\n description:\n 'Maximum authentication attempts (login, register, password reset) per IP per window. Protects against brute force attacks.',\n inputType: 'select',\n min: 1,\n unit: 'requests',\n presets: [\n { label: '5 (Strict)', value: '5' },\n { label: '10 (Recommended)', value: '10' },\n { label: '20', value: '20' },\n { label: '50 (Permissive)', value: '50' },\n ],\n warningThreshold: {\n above: 20,\n message: 'High auth limits may allow brute force attempts.',\n },\n },\n rate_limit_general: {\n key: 'rate_limit_general',\n label: 'General Request Limit',\n description: 'Maximum general API requests per IP per window. Affects all non-auth endpoints.',\n inputType: 'select',\n min: 1,\n unit: 'requests',\n presets: [\n { label: '30', value: '30' },\n { label: '60 (Recommended)', value: '60' },\n { label: '120', value: '120' },\n { label: '300', value: '300' },\n ],\n },\n rate_limit_credit: {\n key: 'rate_limit_credit',\n label: 'Credit Request Limit',\n description:\n 'Maximum credit/balance check requests per IP per window. Higher for apps that poll balance frequently.',\n inputType: 'select',\n min: 1,\n unit: 'requests',\n presets: [\n { label: '10', value: '10' },\n { label: '30 (Recommended)', value: '30' },\n { label: '60', value: '60' },\n { label: '120', value: '120' },\n ],\n },\n rate_limit_window: {\n key: 'rate_limit_window',\n label: 'Rate Limit Window',\n description:\n 'Time window for rate limiting. All limits above are \"per window\". Shorter windows are stricter.',\n inputType: 'duration',\n min: 1,\n presets: [\n { label: '30 seconds', value: '30' },\n { label: '1 minute', value: '60' },\n { label: '5 minutes', value: '300' },\n { label: '15 minutes', value: '900' },\n ],\n },\n\n // ============= Deposit General Settings =============\n solana_rpc_url: {\n key: 'solana_rpc_url',\n label: 'Solana RPC URL',\n description:\n 'Get a fast RPC endpoint from <a href=\"https://helius.dev\" target=\"_blank\" rel=\"noopener\">Helius</a> or <a href=\"https://quicknode.com\" target=\"_blank\" rel=\"noopener\">QuickNode</a>.',\n inputType: 'text',\n placeholder: 'https://api.mainnet-beta.solana.com',\n },\n solana_network: {\n key: 'solana_network',\n label: 'Solana Network',\n description: 'The Solana network to use for deposits and withdrawals.',\n inputType: 'select',\n presets: [\n { label: 'Mainnet', value: 'mainnet-beta' },\n { label: 'Devnet', value: 'devnet' },\n ],\n },\n deposit_privacy_enabled: {\n key: 'deposit_privacy_enabled',\n label: 'Enable Private Deposits',\n description:\n 'When enabled, deposits are held for a privacy period before withdrawal. Provides timing privacy but delays fund availability.',\n inputType: 'boolean',\n },\n deposit_company_token: {\n key: 'deposit_company_token',\n label: 'Platform Token',\n description:\n 'The token that represents platform credits. Deposits are converted to this token. Common choices: USDC, SOL.',\n inputType: 'select',\n presets: [\n { label: 'USDC', value: 'USDC' },\n { label: 'USDT', value: 'USDT' },\n { label: 'SOL', value: 'SOL' },\n { label: 'EURC', value: 'EURC' },\n ],\n },\n deposit_micro_enabled: {\n key: 'deposit_micro_enabled',\n label: 'SOL Micro Payments',\n description: 'Allow small SOL deposits (under $10) that are batched together for efficiency.',\n inputType: 'boolean',\n },\n deposit_gasless_swap_enabled: {\n key: 'deposit_gasless_swap_enabled',\n label: 'Gasless Swap Payments',\n description: 'Allow deposits via Jupiter swaps.',\n inputType: 'boolean',\n },\n deposit_min_usd: {\n key: 'deposit_min_usd',\n label: 'Minimum Deposit',\n description: 'Minimum deposit amount in USD equivalent.',\n inputType: 'select',\n unit: 'USD',\n presets: [\n { label: '$1', value: '1' },\n { label: '$5', value: '5' },\n { label: '$10', value: '10' },\n { label: '$25', value: '25' },\n ],\n },\n deposit_max_usd: {\n key: 'deposit_max_usd',\n label: 'Maximum Deposit',\n description:\n 'Maximum deposit amount per transaction in USD equivalent. Set to 0 for unlimited.',\n inputType: 'select',\n unit: 'USD',\n presets: [\n { label: 'Unlimited', value: '0' },\n { label: '$1,000', value: '1000' },\n { label: '$10,000', value: '10000' },\n { label: '$100,000', value: '100000' },\n ],\n },\n\n // Deposit component settings\n deposit_show_explainer: {\n key: 'deposit_show_explainer',\n label: 'Show Explainer Screen',\n description: 'Show the introductory explainer screen at the start of the deposit flow.',\n inputType: 'boolean',\n },\n\n // Deposit token settings\n deposit_quick_action_tokens: {\n key: 'deposit_quick_action_tokens',\n label: 'Quick Action Tokens',\n description:\n 'Comma-separated token symbols shown as quick action buttons. First token is the default.',\n inputType: 'tokenSymbolList',\n },\n deposit_custom_tokens: {\n key: 'deposit_custom_tokens',\n label: 'Custom Dropdown Tokens',\n description:\n 'Comma-separated token symbols shown in the \"Custom\" dropdown. Leave empty to show all.',\n inputType: 'tokenSymbolList',\n },\n deposit_custom_tokens_json: {\n key: 'deposit_custom_tokens_json',\n label: 'Custom Token Definitions',\n description:\n 'Add tokens beyond the built-in list. Define symbol, mint address, decimals, and logo URL.',\n inputType: 'tokenList',\n },\n\n // Deposit fee settings\n deposit_fee_policy: {\n key: 'deposit_fee_policy',\n label: 'Fee Policy',\n description: 'Who pays deposit fees: company absorbs all, or user pays swap/privacy/all fees.',\n inputType: 'select',\n presets: [\n { label: 'Company Pays All', value: 'company_pays_all' },\n { label: 'User Pays Swap Fees', value: 'user_pays_swap' },\n { label: 'User Pays Privacy Fees', value: 'user_pays_privacy' },\n { label: 'User Pays All Fees', value: 'user_pays_all' },\n ],\n },\n privacy_fee_fixed_lamports: {\n key: 'privacy_fee_fixed_lamports',\n label: 'Privacy Fixed Fee',\n description: 'Fixed fee for Privacy Cash deposits in lamports. 1 SOL = 1,000,000,000 lamports.',\n inputType: 'select',\n unit: 'lamports',\n presets: [\n { label: '0 SOL', value: '0' },\n { label: '0.001 SOL', value: '1000000' },\n { label: '0.005 SOL', value: '5000000' },\n { label: '0.006 SOL (Default)', value: '6000000' },\n { label: '0.01 SOL', value: '10000000' },\n ],\n },\n privacy_fee_percent_bps: {\n key: 'privacy_fee_percent_bps',\n label: 'Privacy Percentage Fee',\n description: 'Percentage fee for Privacy Cash deposits in basis points. 100 bps = 1%.',\n inputType: 'select',\n unit: 'bps',\n presets: [\n { label: '0%', value: '0' },\n { label: '0.25%', value: '25' },\n { label: '0.35% (Default)', value: '35' },\n { label: '0.5%', value: '50' },\n { label: '1%', value: '100' },\n ],\n },\n swap_fee_fixed_lamports: {\n key: 'swap_fee_fixed_lamports',\n label: 'Swap Fixed Fee',\n description: 'Fixed fee for Jupiter swaps in lamports. Covers transaction costs.',\n inputType: 'select',\n unit: 'lamports',\n presets: [\n { label: '0 SOL', value: '0' },\n { label: '0.001 SOL (Default)', value: '1000000' },\n { label: '0.002 SOL', value: '2000000' },\n { label: '0.005 SOL', value: '5000000' },\n ],\n },\n swap_fee_percent_bps: {\n key: 'swap_fee_percent_bps',\n label: 'Swap Percentage Fee',\n description: 'Percentage fee for Jupiter swaps in basis points. 100 bps = 1%.',\n inputType: 'select',\n unit: 'bps',\n presets: [\n { label: '0%', value: '0' },\n { label: '0.1% (Default)', value: '10' },\n { label: '0.25%', value: '25' },\n { label: '0.5%', value: '50' },\n ],\n },\n company_fee_fixed_lamports: {\n key: 'company_fee_fixed_lamports',\n label: 'Company Fixed Fee',\n description: 'Additional fixed processing fee in lamports. Set to 0 to disable.',\n inputType: 'select',\n unit: 'lamports',\n presets: [\n { label: 'Disabled', value: '0' },\n { label: '0.001 SOL', value: '1000000' },\n { label: '0.005 SOL', value: '5000000' },\n { label: '0.01 SOL', value: '10000000' },\n ],\n },\n company_fee_percent_bps: {\n key: 'company_fee_percent_bps',\n label: 'Company Percentage Fee',\n description: 'Additional percentage processing fee in basis points. 100 bps = 1%.',\n inputType: 'select',\n unit: 'bps',\n presets: [\n { label: 'Disabled', value: '0' },\n { label: '0.1%', value: '10' },\n { label: '0.25%', value: '25' },\n { label: '0.5%', value: '50' },\n { label: '1%', value: '100' },\n ],\n },\n micro_batch_threshold_usd: {\n key: 'micro_batch_threshold_usd',\n label: 'Batch Threshold',\n description:\n 'Minimum accumulated USD value before triggering a batch swap. Jupiter requires ~$10 minimum.',\n inputType: 'select',\n unit: 'USD',\n presets: [\n { label: '$10 (Minimum)', value: '10' },\n { label: '$25', value: '25' },\n { label: '$50', value: '50' },\n { label: '$100', value: '100' },\n ],\n },\n micro_batch_poll_secs: {\n key: 'micro_batch_poll_secs',\n label: 'Batch Poll Interval',\n description:\n 'How often to check for batchable micro deposits. Lower values process faster but increase load.',\n inputType: 'duration',\n min: 60,\n presets: [\n { label: '1 minute', value: '60' },\n { label: '5 minutes (Default)', value: '300' },\n { label: '15 minutes', value: '900' },\n { label: '1 hour', value: '3600' },\n ],\n },\n private_deposit_min_lamports: {\n key: 'private_deposit_min_lamports',\n label: 'Min Private Deposit',\n description:\n 'Minimum amount for Privacy Cash deposits in lamports. Smaller deposits use micro batching.',\n inputType: 'select',\n unit: 'lamports',\n presets: [\n { label: '0.1 SOL', value: '100000000' },\n { label: '0.25 SOL (Default)', value: '250000000' },\n { label: '0.5 SOL', value: '500000000' },\n { label: '1 SOL', value: '1000000000' },\n ],\n },\n withdrawal_min_lamports: {\n key: 'withdrawal_min_lamports',\n label: 'Min Withdrawal Amount',\n description:\n 'Minimum amount to withdraw in lamports. Deposits below this remain pending. Fees are ~0.006 SOL + 0.35% + Jupiter.',\n inputType: 'select',\n unit: 'lamports',\n presets: [\n { label: '0.5 SOL', value: '500000000' },\n { label: '1 SOL (Default)', value: '1000000000' },\n { label: '2 SOL', value: '2000000000' },\n { label: '5 SOL', value: '5000000000' },\n ],\n warningThreshold: {\n below: 500000000,\n message: 'Very small withdrawals may lose significant value to fees.',\n },\n },\n\n // ============= Sidecar Shared Secrets =============\n sidecar_api_key: {\n key: 'sidecar_api_key',\n label: 'Sidecar API Key',\n description:\n 'Authenticates requests from cedros-login to the login-sidecar. This value must also be set as the SIDECAR_API_KEY environment variable on the sidecar container.',\n inputType: 'readonlySecret',\n },\n note_encryption_key: {\n key: 'note_encryption_key',\n label: 'Note Encryption Key',\n description:\n 'AES-256 key for encrypting privacy cash notes (base64). This value must also be set as the NOTE_ENCRYPTION_KEY environment variable on the sidecar container.',\n inputType: 'readonlySecret',\n },\n\n // ============= Post-Login Flow =============\n postlogin_redirect_url: {\n key: 'postlogin_redirect_url',\n label: 'Redirect URL',\n description:\n 'URL to redirect to after login. Leave empty for default behavior (consumer app decides).',\n inputType: 'text',\n placeholder: 'https://example.com/dashboard',\n },\n postlogin_welcome_enabled: {\n key: 'postlogin_welcome_enabled',\n label: 'Enable Welcome Page',\n description:\n 'Show a one-time welcome/onboarding page to new users after their first login.',\n inputType: 'boolean',\n },\n postlogin_welcome_route: {\n key: 'postlogin_welcome_route',\n label: 'Welcome Route',\n description: 'Route for the welcome/onboarding page.',\n inputType: 'text',\n placeholder: '/welcome',\n },\n postlogin_complete_enabled: {\n key: 'postlogin_complete_enabled',\n label: 'Prompt Profile Completion',\n description:\n 'Prompt users to fill in missing name or email after login. Shows every login until the user completes or skips.',\n inputType: 'boolean',\n },\n postlogin_username_enabled: {\n key: 'postlogin_username_enabled',\n label: 'Require Username Selection',\n description:\n 'Prompt new users to choose a unique handle-style username (e.g. @swift_falcon_42) after signup. Shows until the user picks a username or skips.',\n inputType: 'boolean',\n },\n\n // ============= Wallet Enrollment =============\n postlogin_wallet_enroll_enabled: {\n key: 'postlogin_wallet_enroll_enabled',\n label: 'Prompt Wallet Enrollment',\n description:\n 'Prompt users to enroll an embedded wallet after signup. Requires the Embedded Wallet feature to be enabled.',\n inputType: 'boolean',\n },\n wallet_enroll_solana_users: {\n key: 'wallet_enroll_solana_users',\n label: 'Enroll Solana Wallet Users',\n description:\n 'Also prompt Solana wallet users to enroll an embedded wallet. By default they are skipped since they already have a wallet.',\n inputType: 'boolean',\n },\n postlogin_show_recovery_enabled: {\n key: 'postlogin_show_recovery_enabled',\n label: 'Show Recovery Info',\n description:\n 'Show wallet recovery information screen after account creation. Displays recovery phrase based on the configured recovery mode.',\n inputType: 'boolean',\n },\n\n // ============= Image Storage Settings =============\n image_storage_enabled: {\n key: 'image_storage_enabled',\n label: 'Enable Image Storage',\n description:\n 'Enable S3-compatible object storage for user avatar uploads. When disabled, users cannot upload profile pictures.',\n inputType: 'boolean',\n },\n image_storage_provider: {\n key: 'image_storage_provider',\n label: 'Storage Provider',\n description: 'Select your S3-compatible storage provider to auto-fill endpoint and region hints.',\n inputType: 'select',\n presets: [\n { label: 'DigitalOcean Spaces', value: 'digitalocean' },\n { label: 'AWS S3', value: 's3' },\n { label: 'Custom S3-Compatible', value: 'custom' },\n ],\n },\n image_storage_bucket: {\n key: 'image_storage_bucket',\n label: 'Bucket Name',\n description: 'The name of your S3 bucket or DigitalOcean Space.',\n inputType: 'text',\n placeholder: 'my-app-avatars',\n },\n image_storage_region: {\n key: 'image_storage_region',\n label: 'Region',\n description:\n 'AWS region or DigitalOcean datacenter (e.g., us-east-1, nyc3, ams3).',\n inputType: 'text',\n placeholder: 'us-east-1',\n },\n image_storage_endpoint: {\n key: 'image_storage_endpoint',\n label: 'Endpoint URL',\n description:\n 'S3-compatible endpoint URL. For DigitalOcean Spaces: https://{region}.digitaloceanspaces.com. Leave empty for AWS S3.',\n inputType: 'text',\n placeholder: 'https://nyc3.digitaloceanspaces.com',\n },\n image_storage_access_key: {\n key: 'image_storage_access_key',\n label: 'Access Key',\n description: 'S3 access key ID or DigitalOcean Spaces access key.',\n inputType: 'secret',\n },\n image_storage_secret_key: {\n key: 'image_storage_secret_key',\n label: 'Secret Key',\n description: 'S3 secret access key or DigitalOcean Spaces secret key.',\n inputType: 'secret',\n },\n image_storage_cdn_url: {\n key: 'image_storage_cdn_url',\n label: 'CDN URL (optional)',\n description:\n 'Custom CDN URL prefix for serving images (e.g., https://cdn.example.com). If empty, images are served directly from the bucket URL.',\n inputType: 'text',\n placeholder: 'https://cdn.example.com',\n },\n\n // ============= KYC / Identity Verification =============\n kyc_enabled: {\n key: 'kyc_enabled',\n label: 'Enable KYC Verification',\n description: 'Enable identity verification for users via Stripe Identity.',\n inputType: 'boolean',\n },\n kyc_provider: {\n key: 'kyc_provider',\n label: 'KYC Provider',\n description: 'Identity verification provider.',\n inputType: 'select',\n presets: [{ label: 'Stripe Identity', value: 'stripe' }],\n },\n kyc_api_secret_key: {\n key: 'kyc_api_secret_key',\n label: 'Stripe Secret Key',\n description:\n 'Stripe API secret key for Identity API calls (sk_live_... or sk_test_...).',\n inputType: 'secret',\n placeholder: 'sk_...',\n },\n kyc_webhook_secret: {\n key: 'kyc_webhook_secret',\n label: 'Webhook Signing Secret',\n description:\n 'Stripe webhook endpoint secret for verifying webhook signatures (whsec_...).',\n inputType: 'secret',\n placeholder: 'whsec_...',\n },\n kyc_enforcement_mode: {\n key: 'kyc_enforcement_mode',\n label: 'Enforcement Mode',\n description:\n 'When to require KYC verification. \"None\" disables enforcement. \"Optional\" lets users verify voluntarily.',\n inputType: 'select',\n presets: [\n { label: 'None (disabled)', value: 'none' },\n { label: 'Withdrawals only', value: 'withdrawals' },\n { label: 'Deposits only', value: 'deposits' },\n { label: 'All financial operations', value: 'all' },\n { label: 'Optional (user choice)', value: 'optional' },\n ],\n },\n kyc_expiry_days: {\n key: 'kyc_expiry_days',\n label: 'Verification Expiry',\n description:\n 'How long a verification remains valid. Set to 0 for no expiry.',\n inputType: 'select',\n presets: [\n { label: 'Never expires', value: '0' },\n { label: '90 days', value: '90' },\n { label: '365 days', value: '365' },\n ],\n },\n kyc_redirect_url: {\n key: 'kyc_redirect_url',\n label: 'Return URL',\n description:\n 'URL where users are redirected after completing Stripe Identity verification.',\n inputType: 'text',\n placeholder: 'https://app.example.com/kyc/callback',\n },\n kyc_document_types: {\n key: 'kyc_document_types',\n label: 'Accepted Document Types',\n description:\n 'Comma-separated list of accepted document types: driving_license, id_card, passport.',\n inputType: 'text',\n placeholder: 'driving_license,id_card,passport',\n },\n kyc_require_selfie: {\n key: 'kyc_require_selfie',\n label: 'Require Selfie',\n description:\n 'Require a selfie photo that matches the document photo for identity verification.',\n inputType: 'boolean',\n },\n kyc_cumulative_deposit_usd: {\n key: 'kyc_cumulative_deposit_usd',\n label: 'Cumulative Deposit Threshold (USD)',\n description:\n 'Require KYC when a user\\'s total deposits exceed this USD amount. Set to 0 to disable. Works independently of enforcement mode.',\n inputType: 'text',\n placeholder: '0',\n unit: 'USD',\n },\n kyc_single_deposit_usd: {\n key: 'kyc_single_deposit_usd',\n label: 'Single Deposit Threshold (USD)',\n description:\n 'Require KYC when any individual deposit exceeds this USD amount. Set to 0 to disable. Works independently of enforcement mode.',\n inputType: 'text',\n placeholder: '0',\n unit: 'USD',\n },\n kyc_single_purchase_usd: {\n key: 'kyc_single_purchase_usd',\n label: 'Single Purchase Threshold (USD)',\n description:\n 'Require KYC when any individual credit spend/purchase exceeds this USD amount. Set to 0 to disable. Works independently of enforcement mode.',\n inputType: 'text',\n placeholder: '0',\n unit: 'USD',\n },\n\n // ============= Sanctions Screening =============\n sanctions_enabled: {\n key: 'sanctions_enabled',\n label: 'Enable Sanctions Screening',\n description:\n 'Block transactions to or from wallet addresses that appear on the sanctions list fetched from the configured API URL.',\n inputType: 'boolean',\n },\n sanctions_api_url: {\n key: 'sanctions_api_url',\n label: 'Sanctions API URL',\n description:\n 'Base URL for the sanctions list API (e.g. <code>https://sunscreen.cedros.io</code>). The service calls <code>GET {url}/v1/lists</code>.',\n inputType: 'text',\n placeholder: 'https://sunscreen.cedros.io',\n },\n sanctions_refresh_interval_secs: {\n key: 'sanctions_refresh_interval_secs',\n label: 'Refresh Interval',\n description: 'How often to re-fetch the sanctions list. Minimum 60 seconds.',\n inputType: 'text',\n unit: 'seconds',\n placeholder: '3600',\n },\n sanctions_geoip_header: {\n key: 'sanctions_geoip_header',\n label: 'GeoIP Country Header',\n description:\n 'HTTP header containing the client\\'s ISO country code. Common values: <code>CF-IPCountry</code> (Cloudflare), <code>X-Vercel-IP-Country</code> (Vercel). Leave empty to disable country screening.',\n inputType: 'text',\n placeholder: 'CF-IPCountry',\n },\n\n // ============= Accredited Investor Verification =============\n accreditation_enabled: {\n key: 'accreditation_enabled',\n label: 'Enable Accreditation Verification',\n description: 'Enable accredited investor self-service verification.',\n inputType: 'boolean',\n },\n accreditation_enforcement_mode: {\n key: 'accreditation_enforcement_mode',\n label: 'Enforcement Mode',\n description: 'When to require accreditation.',\n inputType: 'select',\n presets: [\n { label: 'None (disabled)', value: 'none' },\n { label: 'Optional (user choice)', value: 'optional' },\n { label: 'Required', value: 'required' },\n ],\n },\n accreditation_default_expiry_days_income: {\n key: 'accreditation_default_expiry_days_income',\n label: 'Income/Net Worth Expiry',\n description: 'Default validity for income and net worth verifications.',\n inputType: 'text',\n unit: 'days',\n placeholder: '365',\n },\n accreditation_default_expiry_days_letter: {\n key: 'accreditation_default_expiry_days_letter',\n label: 'Letter Expiry',\n description: 'Default validity for third-party verification letters.',\n inputType: 'text',\n unit: 'days',\n placeholder: '90',\n },\n accreditation_default_expiry_days_credential: {\n key: 'accreditation_default_expiry_days_credential',\n label: 'Credential Expiry',\n description: 'Default validity for FINRA credential verifications.',\n inputType: 'text',\n unit: 'days',\n placeholder: '365',\n },\n accreditation_max_upload_size_mb: {\n key: 'accreditation_max_upload_size_mb',\n label: 'Max Upload Size',\n description: 'Maximum file size per document upload.',\n inputType: 'text',\n unit: 'MB',\n placeholder: '10',\n },\n accreditation_income_threshold_individual: {\n key: 'accreditation_income_threshold_individual',\n label: 'Income Threshold (Individual)',\n description: 'Annual income threshold for individual accreditation (USD).',\n inputType: 'text',\n unit: 'USD',\n placeholder: '200000',\n },\n accreditation_income_threshold_joint: {\n key: 'accreditation_income_threshold_joint',\n label: 'Income Threshold (Joint)',\n description: 'Annual income threshold for joint accreditation (USD).',\n inputType: 'text',\n unit: 'USD',\n placeholder: '300000',\n },\n accreditation_net_worth_threshold: {\n key: 'accreditation_net_worth_threshold',\n label: 'Net Worth Threshold',\n description: 'Net worth threshold excluding primary residence (USD).',\n inputType: 'text',\n unit: 'USD',\n placeholder: '1000000',\n },\n accreditation_investment_threshold_individual: {\n key: 'accreditation_investment_threshold_individual',\n label: 'Investment Threshold (Individual)',\n description:\n 'Minimum investment commitment for individual simplified verification (USD).',\n inputType: 'text',\n unit: 'USD',\n placeholder: '200000',\n },\n accreditation_investment_threshold_entity: {\n key: 'accreditation_investment_threshold_entity',\n label: 'Investment Threshold (Entity)',\n description:\n 'Minimum investment commitment for entity simplified verification (USD).',\n inputType: 'text',\n unit: 'USD',\n placeholder: '1000000',\n },\n\n // ============= Token Gating =============\n token_gating_enabled: {\n key: 'token_gating_enabled',\n label: 'Enable Token Gating',\n description: 'Require Solana wallet holdings for access.',\n inputType: 'boolean',\n },\n token_gating_rpc_url: {\n key: 'token_gating_rpc_url',\n label: 'Solana RPC/DAS URL',\n description: 'RPC endpoint that supports DAS API for NFT queries.',\n inputType: 'secret',\n placeholder: 'https://mainnet.helius-rpc.com/?api-key=...',\n },\n token_gating_rules: {\n key: 'token_gating_rules',\n label: 'Token Gate Rules',\n description: 'JSON array of gate rules. Managed via admin API.',\n inputType: 'text',\n multiline: true,\n placeholder: '[]',\n },\n token_gating_cache_ttl_secs: {\n key: 'token_gating_cache_ttl_secs',\n label: 'Cache TTL',\n description: 'How long to cache wallet holdings (seconds).',\n inputType: 'text',\n unit: 'seconds',\n placeholder: '60',\n },\n};\n\n// =============================================================================\n// CATEGORY METADATA\n// =============================================================================\n\nexport interface CategoryMeta {\n label: string;\n description: string;\n icon: string;\n}\n\nexport const CATEGORY_METADATA: Record<string, CategoryMeta> = {\n // Auth providers (sorted alphabetically by subcategory)\n 'auth.apple': {\n label: 'Apple Sign-In',\n description: 'Configure Sign in with Apple OAuth integration.',\n icon: '',\n },\n 'auth.email': {\n label: 'Email Authentication',\n description: 'Configure email/password authentication settings.',\n icon: '',\n },\n 'auth.google': {\n label: 'Google Sign-In',\n description: 'Configure Google OAuth integration.',\n icon: '',\n },\n 'auth.solana': {\n label: 'Solana Wallet Auth',\n description: 'Configure Solana wallet signature authentication.',\n icon: '',\n },\n 'auth.webauthn': {\n label: 'WebAuthn / Passkeys',\n description: 'Configure FIDO2/WebAuthn passwordless authentication.',\n icon: '',\n },\n 'auth.instantlink': {\n label: 'Instant Link',\n description:\n 'Passwordless sign-in via email link. Replaces \"Forgot your password?\" with a one-time login link instead of a password reset.',\n icon: '',\n },\n 'deposit.general': {\n label: 'General',\n description: 'Core deposit and credit system configuration.',\n icon: '',\n },\n postlogin: {\n label: 'Post-Login',\n description: 'Configure what happens after a user logs in.',\n icon: '',\n },\n 'postlogin.welcome': {\n label: 'Welcome Page',\n description: 'One-time onboarding page shown to new users after first login.',\n icon: '',\n },\n 'postlogin.complete': {\n label: 'Profile Completion',\n description: 'Prompt users to fill in missing profile information.',\n icon: '',\n },\n 'postlogin.username': {\n label: 'Username Selection',\n description: 'Prompt users to choose a unique handle-style username.',\n icon: '',\n },\n 'postlogin.wallet': {\n label: 'Wallet Enrollment',\n description: 'Prompt users to enroll an embedded wallet after signup.',\n icon: '',\n },\n deposit: {\n label: 'Deposit Settings',\n description: 'Configure deposit tokens, fees, and related settings.',\n icon: '',\n },\n email: {\n label: 'Email / SMTP',\n description:\n 'Configure outbound email delivery for verification, password reset, and notifications.',\n icon: '',\n },\n features: {\n label: 'Feature Flags',\n description: 'Enable or disable major platform features.',\n icon: '',\n },\n privacy: {\n label: 'Privacy Settings',\n description:\n 'Control the privacy period for deposits. Longer periods provide better timing privacy but delay fund availability.',\n icon: '',\n },\n referral: {\n label: 'Referral & Payouts',\n description:\n 'Configure referral rewards, payout triggers, and the automated payout worker.',\n icon: '',\n },\n rate_limit: {\n label: 'Rate Limiting',\n description:\n 'Protect the system from abuse by limiting request rates. Balance security with user experience.',\n icon: '',\n },\n security: {\n label: 'Security',\n description: 'Configure CORS, cookies, sessions, and JWT settings.',\n icon: '',\n },\n server: {\n label: 'Server',\n description: 'Server infrastructure settings. Some may be overridden by environment variables.',\n icon: '',\n },\n webhook: {\n label: 'Webhooks',\n description: 'Configure HTTP webhook notifications for auth events.',\n icon: '',\n },\n withdrawal: {\n label: 'Withdrawal Worker',\n description:\n 'Configure how the automated withdrawal processor handles pending withdrawals. These settings affect throughput and privacy.',\n icon: '',\n },\n image_storage: {\n label: 'Image Storage',\n description:\n 'Configure S3-compatible object storage for user avatars and images.',\n icon: '',\n },\n kyc: {\n label: 'KYC / Identity Verification',\n description:\n 'Configure identity verification requirements using Stripe Identity.',\n icon: '',\n },\n sanctions: {\n label: 'Sanctions Screening',\n description:\n 'Block transactions involving wallet addresses on OFAC or custom sanctions lists.',\n icon: '',\n },\n accreditation: {\n label: 'Accredited Investor Verification',\n description:\n 'Configure accredited investor verification requirements and thresholds per SEC Regulation D.',\n icon: '',\n },\n token_gating: {\n label: 'Token Gating',\n description: 'Configure Solana wallet holdings requirements for gated access.',\n icon: '',\n },\n};\n\n/** Preset tokens that are always available without needing to be redefined */\nexport const PRESET_TOKEN_SYMBOLS = [\n 'SOL',\n 'USDC',\n 'USDT',\n 'EURC',\n 'USD1',\n 'PYUSD',\n 'USDH',\n 'CASH',\n 'BONK',\n 'ORE',\n];\n","/**\n * Settings input components - reusable inputs for system settings\n */\nimport { useState, useCallback, useMemo, type ReactNode } from 'react';\nimport type { SystemSetting, SettingMeta } from '../../../types';\nimport { formatDuration, SETTING_METADATA, PRESET_TOKEN_SYMBOLS } from './settingsMetadata';\nimport { useCedrosLogin as useCedrosLoginContext } from '../../../context/useCedrosLogin';\n\n/** UI-01: Safely render description text that may contain simple <a> tags */\nfunction renderDescription(html: string): ReactNode {\n // Split on <a href=\"...\">...</a> pattern, render links as React elements\n const parts = html.split(/(<a\\s[^>]*>.*?<\\/a>)/g);\n if (parts.length === 1) return html;\n return parts.map((part, i) => {\n const match = part.match(/^<a\\s+href=\"([^\"]+)\"[^>]*>([^<]+)<\\/a>$/);\n if (match) {\n return (\n <a key={i} href={match[1]} target=\"_blank\" rel=\"noopener noreferrer\">\n {match[2]}\n </a>\n );\n }\n return part;\n });\n}\n\n// =============================================================================\n// SETTINGS SECTION\n// =============================================================================\n\nexport interface SettingsSectionProps {\n settings: SystemSetting[];\n edits: Record<string, string>;\n onChange: (key: string, value: string) => void;\n /** External warnings keyed by setting key */\n externalWarnings?: Record<string, string>;\n}\n\nexport function SettingsSection({\n settings,\n edits,\n onChange,\n externalWarnings,\n}: SettingsSectionProps) {\n return (\n <div className=\"cedros-settings-grid\">\n {settings.map((setting) => (\n <SettingRow\n key={setting.key}\n setting={setting}\n editValue={edits[setting.key]}\n onChange={onChange}\n externalWarning={externalWarnings?.[setting.key]}\n />\n ))}\n </div>\n );\n}\n\n// =============================================================================\n// SETTING ROW\n// =============================================================================\n\ninterface SettingRowProps {\n setting: SystemSetting;\n editValue?: string;\n onChange: (key: string, value: string) => void;\n /** External warning message that overrides threshold-based warnings */\n externalWarning?: string;\n}\n\nexport function SettingRow({ setting, editValue, onChange, externalWarning }: SettingRowProps) {\n const meta = SETTING_METADATA[setting.key];\n const currentValue = editValue ?? setting.value;\n const hasChange = editValue !== undefined && editValue !== setting.value;\n const isBoolean = meta?.inputType === 'boolean';\n\n // Check for warnings (external warnings take precedence)\n const warning = useMemo(() => {\n if (externalWarning) return externalWarning;\n if (!meta?.warningThreshold) return null;\n const numValue = parseInt(currentValue, 10);\n if (isNaN(numValue)) return null;\n const { above, below, message } = meta.warningThreshold;\n if (above !== undefined && numValue > above) return message;\n if (below !== undefined && numValue < below) return message;\n return null;\n }, [currentValue, meta?.warningThreshold, externalWarning]);\n\n if (!meta) {\n // Fallback for unknown settings\n return (\n <div className={`cedros-setting-row ${hasChange ? 'cedros-setting-row-changed' : ''}`}>\n <div className=\"cedros-setting-label\">\n <span className=\"cedros-setting-name\">{setting.key}</span>\n {setting.description && (\n <span className=\"cedros-setting-description\">{setting.description}</span>\n )}\n </div>\n <div className=\"cedros-setting-input-wrapper\">\n <input\n type=\"text\"\n value={currentValue}\n onChange={(e) => onChange(setting.key, e.target.value)}\n className=\"cedros-setting-input\"\n />\n </div>\n </div>\n );\n }\n\n return (\n <div\n className={`cedros-setting-row ${hasChange ? 'cedros-setting-row-changed' : ''} ${warning ? 'cedros-setting-row-warning' : ''} ${isBoolean ? 'cedros-setting-row-toggle' : ''}`}\n >\n {isBoolean ? (\n <>\n <div className=\"cedros-setting-control cedros-setting-control-toggle\">\n <SettingInput\n meta={meta}\n value={currentValue}\n onChange={(value) => onChange(setting.key, value)}\n />\n {warning && <div className=\"cedros-setting-warning\">{warning}</div>}\n </div>\n <div className=\"cedros-setting-label\">\n <span className=\"cedros-setting-name\">{meta.label}</span>\n <span className=\"cedros-setting-description\">\n {renderDescription(meta.description)}\n </span>\n </div>\n </>\n ) : (\n <>\n <div className=\"cedros-setting-label\">\n <span className=\"cedros-setting-name\">{meta.label}</span>\n <span className=\"cedros-setting-description\">\n {renderDescription(meta.description)}\n </span>\n </div>\n\n <div className=\"cedros-setting-control\">\n <SettingInput\n meta={meta}\n value={currentValue}\n onChange={(value) => onChange(setting.key, value)}\n />\n {warning && <div className=\"cedros-setting-warning\">{warning}</div>}\n </div>\n </>\n )}\n </div>\n );\n}\n\n// =============================================================================\n// SETTING INPUT - Renders the appropriate input based on type\n// =============================================================================\n\ninterface SettingInputProps {\n meta: SettingMeta;\n value: string;\n onChange: (value: string) => void;\n}\n\nfunction SettingInput({ meta, value, onChange }: SettingInputProps) {\n switch (meta.inputType) {\n case 'duration':\n return (\n <DurationInput value={value} onChange={onChange} presets={meta.presets} min={meta.min} />\n );\n case 'percentage':\n return (\n <PercentageInput\n value={value}\n onChange={onChange}\n min={meta.min ?? 1}\n max={meta.max ?? 100}\n step={meta.step ?? 5}\n presets={meta.presets}\n />\n );\n case 'select':\n return (\n <SelectInput\n value={value}\n onChange={onChange}\n presets={meta.presets ?? []}\n unit={meta.unit}\n />\n );\n case 'number':\n return (\n <NumberInput\n value={value}\n onChange={onChange}\n min={meta.min}\n max={meta.max}\n unit={meta.unit}\n />\n );\n case 'tokenList':\n return <TokenListInput value={value} onChange={onChange} />;\n case 'text':\n return (\n <input\n type=\"text\"\n value={value}\n onChange={(e) => onChange(e.target.value)}\n className=\"cedros-setting-input\"\n placeholder={meta.label}\n />\n );\n case 'boolean':\n return <BooleanInput value={value} onChange={onChange} />;\n case 'secret':\n return <SecretInput value={value} onChange={onChange} multiline={meta.multiline} />;\n case 'readonlySecret':\n return <ReadonlySecretInput settingKey={meta.key} value={value} />;\n case 'tokenSymbolList':\n return <TokenSymbolListInput value={value} onChange={onChange} />;\n default:\n return (\n <input\n type=\"text\"\n value={value}\n onChange={(e) => onChange(e.target.value)}\n className=\"cedros-setting-input\"\n />\n );\n }\n}\n\n// =============================================================================\n// DURATION INPUT\n// =============================================================================\n\ninterface DurationInputProps {\n value: string;\n onChange: (value: string) => void;\n presets?: { label: string; value: string }[];\n min?: number;\n}\n\nexport function DurationInput({ value, onChange, presets, min = 0 }: DurationInputProps) {\n const numValue = parseInt(value, 10) || 0;\n const displayValue = formatDuration(numValue);\n\n const handlePresetChange = useCallback(\n (e: React.ChangeEvent<HTMLSelectElement>) => {\n if (e.target.value) {\n onChange(e.target.value);\n }\n },\n [onChange]\n );\n\n const handleCustomChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = Math.max(min, parseInt(e.target.value, 10) || 0);\n onChange(String(newValue));\n },\n [onChange, min]\n );\n\n return (\n <div className=\"cedros-duration-input\">\n {presets && presets.length > 0 && (\n <select\n value={presets.find((p) => p.value === value)?.value ?? ''}\n onChange={handlePresetChange}\n className=\"cedros-setting-select\"\n >\n <option value=\"\">Custom...</option>\n {presets.map((preset) => (\n <option key={preset.value} value={preset.value}>\n {preset.label}\n </option>\n ))}\n </select>\n )}\n <div className=\"cedros-duration-custom\">\n <input\n type=\"number\"\n value={numValue}\n onChange={handleCustomChange}\n min={min}\n className=\"cedros-setting-input cedros-setting-input-sm\"\n />\n <span className=\"cedros-setting-unit\">seconds</span>\n <span className=\"cedros-duration-display\">= {displayValue}</span>\n </div>\n </div>\n );\n}\n\n// =============================================================================\n// PERCENTAGE INPUT\n// =============================================================================\n\ninterface PercentageInputProps {\n value: string;\n onChange: (value: string) => void;\n min: number;\n max: number;\n step: number;\n presets?: { label: string; value: string }[];\n}\n\nexport function PercentageInput({\n value,\n onChange,\n min,\n max,\n step,\n presets,\n}: PercentageInputProps) {\n const numValue = parseInt(value, 10) || min;\n\n const handleSliderChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n onChange(e.target.value);\n },\n [onChange]\n );\n\n const handlePresetClick = useCallback(\n (presetValue: string) => {\n onChange(presetValue);\n },\n [onChange]\n );\n\n return (\n <div className=\"cedros-percentage-input\">\n <div className=\"cedros-percentage-slider-row\">\n <input\n type=\"range\"\n value={numValue}\n onChange={handleSliderChange}\n min={min}\n max={max}\n step={step}\n className=\"cedros-percentage-slider\"\n />\n <span className=\"cedros-percentage-value\">{numValue}%</span>\n </div>\n {presets && presets.length > 0 && (\n <div className=\"cedros-preset-buttons\">\n {presets.map((preset) => (\n <button\n key={preset.value}\n type=\"button\"\n className={`cedros-preset-button ${preset.value === value ? 'cedros-preset-button-active' : ''}`}\n onClick={() => handlePresetClick(preset.value)}\n >\n {preset.label}\n </button>\n ))}\n </div>\n )}\n </div>\n );\n}\n\n// =============================================================================\n// SELECT INPUT\n// =============================================================================\n\ninterface SelectInputProps {\n value: string;\n onChange: (value: string) => void;\n presets: { label: string; value: string }[];\n unit?: string;\n}\n\nexport function SelectInput({ value, onChange, presets, unit }: SelectInputProps) {\n const isCustomValue = !presets.some((p) => p.value === value);\n\n const handleSelectChange = useCallback(\n (e: React.ChangeEvent<HTMLSelectElement>) => {\n if (e.target.value !== '__custom__') {\n onChange(e.target.value);\n }\n },\n [onChange]\n );\n\n const handleCustomChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n onChange(e.target.value);\n },\n [onChange]\n );\n\n return (\n <div className=\"cedros-select-input\">\n <select\n value={isCustomValue ? '__custom__' : value}\n onChange={handleSelectChange}\n className=\"cedros-setting-select\"\n >\n {presets.map((preset) => (\n <option key={preset.value} value={preset.value}>\n {preset.label}\n </option>\n ))}\n <option value=\"__custom__\">Custom...</option>\n </select>\n {isCustomValue && (\n <div className=\"cedros-select-custom\">\n <input\n type=\"number\"\n value={value}\n onChange={handleCustomChange}\n className=\"cedros-setting-input cedros-setting-input-sm\"\n />\n {unit && <span className=\"cedros-setting-unit\">{unit}</span>}\n </div>\n )}\n </div>\n );\n}\n\n// =============================================================================\n// NUMBER INPUT\n// =============================================================================\n\ninterface NumberInputProps {\n value: string;\n onChange: (value: string) => void;\n min?: number;\n max?: number;\n unit?: string;\n}\n\nexport function NumberInput({ value, onChange, min, max, unit }: NumberInputProps) {\n const handleChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n onChange(e.target.value);\n },\n [onChange]\n );\n\n return (\n <div className=\"cedros-number-input\">\n <input\n type=\"number\"\n value={value}\n onChange={handleChange}\n min={min}\n max={max}\n className=\"cedros-setting-input\"\n />\n {unit && <span className=\"cedros-setting-unit\">{unit}</span>}\n </div>\n );\n}\n\n// =============================================================================\n// BOOLEAN INPUT (Toggle)\n// =============================================================================\n\ninterface BooleanInputProps {\n value: string;\n onChange: (value: string) => void;\n}\n\nexport function BooleanInput({ value, onChange }: BooleanInputProps) {\n const isEnabled = value === 'true';\n\n const handleToggle = useCallback(() => {\n onChange(isEnabled ? 'false' : 'true');\n }, [isEnabled, onChange]);\n\n return (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={isEnabled}\n className={`cedros-toggle ${isEnabled ? 'cedros-toggle-on' : 'cedros-toggle-off'}`}\n onClick={handleToggle}\n >\n <span className=\"cedros-toggle-track\">\n <span className=\"cedros-toggle-thumb\" />\n </span>\n <span className=\"cedros-toggle-label\">{isEnabled ? 'Enabled' : 'Disabled'}</span>\n </button>\n );\n}\n\n// =============================================================================\n// SECRET INPUT (Masked)\n// =============================================================================\n\ninterface SecretInputProps {\n value: string;\n onChange: (value: string) => void;\n multiline?: boolean;\n}\n\nexport function SecretInput({ value, onChange, multiline }: SecretInputProps) {\n const [isEditing, setIsEditing] = useState(false);\n const [showValue, setShowValue] = useState(false);\n const hasValue = value && value.length > 0;\n\n const handleEdit = useCallback(() => {\n setIsEditing(true);\n setShowValue(true);\n }, []);\n\n const handleDone = useCallback(() => {\n setIsEditing(false);\n setShowValue(false);\n }, []);\n\n const handleChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {\n onChange(e.target.value);\n },\n [onChange]\n );\n\n if (!isEditing && hasValue) {\n return (\n <div className=\"cedros-secret-input cedros-secret-input-masked\">\n <span className=\"cedros-secret-masked\">{'•'.repeat(Math.min(value.length, 20))}</span>\n <button type=\"button\" className=\"cedros-secret-edit-btn\" onClick={handleEdit}>\n Edit\n </button>\n </div>\n );\n }\n\n return (\n <div className=\"cedros-secret-input\">\n {multiline ? (\n <textarea\n value={value}\n onChange={handleChange}\n className=\"cedros-setting-input cedros-setting-textarea\"\n placeholder=\"Enter secret value...\"\n rows={4}\n />\n ) : (\n <input\n type={showValue ? 'text' : 'password'}\n value={value}\n onChange={handleChange}\n className=\"cedros-setting-input\"\n placeholder=\"Enter secret value...\"\n />\n )}\n <div className=\"cedros-secret-actions\">\n {!multiline && (\n <button\n type=\"button\"\n className=\"cedros-secret-toggle-btn\"\n onClick={() => setShowValue(!showValue)}\n >\n {showValue ? 'Hide' : 'Show'}\n </button>\n )}\n {isEditing && (\n <button type=\"button\" className=\"cedros-secret-done-btn\" onClick={handleDone}>\n Done\n </button>\n )}\n </div>\n </div>\n );\n}\n\n// =============================================================================\n// READONLY SECRET INPUT (copy + regenerate)\n// =============================================================================\n\ninterface ReadonlySecretInputProps {\n /** The setting key (e.g., \"sidecar_api_key\") — used for the regenerate API call */\n settingKey: string;\n /** Current (possibly encrypted/masked) value from the settings store */\n value: string;\n}\n\n/**\n * Read-only secret field with Copy and Regenerate buttons.\n * Used for auto-generated sidecar secrets that the admin copies into deploy env vars.\n */\nexport function ReadonlySecretInput({ settingKey, value }: ReadonlySecretInputProps) {\n const [revealed, setRevealed] = useState<string | null>(null);\n const [copied, setCopied] = useState(false);\n const [isRegenerating, setIsRegenerating] = useState(false);\n const [regenerateError, setRegenerateError] = useState<string | null>(null);\n const [showConfirm, setShowConfirm] = useState(false);\n const { config, _internal } = useCedrosLoginContext();\n\n const displayValue = revealed ?? value;\n const hasValue = displayValue && displayValue.length > 0;\n const masked = hasValue && !revealed;\n\n const handleCopy = useCallback(async () => {\n if (!displayValue) return;\n try {\n await navigator.clipboard.writeText(displayValue);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n } catch {\n // Fallback for insecure contexts\n const textarea = document.createElement('textarea');\n textarea.value = displayValue;\n document.body.appendChild(textarea);\n textarea.select();\n document.execCommand('copy');\n document.body.removeChild(textarea);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n }\n }, [displayValue]);\n\n const handleRegenerate = useCallback(async () => {\n setIsRegenerating(true);\n setRegenerateError(null);\n try {\n const token = _internal?.getAccessToken?.();\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (token) headers['Authorization'] = `Bearer ${token}`;\n\n const response = await fetch(\n `${config.serverUrl}/auth/admin/settings/regenerate/${settingKey}`,\n { method: 'POST', headers, credentials: 'include' }\n );\n\n if (!response.ok) {\n const body = await response.json().catch(() => null);\n throw new Error(body?.message || body?.error || `Regenerate failed (${response.status})`);\n }\n\n const data: { key: string; value: string } = await response.json();\n setRevealed(data.value);\n setShowConfirm(false);\n } catch (err) {\n setRegenerateError(err instanceof Error ? err.message : 'Failed to regenerate');\n } finally {\n setIsRegenerating(false);\n }\n }, [config.serverUrl, _internal, settingKey]);\n\n return (\n <div className=\"cedros-readonly-secret\">\n <div className=\"cedros-readonly-secret-value\">\n {masked ? (\n <span className=\"cedros-secret-masked\">{'•'.repeat(20)}</span>\n ) : hasValue ? (\n <code className=\"cedros-readonly-secret-code\">{displayValue}</code>\n ) : (\n <span className=\"cedros-readonly-secret-empty\">Not generated yet</span>\n )}\n </div>\n <div className=\"cedros-readonly-secret-actions\">\n {hasValue && (\n <button type=\"button\" className=\"cedros-secret-action-btn\" onClick={handleCopy}>\n {copied ? 'Copied!' : 'Copy'}\n </button>\n )}\n {!showConfirm ? (\n <button\n type=\"button\"\n className=\"cedros-secret-action-btn cedros-secret-action-btn--danger\"\n onClick={() => setShowConfirm(true)}\n disabled={isRegenerating}\n >\n Regenerate\n </button>\n ) : (\n <span className=\"cedros-readonly-secret-confirm\">\n <span className=\"cedros-readonly-secret-confirm-text\">\n Update deploy secret too?\n </span>\n <button\n type=\"button\"\n className=\"cedros-secret-action-btn cedros-secret-action-btn--danger\"\n onClick={handleRegenerate}\n disabled={isRegenerating}\n >\n {isRegenerating ? 'Regenerating...' : 'Confirm'}\n </button>\n <button\n type=\"button\"\n className=\"cedros-secret-action-btn\"\n onClick={() => setShowConfirm(false)}\n disabled={isRegenerating}\n >\n Cancel\n </button>\n </span>\n )}\n </div>\n {regenerateError && (\n <p className=\"cedros-readonly-secret-error\">{regenerateError}</p>\n )}\n </div>\n );\n}\n\n// =============================================================================\n// TOKEN LIST INPUT\n// =============================================================================\n\ninterface TokenDefinition {\n symbol: string;\n mint: string;\n decimals: number;\n logoUrl?: string;\n}\n\ninterface TokenListInputProps {\n value: string;\n onChange: (value: string) => void;\n}\n\nexport function TokenListInput({ value, onChange }: TokenListInputProps) {\n const tokens: TokenDefinition[] = useMemo(() => {\n try {\n return JSON.parse(value || '[]');\n } catch {\n return [];\n }\n }, [value]);\n\n const updateTokens = useCallback(\n (updated: TokenDefinition[]) => {\n onChange(JSON.stringify(updated));\n },\n [onChange]\n );\n\n const addToken = useCallback(() => {\n updateTokens([...tokens, { symbol: '', mint: '', decimals: 6 }]);\n }, [tokens, updateTokens]);\n\n const updateToken = useCallback(\n (index: number, field: keyof TokenDefinition, val: string | number | undefined) => {\n const updated = [...tokens];\n updated[index] = { ...updated[index], [field]: val };\n updateTokens(updated);\n },\n [tokens, updateTokens]\n );\n\n const removeToken = useCallback(\n (index: number) => {\n updateTokens(tokens.filter((_, i) => i !== index));\n },\n [tokens, updateTokens]\n );\n\n return (\n <div className=\"cedros-token-list-input\">\n {/* Preset tokens info */}\n <div className=\"cedros-token-presets\">\n <span className=\"cedros-token-presets-label\">Built-in tokens:</span>\n <div className=\"cedros-token-presets-list\">\n {PRESET_TOKEN_SYMBOLS.map((symbol) => (\n <span key={symbol} className=\"cedros-token-preset-chip\">\n {symbol}\n </span>\n ))}\n </div>\n </div>\n\n {tokens.length === 0 && (\n <p className=\"cedros-token-list-empty\">\n No custom tokens added. Use the built-in tokens above or add your own.\n </p>\n )}\n\n {tokens.map((token, i) => (\n <div key={i} className=\"cedros-token-row\">\n <div className=\"cedros-token-row-fields\">\n <input\n type=\"text\"\n placeholder=\"Symbol\"\n value={token.symbol}\n onChange={(e) => updateToken(i, 'symbol', e.target.value.toUpperCase())}\n className=\"cedros-setting-input cedros-token-input-symbol\"\n maxLength={10}\n />\n <input\n type=\"text\"\n placeholder=\"Mint address\"\n value={token.mint}\n onChange={(e) => updateToken(i, 'mint', e.target.value)}\n className=\"cedros-setting-input cedros-token-input-mint\"\n />\n <input\n type=\"number\"\n placeholder=\"Decimals\"\n value={token.decimals}\n onChange={(e) => updateToken(i, 'decimals', parseInt(e.target.value, 10) || 0)}\n className=\"cedros-setting-input cedros-token-input-decimals\"\n min={0}\n max={18}\n />\n <input\n type=\"text\"\n placeholder=\"Logo URL (optional)\"\n value={token.logoUrl || ''}\n onChange={(e) => updateToken(i, 'logoUrl', e.target.value || undefined)}\n className=\"cedros-setting-input cedros-token-input-logo\"\n />\n </div>\n <button\n type=\"button\"\n className=\"cedros-token-remove-btn\"\n onClick={() => removeToken(i)}\n title=\"Remove token\"\n >\n ×\n </button>\n </div>\n ))}\n\n <button type=\"button\" className=\"cedros-token-add-btn\" onClick={addToken}>\n + Add Token\n </button>\n </div>\n );\n}\n\n// =============================================================================\n// TOKEN SYMBOL LIST INPUT\n// =============================================================================\n\ninterface TokenSymbolListInputProps {\n value: string;\n onChange: (value: string) => void;\n}\n\nexport function TokenSymbolListInput({ value, onChange }: TokenSymbolListInputProps) {\n const symbols = useMemo(() => {\n return value\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n }, [value]);\n\n const addSymbol = useCallback(\n (symbol: string) => {\n if (!symbol || symbols.includes(symbol)) return;\n const updated = [...symbols, symbol].join(', ');\n onChange(updated);\n },\n [symbols, onChange]\n );\n\n const removeSymbol = useCallback(\n (symbol: string) => {\n const updated = symbols.filter((s) => s !== symbol).join(', ');\n onChange(updated);\n },\n [symbols, onChange]\n );\n\n return (\n <div className=\"cedros-token-symbol-list-input\">\n {/* Preset tokens - click to add */}\n <div className=\"cedros-token-presets\">\n <span className=\"cedros-token-presets-label\">Click to add:</span>\n <div className=\"cedros-token-presets-list\">\n {PRESET_TOKEN_SYMBOLS.map((symbol) => {\n const isSelected = symbols.includes(symbol);\n return (\n <button\n key={symbol}\n type=\"button\"\n className={`cedros-token-preset-chip ${isSelected ? 'cedros-token-preset-chip-selected' : ''}`}\n onClick={() => (isSelected ? removeSymbol(symbol) : addSymbol(symbol))}\n title={isSelected ? `Remove ${symbol}` : `Add ${symbol}`}\n >\n {symbol}\n {isSelected && <span className=\"cedros-token-chip-check\">✓</span>}\n </button>\n );\n })}\n </div>\n </div>\n\n {/* Text input for manual entry or custom symbols */}\n <input\n type=\"text\"\n value={value}\n onChange={(e) => onChange(e.target.value)}\n className=\"cedros-setting-input\"\n placeholder=\"USDC, SOL, BONK...\"\n />\n </div>\n );\n}\n","import { useState, useCallback, useEffect, useRef } from 'react';\nimport type { UpdateSettingRequest } from '../types';\nimport { useSystemSettings } from './useSystemSettings';\n\n/** Autosave status */\nexport type AutosaveStatus = 'idle' | 'pending' | 'saving' | 'saved' | 'error';\n\n/** Debounce delay in milliseconds */\nconst DEBOUNCE_MS = 800;\n\n/** How long to show \"saved\" status before returning to idle */\nconst SAVED_DISPLAY_MS = 2000;\n\nexport interface UseSettingsAutosaveReturn {\n /** Settings grouped by category */\n settings: Record<string, import('../types').SystemSetting[]>;\n /** Current edits (key -> value) */\n edits: Record<string, string>;\n /** Whether initial load is in progress */\n isLoading: boolean;\n /** Current autosave status */\n autosaveStatus: AutosaveStatus;\n /** Error message if autosave failed */\n autosaveError: string | null;\n /** Loading error */\n error: Error | null;\n /** Fetch settings from server */\n fetchSettings: () => Promise<void>;\n /** Handle a setting change (triggers autosave) */\n handleChange: (key: string, value: string) => void;\n /** Get effective value (edit or original) */\n getEffectiveValue: (key: string) => string;\n}\n\n/**\n * Hook for managing system settings with autosave.\n *\n * Automatically saves changes after a debounce period.\n * Provides status feedback for the autosave process.\n */\nexport function useSettingsAutosave(): UseSettingsAutosaveReturn {\n const { settings, isLoading, error, fetchSettings, updateSettings } = useSystemSettings();\n\n const [edits, setEdits] = useState<Record<string, string>>({});\n const [autosaveStatus, setAutosaveStatus] = useState<AutosaveStatus>('idle');\n const [autosaveError, setAutosaveError] = useState<string | null>(null);\n\n // Refs for debounce timer and pending edits\n const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const savedTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const pendingEditsRef = useRef<Record<string, string>>({});\n\n // Cleanup timers on unmount\n useEffect(() => {\n return () => {\n if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);\n if (savedTimerRef.current) clearTimeout(savedTimerRef.current);\n };\n }, []);\n\n // Perform the actual save\n const performSave = useCallback(async () => {\n const editsToSave = { ...pendingEditsRef.current };\n if (Object.keys(editsToSave).length === 0) {\n setAutosaveStatus('idle');\n return;\n }\n\n setAutosaveStatus('saving');\n setAutosaveError(null);\n\n const updates: UpdateSettingRequest[] = Object.entries(editsToSave).map(([key, value]) => ({\n key,\n value,\n }));\n\n try {\n await updateSettings(updates);\n\n // Clear saved edits from state\n setEdits((prev) => {\n const next = { ...prev };\n for (const key of Object.keys(editsToSave)) {\n delete next[key];\n }\n return next;\n });\n\n // Clear from pending ref\n for (const key of Object.keys(editsToSave)) {\n delete pendingEditsRef.current[key];\n }\n\n setAutosaveStatus('saved');\n\n // Reset to idle after delay\n if (savedTimerRef.current) clearTimeout(savedTimerRef.current);\n savedTimerRef.current = setTimeout(() => {\n setAutosaveStatus('idle');\n }, SAVED_DISPLAY_MS);\n } catch (err) {\n setAutosaveStatus('error');\n setAutosaveError(err instanceof Error ? err.message : 'Failed to save');\n }\n }, [updateSettings]);\n\n // Handle a setting change\n const handleChange = useCallback(\n (key: string, value: string) => {\n // Update local edits\n setEdits((prev) => ({ ...prev, [key]: value }));\n pendingEditsRef.current[key] = value;\n\n // Clear any error state\n setAutosaveError(null);\n\n // Set status to pending\n setAutosaveStatus('pending');\n\n // Reset debounce timer\n if (debounceTimerRef.current) {\n clearTimeout(debounceTimerRef.current);\n }\n\n debounceTimerRef.current = setTimeout(() => {\n performSave();\n }, DEBOUNCE_MS);\n },\n [performSave]\n );\n\n // Get effective value (edit or original)\n const getEffectiveValue = useCallback(\n (key: string) => {\n if (edits[key] !== undefined) return edits[key];\n for (const categorySettings of Object.values(settings)) {\n const found = categorySettings.find((s) => s.key === key);\n if (found) return found.value;\n }\n return '';\n },\n [edits, settings]\n );\n\n return {\n settings,\n edits,\n isLoading,\n autosaveStatus,\n autosaveError,\n error,\n fetchSettings,\n handleChange,\n getEffectiveValue,\n };\n}\n","/**\n * Autosave status indicator for settings pages\n */\nimport type { AutosaveStatus as Status } from '../../../hooks/useSettingsAutosave';\n\nexport interface AutosaveStatusProps {\n status: Status;\n error?: string | null;\n}\n\nexport function AutosaveStatus({ status, error }: AutosaveStatusProps) {\n if (status === 'idle') return null;\n\n return (\n <div className={`cedros-autosave-status cedros-autosave-status--${status}`}>\n {status === 'pending' && (\n <>\n <span className=\"cedros-autosave-dot\" />\n <span>Unsaved changes</span>\n </>\n )}\n {status === 'saving' && (\n <>\n <span className=\"cedros-autosave-spinner\" />\n <span>Saving...</span>\n </>\n )}\n {status === 'saved' && (\n <>\n <span className=\"cedros-autosave-check\">&#10003;</span>\n <span>Saved</span>\n </>\n )}\n {status === 'error' && (\n <>\n <span className=\"cedros-autosave-error-icon\">!</span>\n <span>{error || 'Save failed'}</span>\n </>\n )}\n </div>\n );\n}\n"],"names":["secondsToDuration","totalSeconds","days","hours","minutes","seconds","formatDuration","parts","SETTING_METADATA","CATEGORY_METADATA","PRESET_TOKEN_SYMBOLS","renderDescription","html","part","i","match","jsx","SettingsSection","settings","edits","onChange","externalWarnings","setting","SettingRow","editValue","externalWarning","meta","currentValue","hasChange","isBoolean","warning","useMemo","numValue","above","below","message","jsxs","Fragment","SettingInput","value","e","DurationInput","PercentageInput","SelectInput","NumberInput","TokenListInput","BooleanInput","SecretInput","ReadonlySecretInput","TokenSymbolListInput","presets","min","displayValue","handlePresetChange","useCallback","handleCustomChange","newValue","p","preset","max","step","handleSliderChange","handlePresetClick","presetValue","unit","isCustomValue","handleSelectChange","handleChange","isEnabled","handleToggle","multiline","isEditing","setIsEditing","useState","showValue","setShowValue","hasValue","handleEdit","handleDone","settingKey","revealed","setRevealed","copied","setCopied","isRegenerating","setIsRegenerating","regenerateError","setRegenerateError","showConfirm","setShowConfirm","config","_internal","useCedrosLoginContext","masked","handleCopy","textarea","handleRegenerate","token","headers","response","body","data","err","tokens","updateTokens","updated","addToken","updateToken","index","field","val","removeToken","_","symbol","symbols","s","addSymbol","removeSymbol","isSelected","DEBOUNCE_MS","SAVED_DISPLAY_MS","useSettingsAutosave","isLoading","error","fetchSettings","updateSettings","useSystemSettings","setEdits","autosaveStatus","setAutosaveStatus","autosaveError","setAutosaveError","debounceTimerRef","useRef","savedTimerRef","pendingEditsRef","useEffect","performSave","editsToSave","updates","key","prev","next","getEffectiveValue","categorySettings","found","AutosaveStatus","status"],"mappings":"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"}
@@ -1308,6 +1308,36 @@ const W = {
1308
1308
  inputType: "text",
1309
1309
  unit: "USD",
1310
1310
  placeholder: "1000000"
1311
+ },
1312
+ // ============= Token Gating =============
1313
+ token_gating_enabled: {
1314
+ key: "token_gating_enabled",
1315
+ label: "Enable Token Gating",
1316
+ description: "Require Solana wallet holdings for access.",
1317
+ inputType: "boolean"
1318
+ },
1319
+ token_gating_rpc_url: {
1320
+ key: "token_gating_rpc_url",
1321
+ label: "Solana RPC/DAS URL",
1322
+ description: "RPC endpoint that supports DAS API for NFT queries.",
1323
+ inputType: "secret",
1324
+ placeholder: "https://mainnet.helius-rpc.com/?api-key=..."
1325
+ },
1326
+ token_gating_rules: {
1327
+ key: "token_gating_rules",
1328
+ label: "Token Gate Rules",
1329
+ description: "JSON array of gate rules. Managed via admin API.",
1330
+ inputType: "text",
1331
+ multiline: !0,
1332
+ placeholder: "[]"
1333
+ },
1334
+ token_gating_cache_ttl_secs: {
1335
+ key: "token_gating_cache_ttl_secs",
1336
+ label: "Cache TTL",
1337
+ description: "How long to cache wallet holdings (seconds).",
1338
+ inputType: "text",
1339
+ unit: "seconds",
1340
+ placeholder: "60"
1311
1341
  }
1312
1342
  }, ae = {
1313
1343
  // Auth providers (sorted alphabetically by subcategory)
@@ -1440,8 +1470,13 @@ const W = {
1440
1470
  label: "Accredited Investor Verification",
1441
1471
  description: "Configure accredited investor verification requirements and thresholds per SEC Regulation D.",
1442
1472
  icon: ""
1473
+ },
1474
+ token_gating: {
1475
+ label: "Token Gating",
1476
+ description: "Configure Solana wallet holdings requirements for gated access.",
1477
+ icon: ""
1443
1478
  }
1444
- }, R = [
1479
+ }, L = [
1445
1480
  "SOL",
1446
1481
  "USDC",
1447
1482
  "USDT",
@@ -1453,7 +1488,7 @@ const W = {
1453
1488
  "BONK",
1454
1489
  "ORE"
1455
1490
  ];
1456
- function A(t) {
1491
+ function D(t) {
1457
1492
  const i = t.split(/(<a\s[^>]*>.*?<\/a>)/g);
1458
1493
  return i.length === 1 ? t : i.map((a, n) => {
1459
1494
  const r = a.match(/^<a\s+href="([^"]+)"[^>]*>([^<]+)<\/a>$/);
@@ -1493,7 +1528,7 @@ function j({ setting: t, editValue: i, onChange: a, externalWarning: n }) {
1493
1528
  children: l ? /* @__PURE__ */ d(T, { children: [
1494
1529
  /* @__PURE__ */ d("div", { className: "cedros-setting-control cedros-setting-control-toggle", children: [
1495
1530
  /* @__PURE__ */ e(
1496
- L,
1531
+ R,
1497
1532
  {
1498
1533
  meta: r,
1499
1534
  value: s,
@@ -1504,16 +1539,16 @@ function j({ setting: t, editValue: i, onChange: a, externalWarning: n }) {
1504
1539
  ] }),
1505
1540
  /* @__PURE__ */ d("div", { className: "cedros-setting-label", children: [
1506
1541
  /* @__PURE__ */ e("span", { className: "cedros-setting-name", children: r.label }),
1507
- /* @__PURE__ */ e("span", { className: "cedros-setting-description", children: A(r.description) })
1542
+ /* @__PURE__ */ e("span", { className: "cedros-setting-description", children: D(r.description) })
1508
1543
  ] })
1509
1544
  ] }) : /* @__PURE__ */ d(T, { children: [
1510
1545
  /* @__PURE__ */ d("div", { className: "cedros-setting-label", children: [
1511
1546
  /* @__PURE__ */ e("span", { className: "cedros-setting-name", children: r.label }),
1512
- /* @__PURE__ */ e("span", { className: "cedros-setting-description", children: A(r.description) })
1547
+ /* @__PURE__ */ e("span", { className: "cedros-setting-description", children: D(r.description) })
1513
1548
  ] }),
1514
1549
  /* @__PURE__ */ d("div", { className: "cedros-setting-control", children: [
1515
1550
  /* @__PURE__ */ e(
1516
- L,
1551
+ R,
1517
1552
  {
1518
1553
  meta: r,
1519
1554
  value: s,
@@ -1540,7 +1575,7 @@ function j({ setting: t, editValue: i, onChange: a, externalWarning: n }) {
1540
1575
  ) })
1541
1576
  ] });
1542
1577
  }
1543
- function L({ meta: t, value: i, onChange: a }) {
1578
+ function R({ meta: t, value: i, onChange: a }) {
1544
1579
  switch (t.inputType) {
1545
1580
  case "duration":
1546
1581
  return /* @__PURE__ */ e(F, { value: i, onChange: a, presets: t.presets, min: t.min });
@@ -1593,9 +1628,9 @@ function L({ meta: t, value: i, onChange: a }) {
1593
1628
  case "boolean":
1594
1629
  return /* @__PURE__ */ e(H, { value: i, onChange: a });
1595
1630
  case "secret":
1596
- return /* @__PURE__ */ e(K, { value: i, onChange: a, multiline: t.multiline });
1631
+ return /* @__PURE__ */ e(G, { value: i, onChange: a, multiline: t.multiline });
1597
1632
  case "readonlySecret":
1598
- return /* @__PURE__ */ e(G, { settingKey: t.key, value: i });
1633
+ return /* @__PURE__ */ e(K, { settingKey: t.key, value: i });
1599
1634
  case "tokenSymbolList":
1600
1635
  return /* @__PURE__ */ e(z, { value: i, onChange: a });
1601
1636
  default:
@@ -1785,7 +1820,7 @@ function H({ value: t, onChange: i }) {
1785
1820
  }
1786
1821
  );
1787
1822
  }
1788
- function K({ value: t, onChange: i, multiline: a }) {
1823
+ function G({ value: t, onChange: i, multiline: a }) {
1789
1824
  const [n, r] = f(!1), [s, p] = f(!1), l = t && t.length > 0, o = m(() => {
1790
1825
  r(!0), p(!0);
1791
1826
  }, []), c = m(() => {
@@ -1833,27 +1868,27 @@ function K({ value: t, onChange: i, multiline: a }) {
1833
1868
  ] })
1834
1869
  ] });
1835
1870
  }
1836
- function G({ settingKey: t, value: i }) {
1837
- const [a, n] = f(null), [r, s] = f(!1), [p, l] = f(!1), [o, c] = f(null), [y, b] = f(!1), { config: _, _internal: w } = U(), v = a ?? i, x = v && v.length > 0, C = x && !a, h = m(async () => {
1838
- if (v)
1871
+ function K({ settingKey: t, value: i }) {
1872
+ const [a, n] = f(null), [r, s] = f(!1), [p, l] = f(!1), [o, c] = f(null), [y, b] = f(!1), { config: _, _internal: w } = U(), g = a ?? i, x = g && g.length > 0, C = x && !a, h = m(async () => {
1873
+ if (g)
1839
1874
  try {
1840
- await navigator.clipboard.writeText(v), s(!0), setTimeout(() => s(!1), 2e3);
1875
+ await navigator.clipboard.writeText(g), s(!0), setTimeout(() => s(!1), 2e3);
1841
1876
  } catch {
1842
1877
  const u = document.createElement("textarea");
1843
- u.value = v, document.body.appendChild(u), u.select(), document.execCommand("copy"), document.body.removeChild(u), s(!0), setTimeout(() => s(!1), 2e3);
1878
+ u.value = g, document.body.appendChild(u), u.select(), document.execCommand("copy"), document.body.removeChild(u), s(!0), setTimeout(() => s(!1), 2e3);
1844
1879
  }
1845
- }, [v]), k = m(async () => {
1880
+ }, [g]), k = m(async () => {
1846
1881
  l(!0), c(null);
1847
1882
  try {
1848
- const u = w?.getAccessToken?.(), g = { "Content-Type": "application/json" };
1849
- u && (g.Authorization = `Bearer ${u}`);
1883
+ const u = w?.getAccessToken?.(), v = { "Content-Type": "application/json" };
1884
+ u && (v.Authorization = `Bearer ${u}`);
1850
1885
  const S = await fetch(
1851
1886
  `${_.serverUrl}/auth/admin/settings/regenerate/${t}`,
1852
- { method: "POST", headers: g, credentials: "include" }
1887
+ { method: "POST", headers: v, credentials: "include" }
1853
1888
  );
1854
1889
  if (!S.ok) {
1855
- const D = await S.json().catch(() => null);
1856
- throw new Error(D?.message || D?.error || `Regenerate failed (${S.status})`);
1890
+ const A = await S.json().catch(() => null);
1891
+ throw new Error(A?.message || A?.error || `Regenerate failed (${S.status})`);
1857
1892
  }
1858
1893
  const E = await S.json();
1859
1894
  n(E.value), b(!1);
@@ -1864,7 +1899,7 @@ function G({ settingKey: t, value: i }) {
1864
1899
  }
1865
1900
  }, [_.serverUrl, w, t]);
1866
1901
  return /* @__PURE__ */ d("div", { className: "cedros-readonly-secret", children: [
1867
- /* @__PURE__ */ e("div", { className: "cedros-readonly-secret-value", children: C ? /* @__PURE__ */ e("span", { className: "cedros-secret-masked", children: "•".repeat(20) }) : x ? /* @__PURE__ */ e("code", { className: "cedros-readonly-secret-code", children: v }) : /* @__PURE__ */ e("span", { className: "cedros-readonly-secret-empty", children: "Not generated yet" }) }),
1902
+ /* @__PURE__ */ e("div", { className: "cedros-readonly-secret-value", children: C ? /* @__PURE__ */ e("span", { className: "cedros-secret-masked", children: "•".repeat(20) }) : x ? /* @__PURE__ */ e("code", { className: "cedros-readonly-secret-code", children: g }) : /* @__PURE__ */ e("span", { className: "cedros-readonly-secret-empty", children: "Not generated yet" }) }),
1868
1903
  /* @__PURE__ */ d("div", { className: "cedros-readonly-secret-actions", children: [
1869
1904
  x && /* @__PURE__ */ e("button", { type: "button", className: "cedros-secret-action-btn", onClick: h, children: r ? "Copied!" : "Copy" }),
1870
1905
  y ? /* @__PURE__ */ d("span", { className: "cedros-readonly-secret-confirm", children: [
@@ -1932,7 +1967,7 @@ function J({ value: t, onChange: i }) {
1932
1967
  return /* @__PURE__ */ d("div", { className: "cedros-token-list-input", children: [
1933
1968
  /* @__PURE__ */ d("div", { className: "cedros-token-presets", children: [
1934
1969
  /* @__PURE__ */ e("span", { className: "cedros-token-presets-label", children: "Built-in tokens:" }),
1935
- /* @__PURE__ */ e("div", { className: "cedros-token-presets-list", children: R.map((l) => /* @__PURE__ */ e("span", { className: "cedros-token-preset-chip", children: l }, l)) })
1970
+ /* @__PURE__ */ e("div", { className: "cedros-token-presets-list", children: L.map((l) => /* @__PURE__ */ e("span", { className: "cedros-token-preset-chip", children: l }, l)) })
1936
1971
  ] }),
1937
1972
  a.length === 0 && /* @__PURE__ */ e("p", { className: "cedros-token-list-empty", children: "No custom tokens added. Use the built-in tokens above or add your own." }),
1938
1973
  a.map((l, o) => /* @__PURE__ */ d("div", { className: "cedros-token-row", children: [
@@ -2013,7 +2048,7 @@ function z({ value: t, onChange: i }) {
2013
2048
  return /* @__PURE__ */ d("div", { className: "cedros-token-symbol-list-input", children: [
2014
2049
  /* @__PURE__ */ d("div", { className: "cedros-token-presets", children: [
2015
2050
  /* @__PURE__ */ e("span", { className: "cedros-token-presets-label", children: "Click to add:" }),
2016
- /* @__PURE__ */ e("div", { className: "cedros-token-presets-list", children: R.map((s) => {
2051
+ /* @__PURE__ */ e("div", { className: "cedros-token-presets-list", children: L.map((s) => {
2017
2052
  const p = a.includes(s);
2018
2053
  return /* @__PURE__ */ d(
2019
2054
  "button",
@@ -2049,23 +2084,23 @@ function re() {
2049
2084
  I(() => () => {
2050
2085
  b.current && clearTimeout(b.current), _.current && clearTimeout(_.current);
2051
2086
  }, []);
2052
- const v = m(async () => {
2087
+ const g = m(async () => {
2053
2088
  const h = { ...w.current };
2054
2089
  if (Object.keys(h).length === 0) {
2055
2090
  o("idle");
2056
2091
  return;
2057
2092
  }
2058
2093
  o("saving"), y(null);
2059
- const k = Object.entries(h).map(([u, g]) => ({
2094
+ const k = Object.entries(h).map(([u, v]) => ({
2060
2095
  key: u,
2061
- value: g
2096
+ value: v
2062
2097
  }));
2063
2098
  try {
2064
2099
  await r(k), p((u) => {
2065
- const g = { ...u };
2100
+ const v = { ...u };
2066
2101
  for (const S of Object.keys(h))
2067
- delete g[S];
2068
- return g;
2102
+ delete v[S];
2103
+ return v;
2069
2104
  });
2070
2105
  for (const u of Object.keys(h))
2071
2106
  delete w.current[u];
@@ -2078,15 +2113,15 @@ function re() {
2078
2113
  }, [r]), x = m(
2079
2114
  (h, k) => {
2080
2115
  p((u) => ({ ...u, [h]: k })), w.current[h] = k, y(null), o("pending"), b.current && clearTimeout(b.current), b.current = setTimeout(() => {
2081
- v();
2116
+ g();
2082
2117
  }, Y);
2083
2118
  },
2084
- [v]
2119
+ [g]
2085
2120
  ), C = m(
2086
2121
  (h) => {
2087
2122
  if (s[h] !== void 0) return s[h];
2088
2123
  for (const k of Object.values(t)) {
2089
- const u = k.find((g) => g.key === h);
2124
+ const u = k.find((v) => v.key === h);
2090
2125
  if (u) return u.value;
2091
2126
  }
2092
2127
  return "";