@coinlist-co/react 0.5.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/{chunk-5E3P7AMH.js → chunk-AAER5LOL.js} +3 -1
  2. package/dist/chunk-AAER5LOL.js.map +1 -0
  3. package/dist/chunk-I5YTJ5SL.js +644 -0
  4. package/dist/chunk-I5YTJ5SL.js.map +1 -0
  5. package/dist/{chunk-N3WBC2VS.js → chunk-MKCOK3DF.js} +68 -57
  6. package/dist/chunk-MKCOK3DF.js.map +1 -0
  7. package/dist/chunk-Z2HAA2TI.js +768 -0
  8. package/dist/chunk-Z2HAA2TI.js.map +1 -0
  9. package/dist/client/index.cjs +3360 -556
  10. package/dist/client/index.cjs.map +1 -1
  11. package/dist/client/index.d.cts +921 -18
  12. package/dist/client/index.d.ts +921 -18
  13. package/dist/client/index.js +2275 -392
  14. package/dist/client/index.js.map +1 -1
  15. package/dist/collections-B84Vw55t.d.cts +28 -0
  16. package/dist/collections-BQbFJS3g.d.ts +28 -0
  17. package/dist/requirement-C2w45Q11.d.cts +969 -0
  18. package/dist/requirement-C2w45Q11.d.ts +969 -0
  19. package/dist/server/index.cjs +521 -37
  20. package/dist/server/index.cjs.map +1 -1
  21. package/dist/server/index.d.cts +116 -9
  22. package/dist/server/index.d.ts +116 -9
  23. package/dist/server/index.js +95 -28
  24. package/dist/server/index.js.map +1 -1
  25. package/dist/shared/index.cjs +1264 -42
  26. package/dist/shared/index.cjs.map +1 -1
  27. package/dist/shared/index.d.cts +644 -3
  28. package/dist/shared/index.d.ts +644 -3
  29. package/dist/shared/index.js +220 -5
  30. package/dist/shared/index.js.map +1 -1
  31. package/package.json +33 -30
  32. package/dist/chunk-5E3P7AMH.js.map +0 -1
  33. package/dist/chunk-CRACFEJ4.js +0 -17
  34. package/dist/chunk-CRACFEJ4.js.map +0 -1
  35. package/dist/chunk-N3WBC2VS.js.map +0 -1
  36. package/dist/chunk-V6WO67RO.js +0 -311
  37. package/dist/chunk-V6WO67RO.js.map +0 -1
  38. package/dist/client/styles.css +0 -2
  39. package/dist/requirement-BEO42QOr.d.cts +0 -387
  40. package/dist/requirement-BEO42QOr.d.ts +0 -387
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/client/index.ts","../../src/client/CoinListProvider.tsx","../../src/client/core/api/middleware/device-id.ts","../../src/client/core/api/middleware/user-agent.ts","../../src/client/core/api/api-client.ts","../../src/client/core/coinlist-client.ts","../../src/client/components/design-system/AlertBanner.tsx","../../src/client/components/design-system/tokens/typography.ts","../../src/client/components/design-system/utils.ts","../../src/client/components/design-system/CloseButton.tsx","../../src/client/components/design-system/logos/CoinListWordmark.tsx","../../src/client/components/design-system/PoweredByCoinList.tsx","../../src/client/components/design-system/ClButton.tsx","../../src/client/components/design-system/logos/CoinListLogomark.tsx","../../src/client/components/oauth/CoinListSignInButton.tsx","../../src/client/hooks/useCoinList.ts","../../src/client/components/oauth/CoinListSignInCard.tsx","../../src/client/components/offers/OfferCard.tsx","../../src/client/hooks/useOffers.ts","../../src/client/components/offers/OffersGrid.tsx","../../src/client/components/requirements/RequirementItem.tsx","../../src/client/components/design-system/StepStatusIcon.tsx","../../src/client/components/requirements/RequirementsChecklist.tsx","../../src/client/hooks/useRequirements.ts","../../src/client/hooks/useCompleteOAuth.ts","../../src/client/hooks/useOfferDetails.ts","../../src/client/hooks/useParticipations.ts"],"sourcesContent":["import '@/client/styles.css';\n\n// Provider\nexport * from '@/client/CoinListProvider';\n// Components\nexport * from '@/client/components/oauth/CoinListSignInCard';\nexport {\n OfferCard,\n OfferCardUi,\n type Props as OfferCardProps,\n} from '@/client/components/offers/OfferCard';\nexport * from '@/client/components/offers/OffersGrid';\nexport * from '@/client/components/requirements/RequirementItem';\nexport * from '@/client/components/requirements/RequirementsChecklist';\n// Core client\nexport * from '@/client/core/coinlist-client';\nexport * from '@/client/core/types/client-types';\n// Hooks\nexport * from '@/client/hooks/useCoinList';\nexport * from '@/client/hooks/useCompleteOAuth';\nexport * from '@/client/hooks/useOfferDetails';\nexport * from '@/client/hooks/useOffers';\nexport * from '@/client/hooks/useParticipations';\nexport * from '@/client/hooks/useRequirements';\n","/**\n * Global CoinList initialization for React apps.\n * Wrap your app once at the root; use useCoinList() anywhere below.\n */\n\nimport {\n createContext,\n type ReactNode,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport {\n type ClientConfig,\n type CoinListClient,\n createCoinListClient,\n} from '@/client/core/coinlist-client';\n\nexport type CoinListContextValue = {\n coinlist: CoinListClient;\n isReady: boolean;\n};\n\nexport const CoinListContext = createContext<CoinListContextValue | null>(null);\n\nexport type CoinListProviderProps = {\n config: ClientConfig;\n children: ReactNode;\n};\n\n/**\n * Provide CoinList (api + config) to the tree. Initialize once at app root with your config.\n */\nexport function CoinListProvider({ config, children }: CoinListProviderProps) {\n const [isReady, setIsReady] = useState(false);\n const coinlist = useMemo(() => createCoinListClient(config), [config]);\n\n useEffect(() => {\n let isCancelled = false;\n if (coinlist.getAuthState() === 'unknown') {\n coinlist\n .init()\n .then(() => {\n if (!isCancelled) {\n setIsReady(true);\n }\n })\n .catch(() => {\n if (!isCancelled) {\n setIsReady(true);\n }\n });\n } else {\n setIsReady(true);\n }\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist]);\n\n const value = useMemo(() => ({ coinlist, isReady }), [coinlist, isReady]);\n\n return (\n <CoinListContext.Provider value={value}>\n {children}\n </CoinListContext.Provider>\n );\n}\n","'use client';\n\nimport { getUUIDv4 } from '@/shared/utils';\n\nconst DEVICE_ID_KEY = 'coinlist.device_id';\n\n/**\n * Get or create a device ID stored in localStorage.\n * Uses a crypto UUID that persists across sessions.\n */\nexport function getDeviceId(): string {\n let deviceId = localStorage.getItem(DEVICE_ID_KEY);\n\n if (!deviceId) {\n deviceId = getUUIDv4();\n localStorage.setItem(DEVICE_ID_KEY, deviceId);\n }\n\n return deviceId;\n}\n\n/**\n * Clear the stored device ID (useful for testing or logout).\n */\nexport function clearDeviceId(): void {\n localStorage.removeItem(DEVICE_ID_KEY);\n}\n","'use client';\n\nimport { getDeviceId } from '@/client/core/api/middleware/device-id';\nimport { HEADER_USER_AGENT } from '@/shared/api/frontline/config';\nimport type { HttpRequest } from '@/shared/api/http';\nimport { Attributes } from '@/shared/api/http-attributes';\nimport type { BeforeRequestMiddleware } from '@/shared/api/http-client';\n\nexport const userAgentMiddleware: BeforeRequestMiddleware = async (\n request: HttpRequest\n): Promise<HttpRequest> => {\n if (!Attributes.needUserAgent(request.attributes)) {\n return request;\n }\n\n const userAgent = generateUserAgent();\n return {\n ...request,\n headers: {\n ...(request.headers ?? {}),\n [HEADER_USER_AGENT]: userAgent,\n },\n };\n};\n\n// Generate User-Agent in the required format for Frontline API\n// Format: <app-info> (<device-info>; DevicePlatform <device-platform>; DeviceAppID <device-app-id>; DeviceID <device-id>)\nfunction generateUserAgent(): string {\n const appInfo = `CoinList/1.0`;\n const deviceInfo = 'Web Browser';\n const devicePlatform = 'DevicePlatform web'; // Must be 'web' for validation\n\n const deviceAppId = 'DeviceAppID co.coinlist.sdk'; // SDK app ID\n\n const deviceId = getDeviceId();\n const finalDeviceId = `DeviceID ${deviceId}`;\n\n return `${appInfo} (${deviceInfo}; ${devicePlatform}; ${deviceAppId}; ${finalDeviceId})`;\n}\n","'use client';\n\nimport { userAgentMiddleware } from '@/client/core/api/middleware/user-agent';\nimport { AuthenticatedApiClient } from '@/shared/api/authenticated-api-client';\nimport type { HttpClientConfig, HttpRequest } from '@/shared/api/http';\nimport type { OAuthAccessToken } from '@/shared/types/oauth-session';\n\nexport class ApiClient {\n private readonly client: AuthenticatedApiClient;\n\n constructor(\n config: HttpClientConfig,\n fetchAccessToken: (refresh: boolean) => Promise<OAuthAccessToken | null>\n ) {\n this.client = new AuthenticatedApiClient(config, fetchAccessToken, [\n userAgentMiddleware,\n ]);\n }\n\n async send<TResponse>(request: HttpRequest): Promise<TResponse> {\n return this.client.send<TResponse>(request);\n }\n}\n","'use client';\n\nimport { ApiClient } from '@/client/core/api/api-client';\nimport type {\n AuthState,\n OauthClientResult,\n} from '@/client/core/types/client-types';\nimport {\n API_VERSION,\n COINLIST_BASE_URL,\n OAUTH_PAGE_PATH,\n PUBLIC_API_BASE_URL,\n SUPPORT_NEW_TICKET_URL,\n VERIFY_IDENTITY_ACCREDITATION_PATH,\n VERIFY_IDENTITY_PATH,\n VERIFY_IDENTITY_PROOF_OF_ADDRESS_PATH,\n VERIFY_IDENTITY_SOURCE_OF_FUNDS_PATH,\n VERIFY_IDENTITY_VERIFIED_PATH,\n WALLET_PATH,\n} from '@/shared/api/frontline/config';\nimport * as offersApi from '@/shared/api/frontline/offers';\nimport * as participationsApi from '@/shared/api/frontline/participations';\nimport * as requirementsApi from '@/shared/api/frontline/requirements';\nimport type {\n PaginatedResponse,\n PaginationParams,\n} from '@/shared/api/pagination';\nimport type { Config } from '@/shared/types/config';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport { AuthorizationCode, CodeVerifier } from '@/shared/types/oauth';\nimport type { OAuthAccessToken } from '@/shared/types/oauth-session';\nimport type { Offer, OfferId } from '@/shared/types/offer';\nimport type { OfferDetail, OfferOptionId } from '@/shared/types/offer-detail';\nimport type {\n CreateParticipationParams,\n Participation,\n ParticipationId,\n ParticipationsPaginationParams,\n} from '@/shared/types/participation';\nimport type {\n Requirement,\n RequirementStatusInfo,\n} from '@/shared/types/requirement';\nimport {\n arrayBufferToBase64Url,\n generateSecureRandomBase64Url,\n sha256,\n} from '@/shared/utils';\n\n/** Session storage keys for OAuth PKCE (used by startOauth and completeOauth). */\nexport const OAUTH_STATE_KEY = 'coinlist.oauth_state';\nexport const OAUTH_CODE_VERIFIER_KEY = 'coinlist.oauth_code_verifier';\n\nexport interface ClientConfig extends Config {\n /**\n * The SDK user must provide this function. It is responsible for fetching a\n * valid {@link OAuthAccessToken}, or **null** for logged-out users. If your\n * backend is in TypeScript, it is recommended to use\n * {@link CoinListServer#accessToken} from `@/server/coinlist.server`.\n */\n getAccessToken: () => Promise<OAuthAccessToken | null>;\n /**\n * Recommended to leave undefined. Used to change the CoinList environment;\n * default is production.\n */\n coinlistBaseUrl?: string;\n}\n\nexport interface CoinListClient {\n /**\n * Calls the provided {@link ClientConfig.getAccessToken} lambda to determine\n * the user's {@link AuthState}. This is called automatically by {@link CoinListProvider};\n * you typically do not need to call it yourself unless you are using the client\n * outside of the provider.\n */\n init(): Promise<AuthState>;\n /**\n * Returns the current auth state: `'logged-in'`, `'logged-out'`, or `'unknown'`.\n * Returns **unknown** until {@link CoinListClient.init} has completed. It is\n * recommended to use the `const { isReady, coinlist } = useCoinList()` hook to know when\n * the SDK has initialized, or to manually await {@link CoinListClient.init}\n * before relying on this value.\n */\n getAuthState(): AuthState;\n /**\n * Starts the OAuth flow with PKCE. Generates a random `state` and `code_verifier`,\n * stores them in sessionStorage (for validation in {@link CoinListClient.completeOAuth}\n * on redirect), then redirects the user to the CoinList authorization page. After\n * the user authorizes, they are sent back to your application's redirect URI; call\n * {@link CoinListClient.completeOAuth} on that page to finish the flow.\n */\n startOAuth(): Promise<void>;\n /**\n * Completes the OAuth flow on the FE with PKCE and state validation. Parses the\n * redirect URL (state, code) and validates them against sessionStorage\n * (state, code_verifier). The state check protects against CSRF (cross-site\n * request forgery). Call this on the frontend page the user is redirected\n * to after authorizing.\n *\n * On `ok`: Call your backend to exchange the short-lived `authorizationCode`\n * (and the returned `codeVerifier`) for a long-lived session. If your backend\n * is in TypeScript, you can use {@link CoinListServer#completeOAuth} from\n * `@/server/coinlist.server` (CoinListServer) to perform that exchange.\n *\n * On `error`: `reason` is an {@link OauthClientErrorReason} (e.g. `'missing_state'`, `'invalid_state'`) so you can switch on it and surface a message to the user.\n */\n completeOAuth(): OauthClientResult;\n /**\n * Clears the in-memory access token. Note: you need to manually\n * also logout on the backend via CoinListServer#logout to clear the session cookie.\n */\n logout(): void;\n\n /**\n * Fetches all offers by iterating through every paginated response.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n fetchOffers(): Promise<Offer[]>;\n /**\n * Fetches a single page of offers.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n fetchOffersPage(params: PaginationParams): Promise<PaginatedResponse<Offer>>;\n /**\n * Fetches details for a given offer by its id.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n fetchOfferDetails(id: OfferId): Promise<OfferDetail>;\n /**\n * Fetches all participations by iterating through every paginated response.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n fetchParticipations(offerId?: OfferId): Promise<Participation[]>;\n /**\n * Fetches a single page of participations, optionally filtered by offer.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n fetchParticipationsPage(\n params: ParticipationsPaginationParams\n ): Promise<PaginatedResponse<Participation>>;\n /**\n * Fetches a participation by id.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n fetchParticipation(id: ParticipationId): Promise<Participation>;\n /**\n * Creates a participation.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n createParticipation(\n params: CreateParticipationParams\n ): Promise<Participation>;\n /**\n * Fetches the requirements for all options of a given offer, grouped by option ID.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n fetchOfferRequirements(\n offerId: OfferId\n ): Promise<Record<OfferOptionId, Requirement[]>>;\n /**\n * Fetches the user's requirement statuses for a given offer.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n fetchRequirementStatuses(offerId: OfferId): Promise<RequirementStatusInfo[]>;\n /**\n * Opens the CoinList page for completing a given requirement in a new tab.\n * For `jurisdiction` requirements there is no CTA, so this is a no-op.\n */\n handleRequirement(requirement: Requirement): void;\n /**\n * Opens the CoinList support ticket page in a new tab.\n */\n contactSupport(): void;\n}\n\nclass CoinListClientImpl implements CoinListClient {\n /** Cached access token: undefined = loading, null = no token, AccessToken = logged in */\n private _accessToken: OAuthAccessToken | null | undefined = undefined;\n private readonly api: ApiClient;\n\n constructor(readonly _config: ClientConfig) {\n this.api = new ApiClient(\n {\n baseUrl: _config.baseUrl || PUBLIC_API_BASE_URL,\n xApiVersion: API_VERSION,\n },\n this.fetchAccessToken.bind(this)\n );\n }\n\n async init(): Promise<AuthState> {\n await this.fetchAccessToken(true);\n return this.getAuthState();\n }\n\n async fetchAccessToken(refresh: boolean): Promise<OAuthAccessToken | null> {\n if (!refresh && this._accessToken !== undefined) return this._accessToken;\n\n try {\n const accessToken = await this._config.getAccessToken();\n this._accessToken = accessToken;\n return accessToken;\n } catch (_) {\n this._accessToken = null;\n return null;\n }\n }\n\n getAuthState(): AuthState {\n if (this._accessToken === undefined) {\n return 'unknown';\n }\n return this._accessToken !== null ? 'logged-in' : 'logged-out';\n }\n\n async startOAuth(): Promise<void> {\n const state = generateSecureRandomBase64Url(32);\n const codeVerifier = generateSecureRandomBase64Url(32);\n\n const codeChallengeRaw = await sha256(codeVerifier);\n const codeChallenge = arrayBufferToBase64Url(codeChallengeRaw, false);\n\n sessionStorage.setItem(OAUTH_STATE_KEY, state);\n sessionStorage.setItem(OAUTH_CODE_VERIFIER_KEY, codeVerifier);\n\n const params = new URLSearchParams({\n client_id: this._config.clientId,\n response_type: 'code',\n redirect_uri: this._config.redirectUri,\n code_challenge: codeChallenge,\n code_challenge_method: 'S256',\n state,\n });\n const baseUrl = this._config.coinlistBaseUrl ?? COINLIST_BASE_URL;\n const url = `${baseUrl}${OAUTH_PAGE_PATH}?${params.toString()}`;\n window.location.href = url;\n }\n\n completeOAuth(): OauthClientResult {\n const params = new URLSearchParams(window.location.search);\n\n const coinlistError = params.get('error');\n if (coinlistError) {\n return { type: 'error', reason: 'user_canceled' };\n }\n\n const stateParam = params.get('state');\n if (!stateParam) {\n return { type: 'error', reason: 'missing_state' };\n }\n const storedState = sessionStorage.getItem(OAUTH_STATE_KEY);\n if (storedState === null || storedState !== stateParam) {\n return { type: 'error', reason: 'invalid_state' };\n }\n\n const codeParam = params.get('code');\n if (!codeParam) {\n return { type: 'error', reason: 'missing_code' };\n }\n\n const codeVerifierValue = sessionStorage.getItem(OAUTH_CODE_VERIFIER_KEY);\n if (!codeVerifierValue) {\n return { type: 'error', reason: 'missing_code_verifier' };\n }\n\n return {\n type: 'ok',\n code: AuthorizationCode(codeParam),\n codeVerifier: CodeVerifier(codeVerifierValue),\n };\n }\n\n logout(): void {\n this._accessToken = null;\n }\n\n async fetchOffers(): Promise<Offer[]> {\n this.ensureAuthenticated();\n return offersApi.fetchOffers(this.api);\n }\n\n async fetchOffersPage(\n params: PaginationParams\n ): Promise<PaginatedResponse<Offer>> {\n this.ensureAuthenticated();\n return offersApi.fetchOffersPage(this.api, params);\n }\n\n async fetchOfferDetails(id: OfferId): Promise<OfferDetail> {\n this.ensureAuthenticated();\n return offersApi.fetchOfferDetails(this.api, id);\n }\n\n async fetchParticipations(offerId?: OfferId): Promise<Participation[]> {\n this.ensureAuthenticated();\n return participationsApi.fetchParticipations(this.api, offerId);\n }\n\n async fetchParticipationsPage(\n params: ParticipationsPaginationParams\n ): Promise<PaginatedResponse<Participation>> {\n this.ensureAuthenticated();\n return participationsApi.fetchParticipationsPage(this.api, params);\n }\n\n async fetchParticipation(id: ParticipationId): Promise<Participation> {\n this.ensureAuthenticated();\n return participationsApi.fetchParticipation(this.api, id);\n }\n\n async createParticipation(\n params: CreateParticipationParams\n ): Promise<Participation> {\n this.ensureAuthenticated();\n return participationsApi.createParticipation(this.api, params);\n }\n\n async fetchOfferRequirements(\n offerId: OfferId\n ): Promise<Record<OfferOptionId, Requirement[]>> {\n this.ensureAuthenticated();\n return requirementsApi.fetchOfferRequirements(this.api, offerId);\n }\n\n async fetchRequirementStatuses(\n offerId: OfferId\n ): Promise<RequirementStatusInfo[]> {\n this.ensureAuthenticated();\n return requirementsApi.fetchRequirementStatuses(this.api, offerId);\n }\n\n handleRequirement(requirement: Requirement): void {\n const baseUrl = this._config.coinlistBaseUrl ?? COINLIST_BASE_URL;\n let path: string | null;\n switch (requirement.type) {\n case 'kyc_approved':\n path = VERIFY_IDENTITY_PATH;\n break;\n case 'identity_verified':\n path = VERIFY_IDENTITY_VERIFIED_PATH;\n break;\n case 'proof_of_address':\n path = VERIFY_IDENTITY_PROOF_OF_ADDRESS_PATH;\n break;\n case 'source_of_funds':\n path = VERIFY_IDENTITY_SOURCE_OF_FUNDS_PATH;\n break;\n case 'accreditation':\n path = VERIFY_IDENTITY_ACCREDITATION_PATH;\n break;\n case 'external_wallet':\n case 'whitelisted_wallet':\n path = WALLET_PATH;\n break;\n case 'jurisdiction':\n path = null;\n break;\n default: {\n const _exhaustive: never = requirement.type;\n return;\n }\n }\n if (path === null) return;\n openInNewTab(new URL(path, baseUrl).toString());\n }\n\n contactSupport(): void {\n openInNewTab(SUPPORT_NEW_TICKET_URL);\n }\n\n private ensureAuthenticated() {\n if (this.getAuthState() !== 'logged-in') {\n throw new NotAuthenticatedError();\n }\n }\n}\n\nfunction openInNewTab(url: string): void {\n window.open(url, '_blank', 'noopener,noreferrer');\n}\n\nexport function createCoinListClient(config: ClientConfig): CoinListClient {\n return new CoinListClientImpl(config);\n}\n","import type { LucideIcon } from 'lucide-react';\nimport { CircleCheck, Info } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\n\nexport type AlertBannerVariant = 'info' | 'success' | 'warning' | 'error';\n\ninterface AlertBannerProps {\n variant: AlertBannerVariant;\n content: ReactNode;\n icon?: boolean;\n className?: string;\n}\n\nconst variantConfig: Record<\n AlertBannerVariant,\n { container: string; text: string; Icon: LucideIcon }\n> = {\n info: {\n container: 'bg-surface border-border',\n text: 'text-text-secondary',\n Icon: Info,\n },\n success: {\n container: 'bg-success-subtle border-success-border',\n text: 'text-success',\n Icon: CircleCheck,\n },\n warning: {\n container: 'bg-warning-subtle border-warning-border',\n text: 'text-warning',\n Icon: Info,\n },\n error: {\n container: 'bg-error-subtle border-error-border',\n text: 'text-error',\n Icon: Info,\n },\n};\n\nexport function AlertBanner({\n variant,\n content,\n icon = false,\n className,\n}: AlertBannerProps) {\n const { container, text, Icon } = variantConfig[variant];\n\n return (\n <div\n className={cn(\n 'flex items-center rounded-btn border p-3',\n icon && 'gap-2',\n container,\n className\n )}\n >\n {icon && (\n <Icon className={cn('h-4 w-4 shrink-0', text)} aria-hidden=\"true\" />\n )}\n <p className={cn(typeClasses.subhead, text)}>{content}</p>\n </div>\n );\n}\n","/**\n * CoinList Sale SDK — Typography Tokens\n *\n * Scale based on design system.\n * fontSize in px, lineHeight as percentage string, fontWeight as number.\n * Use the cn() Tailwind classes where possible, these values\n * are for programmatic access or non-Tailwind contexts.\n */\n\nexport const typeScale = {\n hero: {\n fontSize: 64,\n lineHeight: '110%',\n fontWeight: 600,\n },\n display: {\n fontSize: 48,\n lineHeight: '110%',\n fontWeight: 600,\n },\n h1: {\n fontSize: 36,\n lineHeight: '120%',\n fontWeight: 600,\n },\n h2: {\n fontSize: 28,\n lineHeight: '125%',\n fontWeight: 600,\n },\n h3: {\n fontSize: 22,\n lineHeight: '130%',\n fontWeight: 600,\n },\n h4: {\n fontSize: 18,\n lineHeight: '135%',\n fontWeight: 500,\n },\n body: {\n fontSize: 16,\n lineHeight: '150%',\n fontWeight: 400,\n },\n subhead: {\n fontSize: 14,\n lineHeight: '150%',\n fontWeight: 400,\n },\n caption: {\n fontSize: 12,\n lineHeight: '140%',\n fontWeight: 400,\n },\n label: {\n fontSize: 14,\n lineHeight: '140%',\n fontWeight: 500,\n },\n data: {\n fontSize: 14,\n lineHeight: '140%',\n fontWeight: 400,\n },\n} as const;\n\n/**\n * Tailwind class mappings for each type style.\n * Use these className strings directly in components.\n *\n * e.g. <h1 className={typeClasses.h1}>Hello</h1>\n */\nexport const typeClasses = {\n hero: 'text-[64px] leading-[110%] font-semibold',\n display: 'text-[48px] leading-[110%] font-semibold',\n h1: 'text-[36px] leading-[120%] font-semibold',\n h2: 'text-[28px] leading-[125%] font-semibold',\n h3: 'text-[22px] leading-[130%] font-semibold',\n h4: 'text-[18px] leading-[135%] font-medium',\n body: 'text-[16px] leading-[150%] font-normal',\n subhead: 'text-[14px] leading-[150%] font-normal',\n caption: 'text-[12px] leading-[140%] font-normal',\n label: 'text-[14px] leading-[140%] font-medium',\n data: 'text-[14px] leading-[140%] font-normal',\n} as const;\n\nexport type TypeScale = keyof typeof typeScale;\n","import { type ClassValue, clsx } from 'clsx';\n\n/**\n * Utility function to merge class names using clsx.\n */\nexport function cn(...inputs: ClassValue[]) {\n return clsx(inputs);\n}\n","'use client';\n\nimport { X } from 'lucide-react';\nimport { cn } from '@/client/components/design-system/utils';\n\ninterface CloseButtonProps {\n onClick: () => void;\n 'aria-label'?: string;\n className?: string;\n}\n\nexport function CloseButton({\n onClick,\n 'aria-label': ariaLabel = 'Close',\n className,\n}: CloseButtonProps) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-label={ariaLabel}\n className={cn(\n 'cursor-pointer rounded-full p-1.5 text-text-secondary transition-colors hover:bg-surface hover:text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-gray-400 focus-visible:ring-offset-2',\n className\n )}\n >\n <X className=\"h-5 w-5\" />\n </button>\n );\n}\n","import type { SVGProps } from 'react';\n\nexport function CoinListWordmark(props: SVGProps<SVGSVGElement>) {\n return (\n <svg\n width=\"638\"\n height=\"125\"\n viewBox=\"0 0 638 125\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n {...props}\n >\n <path\n d=\"M68.7724 123.966C74.8226 124.172 80.7696 123.519 86.5104 121.799C97.4076 118.531 106.551 112.58 113.942 103.947C113.942 103.947 113.942 103.947 113.908 103.912C111.879 102.193 109.851 100.507 107.857 98.8218L105.829 97.1363C105.451 96.8268 105.107 96.5172 104.729 96.2076C103.939 95.5197 103.148 94.8662 102.323 94.2126C95.3107 98.8562 87.6104 101.539 79.1196 101.883C74.8569 102.055 70.6287 101.642 66.5036 100.507C59.5252 98.6154 53.2688 95.1757 48.2499 89.7755C39.1059 79.938 35.8745 68.1743 38.2465 55.0348C39.7246 46.9172 43.4373 40.0723 49.1093 34.5C47.9061 34.7408 46.703 35.016 45.5342 35.3943C36.5277 38.2148 29.6181 43.6839 24.6336 51.6639C20.6803 58.0273 18.5834 64.9411 18.3428 72.4739C18.2053 76.7047 18.4803 80.7979 19.4428 84.7879C22.5023 97.2395 29.3087 107.043 39.6903 114.335H39.7934V114.403C40.1372 114.644 40.4809 114.919 40.8247 115.16C49.2812 120.801 58.5971 123.691 68.7724 124.035V123.966Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M72.2101 89.052C68.1881 90.8406 64.0286 91.8725 59.6973 92.2165C64.9912 95.209 70.8007 96.688 77.1259 96.8256C79.1885 96.86 81.251 96.6536 83.4167 96.3097C88.745 95.4841 93.6951 93.5579 98.3015 90.7374C93.9358 87.057 89.6044 83.4109 85.2386 79.7305C81.526 83.6861 77.1946 86.8506 72.2101 89.052Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M66.9848 0.241609C66.4348 0.276006 65.8848 0.344799 65.3691 0.413592C70.663 1.4111 75.7851 3.13093 80.6321 5.71068C90.0511 10.7326 97.3732 17.9215 102.289 27.4494L104.936 25.1448C107.652 22.7714 110.368 20.3981 113.084 18.0247C106.655 11.1797 99.092 6.15784 90.223 3.06214C84.3103 0.998336 78.2601 -0.0335643 72.0381 0.000832319C70.388 0.000832319 68.7036 0.138419 66.9848 0.241609Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M25.4242 107.871C17.4833 97.9988 13.1519 86.7167 13.2207 73.818C13.2207 67.317 14.5614 61.0568 17.1396 55.1062C20.9553 46.2662 26.9711 39.1805 35.4276 34.2962C43.3685 29.687 51.9968 27.8984 61.1752 29.2743C70.5943 30.7189 78.3976 35.2249 84.6541 42.2762C84.6541 42.2762 84.8603 42.5514 84.9634 42.6546C85.8916 41.8291 86.8541 41.0035 87.7823 40.178L88.9167 39.1805C89.8792 38.355 90.8417 37.4951 91.8043 36.6696C94.0043 34.7434 96.17 32.8515 98.3357 30.9253C94.1075 22.223 87.7479 15.55 79.3258 10.8377C69.3911 5.26541 58.7002 3.54557 47.3904 5.02463C41.7528 5.78136 36.3557 7.50119 31.1993 10.0465C13.702 18.7145 1.08597 36.532 0.0546833 58.4771C-0.117196 62.0887 0.123436 65.7348 0.673452 69.3464C2.04849 78.3239 5.34859 86.4759 10.6425 93.8368C14.7676 99.5123 19.6834 104.19 25.3898 107.871H25.4242Z\"\n fill=\"currentColor\"\n />\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M366.034 58.1654C366.034 46.8145 375.178 37.665 386.419 37.665C397.66 37.665 406.804 46.8145 406.804 58.1654V99.3727H420.727V58.1654C420.727 39.1785 405.395 23.7344 386.419 23.7344C367.444 23.7344 352.112 39.1785 352.112 58.1654V99.3727H366.034V58.1654ZM278.616 38.1466C265.141 38.1466 254.244 49.0503 254.244 62.5338C254.244 76.0173 265.141 86.9211 278.616 86.9211C292.092 86.9211 302.989 76.0173 302.989 62.5338C302.989 49.0503 292.092 38.1466 278.616 38.1466ZM240.321 62.5338C240.321 41.3799 257.475 24.2159 278.616 24.2159C299.757 24.2159 316.911 41.3799 316.911 62.5338C316.911 83.6878 299.757 100.852 278.616 100.852C257.475 100.852 240.321 83.6878 240.321 62.5338ZM208.386 38.2154C195.082 37.9402 184.048 48.5 183.738 61.8115C183.463 75.123 194.017 86.1643 207.32 86.4739C215.192 86.6459 222.274 82.9998 226.812 77.2212L237.777 85.8204C230.662 94.9011 219.455 100.645 207.011 100.37C186.007 99.923 169.335 82.5183 169.782 61.5019C170.229 40.4856 187.623 23.8032 208.627 24.2503C219.524 24.4911 229.287 29.3066 236.059 36.8051L225.712 46.1266C221.415 41.3455 215.227 38.3186 208.317 38.1466L208.386 38.2154ZM340.527 25.2134V99.3727H326.605V25.2134H340.527ZM508.282 25.2134H494.36V99.8542H508.282V25.2134ZM483.154 99.8542H448.846C439.221 99.8542 431.452 92.0462 431.452 82.4495V25.2134H445.374V82.4495C445.374 84.3757 446.921 85.9236 448.846 85.9236H483.154V99.8542ZM583.772 25.2134H567.856H542.83C530.661 25.2134 520.933 35.1885 520.933 47.2273C520.933 59.2661 530.661 69.2412 542.83 69.2412H552.421C556.821 69.2412 560.396 72.8184 560.396 77.1868V77.9435C560.396 82.3463 556.821 85.8892 552.421 85.8892H520.451V99.8198H552.421C564.522 99.8198 574.319 90.0168 574.319 77.9091V77.1524C574.319 65.0448 564.522 55.2417 552.421 55.2417H542.83C538.499 55.2417 534.855 51.6301 534.855 47.1585C534.855 42.6869 538.499 39.0753 542.83 39.0753H574.319H583.772C591.472 39.0753 597.694 45.3011 597.694 53.0059V99.3039H611.617V53.0059C611.617 37.6306 599.138 25.1446 583.772 25.1446V25.2134ZM637.021 39.1441H609.038V25.2134H637.021V39.1441Z\"\n fill=\"currentColor\"\n />\n </svg>\n );\n}\n","import { CoinListWordmark } from '@/client/components/design-system/logos/CoinListWordmark';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\n\ninterface PoweredByCoinListProps {\n className?: string;\n}\n\nexport function PoweredByCoinList({ className }: PoweredByCoinListProps) {\n return (\n <div\n className={cn(\n 'flex items-center justify-center gap-[5px] text-text-secondary',\n className\n )}\n >\n <span className={cn(typeClasses.caption, 'tracking-[0.12px]')}>\n Powered by\n </span>\n <CoinListWordmark className=\"h-3 w-auto\" />\n </div>\n );\n}\n","'use client';\n\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { type ButtonHTMLAttributes, forwardRef, type ReactNode } from 'react';\nimport { cn } from '@/client/components/design-system/utils';\n\n// Button variants using class-variance-authority for consistent styling\nconst buttonVariants = cva(\n 'inline-flex items-center justify-center gap-3 whitespace-nowrap transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-40 cursor-pointer',\n {\n variants: {\n variant: {\n // Primary — tokens auto-switch: dark bg (#171717) → light bg (#f4f4f5) in dark mode\n primary:\n 'bg-brand-primary text-text-inverse font-semibold hover:bg-brand-primary-hover active:bg-brand-primary-active focus-visible:ring-gray-500',\n // Secondary — bg-section, border-border, text-text-primary all auto-switch\n // hover maps to border token value; active has no token so uses dark: override\n secondary:\n 'bg-section border border-border text-text-primary font-medium hover:bg-border active:bg-[#d9d9d9] dark:active:bg-divider focus-visible:ring-gray-400',\n // Destructive — error tokens auto-switch to translucent dark equivalents\n // hover/active have no tokens so use dark: overrides\n destructive:\n 'bg-error-subtle border border-error-border text-error font-semibold hover:bg-[#fcdcd8] active:bg-[#f9c9c4] dark:hover:bg-[rgba(248,113,113,0.20)] dark:active:bg-[rgba(248,113,113,0.30)] focus-visible:ring-red-400',\n // Ghost — transparent base; hover/active use section/border tokens (auto-switch)\n ghost:\n 'bg-transparent text-text-primary font-medium hover:bg-section active:bg-border focus-visible:ring-gray-400',\n // Link — text-text-primary auto-switches light/dark\n link: 'h-auto p-0 text-text-primary font-medium underline-offset-4 hover:underline focus-visible:ring-gray-500',\n // Destructive link — text-error auto-switches (#b42318 → #f87171 in dark)\n destructiveLink:\n 'h-auto p-0 text-error font-medium hover:text-[#8b1a13] active:text-[#6d1510] dark:hover:text-[#fca5a5] dark:active:text-[#f87171] focus-visible:ring-red-500',\n },\n size: {\n sm: 'h-9 px-4 text-sm tracking-[0.28px]',\n default: 'h-11 px-5 text-sm tracking-[0.28px]',\n lg: 'h-14 px-6 text-base',\n icon: 'h-12 w-12',\n },\n radius: {\n pill: 'rounded-full',\n // compound variants below handle size-specific radii\n rounded: '',\n },\n fullWidth: {\n true: 'w-full',\n false: '',\n },\n },\n compoundVariants: [\n { size: 'sm', radius: 'rounded', className: 'rounded-lg' },\n { size: 'default', radius: 'rounded', className: 'rounded-2xl' },\n { size: 'lg', radius: 'rounded', className: 'rounded-2xl' },\n { size: 'icon', radius: 'rounded', className: 'rounded-md' },\n ],\n defaultVariants: {\n variant: 'primary',\n size: 'default',\n radius: 'pill',\n fullWidth: false,\n },\n }\n);\n\ninterface ClButtonProps\n extends ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n children?: ReactNode;\n isLoading?: boolean;\n loadingText?: string;\n startIcon?: ReactNode;\n endIcon?: ReactNode;\n}\n\nconst ClButton = forwardRef<HTMLButtonElement, ClButtonProps>(\n (\n {\n className,\n variant,\n size,\n radius,\n fullWidth,\n children,\n isLoading = false,\n loadingText,\n startIcon,\n endIcon,\n disabled,\n ...props\n },\n ref\n ) => {\n const isDisabled = disabled || isLoading;\n\n return (\n <button\n className={cn(\n buttonVariants({ variant, size, radius, fullWidth }),\n className\n )}\n ref={ref}\n disabled={isDisabled}\n {...props}\n >\n {isLoading && (\n <span\n className=\"h-4 w-4 shrink-0 animate-spin rounded-full border-2 border-current border-t-transparent opacity-60\"\n aria-hidden=\"true\"\n />\n )}\n\n {startIcon && !isLoading && (\n <span className=\"shrink-0\">{startIcon}</span>\n )}\n\n <span className={cn(isLoading && 'opacity-60')}>\n {isLoading && loadingText ? loadingText : children}\n </span>\n\n {endIcon && !isLoading && <span className=\"shrink-0\">{endIcon}</span>}\n </button>\n );\n }\n);\n\nClButton.displayName = 'ClButton';\n\nexport { ClButton, buttonVariants };\nexport type { ClButtonProps };\n","import type { SVGProps } from 'react';\n\nexport function CoinListLogomark(props: SVGProps<SVGSVGElement>) {\n return (\n <svg\n width=\"115\"\n height=\"125\"\n viewBox=\"0 0 115 125\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n {...props}\n >\n <path\n d=\"M69.7519 123.966C75.8021 124.172 81.7491 123.519 87.4899 121.799C98.3871 118.531 107.531 112.58 114.922 103.947C114.922 103.947 114.922 103.947 114.888 103.912C112.859 102.193 110.831 100.507 108.837 98.8218L106.809 97.1363C106.431 96.8268 106.087 96.5172 105.709 96.2076C104.919 95.5197 104.128 94.8662 103.303 94.2126C96.2902 98.8562 88.5899 101.539 80.0991 101.883C75.8364 102.055 71.6082 101.642 67.4831 100.507C60.5047 98.6154 54.2483 95.1757 49.2294 89.7755C40.0854 79.938 36.854 68.1743 39.226 55.0348C40.7041 46.9172 44.4168 40.0723 50.0888 34.5C48.8856 34.7408 47.6825 35.016 46.5137 35.3943C37.5072 38.2148 30.5976 43.6839 25.6131 51.6639C21.6598 58.0273 19.5629 64.9411 19.3223 72.4739C19.1848 76.7047 19.4598 80.7979 20.4223 84.7879C23.4818 97.2395 30.2882 107.043 40.6698 114.335H40.7729V114.403C41.1167 114.644 41.4604 114.919 41.8042 115.16C50.2607 120.801 59.5766 123.691 69.7519 124.035V123.966Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M73.1896 89.052C69.1676 90.8406 65.0081 91.8725 60.6768 92.2165C65.9707 95.209 71.7802 96.688 78.1054 96.8256C80.168 96.86 82.2305 96.6536 84.3962 96.3097C89.7245 95.4841 94.6746 93.5579 99.281 90.7374C94.9153 87.057 90.5839 83.4109 86.2181 79.7305C82.5055 83.6861 78.1741 86.8506 73.1896 89.052Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M67.9643 0.241609C67.4143 0.276006 66.8643 0.344799 66.3486 0.413592C71.6425 1.4111 76.7646 3.13093 81.6116 5.71068C91.0306 10.7326 98.3527 17.9215 103.268 27.4494L105.915 25.1448C108.631 22.7714 111.347 20.3981 114.063 18.0247C107.634 11.1797 100.072 6.15784 91.2025 3.06214C85.2898 0.998336 79.2396 -0.0335643 73.0176 0.000832322C71.3675 0.000832322 69.6831 0.138419 67.9643 0.241609Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M26.4037 107.871C18.4628 97.9988 14.1314 86.7167 14.2002 73.818C14.2002 67.317 15.5409 61.0568 18.1191 55.1062C21.9348 46.2662 27.9506 39.1805 36.4071 34.2962C44.348 29.687 52.9763 27.8984 62.1547 29.2743C71.5738 30.7189 79.3771 35.2249 85.6336 42.2762C85.6336 42.2762 85.8398 42.5514 85.9429 42.6546C86.8711 41.8291 87.8336 41.0035 88.7618 40.178L89.8962 39.1805C90.8587 38.355 91.8212 37.4951 92.7838 36.6696C94.9838 34.7434 97.1495 32.8515 99.3152 30.9253C95.087 22.223 88.7274 15.55 80.3053 10.8377C70.3706 5.26541 59.6797 3.54557 48.37 5.02463C42.7323 5.78136 37.3352 7.50119 32.1788 10.0465C14.6815 18.7145 2.06546 36.532 1.03418 58.4771C0.862296 62.0887 1.10293 65.7348 1.65294 69.3464C3.02798 78.3239 6.32808 86.4759 11.622 93.8368C15.7471 99.5123 20.6629 104.19 26.3693 107.871H26.4037Z\"\n fill=\"currentColor\"\n />\n </svg>\n );\n}\n","'use client';\n\nimport {\n ClButton,\n type ClButtonProps,\n} from '@/client/components/design-system/ClButton';\nimport { CoinListLogomark } from '@/client/components/design-system/logos/CoinListLogomark';\n\ninterface CoinListSignInButtonProps\n extends Pick<\n ClButtonProps,\n 'onClick' | 'disabled' | 'fullWidth' | 'isLoading' | 'className'\n > {}\n\nexport function CoinListSignInButton({\n onClick,\n disabled = false,\n fullWidth = false,\n isLoading = false,\n className,\n}: CoinListSignInButtonProps) {\n return (\n <ClButton\n variant=\"primary\"\n size=\"lg\"\n fullWidth={fullWidth}\n onClick={onClick}\n disabled={disabled}\n isLoading={isLoading}\n loadingText=\"Signing in...\"\n startIcon={<CoinListLogomark className=\"h-[18px] w-[16px] shrink-0\" />}\n className={className}\n >\n Continue with CoinList\n </ClButton>\n );\n}\n","import { useContext } from 'react';\nimport { CoinListContext } from '@/client/CoinListProvider';\nimport type { CoinListClient } from '@/client/core/coinlist-client';\n\nexport interface UseCoinListResult {\n /**\n * Indicates whether the CoinList client has been initialized and ready to use.\n * While isReady is false, then the current user state will be `unknown`.\n */\n isReady: boolean;\n coinlist: CoinListClient;\n}\n\nexport function useCoinList(): UseCoinListResult {\n const context = useContext(CoinListContext);\n if (context === null) {\n throw new CoinListClientInitializationError();\n }\n\n return {\n isReady: context.isReady,\n coinlist: context.coinlist,\n };\n}\n\nexport class CoinListClientInitializationError extends Error {\n constructor(\n message = 'useCoinList() must be used within CoinListProvider. Wrap your app with <CoinListProvider config={...}>.'\n ) {\n super(message);\n this.name = 'CoinListClientInitializationError';\n }\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { AlertBanner } from '@/client/components/design-system/AlertBanner';\nimport { CloseButton } from '@/client/components/design-system/CloseButton';\nimport { PoweredByCoinList } from '@/client/components/design-system/PoweredByCoinList';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport { CoinListSignInButton } from '@/client/components/oauth/CoinListSignInButton';\nimport { useCoinList } from '@/client/hooks/useCoinList';\n\nexport interface CoinListSignInCardProps {\n state?: 'idle' | 'error';\n /**\n * Called when the user clicks the sign-in button. Defaults to\n * {@link CoinListClient#startOAuth}, which redirects to the CoinList\n * authorization page. Pass your own handler to override this behavior.\n */\n onSignIn?: () => void;\n /** Called when the user clicks the close button. When omitted, no close button is rendered. */\n onClose?: () => void;\n className?: string;\n}\n\n/**\n * Sign-in card that prompts the user to authenticate with CoinList.\n *\n * Use this component only inside a tree wrapped by {@link CoinListProvider}.\n * By default, clicking the sign-in button starts the CoinList OAuth flow via\n * {@link CoinListClient#startOAuth}; pass `onSignIn` to override.\n */\nexport function CoinListSignInCard({\n state = 'idle',\n onSignIn,\n onClose,\n className,\n}: CoinListSignInCardProps = {}): ReactNode {\n const { coinlist } = useCoinList();\n const handleSignIn =\n onSignIn ??\n (() => {\n void coinlist.startOAuth();\n });\n\n return (\n <div\n className={cn(\n 'relative flex w-full max-w-md flex-col rounded-card border border-border bg-background p-6 shadow-card',\n className\n )}\n >\n {onClose && (\n <CloseButton onClick={onClose} className=\"absolute right-4 top-4\" />\n )}\n\n <div className=\"flex flex-col gap-2\">\n <h3 className={cn(typeClasses.h3, 'text-text-primary')}>\n Sign in to participate\n </h3>\n <p className={cn(typeClasses.body, 'text-text-secondary')}>\n A CoinList account is required to participate in this sale.\n </p>\n </div>\n\n <CoinListSignInButton onClick={handleSignIn} fullWidth className=\"mt-4\" />\n\n {state === 'error' && (\n <AlertBanner\n variant=\"error\"\n icon\n content=\"Error signing in. Please try again.\"\n className=\"mt-4\"\n />\n )}\n\n <PoweredByCoinList className=\"mt-4\" />\n </div>\n );\n}\n","import type { ReactNode } from 'react';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport type { Offer } from '@/shared/types/offer';\n\nexport type OfferCardUi = {\n tagline: string | null;\n bannerUrl: string | null;\n logoUrl: string | null;\n formattedStartsAt: string;\n formattedEndsAt: string;\n};\n\nconst monthYearFormatter = new Intl.DateTimeFormat('en-US', {\n month: 'short',\n year: 'numeric',\n});\n\nexport const OfferCardUi = {\n fromDomain: (offer: Offer): OfferCardUi => ({\n tagline: offer.tagline,\n bannerUrl: offer.bannerUrl,\n logoUrl: offer.logoUrl,\n formattedStartsAt: monthYearFormatter.format(offer.startsAt),\n formattedEndsAt: monthYearFormatter.format(offer.endsAt),\n }),\n};\n\nexport interface Props {\n offer: OfferCardUi;\n /** Optional click handler. When provided, the card renders as interactive. */\n onClick?: () => void;\n /** Optional className applied to the card root element. */\n className?: string;\n /** Optional className applied to an outer wrapper element. */\n containerClassName?: string;\n}\n\nexport function OfferCard({\n offer,\n onClick,\n className,\n containerClassName,\n}: Props): ReactNode {\n const cardLabel = 'Open offer details';\n\n const cardContent = (\n <>\n <div className=\"relative mb-6 h-52 w-full overflow-hidden rounded-2xl border border-border/60 bg-section\">\n {offer.bannerUrl ? (\n <img\n src={offer.bannerUrl}\n alt=\"Offer banner\"\n className=\"h-full w-full object-cover\"\n />\n ) : (\n <div className=\"h-full w-full bg-gradient-to-br from-surface via-section to-background\" />\n )}\n <div className=\"absolute inset-0 bg-gradient-to-b from-transparent via-transparent to-overlay/35\" />\n\n <div className=\"absolute inset-0 flex items-center justify-center p-6\">\n {offer.logoUrl ? (\n <img\n src={offer.logoUrl}\n alt=\"Offer logo\"\n className=\"h-28 w-28 rounded-full border border-border bg-surface object-cover shadow-[0_10px_24px_rgba(0,0,0,0.25)]\"\n />\n ) : (\n <div className=\"h-28 w-28 rounded-full border border-border bg-surface shadow-[0_10px_24px_rgba(0,0,0,0.18)]\" />\n )}\n </div>\n </div>\n\n {offer.tagline && (\n <p className={cn(typeClasses.h3, 'min-h-[2.4rem] text-text-primary')}>\n {offer.tagline}\n </p>\n )}\n\n <div className=\"mt-4 grid grid-cols-2 gap-5 border-t border-divider pt-4\">\n <div className=\"flex flex-col gap-1\">\n <span className={cn(typeClasses.subhead, 'text-text-secondary')}>\n Starts\n </span>\n <span className={cn(typeClasses.label, 'text-text-primary')}>\n {offer.formattedStartsAt}\n </span>\n </div>\n\n <div className=\"flex flex-col gap-1\">\n <span className={cn(typeClasses.subhead, 'text-text-secondary')}>\n Ends\n </span>\n <span className={cn(typeClasses.label, 'text-text-primary')}>\n {offer.formattedEndsAt}\n </span>\n </div>\n </div>\n </>\n );\n\n const baseClasses = cn(\n 'relative flex w-full max-w-[28rem] flex-col rounded-card border border-border bg-background p-6 text-left shadow-card transition-all duration-200',\n className,\n onClick &&\n 'cursor-pointer hover:-translate-y-0.5 hover:border-divider hover:shadow-[0px_14px_32px_-10px_rgba(0,0,0,0.35)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent-focus focus-visible:ring-offset-2'\n );\n\n let cardNode: ReactNode;\n if (onClick) {\n cardNode = (\n <button\n type=\"button\"\n aria-label={cardLabel}\n className={baseClasses}\n onClick={onClick}\n >\n {cardContent}\n </button>\n );\n } else {\n cardNode = <div className={baseClasses}>{cardContent}</div>;\n }\n\n if (!containerClassName) {\n return cardNode;\n }\n\n return <div className={containerClassName}>{cardNode}</div>;\n}\n","import { useEffect, useState } from 'react';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type { Offer } from '@/shared/types/offer';\n\nexport type LoadOffersReason = 'not-authenticated' | 'generic-error';\n\nexport type LoadOffersState =\n | {\n type: 'LOADING';\n }\n | {\n type: 'ERROR';\n reason: LoadOffersReason;\n }\n | {\n type: 'CONTENT';\n offers: Offer[];\n };\n\nexport interface UseOffersOptions {\n /**\n * Offers pre-fetched on the server (e.g. via `CoinListServer.fetchOffers()`).\n * When provided, the hook uses this data as-is and skips the client-side fetch entirely.\n */\n data?: Offer[];\n}\n\nexport interface UseOffersResult {\n offersState: LoadOffersState;\n}\n\nconst LOADING_STATE: LoadOffersState = { type: 'LOADING' };\n\n/**\n * Loads all CoinList offers for the current user and exposes a UI-friendly state.\n *\n * Pass `data` (pre-fetched server-side) to use that data as-is and skip\n * the client-side fetch entirely.\n *\n * Returns `LOADING` while CoinList is initializing or while offers are being fetched.\n * Returns `CONTENT` with all offers when `fetchOffers()` succeeds.\n * Returns `ERROR` with:\n * - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}\n * - `generic-error` for any other failure\n */\nexport function useOffers(options: UseOffersOptions = {}): UseOffersResult {\n const { coinlist, isReady } = useCoinList();\n const { data: serverOffers } = options;\n const [offersState, setOffersState] = useState<LoadOffersState>(\n serverOffers !== undefined\n ? { type: 'CONTENT', offers: serverOffers }\n : LOADING_STATE\n );\n\n useEffect(() => {\n let isCancelled = false;\n\n // Wait until CoinListProvider finishes auth initialization.\n if (!isReady) {\n if (serverOffers === undefined) {\n setOffersState(LOADING_STATE);\n }\n return () => {\n isCancelled = true;\n };\n }\n\n if (serverOffers !== undefined) {\n return () => {\n isCancelled = true;\n };\n }\n\n setOffersState(LOADING_STATE);\n coinlist\n .fetchOffers()\n .then((offers) => {\n if (!isCancelled) {\n setOffersState({ type: 'CONTENT', offers });\n }\n })\n .catch((error: unknown) => {\n if (!isCancelled) {\n const reason: LoadOffersReason =\n error instanceof NotAuthenticatedError\n ? 'not-authenticated'\n : 'generic-error';\n setOffersState({ type: 'ERROR', reason });\n }\n });\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist, isReady, serverOffers]);\n\n return { offersState };\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { AlertBanner } from '@/client/components/design-system/AlertBanner';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport { OfferCard, OfferCardUi } from '@/client/components/offers/OfferCard';\nimport { useOffers } from '@/client/hooks/useOffers';\nimport type { Offer } from '@/shared/types/offer';\n\nconst DEFAULT_MAX_COLUMNS = 3;\n\nexport interface OffersGridProps {\n /** Maximum number of columns to render when horizontal space allows. */\n maxColumns?: number;\n /** Optional className applied to the grid element. */\n className?: string;\n /** Optional className applied to the outer wrapper element. */\n containerClassName?: string;\n /** Optional loading slot shown while offers are being fetched. */\n loading?: ReactNode;\n /** Optional error slot shown when loading offers fails. */\n error?: ReactNode;\n /** Optional empty state slot shown when there are no available offers. */\n emptyState?: ReactNode;\n /** Optional per-offer click handler; when omitted, cards are not clickable. */\n onOfferClick?: (offer: Offer) => void;\n /**\n * Offers pre-fetched on the server (e.g. via `CoinListServer.fetchOffers()`).\n * When provided, the component uses this data as-is and skips the client-side fetch entirely.\n */\n data?: Offer[];\n}\n\n/**\n * Displays a responsive grid of offers backed by {@link useOffers}.\n *\n * Pass `data` (pre-fetched server-side) to use that data as-is and skip\n * the client-side fetch entirely.\n *\n * Uses `loading` / `error` slots when provided; otherwise renders standard\n * fallback loading and error states. Offer cards are interactive only when\n * `onOfferClick` is provided.\n */\nexport function OffersGrid({\n data,\n maxColumns,\n className,\n containerClassName,\n loading,\n error,\n emptyState,\n onOfferClick,\n}: OffersGridProps = {}): ReactNode {\n const { offersState } = useOffers({ data });\n const cols = Math.max(1, maxColumns ?? DEFAULT_MAX_COLUMNS);\n\n if (offersState.type === 'LOADING') {\n if (loading) {\n return loading;\n }\n\n return (\n <output\n aria-live=\"polite\"\n className=\"flex min-h-40 items-center justify-center rounded-2xl border border-border bg-background p-6\"\n >\n <p className={cn(typeClasses.body, 'text-text-secondary')}>\n Loading offers...\n </p>\n </output>\n );\n }\n\n if (offersState.type === 'ERROR') {\n if (error) {\n return error;\n }\n\n const errorMessage =\n offersState.reason === 'not-authenticated'\n ? 'Sign in to view available offers.'\n : 'Unable to load offers right now. Please try again.';\n\n return (\n <AlertBanner\n variant=\"error\"\n icon\n content={errorMessage}\n className=\"w-full max-w-[28rem]\"\n />\n );\n }\n\n if (offersState.offers.length === 0) {\n if (emptyState) {\n return emptyState;\n }\n\n return (\n <output\n aria-live=\"polite\"\n className=\"flex min-h-40 flex-col items-center justify-center rounded-2xl border border-border bg-background p-6 text-center\"\n >\n <p className={cn(typeClasses.body, 'font-medium text-text-primary')}>\n No offers available\n </p>\n <p className={cn(typeClasses.subhead, 'text-text-secondary')}>\n Check back soon for upcoming opportunities.\n </p>\n </output>\n );\n }\n\n const maxGridWidth = `calc(${cols} * 28rem + ${Math.max(cols - 1, 0)} * 1.5rem)`;\n\n return (\n <div className={cn('flex w-full justify-center', containerClassName)}>\n <div\n className={cn('grid w-full gap-6', className)}\n style={{\n gridTemplateColumns:\n 'repeat(auto-fit, minmax(min(100%, 20rem), 1fr))',\n maxWidth: maxGridWidth,\n }}\n >\n {offersState.offers.map((offer) => (\n <OfferCard\n key={offer.id}\n offer={OfferCardUi.fromDomain(offer)}\n onClick={onOfferClick ? () => onOfferClick(offer) : undefined}\n />\n ))}\n </div>\n </div>\n );\n}\n","'use client';\n\nimport { ChevronRight } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport { AlertBanner } from '@/client/components/design-system/AlertBanner';\nimport { ClButton } from '@/client/components/design-system/ClButton';\nimport { StepStatusIcon } from '@/client/components/design-system/StepStatusIcon';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport type {\n Requirement,\n RequirementStatusInfo,\n RequirementStatusValue,\n RequirementType,\n} from '@/shared/types/requirement';\n\nexport type RequirementVariant = 'verification' | 'wallet';\nexport const RequirementVariant = {\n fromType(type: RequirementType): RequirementVariant {\n switch (type) {\n case 'external_wallet':\n case 'whitelisted_wallet':\n return 'wallet';\n default:\n return 'verification';\n }\n },\n};\n\nexport type RequirementStatus =\n | 'required'\n | 'pending'\n | 'completed'\n | 'rejected';\nexport const RequirementStatus = {\n fromStatusValue(status: RequirementStatusValue): RequirementStatus {\n switch (status) {\n case 'not_started':\n case 'action_needed':\n return 'required';\n case 'in_progress':\n return 'pending';\n case 'completed':\n return 'completed';\n case 'rejected':\n return 'rejected';\n }\n },\n};\n\nexport type ChecklistStatus = 'inProgress' | 'eligible' | 'ineligible';\nexport const ChecklistStatus = {\n derive(statuses: RequirementStatusInfo[]): ChecklistStatus {\n if (statuses.some((s) => s.status === 'rejected')) return 'ineligible';\n if (statuses.every((s) => s.status === 'completed')) return 'eligible';\n return 'inProgress';\n },\n};\n\nexport type RequirementItemUi = {\n variant: RequirementVariant;\n status: RequirementStatus;\n label: string;\n description: string;\n walletAddress?: string;\n};\n\nexport const RequirementItemUi = {\n fromDomain(\n req: Requirement,\n statusInfo: RequirementStatusInfo | undefined,\n label: string,\n description: string,\n walletAddress?: string\n ): RequirementItemUi {\n return {\n variant: RequirementVariant.fromType(req.type),\n status: statusInfo\n ? RequirementStatus.fromStatusValue(statusInfo.status)\n : 'required',\n label,\n description,\n walletAddress,\n };\n },\n};\n\nexport interface RequirementItemProps {\n ui: RequirementItemUi;\n expanded?: boolean;\n onToggle?: () => void;\n walletAddress?: string;\n className?: string;\n onAction?: (() => void) | null;\n onContactSupport?: (() => void) | null;\n}\n\nfunction VerificationActionZone({\n status,\n onAction,\n onContactSupport,\n}: {\n status: RequirementStatus;\n onAction?: (() => void) | null;\n onContactSupport?: (() => void) | null;\n}): ReactNode {\n switch (status) {\n case 'required':\n if (onAction === null) return null;\n return (\n <ClButton size=\"sm\" onClick={onAction}>\n Continue\n </ClButton>\n );\n case 'pending':\n return (\n <AlertBanner\n variant=\"warning\"\n content=\"Under review. We'll notify you when complete.\"\n />\n );\n case 'completed':\n return <AlertBanner variant=\"success\" content=\"Identity verified.\" />;\n case 'rejected':\n return (\n <AlertBanner\n variant=\"error\"\n content={\n onContactSupport === null ? (\n 'Verification rejected.'\n ) : (\n <>\n Verification rejected.{' '}\n <button\n type=\"button\"\n onClick={onContactSupport}\n className=\"underline\"\n >\n Contact support\n </button>\n .\n </>\n )\n }\n />\n );\n }\n}\n\nfunction WalletActionZone({\n status,\n walletAddress,\n onAction,\n}: {\n status: RequirementStatus;\n walletAddress?: string;\n onAction?: (() => void) | null;\n}): ReactNode {\n if (status === 'completed') {\n return (\n <>\n {onAction !== null && (\n <ClButton size=\"sm\" variant=\"secondary\" onClick={onAction}>\n Change wallet\n </ClButton>\n )}\n <AlertBanner\n variant=\"success\"\n content={walletAddress ?? 'Connected: 0xBa4b...9f2c'}\n />\n </>\n );\n }\n\n if (status === 'rejected') {\n return (\n <>\n {onAction !== null && (\n <ClButton size=\"sm\" onClick={onAction}>\n Connect wallet\n </ClButton>\n )}\n <AlertBanner\n variant=\"error\"\n content=\"This wallet is not eligible for this sale.\"\n />\n </>\n );\n }\n\n if (onAction === null) return null;\n return (\n <ClButton size=\"sm\" onClick={onAction}>\n Connect wallet\n </ClButton>\n );\n}\n\nexport function RequirementItem({\n ui,\n expanded = false,\n onToggle,\n className,\n onAction,\n onContactSupport,\n}: RequirementItemProps) {\n return (\n <div className={cn('flex w-full flex-col', className)}>\n <button\n type=\"button\"\n onClick={onToggle}\n aria-expanded={expanded}\n className=\"flex h-14 w-full cursor-pointer items-center justify-between rounded-2xl px-2 transition-colors hover:bg-surface\"\n >\n <div className=\"flex items-center gap-3\">\n <StepStatusIcon status={ui.status} />\n <span\n className={cn(\n typeClasses.body,\n 'whitespace-nowrap font-medium text-text-primary'\n )}\n >\n {ui.label}\n </span>\n </div>\n <ChevronRight\n className={cn(\n 'h-6 w-6 shrink-0 text-text-secondary transition-transform duration-300',\n expanded && 'rotate-90'\n )}\n aria-hidden=\"true\"\n />\n </button>\n\n <div\n className={cn(\n 'grid transition-[grid-template-rows] duration-300 ease-in-out',\n expanded ? 'grid-rows-[1fr]' : 'grid-rows-[0fr]'\n )}\n >\n {/* min-h-0 lets the grid item collapse to 0 when grid-rows is 0fr */}\n <div className=\"min-h-0 overflow-hidden\">\n <div className=\"flex flex-col gap-4 px-2 pb-4\">\n <p className={cn(typeClasses.subhead, 'text-text-secondary')}>\n {ui.description}\n </p>\n {ui.variant === 'verification' ? (\n <VerificationActionZone\n status={ui.status}\n onAction={onAction}\n onContactSupport={onContactSupport}\n />\n ) : (\n <WalletActionZone\n status={ui.status}\n walletAddress={ui.walletAddress}\n onAction={onAction}\n />\n )}\n </div>\n </div>\n </div>\n </div>\n );\n}\n","import type { LucideIcon } from 'lucide-react';\nimport { CircleCheck, CircleX, Info } from 'lucide-react';\nimport { cn } from '@/client/components/design-system/utils';\n\nexport type StepStatus = 'required' | 'pending' | 'completed' | 'rejected';\n\ninterface StepStatusIconProps {\n status: StepStatus;\n className?: string;\n}\n\nconst statusConfig: Record<\n StepStatus,\n { Icon: LucideIcon; colorClass: string; fillClass: string }\n> = {\n required: {\n Icon: Info,\n colorClass: 'text-warning',\n fillClass: '[&_circle]:fill-warning-subtle',\n },\n pending: {\n Icon: Info,\n colorClass: 'text-warning',\n fillClass: '[&_circle]:fill-warning-subtle',\n },\n completed: {\n Icon: CircleCheck,\n colorClass: 'text-success',\n fillClass: '[&_circle]:fill-success-subtle',\n },\n rejected: {\n Icon: CircleX,\n colorClass: 'text-error',\n fillClass: '[&_circle]:fill-error-subtle',\n },\n};\n\nexport function StepStatusIcon({ status, className }: StepStatusIconProps) {\n const { Icon, colorClass, fillClass } = statusConfig[status];\n return (\n <Icon\n className={cn('h-6 w-6 shrink-0', colorClass, fillClass, className)}\n aria-hidden=\"true\"\n />\n );\n}\n","'use client';\n\nimport { type ReactNode, useState } from 'react';\nimport { AlertBanner } from '@/client/components/design-system/AlertBanner';\nimport { ClButton } from '@/client/components/design-system/ClButton';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport {\n ChecklistStatus,\n RequirementItem,\n RequirementItemUi,\n} from '@/client/components/requirements/RequirementItem';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport type { RequirementsData } from '@/client/hooks/useRequirements';\nimport { useRequirements } from '@/client/hooks/useRequirements';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport type { Requirement, RequirementType } from '@/shared/types/requirement';\n\nconst DEFAULT_LABELS: Record<RequirementType, string> = {\n kyc_approved: 'KYC Verification',\n identity_verified: 'Identity Verification',\n proof_of_address: 'Proof of Address',\n source_of_funds: 'Source of Funds',\n external_wallet: 'External Wallet',\n whitelisted_wallet: 'Whitelisted Wallet',\n jurisdiction: 'Jurisdiction Check',\n accreditation: 'Accreditation',\n};\n\nconst DEFAULT_DESCRIPTIONS: Record<RequirementType, string> = {\n kyc_approved: 'Complete Know Your Customer verification.',\n identity_verified: 'Verify your identity.',\n proof_of_address: 'Provide proof of your residential address.',\n source_of_funds: 'Provide documentation for your source of funds.',\n external_wallet: 'Connect an external wallet.',\n whitelisted_wallet: 'Connect a whitelisted wallet.',\n jurisdiction: 'Confirm your jurisdiction eligibility.',\n accreditation: 'Verify your accreditation status.',\n};\n\nexport interface RequirementsChecklistProps {\n offerId: OfferId;\n optionId: OfferOptionId;\n title: string;\n description: string;\n onContinue?: () => void;\n /**\n * Called when the user clicks a requirement's action button (e.g. \"Continue\", \"Connect wallet\").\n * Defaults to {@link CoinListClient#handleRequirement}, which opens the corresponding CoinList\n * page in a new tab. Pass your own handler to override this behavior, or pass `null` to disable\n * the action button entirely.\n */\n onRequirementActionOverride?: ((requirement: Requirement) => void) | null;\n /**\n * Called when the user clicks \"Contact support\" on a rejected requirement.\n * Defaults to {@link CoinListClient#contactSupport}, which opens the CoinList support ticket\n * page in a new tab. Pass your own handler to override this behavior, or pass `null` to disable\n * the contact support button entirely.\n */\n onContactSupportOverride?: ((requirement: Requirement) => void) | null;\n /** Override the default label for a requirement type. */\n getLabel?: (requirement: Requirement) => string;\n /** Override the default description for a requirement type. */\n getDescription?: (requirement: Requirement) => string | null;\n /** Optional loading slot. */\n loading?: ReactNode;\n /** Optional error slot. */\n error?: ReactNode;\n className?: string;\n /**\n * Requirements data pre-fetched on the server (e.g. via\n * `CoinListServer.fetchOfferRequirements()` + `fetchRequirementStatuses()`).\n * When provided, the component uses this data as-is and skips the client-side fetch entirely.\n */\n data?: RequirementsData;\n}\n\n/**\n * Connected requirements checklist that fetches requirements and statuses\n * via {@link useRequirements} and renders requirement items for the\n * specified option.\n *\n * Pass `data` (pre-fetched server-side) to use that data as-is and skip\n * the initial client-side fetch.\n *\n * By default, clicking a requirement's action button opens the corresponding\n * CoinList page in a new tab via {@link CoinListClient#handleRequirement}. It is\n * recommended to omit `onRequirementActionOverride` and rely on this default.\n * Pass your own handler only if you need custom navigation behavior, or `null`\n * to disable the action button entirely.\n */\nexport function RequirementsChecklist({\n offerId,\n optionId,\n title,\n description,\n onContinue,\n onRequirementActionOverride,\n onContactSupportOverride,\n getLabel,\n getDescription,\n loading,\n error,\n className,\n data,\n}: RequirementsChecklistProps): ReactNode {\n const { coinlist } = useCoinList();\n const { requirementsState } = useRequirements(offerId, { data });\n const [expandedIndex, setExpandedIndex] = useState<number | null>(null);\n\n const onRequirementAction =\n onRequirementActionOverride !== undefined\n ? onRequirementActionOverride\n : (requirement: Requirement) => coinlist.handleRequirement(requirement);\n const onContactSupport =\n onContactSupportOverride !== undefined\n ? onContactSupportOverride\n : () => coinlist.contactSupport();\n\n if (requirementsState.type === 'LOADING') {\n if (loading) return loading;\n return (\n <output\n aria-live=\"polite\"\n className=\"flex min-h-40 items-center justify-center rounded-2xl border border-border bg-background p-6\"\n >\n <p className={cn(typeClasses.body, 'text-text-secondary')}>\n Loading requirements...\n </p>\n </output>\n );\n }\n\n if (requirementsState.type === 'ERROR') {\n if (error) return error;\n const errorMessage =\n requirementsState.reason === 'not-authenticated'\n ? 'Sign in to view requirements.'\n : 'Unable to load requirements right now. Please try again.';\n return (\n <AlertBanner\n variant=\"error\"\n icon\n content={errorMessage}\n className=\"w-full max-w-[28rem]\"\n />\n );\n }\n\n const { requirements: requirementsByOptionId, statuses } = requirementsState;\n const requirements = requirementsByOptionId[optionId] ?? [];\n const requirementIds = new Set(requirements.map((r) => r.id));\n const optionStatuses = statuses.filter((s) => requirementIds.has(s.id));\n const statusByRequirementId = new Map(optionStatuses.map((s) => [s.id, s]));\n const checklistStatus: ChecklistStatus =\n ChecklistStatus.derive(optionStatuses);\n\n return (\n <div className={cn('flex w-full flex-col gap-4', className)}>\n <div className=\"flex flex-col gap-2\">\n <h3 className={cn(typeClasses.h3, 'text-text-primary')}>{title}</h3>\n <p className={cn(typeClasses.body, 'text-text-secondary')}>\n {description}\n </p>\n </div>\n\n <div className=\"flex flex-col divide-y divide-divider\">\n {requirements.map((req, index) => {\n const statusInfo = statusByRequirementId.get(req.id);\n const label = getLabel ? getLabel(req) : DEFAULT_LABELS[req.type];\n const itemDescription =\n (getDescription ? getDescription(req) : null) ??\n DEFAULT_DESCRIPTIONS[req.type];\n\n let onActionBound: (() => void) | null | undefined;\n if (onRequirementAction === null) {\n onActionBound = null;\n } else if (onRequirementAction) {\n onActionBound = () => onRequirementAction(req);\n }\n\n let onContactSupportBound: (() => void) | null | undefined;\n if (onContactSupport === null) {\n onContactSupportBound = null;\n } else if (onContactSupport) {\n onContactSupportBound = () => onContactSupport(req);\n }\n\n return (\n <RequirementItem\n key={req.id}\n ui={RequirementItemUi.fromDomain(\n req,\n statusInfo,\n label,\n itemDescription\n )}\n expanded={expandedIndex === index}\n onToggle={() =>\n setExpandedIndex((prev) => (prev === index ? null : index))\n }\n onAction={onActionBound}\n onContactSupport={onContactSupportBound}\n />\n );\n })}\n </div>\n\n {checklistStatus === 'ineligible' && (\n <AlertBanner\n variant=\"error\"\n icon\n content=\"You are not eligible to participate.\"\n />\n )}\n\n {onContinue && (\n <ClButton\n fullWidth\n disabled={checklistStatus !== 'eligible'}\n onClick={onContinue}\n >\n Continue\n </ClButton>\n )}\n </div>\n );\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport type {\n Requirement,\n RequirementStatusInfo,\n} from '@/shared/types/requirement';\n\nexport type LoadRequirementsReason = 'not-authenticated' | 'generic-error';\n\nexport type LoadRequirementsState =\n | {\n type: 'LOADING';\n }\n | {\n type: 'ERROR';\n reason: LoadRequirementsReason;\n }\n | {\n type: 'CONTENT';\n requirements: Record<OfferOptionId, Requirement[]>;\n statuses: RequirementStatusInfo[];\n };\n\nexport type RequirementsData = {\n requirements: Record<OfferOptionId, Requirement[]>;\n statuses: RequirementStatusInfo[];\n};\n\nexport interface UseRequirementsOptions {\n /**\n * Requirements data pre-fetched on the server (e.g. via\n * `CoinListServer.fetchOfferRequirements()` + `fetchRequirementStatuses()`).\n * When provided, the hook uses this data as-is and skips the initial client-side fetch.\n * Calling `refetch()` will still trigger a fresh fetch.\n */\n data?: RequirementsData;\n}\n\nexport interface UseRequirementsResult {\n requirementsState: LoadRequirementsState;\n /** Triggers a re-fetch of requirements and statuses. */\n refetch: () => void;\n}\n\nconst LOADING_STATE: LoadRequirementsState = { type: 'LOADING' };\n\n/**\n * Loads requirements (grouped by option ID) and requirement statuses for a\n * given offer, then exposes them via a state machine.\n *\n * Pass `data` (pre-fetched server-side) to use that data as-is and skip\n * the initial client-side fetch. Calling `refetch()` will still trigger a fresh fetch.\n *\n * Returns `LOADING` while CoinList is initializing or while data is being fetched.\n * Returns `CONTENT` with requirements and statuses on success.\n * Returns `ERROR` with:\n * - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}\n * - `generic-error` for any other failure\n */\nexport function useRequirements(\n offerId: OfferId,\n options: UseRequirementsOptions = {}\n): UseRequirementsResult {\n const { coinlist, isReady } = useCoinList();\n const { data } = options;\n const [requirementsState, setRequirementsState] =\n useState<LoadRequirementsState>(\n data !== undefined ? { type: 'CONTENT', ...data } : LOADING_STATE\n );\n const [fetchKey, setFetchKey] = useState(0);\n const refetch = useCallback(() => setFetchKey((k) => k + 1), []);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: fetchKey is an intentional refetch trigger\n useEffect(() => {\n let isCancelled = false;\n\n if (!isReady) {\n if (data === undefined) {\n setRequirementsState(LOADING_STATE);\n }\n return () => {\n isCancelled = true;\n };\n }\n\n if (data !== undefined && fetchKey === 0) {\n return () => {\n isCancelled = true;\n };\n }\n\n setRequirementsState(LOADING_STATE);\n Promise.all([\n coinlist.fetchOfferRequirements(offerId),\n coinlist.fetchRequirementStatuses(offerId),\n ])\n .then(([requirementsByOptionId, statuses]) => {\n if (!isCancelled) {\n setRequirementsState({\n type: 'CONTENT',\n requirements: requirementsByOptionId,\n statuses,\n });\n }\n })\n .catch((error: unknown) => {\n if (!isCancelled) {\n const reason: LoadRequirementsReason =\n error instanceof NotAuthenticatedError\n ? 'not-authenticated'\n : 'generic-error';\n setRequirementsState({ type: 'ERROR', reason });\n }\n });\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist, isReady, offerId, fetchKey]);\n\n return { requirementsState, refetch };\n}\n","import { useEffect, useRef } from 'react';\nimport type { OauthClientErrorReason } from '@/client/core/types/client-types';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport type { AuthorizationCode, CodeVerifier } from '@/shared/types/oauth';\n\n/**\n * Reasons passed to {@link UseCompleteOAuthOptions.onFailure} when the\n * OAuth callback cannot be completed. Includes PKCE / redirect validation\n * errors from {@link CoinListClient.completeOAuth} and a dedicated value when\n * {@link UseCompleteOAuthOptions.postOAuthComplete} fails or rejects.\n */\nexport type CompleteOAuthFailureReason =\n | OauthClientErrorReason\n | 'complete_request_failed';\n\nexport interface UseCompleteOAuthOptions {\n /**\n * Exchange the authorization code on your backend (e.g. POST to your API).\n * Return `true` when the session was established successfully, `false` when\n * the request completed but signing in failed. Rejections are treated like\n * `false` and reported as {@link CompleteOAuthFailureReason}\n * `\"complete_request_failed\"`.\n */\n postOAuthComplete: (payload: {\n code: AuthorizationCode;\n codeVerifier: CodeVerifier;\n }) => Promise<boolean>;\n /**\n * Called when the user denied access (`error` query parameter), when\n * {@link CoinListClient.completeOAuth} fails PKCE/state validation, or when\n * {@link UseCompleteOAuthOptions.postOAuthComplete} fails.\n */\n onFailure: (reason: CompleteOAuthFailureReason) => void | Promise<void>;\n /** Invoked after {@link UseCompleteOAuthOptions.postOAuthComplete} succeeds and {@link CoinListClient.init} has refreshed the client session. */\n onSuccess: () => void | Promise<void>;\n}\n\n/**\n * Runs the CoinList OAuth callback once on mount: validates the redirect URL via\n * {@link CoinListClient.completeOAuth}, exchanges the code via {@link UseCompleteOAuthOptions.postOAuthComplete},\n * refreshes tokens with {@link CoinListClient.init}, then calls {@link UseCompleteOAuthOptions.onSuccess}.\n *\n * Framework-agnostic: reads `window.location` like {@link CoinListClient.completeOAuth}. Supply\n * {@link UseCompleteOAuthOptions.postOAuthComplete}, {@link UseCompleteOAuthOptions.onFailure},\n * and {@link UseCompleteOAuthOptions.onSuccess} to perform redirects or routing in your app.\n *\n * Must be used within {@link CoinListProvider}.\n */\nexport function useCompleteOAuth(options: UseCompleteOAuthOptions): void {\n const { coinlist } = useCoinList();\n\n const postOAuthCompleteRef = useRef(options.postOAuthComplete);\n const onFailureRef = useRef(options.onFailure);\n const onSuccessRef = useRef(options.onSuccess);\n\n postOAuthCompleteRef.current = options.postOAuthComplete;\n onFailureRef.current = options.onFailure;\n onSuccessRef.current = options.onSuccess;\n\n const hasStartedExchangeRef = useRef(false);\n\n useEffect(() => {\n if (typeof window === 'undefined') return;\n\n const params = new URLSearchParams(window.location.search);\n if (!params.has('code') && !params.has('error')) return;\n\n if (hasStartedExchangeRef.current) return;\n\n const oauthResult = coinlist.completeOAuth();\n if (oauthResult.type === 'error') {\n void Promise.resolve(onFailureRef.current(oauthResult.reason)).catch(\n () => {}\n );\n return;\n }\n\n hasStartedExchangeRef.current = true;\n let cancelled = false;\n\n void (async () => {\n try {\n const ok = await postOAuthCompleteRef.current({\n code: oauthResult.code,\n codeVerifier: oauthResult.codeVerifier,\n });\n\n if (cancelled) return;\n\n if (!ok) {\n hasStartedExchangeRef.current = false;\n await onFailureRef.current('complete_request_failed');\n return;\n }\n\n await coinlist.init();\n\n if (cancelled) return;\n\n await onSuccessRef.current();\n } catch {\n if (cancelled) return;\n hasStartedExchangeRef.current = false;\n await onFailureRef.current('complete_request_failed');\n }\n })();\n\n return () => {\n cancelled = true;\n hasStartedExchangeRef.current = false;\n };\n }, [coinlist]);\n}\n","import { useEffect, useState } from 'react';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferDetail } from '@/shared/types/offer-detail';\n\nexport type LoadOfferDetailsReason = 'not-authenticated' | 'generic-error';\n\nexport type LoadOfferDetailsState =\n | {\n type: 'LOADING';\n }\n | {\n type: 'ERROR';\n reason: LoadOfferDetailsReason;\n }\n | {\n type: 'CONTENT';\n offerDetail: OfferDetail;\n };\n\nexport interface UseOfferDetailsOptions {\n /**\n * Offer detail pre-fetched on the server (e.g. via `CoinListServer.fetchOfferDetails()`).\n * When provided, the hook uses this data as-is and skips the client-side fetch entirely.\n */\n data?: OfferDetail;\n}\n\nexport interface UseOfferDetailsResult {\n offerDetailsState: LoadOfferDetailsState;\n}\n\nconst LOADING_STATE: LoadOfferDetailsState = { type: 'LOADING' };\n\n/**\n * Loads CoinList offer details for a given offer id and exposes a UI-friendly state.\n *\n * Pass `data` (pre-fetched server-side) to use that data as-is and skip\n * the client-side fetch entirely.\n *\n * Returns `LOADING` while CoinList is initializing or while details are being fetched.\n * Returns `CONTENT` with the offer when `fetchOfferDetails()` succeeds.\n * Returns `ERROR` with:\n * - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}\n * - `generic-error` for any other failure\n */\nexport function useOfferDetails(\n offerId: OfferId,\n options: UseOfferDetailsOptions = {}\n): UseOfferDetailsResult {\n const { coinlist, isReady } = useCoinList();\n const { data } = options;\n const [offerDetailsState, setOfferDetailsState] =\n useState<LoadOfferDetailsState>(\n data !== undefined\n ? { type: 'CONTENT', offerDetail: data }\n : LOADING_STATE\n );\n\n useEffect(() => {\n let isCancelled = false;\n\n if (!isReady) {\n if (data === undefined) {\n setOfferDetailsState(LOADING_STATE);\n }\n return () => {\n isCancelled = true;\n };\n }\n\n if (data !== undefined) {\n return () => {\n isCancelled = true;\n };\n }\n\n setOfferDetailsState(LOADING_STATE);\n coinlist\n .fetchOfferDetails(offerId)\n .then((offerDetail) => {\n if (!isCancelled) {\n setOfferDetailsState({ type: 'CONTENT', offerDetail });\n }\n })\n .catch((error: unknown) => {\n if (!isCancelled) {\n const reason: LoadOfferDetailsReason =\n error instanceof NotAuthenticatedError\n ? 'not-authenticated'\n : 'generic-error';\n setOfferDetailsState({ type: 'ERROR', reason });\n }\n });\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist, isReady, offerId, data]);\n\n return { offerDetailsState };\n}\n","import { useEffect, useState } from 'react';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { Participation } from '@/shared/types/participation';\n\nexport type LoadParticipationsReason = 'not-authenticated' | 'generic-error';\n\nexport type LoadParticipationsState =\n | {\n type: 'LOADING';\n }\n | {\n type: 'ERROR';\n reason: LoadParticipationsReason;\n }\n | {\n type: 'CONTENT';\n participations: Participation[];\n };\n\nexport interface UseParticipationsOptions {\n /**\n * Participations pre-fetched on the server (e.g. via `CoinListServer.fetchParticipations()`).\n * When provided, the hook uses this data as-is and skips the client-side fetch entirely.\n */\n data?: Participation[];\n}\n\nexport interface UseParticipationsResult {\n participationsState: LoadParticipationsState;\n}\n\nconst LOADING_STATE: LoadParticipationsState = { type: 'LOADING' };\n\n/**\n * Loads all CoinList participations for the current user and exposes a UI-friendly state.\n * Optionally filters by offer when `offerId` is provided.\n *\n * Pass `data` (pre-fetched server-side) to use that data as-is and skip\n * the client-side fetch entirely.\n *\n * Returns `LOADING` while CoinList is initializing or while participations are being fetched.\n * Returns `CONTENT` with all participations when `fetchParticipations()` succeeds.\n * Returns `ERROR` with:\n * - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}\n * - `generic-error` for any other failure\n */\nexport function useParticipations(\n offerId?: OfferId,\n options: UseParticipationsOptions = {}\n): UseParticipationsResult {\n const { coinlist, isReady } = useCoinList();\n const { data } = options;\n const [participationsState, setParticipationsState] =\n useState<LoadParticipationsState>(\n data !== undefined\n ? { type: 'CONTENT', participations: data }\n : LOADING_STATE\n );\n\n useEffect(() => {\n let isCancelled = false;\n\n // Wait until CoinListProvider finishes auth initialization.\n if (!isReady) {\n if (data === undefined) {\n setParticipationsState(LOADING_STATE);\n }\n return () => {\n isCancelled = true;\n };\n }\n\n if (data !== undefined) {\n return () => {\n isCancelled = true;\n };\n }\n\n setParticipationsState(LOADING_STATE);\n coinlist\n .fetchParticipations(offerId)\n .then((participations) => {\n if (!isCancelled) {\n setParticipationsState({ type: 'CONTENT', participations });\n }\n })\n .catch((error: unknown) => {\n if (!isCancelled) {\n const reason: LoadParticipationsReason =\n error instanceof NotAuthenticatedError\n ? 'not-authenticated'\n : 'generic-error';\n setParticipationsState({ type: 'ERROR', reason });\n }\n });\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist, isReady, offerId, data]);\n\n return { participationsState };\n}\n"],"mappings":"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","names":["jsx","jsx","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsx","jsxs","jsx","jsxs","useEffect","useState","useState","useEffect","jsx","jsxs","CircleCheck","Info","jsx","Info","CircleCheck","Fragment","jsx","jsxs","useState","useEffect","useState","LOADING_STATE","useState","useEffect","jsx","jsxs","useState","useEffect","useEffect","useEffect","useState","LOADING_STATE","useState","useEffect","useEffect","useState","LOADING_STATE","useState","useEffect"]}
1
+ {"version":3,"sources":["../../src/client/CoinListProvider.tsx","../../src/client/core/api/middleware/device-id.ts","../../src/client/core/api/middleware/user-agent.ts","../../src/client/core/api/api-client.ts","../../src/client/core/blockchain/wallet-error.ts","../../src/client/core/blockchain/swap-flows.ts","../../src/client/core/client-swap-namespace.ts","../../src/client/core/coinlist-client.ts","../../src/client/CoinListStyleScope.tsx","../../src/client/generated/sdk-styles.gen.ts","../../src/client/components/design-system/AlertBanner.tsx","../../src/client/components/design-system/tokens/typography.ts","../../src/client/components/design-system/utils.ts","../../src/client/components/design-system/CloseButton.tsx","../../src/client/components/design-system/logos/CoinListWordmark.tsx","../../src/client/components/design-system/PoweredByCoinList.tsx","../../src/client/components/design-system/ClButton.tsx","../../src/client/components/design-system/logos/CoinListLogomark.tsx","../../src/client/components/oauth/CoinListSignInButton.tsx","../../src/client/hooks/useCoinList.ts","../../src/client/components/oauth/CoinListSignInCard.tsx","../../src/client/components/offers/OfferCard.tsx","../../src/client/hooks/useOffers.ts","../../src/client/components/offers/OffersGrid.tsx","../../src/client/components/requirements/ConnectedWalletList.tsx","../../src/client/components/requirements/ConnectWalletModal.tsx","../../src/client/hooks/useConnectWallet.ts","../../src/client/core/connect-external-wallet.ts","../../src/client/components/requirements/IdentityVerification.tsx","../../src/client/hooks/useKycToken.ts","../../src/client/components/requirements/RequirementItem.tsx","../../src/client/components/design-system/StepStatusIcon.tsx","../../src/client/components/requirements/RequirementsChecklist.tsx","../../src/client/components/requirements/TaxDocumentModal.tsx","../../src/client/hooks/useTaxDocument.ts","../../src/client/hooks/useOptionAddresses.ts","../../src/client/hooks/useRequirements.ts","../../src/client/hooks/swap/useSwapOutputToken.ts","../../src/client/hooks/swap/useSwapQuote.ts","../../src/client/hooks/swap/useSwapTokenBalances.ts","../../src/client/hooks/useCompleteOAuth.ts","../../src/client/hooks/useOfferDetails.ts","../../src/client/hooks/useParticipations.ts"],"sourcesContent":["'use client';\n\n/**\n * CoinList React context + initialization.\n *\n * Both exports provide the client context and nothing visual, so both are safe to mount\n * app-wide. SDK visual components style themselves (each self-scopes via\n * CoinListStyleScope), so neither provider applies styling to the host's own DOM.\n *\n * - CoinListProvider: the provider to mount once at your app root.\n * - CoinListContextProvider: identical; the explicit name for when you want the\n * intent (context only) spelled out.\n */\n\nimport {\n createContext,\n type ReactNode,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport {\n type ClientConfig,\n type CoinListClient,\n createCoinListClient,\n} from '@/client/core/coinlist-client';\n\nexport type CoinListContextValue = {\n coinlist: CoinListClient;\n isReady: boolean;\n};\n\nexport const CoinListContext = createContext<CoinListContextValue | null>(null);\n\nexport type CoinListProviderProps = {\n config: ClientConfig;\n children: ReactNode;\n};\n\n/**\n * Provide CoinList (api + config) to the tree WITHOUT any styling. Renders only the\n * React context: no DOM, no <style>, no .clco-sdk-root. Safe to mount app-wide:\n * it has zero visual impact on the host's own pages.\n *\n * Use this when you need useCoinList() available app-wide. SDK visual components\n * self-scope, so you do not need to wrap them in {@link CoinListStyleScope}.\n * {@link CoinListProvider} is an identical alias with a friendlier name.\n */\nexport function CoinListContextProvider({\n config,\n children,\n}: CoinListProviderProps) {\n const [isReady, setIsReady] = useState(false);\n const coinlist = useMemo(() => createCoinListClient(config), [config]);\n\n useEffect(() => {\n let isCancelled = false;\n if (coinlist.getAuthState() === 'unknown') {\n coinlist\n .init()\n .then(() => {\n if (!isCancelled) {\n setIsReady(true);\n }\n })\n .catch(() => {\n if (!isCancelled) {\n setIsReady(true);\n }\n });\n } else {\n setIsReady(true);\n }\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist]);\n\n const value = useMemo(() => ({ coinlist, isReady }), [coinlist, isReady]);\n\n return (\n <CoinListContext.Provider value={value}>\n {children}\n </CoinListContext.Provider>\n );\n}\n\n/**\n * The provider to mount once at your app root. Provides the CoinList client context\n * to the whole tree with zero visual impact: it renders no DOM, no `<style>`, and no\n * `.clco-sdk-root`, so it never styles the host's own pages. SDK visual components\n * (CoinListSignInCard, OffersGrid, ...) style themselves, so you do not need to wrap\n * them in {@link CoinListStyleScope}.\n *\n * Alias of {@link CoinListContextProvider}: identical behavior, friendlier name for\n * the common \"mount one provider\" case.\n */\nexport const CoinListProvider = CoinListContextProvider;\n","'use client';\n\nimport { getUUIDv4 } from '@/shared/utils';\n\nconst DEVICE_ID_KEY = 'coinlist.device_id';\n\n/**\n * Get or create a device ID stored in localStorage.\n * Uses a crypto UUID that persists across sessions.\n */\nexport function getDeviceId(): string {\n let deviceId = localStorage.getItem(DEVICE_ID_KEY);\n\n if (!deviceId) {\n deviceId = getUUIDv4();\n localStorage.setItem(DEVICE_ID_KEY, deviceId);\n }\n\n return deviceId;\n}\n\n/**\n * Clear the stored device ID (useful for testing or logout).\n */\nexport function clearDeviceId(): void {\n localStorage.removeItem(DEVICE_ID_KEY);\n}\n","'use client';\n\nimport { getDeviceId } from '@/client/core/api/middleware/device-id';\nimport { HEADER_USER_AGENT } from '@/shared/api/frontline/config';\nimport type { HttpRequest } from '@/shared/api/http';\nimport { Attributes } from '@/shared/api/http-attributes';\nimport type { BeforeRequestMiddleware } from '@/shared/api/http-client';\n\nexport const userAgentMiddleware: BeforeRequestMiddleware = async (\n request: HttpRequest\n): Promise<HttpRequest> => {\n if (!Attributes.needUserAgent(request.attributes)) {\n return request;\n }\n\n const userAgent = generateUserAgent();\n return {\n ...request,\n headers: {\n ...(request.headers ?? {}),\n [HEADER_USER_AGENT]: userAgent,\n },\n };\n};\n\n// Generate User-Agent in the required format for Frontline API\n// Format: <app-info> (<device-info>; DevicePlatform <device-platform>; DeviceAppID <device-app-id>; DeviceID <device-id>)\nfunction generateUserAgent(): string {\n const appInfo = `CoinList/1.0`;\n const deviceInfo = 'Web Browser';\n const devicePlatform = 'DevicePlatform web'; // Must be 'web' for validation\n\n const deviceAppId = 'DeviceAppID co.coinlist.sdk'; // SDK app ID\n\n const deviceId = getDeviceId();\n const finalDeviceId = `DeviceID ${deviceId}`;\n\n return `${appInfo} (${deviceInfo}; ${devicePlatform}; ${deviceAppId}; ${finalDeviceId})`;\n}\n","'use client';\n\nimport { userAgentMiddleware } from '@/client/core/api/middleware/user-agent';\nimport { AuthenticatedApiClient } from '@/shared/api/authenticated-api-client';\nimport type { HttpClientConfig, HttpRequest } from '@/shared/api/http';\nimport type { OAuthAccessToken } from '@/shared/types/oauth-session';\n\nexport class ApiClient {\n private readonly client: AuthenticatedApiClient;\n\n constructor(\n config: HttpClientConfig,\n fetchAccessToken: (refresh: boolean) => Promise<OAuthAccessToken | null>\n ) {\n this.client = new AuthenticatedApiClient(config, fetchAccessToken, [\n userAgentMiddleware,\n ]);\n }\n\n async send<TResponse>(request: HttpRequest): Promise<TResponse> {\n return this.client.send<TResponse>(request);\n }\n}\n","import {\n ContractFunctionRevertedError,\n type Hash,\n InsufficientFundsError,\n UserRejectedRequestError,\n WaitForTransactionReceiptTimeoutError,\n} from 'viem';\n\n/**\n * A classified wallet/transaction failure. The SDK derives this from whatever\n * the {@link EvmWallet} throws, so consumers get a stable, typed error\n * shape regardless of the underlying wallet library.\n */\nexport type WalletError =\n | { type: 'user_rejected' }\n | { type: 'insufficient_funds' }\n | { type: 'contract_reverted'; reason: string }\n | { type: 'timeout'; hash: Hash }\n | { type: 'unknown'; cause: unknown };\n\n/**\n * Classifies an error thrown by an {@link EvmWallet} into a typed\n * {@link WalletError}. Pass the transaction `hash` when awaiting a receipt so a\n * timeout can be reported against it.\n */\nexport function classifyWalletError(\n error: unknown,\n ctx?: { hash?: Hash }\n): WalletError {\n if (error instanceof UserRejectedRequestError) {\n return { type: 'user_rejected' };\n }\n if (error instanceof InsufficientFundsError) {\n return { type: 'insufficient_funds' };\n }\n if (error instanceof ContractFunctionRevertedError) {\n return { type: 'contract_reverted', reason: error.reason ?? error.message };\n }\n if (error instanceof WaitForTransactionReceiptTimeoutError && ctx?.hash) {\n return { type: 'timeout', hash: ctx.hash };\n }\n return { type: 'unknown', cause: error };\n}\n","import type { Hash, Hex, TransactionReceipt } from 'viem';\nimport type { EvmWallet } from '@/client/core/blockchain/evm-wallet';\nimport {\n classifyWalletError,\n type WalletError,\n} from '@/client/core/blockchain/wallet-error';\nimport { ERC20_ABI } from '@/shared/core/blockchain/abis/erc20';\nimport { SUPERSTATE_SWAP_ABI } from '@/shared/core/blockchain/abis/superstate-swap';\nimport { computePrice, computeSlip } from '@/shared/core/blockchain/swap/math';\nimport type { SwapQuote } from '@/shared/core/blockchain/swap/quote';\nimport { isStopped } from '@/shared/core/blockchain/swap/status';\nimport { decodeSwappedOutputAmount } from '@/shared/core/blockchain/swap/swapped-event';\nimport type { CoinListSwapNamespace } from '@/shared/core/swap-namespace';\nimport {\n BlockchainAmount,\n type Bps,\n type EthereumChain,\n type EvmContractAddress,\n type EvmWalletAddress,\n} from '@/shared/types/blockchain/core';\nimport type { OfferId } from '@/shared/types/offer';\nimport type {\n AllowWalletResponse,\n SwapAuthorization,\n SwapStatus,\n TokenAllowance,\n} from '@/shared/types/swap';\nimport type { WalletOwnershipChallenge } from '@/shared/types/wallet-ownership-challenge';\n\n// ---------------------------------------------------------------------------\n// executeSwap\n// ---------------------------------------------------------------------------\n\n/**\n * Progress phases emitted by {@link executeSwap}, in the order they occur. An\n * allowance that already covers the swap skips the approval phases.\n */\nexport type SwapExecutionPhase =\n | 'checking-status'\n | 'checking-allowance'\n | 'resetting-allowance'\n | 'confirming-allowance-reset'\n | 'approving'\n | 'confirming-approval'\n | 'swapping'\n | 'confirming-swap';\n\n/** A step-tagged reason {@link executeSwap} failed. */\nexport type SwapExecutionError =\n | { step: 'status-check' }\n | { step: 'swap-stopped' }\n | { step: 'allowance-check' }\n | { step: 'approval'; cause: WalletError }\n | { step: 'approval-reverted' }\n | { step: 'swap'; cause: WalletError }\n | { step: 'swap-reverted' };\n\nexport type SwapExecutionResult =\n | {\n type: 'success';\n swapTxHash: Hash;\n inputAmount: BlockchainAmount;\n fee: BlockchainAmount;\n outputAmount: BlockchainAmount;\n pricePerShare: BlockchainAmount | null;\n recipientAddress: EvmWalletAddress;\n }\n | { type: 'error'; error: SwapExecutionError };\n\nexport type ExecuteSwapParams = {\n swap: CoinListSwapNamespace;\n wallet: EvmWallet;\n contractAddress: EvmContractAddress;\n chain: EthereumChain;\n inputTokenAddress: EvmContractAddress;\n quote: SwapQuote;\n slippageBps: Bps;\n onProgress?: (phase: SwapExecutionPhase) => void;\n};\n\n/**\n * Executes an on-chain swap end-to-end: verifies the contract is not paused,\n * ensures a sufficient ERC-20 allowance (resetting a stale non-zero allowance\n * first for USDT-style tokens), submits the swap, waits for it to mine, and\n * decodes the confirmed output from the `Swapped` event (falling back to the\n * quote's estimate).\n *\n * The wallet is only asked to sign after all read-only checks pass, so a user\n * never signs a transaction the swap would revert. Progress is reported via\n * `onProgress` for consumers rendering loading states.\n */\nexport async function executeSwap(\n params: ExecuteSwapParams\n): Promise<SwapExecutionResult> {\n const {\n swap,\n wallet,\n contractAddress,\n chain,\n inputTokenAddress,\n quote,\n slippageBps,\n onProgress,\n } = params;\n const emit = (phase: SwapExecutionPhase) => onProgress?.(phase);\n\n const inputAmount = BlockchainAmount.add(\n quote.inputTokenAmount,\n quote.fee\n ).raw;\n const minOut = computeSlip(quote.outputTokenAmount, slippageBps).raw;\n\n // Step 0: Refuse to swap when the contract is stopped (paused). Run before\n // any approval so the user never signs a tx that the swap would revert.\n emit('checking-status');\n let status: SwapStatus;\n try {\n status = await swap.getStatus({ contractAddress, chain });\n } catch {\n // Fail closed: block when we cannot verify the contract status.\n return { type: 'error', error: { step: 'status-check' } };\n }\n if (isStopped(status)) {\n return { type: 'error', error: { step: 'swap-stopped' } };\n }\n\n // Step 1: Read the current ERC-20 allowance for the swap contract.\n emit('checking-allowance');\n let allowance: TokenAllowance;\n try {\n allowance = await swap.getTokenAllowance({\n tokenAddress: inputTokenAddress,\n owner: wallet.address,\n spender: contractAddress,\n chain,\n });\n } catch {\n return { type: 'error', error: { step: 'allowance-check' } };\n }\n\n // Step 2: Approve only when the current allowance is insufficient.\n if (allowance.allowance < inputAmount) {\n // Some ERC-20s (e.g. USDT) reject a non-zero -> non-zero approve(); the\n // existing allowance must first be reset to 0.\n if (allowance.allowance > 0n) {\n const reset = await submitApproval({\n wallet,\n tokenAddress: inputTokenAddress,\n spender: contractAddress,\n chain,\n value: 0n,\n pending: 'resetting-allowance',\n confirming: 'confirming-allowance-reset',\n emit,\n });\n if (reset.type === 'error') return { type: 'error', error: reset.error };\n }\n\n const approve = await submitApproval({\n wallet,\n tokenAddress: inputTokenAddress,\n spender: contractAddress,\n chain,\n value: inputAmount,\n pending: 'approving',\n confirming: 'confirming-approval',\n emit,\n });\n if (approve.type === 'error')\n return { type: 'error', error: approve.error };\n }\n\n // Step 3: Execute the swap.\n emit('swapping');\n let swapTxHash: Hash;\n try {\n swapTxHash = await wallet.writeContract({\n abi: SUPERSTATE_SWAP_ABI,\n address: contractAddress,\n functionName: 'swap',\n args: [inputTokenAddress, inputAmount, minOut],\n chain,\n });\n } catch (error) {\n return {\n type: 'error',\n error: { step: 'swap', cause: classifyWalletError(error) },\n };\n }\n\n // Step 4: Await the swap receipt.\n emit('confirming-swap');\n let receipt: TransactionReceipt;\n try {\n receipt = await wallet.awaitTx(swapTxHash, chain);\n } catch (error) {\n return {\n type: 'error',\n error: {\n step: 'swap',\n cause: classifyWalletError(error, { hash: swapTxHash }),\n },\n };\n }\n // Only complete when the swap mined successfully (not reverted).\n if (receipt.status !== 'success') {\n return { type: 'error', error: { step: 'swap-reverted' } };\n }\n\n // Step 5: Read the confirmed output from the Swapped event, falling back to\n // the quote estimate when the event can't be decoded.\n const outputAmount =\n decodeSwappedOutputAmount(receipt, quote.outputTokenAmount.decimals) ??\n quote.outputTokenAmount;\n const finalQuote: SwapQuote = { ...quote, outputTokenAmount: outputAmount };\n\n return {\n type: 'success',\n swapTxHash,\n inputAmount: finalQuote.inputTokenAmount,\n fee: finalQuote.fee,\n outputAmount,\n pricePerShare: computePrice(finalQuote),\n recipientAddress: wallet.address,\n };\n}\n\n/** Submits an ERC-20 `approve()` and waits for it to mine successfully. */\nasync function submitApproval(args: {\n wallet: EvmWallet;\n tokenAddress: EvmContractAddress;\n spender: EvmContractAddress;\n chain: EthereumChain;\n value: bigint;\n pending: SwapExecutionPhase;\n confirming: SwapExecutionPhase;\n emit: (phase: SwapExecutionPhase) => void;\n}): Promise<{ type: 'ok' } | { type: 'error'; error: SwapExecutionError }> {\n const {\n wallet,\n tokenAddress,\n spender,\n chain,\n value,\n pending,\n confirming,\n emit,\n } = args;\n\n emit(pending);\n let hash: Hash;\n try {\n hash = await wallet.writeContract({\n abi: ERC20_ABI,\n address: tokenAddress,\n functionName: 'approve',\n args: [spender, value],\n chain,\n });\n } catch (error) {\n return {\n type: 'error',\n error: { step: 'approval', cause: classifyWalletError(error) },\n };\n }\n\n emit(confirming);\n let receipt: TransactionReceipt;\n try {\n receipt = await wallet.awaitTx(hash, chain);\n } catch (error) {\n return {\n type: 'error',\n error: { step: 'approval', cause: classifyWalletError(error, { hash }) },\n };\n }\n if (receipt.status !== 'success') {\n return { type: 'error', error: { step: 'approval-reverted' } };\n }\n return { type: 'ok' };\n}\n\n// ---------------------------------------------------------------------------\n// authorizeWallet\n// ---------------------------------------------------------------------------\n\n/** Progress phases emitted by {@link authorizeWallet}, in order. */\nexport type WalletAuthorizationPhase =\n | 'checking-authorization'\n | 'requesting-challenge'\n | 'signing-message'\n | 'submitting-signature'\n | 'broadcasting-transaction'\n | 'awaiting-confirmation'\n | 'verifying-authorization';\n\n/** A step-tagged reason {@link authorizeWallet} failed. */\nexport type WalletAuthorizationError =\n | { step: 'authorization-check' }\n | { step: 'challenge-request' }\n | { step: 'signing'; cause: WalletError }\n | { step: 'allow-wallet' }\n | { step: 'broadcast'; cause: WalletError }\n | { step: 'not-authorized' };\n\nexport type WalletAuthorizationResult =\n | { type: 'success' }\n | { type: 'error'; error: WalletAuthorizationError };\n\nexport type AuthorizeWalletParams = {\n swap: CoinListSwapNamespace;\n wallet: EvmWallet;\n offerId: OfferId;\n contractAddress: EvmContractAddress;\n chain: EthereumChain;\n onProgress?: (phase: WalletAuthorizationPhase) => void;\n};\n\n/**\n * Proves ownership of a wallet and allow-lists it for an offer's swap: checks\n * whether it is already authorized, otherwise signs a challenge, submits it,\n * broadcasts any returned allow-list transaction, and re-verifies on-chain.\n *\n * Wallet selection/connection is the app's responsibility — this operates on an\n * already-connected {@link EvmWallet}. Progress is reported via\n * `onProgress`.\n */\nexport async function authorizeWallet(\n params: AuthorizeWalletParams\n): Promise<WalletAuthorizationResult> {\n const { swap, wallet, offerId, contractAddress, chain, onProgress } = params;\n const emit = (phase: WalletAuthorizationPhase) => onProgress?.(phase);\n const walletAddress = wallet.address;\n\n // Step 1: Check if the wallet is already authorized.\n emit('checking-authorization');\n let auth: SwapAuthorization;\n try {\n auth = await swap.getAuthorization({\n walletAddress,\n contractAddress,\n chain,\n });\n } catch {\n return { type: 'error', error: { step: 'authorization-check' } };\n }\n if (auth.authorized) return { type: 'success' };\n\n // Step 2: Request a challenge to sign.\n emit('requesting-challenge');\n let challenge: WalletOwnershipChallenge;\n try {\n challenge = await swap.requestWalletOwnershipChallenge({\n walletAddress,\n chain,\n challengeType: 'plain',\n });\n } catch {\n return { type: 'error', error: { step: 'challenge-request' } };\n }\n\n // Step 3: Sign the challenge message.\n emit('signing-message');\n let signature: Hex;\n try {\n signature = await wallet.signMessage(challenge.message);\n } catch (error) {\n return {\n type: 'error',\n error: { step: 'signing', cause: classifyWalletError(error) },\n };\n }\n\n // Step 4: Submit the signature to allow-list the wallet.\n emit('submitting-signature');\n let allow: AllowWalletResponse;\n try {\n allow = await swap.allowWallet({\n offerId,\n walletAddress,\n chain,\n signature,\n });\n } catch {\n return { type: 'error', error: { step: 'allow-wallet' } };\n }\n\n // Step 5: Broadcast the allow-list transaction when one is required.\n if (allow.action === 'broadcast_transaction') {\n emit('broadcasting-transaction');\n let hash: Hash;\n try {\n hash = await wallet.broadcastRawTx({\n to: allow.to,\n data: allow.data,\n chain,\n });\n } catch (error) {\n return {\n type: 'error',\n error: { step: 'broadcast', cause: classifyWalletError(error) },\n };\n }\n\n emit('awaiting-confirmation');\n try {\n await wallet.awaitTx(hash, chain);\n } catch (error) {\n return {\n type: 'error',\n error: {\n step: 'broadcast',\n cause: classifyWalletError(error, { hash }),\n },\n };\n }\n }\n\n // Step 6: Re-verify authorization on-chain.\n emit('verifying-authorization');\n let reCheck: SwapAuthorization;\n try {\n reCheck = await swap.getAuthorization({\n walletAddress,\n contractAddress,\n chain,\n });\n } catch {\n return { type: 'error', error: { step: 'authorization-check' } };\n }\n if (!reCheck.authorized) {\n return { type: 'error', error: { step: 'not-authorized' } };\n }\n\n return { type: 'success' };\n}\n","import {\n type AuthorizeWalletParams,\n authorizeWallet,\n type ExecuteSwapParams,\n executeSwap,\n type SwapExecutionResult,\n type WalletAuthorizationResult,\n} from '@/client/core/blockchain/swap-flows';\nimport {\n type CoinListSwapNamespace,\n SwapNamespaceImpl,\n} from '@/shared/core/swap-namespace';\n\n/**\n * The client-side swap namespace: everything the shared\n * {@link CoinListSwapNamespace} reads/writes over the API, plus the on-chain\n * flows that drive a wallet (`executeSwap`, `authorizeWallet`). The flows take\n * the wallet and addresses per call; the namespace itself supplies the API\n * reads they depend on.\n */\nexport interface CoinListClientSwapNamespace extends CoinListSwapNamespace {\n /**\n * Runs an on-chain swap end-to-end against the given wallet: status check,\n * ERC-20 allowance/approval, swap submission, and receipt confirmation.\n */\n executeSwap(\n params: Omit<ExecuteSwapParams, 'swap'>\n ): Promise<SwapExecutionResult>;\n\n /**\n * Proves ownership of a wallet and allow-lists it for an offer's swap,\n * broadcasting any required allow-list transaction.\n */\n authorizeWallet(\n params: Omit<AuthorizeWalletParams, 'swap'>\n ): Promise<WalletAuthorizationResult>;\n}\n\nexport class ClientSwapNamespaceImpl\n extends SwapNamespaceImpl\n implements CoinListClientSwapNamespace\n{\n executeSwap(\n params: Omit<ExecuteSwapParams, 'swap'>\n ): Promise<SwapExecutionResult> {\n return executeSwap({ ...params, swap: this });\n }\n\n authorizeWallet(\n params: Omit<AuthorizeWalletParams, 'swap'>\n ): Promise<WalletAuthorizationResult> {\n return authorizeWallet({ ...params, swap: this });\n }\n}\n","import { ApiClient } from '@/client/core/api/api-client';\nimport {\n ClientSwapNamespaceImpl,\n type CoinListClientSwapNamespace,\n} from '@/client/core/client-swap-namespace';\nimport type {\n AuthState,\n OauthClientResult,\n} from '@/client/core/types/client-types';\nimport {\n API_VERSION,\n COINLIST_BASE_URL,\n OAUTH_PAGE_PATH,\n PUBLIC_API_BASE_URL,\n SUPPORT_NEW_TICKET_URL,\n VERIFY_IDENTITY_ACCREDITATION_PATH,\n VERIFY_IDENTITY_PATH,\n VERIFY_IDENTITY_PROOF_OF_ADDRESS_PATH,\n VERIFY_IDENTITY_SOURCE_OF_FUNDS_PATH,\n VERIFY_IDENTITY_VERIFIED_PATH,\n WALLET_PATH,\n} from '@/shared/api/frontline/config';\nimport * as documentsApi from '@/shared/api/frontline/documents';\nimport * as kycApi from '@/shared/api/frontline/kyc';\nimport * as offersApi from '@/shared/api/frontline/offers';\nimport * as participationsApi from '@/shared/api/frontline/participations';\nimport * as piiApi from '@/shared/api/frontline/pii';\nimport * as requirementsApi from '@/shared/api/frontline/requirements';\nimport * as walletConnectApi from '@/shared/api/frontline/wallet-connect';\nimport type {\n PaginatedResponse,\n PaginationParams,\n} from '@/shared/api/pagination';\nimport { generatePKCEParams } from '@/shared/pkce';\nimport type { Config } from '@/shared/types/config';\nimport type {\n DocumentSubmission,\n DocumentType,\n} from '@/shared/types/document-submission';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type { KycLevelName, KycToken } from '@/shared/types/kyc';\nimport { AuthorizationCode, CodeVerifier } from '@/shared/types/oauth';\nimport type { OAuthAccessToken } from '@/shared/types/oauth-session';\nimport type { Offer, OfferId } from '@/shared/types/offer';\nimport type { OfferDetail, OfferOptionId } from '@/shared/types/offer-detail';\nimport type {\n ConnectExternalWalletParams,\n OfferOptionAddress,\n OfferOptionAddressId,\n} from '@/shared/types/offer-option-address';\nimport type {\n CreateParticipationParams,\n Participation,\n ParticipationId,\n ParticipationsPaginationParams,\n} from '@/shared/types/participation';\nimport type { Pii } from '@/shared/types/pii';\nimport type {\n Requirement,\n RequirementStatusInfo,\n} from '@/shared/types/requirement';\nimport type {\n CreateWalletOwnershipChallengeParams,\n WalletOwnershipChallenge,\n} from '@/shared/types/wallet-ownership-challenge';\n\n/** Session storage keys for OAuth PKCE (used by startOauth and completeOauth). */\nexport const OAUTH_STATE_KEY = 'coinlist.oauth_state';\nexport const OAUTH_CODE_VERIFIER_KEY = 'coinlist.oauth_code_verifier';\n\nexport interface ClientConfig extends Config {\n /**\n * The SDK user must provide this function. It is responsible for fetching a\n * valid {@link OAuthAccessToken}, or **null** for logged-out users. If your\n * backend is in TypeScript, it is recommended to use\n * {@link CoinListServer#accessToken} from `@/server/coinlist.server`.\n */\n getAccessToken: () => Promise<OAuthAccessToken | null>;\n /**\n * Recommended to leave undefined. Used to change the CoinList environment;\n * default is production.\n */\n coinlistBaseUrl?: string;\n}\n\nexport interface CoinListClient {\n /**\n * Calls the provided {@link ClientConfig.getAccessToken} lambda to determine\n * the user's {@link AuthState}. This is called automatically by {@link CoinListProvider};\n * you typically do not need to call it yourself unless you are using the client\n * outside of the provider.\n */\n init(): Promise<AuthState>;\n /**\n * Returns the current auth state: `'logged-in'`, `'logged-out'`, or `'unknown'`.\n * Returns **unknown** until {@link CoinListClient.init} has completed. It is\n * recommended to use the `const { isReady, coinlist } = useCoinList()` hook to know when\n * the SDK has initialized, or to manually await {@link CoinListClient.init}\n * before relying on this value.\n */\n getAuthState(): AuthState;\n /**\n * Starts the OAuth flow with PKCE. Generates a random `state` and `code_verifier`,\n * stores them in sessionStorage (for validation in {@link CoinListClient.completeOAuth}\n * on redirect), then redirects the user to the CoinList authorization page. After\n * the user authorizes, they are sent back to your application's redirect URI; call\n * {@link CoinListClient.completeOAuth} on that page to finish the flow.\n */\n startOAuth(): Promise<void>;\n /**\n * Completes the OAuth flow on the FE with PKCE and state validation. Parses the\n * redirect URL (state, code) and validates them against sessionStorage\n * (state, code_verifier). The state check protects against CSRF (cross-site\n * request forgery). Call this on the frontend page the user is redirected\n * to after authorizing.\n *\n * On `ok`: Call your backend to exchange the short-lived `authorizationCode`\n * (and the returned `codeVerifier`) for a long-lived session. If your backend\n * is in TypeScript, you can use {@link CoinListServer#completeOAuth} from\n * `@/server/coinlist.server` (CoinListServer) to perform that exchange.\n *\n * On `error`: `reason` is an {@link OauthClientErrorReason} (e.g. `'missing_state'`, `'invalid_state'`) so you can switch on it and surface a message to the user.\n */\n completeOAuth(): OauthClientResult;\n /**\n * Clears the in-memory access token. Note: you need to manually\n * also logout on the backend via CoinListServer#logout to clear the session cookie.\n */\n logout(): void;\n\n /**\n * Fetches all offers by iterating through every paginated response.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n fetchOffers(): Promise<Offer[]>;\n /**\n * Fetches a single page of offers.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n fetchOffersPage(params: PaginationParams): Promise<PaginatedResponse<Offer>>;\n /**\n * Fetches details for a given offer by its id.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n fetchOfferDetails(id: OfferId): Promise<OfferDetail>;\n /**\n * Fetches all participations by iterating through every paginated response.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n fetchParticipations(offerId?: OfferId): Promise<Participation[]>;\n /**\n * Fetches a single page of participations, optionally filtered by offer.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n fetchParticipationsPage(\n params: ParticipationsPaginationParams\n ): Promise<PaginatedResponse<Participation>>;\n /**\n * Fetches a participation by id.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n fetchParticipation(id: ParticipationId): Promise<Participation>;\n /**\n * Creates a participation.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n createParticipation(\n params: CreateParticipationParams\n ): Promise<Participation>;\n /**\n * Creates a single-use wallet-ownership challenge for the given wallet and\n * chain. The user signs the returned {@link WalletOwnershipChallenge.message}\n * with their wallet, then passes the signature to\n * {@link connectExternalWallet}.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n createWalletOwnershipChallenge(\n params: CreateWalletOwnershipChallengeParams\n ): Promise<WalletOwnershipChallenge>;\n /**\n * Connects a proven external wallet to an offer option, using a signature of\n * a challenge from {@link createWalletOwnershipChallenge}.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n connectExternalWallet(\n offerId: OfferId,\n params: ConnectExternalWalletParams\n ): Promise<OfferOptionAddress>;\n /**\n * Lists the user's proven wallet bindings for a single offer option (the\n * bound address for `external_wallet`, or all whitelisted wallets for\n * `whitelisted_wallet`).\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n listOptionAddresses(\n offerId: OfferId,\n offerOptionId: OfferOptionId\n ): Promise<OfferOptionAddress[]>;\n /**\n * Removes one of the user's wallet bindings and returns the removed binding.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n removeOptionAddress(\n offerId: OfferId,\n addressId: OfferOptionAddressId\n ): Promise<OfferOptionAddress>;\n /**\n * Fetches the requirements for all options of a given offer, grouped by option ID.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n fetchOfferRequirements(\n offerId: OfferId\n ): Promise<Record<OfferOptionId, Requirement[]>>;\n /**\n * Fetches the user's requirement statuses for a given offer.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n fetchRequirementStatuses(offerId: OfferId): Promise<RequirementStatusInfo[]>;\n /**\n * Fetches the current user's PII, used to pre-fill tax forms such as the\n * W-8BEN. Fields the entity hasn't provided are `null`.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n fetchPii(): Promise<Pii>;\n /**\n * Starts (or resumes) a document signing submission for the given type\n * (currently only `tax_certification`, e.g. W-8BEN/W-8BEN-E). `fields` are\n * signing-form values keyed by the document's DocuSeal field names,\n * forwarded verbatim to Passport to pre-fill the document.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n submitDocument(\n documentType: DocumentType,\n fields: Record<string, string>\n ): Promise<DocumentSubmission>;\n /**\n * Creates a short-lived Sumsub WebSDK access token for the current user so an\n * identity verification (KYC) flow can be started, e.g. by the\n * `IdentityVerification` component. `levelName` selects the Sumsub\n * verification level; defaults to the backend's standard level. `reset`\n * resets the Sumsub applicant first, so an already-approved level can be\n * executed again (e.g. to update stale PII) — pass the `kycReset` value\n * from the requirement status, and never on mid-flow token refreshes.\n *\n * This method must be called only when the user's {@link AuthState} is\n * `'logged-in'`. If the user is not authenticated, it throws\n * {@link NotAuthenticatedError}.\n */\n createKycToken(levelName?: KycLevelName, reset?: boolean): Promise<KycToken>;\n /**\n * Opens the CoinList page for completing a given requirement in a new tab.\n * For `jurisdiction` and `document` requirements there is no CTA, so this\n * is a no-op — `document` requires the caller to use {@link fetchPii} and\n * {@link submitDocument} directly (e.g. via a custom\n * `onRequirementActionOverride`).\n */\n handleRequirement(requirement: Requirement): void;\n /**\n * Opens the CoinList support ticket page in a new tab.\n */\n contactSupport(): void;\n\n /**\n * On-chain swap operations: quoting a swap, reading swap-contract state and\n * token allowances, and proving/allow-listing wallet ownership — e.g.\n * `coinlist.swap.getOutputToken({ contractAddress, chain })`.\n *\n * The API-backed reads must be called only when the user's {@link AuthState}\n * is `'logged-in'`; if the user is not authenticated, they throw\n * {@link NotAuthenticatedError}. The on-chain flows (`executeSwap`,\n * `authorizeWallet`) additionally drive a caller-supplied wallet.\n */\n readonly swap: CoinListClientSwapNamespace;\n}\n\nclass CoinListClientImpl implements CoinListClient {\n /** Cached access token: undefined = loading, null = no token, AccessToken = logged in */\n private _accessToken: OAuthAccessToken | null | undefined = undefined;\n private readonly api: ApiClient;\n readonly swap: CoinListClientSwapNamespace;\n\n constructor(readonly _config: ClientConfig) {\n this.api = new ApiClient(\n {\n baseUrl: _config.baseUrl || PUBLIC_API_BASE_URL,\n xApiVersion: API_VERSION,\n },\n this.fetchAccessToken.bind(this)\n );\n this.swap = new ClientSwapNamespaceImpl({\n api: this.api,\n ensureUserAuthenticated: async () => this.ensureAuthenticated(),\n });\n }\n\n async init(): Promise<AuthState> {\n await this.fetchAccessToken(true);\n return this.getAuthState();\n }\n\n async fetchAccessToken(refresh: boolean): Promise<OAuthAccessToken | null> {\n if (!refresh && this._accessToken !== undefined) return this._accessToken;\n\n try {\n const accessToken = await this._config.getAccessToken();\n this._accessToken = accessToken;\n return accessToken;\n } catch (_) {\n this._accessToken = null;\n return null;\n }\n }\n\n getAuthState(): AuthState {\n if (this._accessToken === undefined) {\n return 'unknown';\n }\n return this._accessToken !== null ? 'logged-in' : 'logged-out';\n }\n\n async startOAuth(): Promise<void> {\n const pkceParams = await generatePKCEParams(this._config);\n\n sessionStorage.setItem(OAUTH_STATE_KEY, pkceParams.state);\n sessionStorage.setItem(OAUTH_CODE_VERIFIER_KEY, pkceParams.codeVerifier);\n\n const params = new URLSearchParams({\n client_id: pkceParams.clientId,\n response_type: pkceParams.responseType,\n redirect_uri: pkceParams.redirectUri,\n code_challenge: pkceParams.codeChallenge,\n code_challenge_method: pkceParams.codeChallengeMethod,\n state: pkceParams.state,\n });\n const baseUrl = this._config.coinlistBaseUrl ?? COINLIST_BASE_URL;\n const url = `${baseUrl}${OAUTH_PAGE_PATH}?${params.toString()}`;\n window.location.href = url;\n }\n\n completeOAuth(): OauthClientResult {\n const params = new URLSearchParams(window.location.search);\n\n const coinlistError = params.get('error');\n if (coinlistError) {\n return { type: 'error', reason: 'user_canceled' };\n }\n\n const stateParam = params.get('state');\n if (!stateParam) {\n return { type: 'error', reason: 'missing_state' };\n }\n const storedState = sessionStorage.getItem(OAUTH_STATE_KEY);\n if (storedState === null || storedState !== stateParam) {\n return { type: 'error', reason: 'invalid_state' };\n }\n\n const codeParam = params.get('code');\n if (!codeParam) {\n return { type: 'error', reason: 'missing_code' };\n }\n\n const codeVerifierValue = sessionStorage.getItem(OAUTH_CODE_VERIFIER_KEY);\n if (!codeVerifierValue) {\n return { type: 'error', reason: 'missing_code_verifier' };\n }\n\n return {\n type: 'ok',\n code: AuthorizationCode(codeParam),\n codeVerifier: CodeVerifier(codeVerifierValue),\n };\n }\n\n logout(): void {\n this._accessToken = null;\n }\n\n async fetchOffers(): Promise<Offer[]> {\n this.ensureAuthenticated();\n return offersApi.fetchOffers(this.api, undefined);\n }\n\n async fetchOffersPage(\n params: PaginationParams\n ): Promise<PaginatedResponse<Offer>> {\n this.ensureAuthenticated();\n return offersApi.fetchOffersPage(this.api, params, undefined);\n }\n\n async fetchOfferDetails(id: OfferId): Promise<OfferDetail> {\n this.ensureAuthenticated();\n return offersApi.fetchOfferDetails(this.api, id, undefined);\n }\n\n async fetchParticipations(offerId?: OfferId): Promise<Participation[]> {\n this.ensureAuthenticated();\n return participationsApi.fetchParticipations(this.api, offerId);\n }\n\n async fetchParticipationsPage(\n params: ParticipationsPaginationParams\n ): Promise<PaginatedResponse<Participation>> {\n this.ensureAuthenticated();\n return participationsApi.fetchParticipationsPage(this.api, params);\n }\n\n async fetchParticipation(id: ParticipationId): Promise<Participation> {\n this.ensureAuthenticated();\n return participationsApi.fetchParticipation(this.api, id);\n }\n\n async createParticipation(\n params: CreateParticipationParams\n ): Promise<Participation> {\n this.ensureAuthenticated();\n return participationsApi.createParticipation(this.api, params);\n }\n\n async createWalletOwnershipChallenge(\n params: CreateWalletOwnershipChallengeParams\n ): Promise<WalletOwnershipChallenge> {\n this.ensureAuthenticated();\n return walletConnectApi.createWalletOwnershipChallenge(this.api, params);\n }\n\n async connectExternalWallet(\n offerId: OfferId,\n params: ConnectExternalWalletParams\n ): Promise<OfferOptionAddress> {\n this.ensureAuthenticated();\n return walletConnectApi.connectExternalWallet(this.api, offerId, params);\n }\n\n async listOptionAddresses(\n offerId: OfferId,\n offerOptionId: OfferOptionId\n ): Promise<OfferOptionAddress[]> {\n this.ensureAuthenticated();\n return walletConnectApi.listOptionAddresses(\n this.api,\n offerId,\n offerOptionId\n );\n }\n\n async removeOptionAddress(\n offerId: OfferId,\n addressId: OfferOptionAddressId\n ): Promise<OfferOptionAddress> {\n this.ensureAuthenticated();\n return walletConnectApi.removeOptionAddress(this.api, offerId, addressId);\n }\n\n async fetchOfferRequirements(\n offerId: OfferId\n ): Promise<Record<OfferOptionId, Requirement[]>> {\n this.ensureAuthenticated();\n return requirementsApi.fetchOfferRequirements(this.api, offerId, undefined);\n }\n\n async fetchRequirementStatuses(\n offerId: OfferId\n ): Promise<RequirementStatusInfo[]> {\n this.ensureAuthenticated();\n return requirementsApi.fetchRequirementStatuses(this.api, offerId);\n }\n\n async fetchPii(): Promise<Pii> {\n this.ensureAuthenticated();\n return piiApi.fetchPii(this.api);\n }\n\n async submitDocument(\n documentType: DocumentType,\n fields: Record<string, string>\n ): Promise<DocumentSubmission> {\n this.ensureAuthenticated();\n return documentsApi.submitDocument(this.api, documentType, fields);\n }\n\n async createKycToken(\n levelName?: KycLevelName,\n reset?: boolean\n ): Promise<KycToken> {\n this.ensureAuthenticated();\n return kycApi.createKycToken(this.api, levelName, reset);\n }\n\n handleRequirement(requirement: Requirement): void {\n const baseUrl = this._config.coinlistBaseUrl ?? COINLIST_BASE_URL;\n let path: string | null;\n switch (requirement.type) {\n case 'kyc_approved':\n path = VERIFY_IDENTITY_PATH;\n break;\n case 'identity_verified':\n path = VERIFY_IDENTITY_VERIFIED_PATH;\n break;\n case 'proof_of_address':\n path = VERIFY_IDENTITY_PROOF_OF_ADDRESS_PATH;\n break;\n case 'source_of_funds':\n path = VERIFY_IDENTITY_SOURCE_OF_FUNDS_PATH;\n break;\n case 'accreditation':\n path = VERIFY_IDENTITY_ACCREDITATION_PATH;\n break;\n case 'external_wallet':\n case 'whitelisted_wallet':\n path = WALLET_PATH;\n break;\n case 'jurisdiction':\n path = null;\n break;\n case 'document':\n path = null;\n break;\n default: {\n const _exhaustive: never = requirement.type;\n return;\n }\n }\n if (path === null) return;\n openInNewTab(new URL(path, baseUrl).toString());\n }\n\n contactSupport(): void {\n openInNewTab(SUPPORT_NEW_TICKET_URL);\n }\n\n private ensureAuthenticated() {\n if (this.getAuthState() !== 'logged-in') {\n throw new NotAuthenticatedError();\n }\n }\n}\n\nfunction openInNewTab(url: string): void {\n window.open(url, '_blank', 'noopener,noreferrer');\n}\n\nexport function createCoinListClient(config: ClientConfig): CoinListClient {\n return new CoinListClientImpl(config);\n}\n","'use client';\n\n/**\n * Styling scope for SDK visual components.\n * Wrap any SDK visual components (CoinListSignInCard, OffersGrid, ...) in this so\n * they render fully styled, with all SDK CSS scoped to .clco-sdk-root and no leak\n * to the host page. Does NOT provide the React context: that's CoinListContextProvider.\n *\n * Idempotent: nesting is a no-op. A CoinListStyleScope rendered inside another\n * CoinListStyleScope (directly, or because a self-scoping SDK component renders\n * another one) detects the outer scope via ScopeContext and renders transparently\n * with no second .clco-sdk-root div and no duplicate <style>. So the SDK's own components\n * can each self-scope without stacking wrappers.\n */\n\nimport { createContext, type ReactNode, useContext } from 'react';\nimport { sdkStyles } from '@/client/generated/sdk-styles.gen';\n\n/**\n * True when the subtree is already inside a .clco-sdk-root scope. Internal only,\n * not exported. Read by CoinListStyleScope to collapse nested scopes.\n */\nconst ScopeContext = createContext(false);\n\nexport type CoinListStyleScopeProps = {\n children: ReactNode;\n};\n\n/**\n * Render the SDK styling wrapper: the Inter font links and the .clco-sdk-root div\n * with the self-contained, scoped <style> injection. Mount this around SDK visual\n * components only. Keep it off the host's own pages to avoid styling them.\n *\n * This component self-injects all SDK styles via a <style> tag so consumers do not\n * need to import any CSS files or configure their bundler. Styles are fully scoped\n * to .clco-sdk-root and do not leak to the host page. On React 19 the <style> is a\n * hoistable resource (href + precedence), so it is lifted to <head> and deduplicated\n * across every scope on the page; on React 18 the extra attributes are inert and it\n * renders in place.\n *\n * The wrapper div uses `display: contents` so it generates no box of its own, so an\n * SDK component wrapped by this stays the layout element in the host's flex/grid.\n * Inheritance (font, color, custom-property tokens) and the scoped descendant reset\n * (`.clco-sdk-root *`) still apply through it.\n */\nexport function CoinListStyleScope({ children }: CoinListStyleScopeProps) {\n const alreadyScoped = useContext(ScopeContext);\n if (alreadyScoped) {\n // Already inside a .clco-sdk-root: render transparently so nested scopes\n // (e.g. OffersGrid → OfferCard, both self-scoping) collapse to a single scope.\n return <>{children}</>;\n }\n\n return (\n <>\n {/*\n Inter font. React 19 hoists <link rel=\"preconnect\"> to <head> and dedupes it.\n A <link rel=\"stylesheet\"> is only hoisted/deduped when it carries a\n `precedence` prop; without one (as here) it renders in place, which is fine:\n the browser still loads it once. Using <link> rather than @import inside the\n injected <style> because @import in an injected style element is unreliable\n cross-browser.\n */}\n <link rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n <link\n rel=\"preconnect\"\n href=\"https://fonts.gstatic.com\"\n crossOrigin=\"anonymous\"\n />\n <link\n rel=\"stylesheet\"\n href=\"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap\"\n />\n {/*\n All SDK CSS is injected here as a self-contained <style> resource.\n - Classes are prefixed clco-sdk-* to prevent collisions with the host app.\n - Design tokens are scoped to .clco-sdk-root (not :root) to prevent leaking.\n - Tailwind Preflight is excluded; a minimal scoped reset lives in globals.css.\n - `href` + `precedence` make it a React 19 hoistable stylesheet: one copy in\n <head> regardless of how many scopes/components render.\n */}\n <div className=\"clco-sdk-root\" style={{ display: 'contents' }}>\n <style\n href=\"clco-sdk-styles\"\n precedence=\"default\"\n // biome-ignore lint/security/noDangerouslySetInnerHtml: sdkStyles is build-time compiled CSS, not user input\n dangerouslySetInnerHTML={{ __html: sdkStyles }}\n />\n <ScopeContext.Provider value={true}>{children}</ScopeContext.Provider>\n </div>\n </>\n );\n}\n","// AUTO-GENERATED — do not edit manually.\n// Run `npm run build:css` to regenerate after CSS changes.\nexport const sdkStyles = \"/*! tailwindcss v4.2.1 | MIT License | https://tailwindcss.com */\\n@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-duration:initial;--tw-ease:initial;--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0}}}@layer theme{:root,:host{--clcosdk-font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \\\"Liberation Mono\\\", \\\"Courier New\\\", monospace;--clcosdk-color-red-400:oklch(70.4% .191 22.216);--clcosdk-color-red-500:oklch(63.7% .237 25.331);--clcosdk-color-amber-500:oklch(76.9% .188 70.08);--clcosdk-color-gray-400:oklch(70.7% .022 261.325);--clcosdk-color-gray-500:oklch(55.1% .027 264.364);--clcosdk-color-black:#000;--clcosdk-spacing:.25rem;--clcosdk-container-md:28rem;--clcosdk-text-xs:.75rem;--clcosdk-text-xs--line-height:calc(1 / .75);--clcosdk-text-sm:.875rem;--clcosdk-text-sm--line-height:calc(1.25 / .875);--clcosdk-text-base:1rem;--clcosdk-text-base--line-height:calc(1.5 / 1);--clcosdk-font-weight-normal:400;--clcosdk-font-weight-medium:500;--clcosdk-font-weight-semibold:600;--clcosdk-radius-md:.375rem;--clcosdk-radius-lg:.5rem;--clcosdk-radius-2xl:1rem;--clcosdk-ease-in-out:cubic-bezier(.4, 0, .2, 1);--clcosdk-animate-spin:spin 1s linear infinite;--clcosdk-animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--clcosdk-color-brand-primary:var(--color-brand-primary)}}@layer base{.clco-sdk-root{--color-brand-primary:#171717;--color-brand-primary-hover:#000;--color-brand-primary-active:#262626;--color-accent:#2b3a67;--color-accent-hover:#243057;--color-accent-active:#1d2647;--color-accent-focus:#c7d2fe;--color-accent-subtle:#eef1f8;--color-text-primary:#171717;--color-text-secondary:#8c8c8c;--color-text-disabled:#d1d1d1;--color-text-inverse:#fff;--color-background:#fff;--color-surface:#fafafa;--color-section:#f3f3f3;--color-border:#e5e5e5;--color-divider:#ececec;--color-overlay:#00000080;--color-positive:#15803d;--color-positive-subtle:#dcfce7;--color-negative:#dc2626;--color-negative-subtle:#fee2e2;--color-success:#2c8c5e;--color-success-subtle:#e6f4ec;--color-success-border:#cfe9db;--color-warning:#e08a1a;--color-warning-subtle:#fff7ed;--color-warning-border:#fdead7;--color-error:#b42318;--color-error-subtle:#feeceb;--color-error-border:#fbd5d2}@media (prefers-color-scheme:dark){.clco-sdk-root:not(:where(.light,.light *)){--color-brand-primary:#f4f4f5;--color-brand-primary-hover:#fff;--color-brand-primary-active:#e4e4e7;--color-accent:#6f82c9;--color-accent-hover:#8799e4;--color-accent-active:#5b6fcf;--color-accent-focus:#6f82c959;--color-accent-subtle:#6f82c91f;--color-text-primary:#f4f4f5;--color-text-secondary:#a1a1aa;--color-text-disabled:#71717a;--color-text-inverse:#171717;--color-background:#0f1115;--color-surface:#161a20;--color-section:#20242c;--color-border:#2a2e35;--color-divider:#323741;--color-overlay:#000000b3;--color-positive:#22c55e;--color-positive-subtle:#22c55e1f;--color-negative:#ef4444;--color-negative-subtle:#ef44441f;--color-success:#34d399;--color-success-subtle:#34d3991f;--color-success-border:#34d39940;--color-warning:#f59e0b;--color-warning-subtle:#f59e0b1f;--color-warning-border:#f59e0b40;--color-error:#f87171;--color-error-subtle:#f871711f;--color-error-border:#f8717140}}:where(.dark,.dark *) .clco-sdk-root{--color-brand-primary:#f4f4f5;--color-brand-primary-hover:#fff;--color-brand-primary-active:#e4e4e7;--color-accent:#6f82c9;--color-accent-hover:#8799e4;--color-accent-active:#5b6fcf;--color-accent-focus:#6f82c959;--color-accent-subtle:#6f82c91f;--color-text-primary:#f4f4f5;--color-text-secondary:#a1a1aa;--color-text-disabled:#71717a;--color-text-inverse:#171717;--color-background:#0f1115;--color-surface:#161a20;--color-section:#20242c;--color-border:#2a2e35;--color-divider:#323741;--color-overlay:#000000b3;--color-positive:#22c55e;--color-positive-subtle:#22c55e1f;--color-negative:#ef4444;--color-negative-subtle:#ef44441f;--color-success:#34d399;--color-success-subtle:#34d3991f;--color-success-border:#34d39940;--color-warning:#f59e0b;--color-warning-subtle:#f59e0b1f;--color-warning-border:#f59e0b40;--color-error:#f87171;--color-error-subtle:#f871711f;--color-error-border:#f8717140}.clco-sdk-root{color:var(--color-text-primary);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:Inter,sans-serif}.clco-sdk-root *,.clco-sdk-root :before,.clco-sdk-root :after{box-sizing:border-box}.clco-sdk-root button{appearance:none;cursor:pointer;font:inherit;color:inherit;background:0 0;border:none;padding:0}.clco-sdk-root a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}.clco-sdk-root ul,.clco-sdk-root ol{margin:0;padding:0;list-style:none}.clco-sdk-root img,.clco-sdk-root svg{max-width:100%;display:block}}@layer components;@layer utilities{.clcosdk\\\\:absolute{position:absolute}.clcosdk\\\\:fixed{position:fixed}.clcosdk\\\\:relative{position:relative}.clcosdk\\\\:inset-0{inset:calc(var(--clcosdk-spacing) * 0)}.clcosdk\\\\:top-4{top:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:right-4{right:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:z-50{z-index:50}.clcosdk\\\\:mt-4{margin-top:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:mb-6{margin-bottom:calc(var(--clcosdk-spacing) * 6)}.clcosdk\\\\:flex{display:flex}.clcosdk\\\\:grid{display:grid}.clcosdk\\\\:inline-flex{display:inline-flex}.clcosdk\\\\:h-3{height:calc(var(--clcosdk-spacing) * 3)}.clcosdk\\\\:h-4{height:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:h-5{height:calc(var(--clcosdk-spacing) * 5)}.clcosdk\\\\:h-6{height:calc(var(--clcosdk-spacing) * 6)}.clcosdk\\\\:h-9{height:calc(var(--clcosdk-spacing) * 9)}.clcosdk\\\\:h-11{height:calc(var(--clcosdk-spacing) * 11)}.clcosdk\\\\:h-12{height:calc(var(--clcosdk-spacing) * 12)}.clcosdk\\\\:h-14{height:calc(var(--clcosdk-spacing) * 14)}.clcosdk\\\\:h-28{height:calc(var(--clcosdk-spacing) * 28)}.clcosdk\\\\:h-52{height:calc(var(--clcosdk-spacing) * 52)}.clcosdk\\\\:h-\\\\[18px\\\\]{height:18px}.clcosdk\\\\:h-auto{height:auto}.clcosdk\\\\:h-full{height:100%}.clcosdk\\\\:max-h-\\\\[92vh\\\\]{max-height:92vh}.clcosdk\\\\:min-h-0{min-height:calc(var(--clcosdk-spacing) * 0)}.clcosdk\\\\:min-h-9{min-height:calc(var(--clcosdk-spacing) * 9)}.clcosdk\\\\:min-h-40{min-height:calc(var(--clcosdk-spacing) * 40)}.clcosdk\\\\:min-h-\\\\[2\\\\.4rem\\\\]{min-height:2.4rem}.clcosdk\\\\:w-4{width:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:w-5{width:calc(var(--clcosdk-spacing) * 5)}.clcosdk\\\\:w-6{width:calc(var(--clcosdk-spacing) * 6)}.clcosdk\\\\:w-12{width:calc(var(--clcosdk-spacing) * 12)}.clcosdk\\\\:w-16{width:calc(var(--clcosdk-spacing) * 16)}.clcosdk\\\\:w-28{width:calc(var(--clcosdk-spacing) * 28)}.clcosdk\\\\:w-48{width:calc(var(--clcosdk-spacing) * 48)}.clcosdk\\\\:w-80{width:calc(var(--clcosdk-spacing) * 80)}.clcosdk\\\\:w-96{width:calc(var(--clcosdk-spacing) * 96)}.clcosdk\\\\:w-\\\\[16px\\\\]{width:16px}.clcosdk\\\\:w-\\\\[448px\\\\]{width:448px}.clcosdk\\\\:w-auto{width:auto}.clcosdk\\\\:w-full{width:100%}.clcosdk\\\\:max-w-\\\\[22rem\\\\]{max-width:22rem}.clcosdk\\\\:max-w-\\\\[28rem\\\\]{max-width:28rem}.clcosdk\\\\:max-w-\\\\[30rem\\\\]{max-width:30rem}.clcosdk\\\\:max-w-\\\\[760px\\\\]{max-width:760px}.clcosdk\\\\:max-w-\\\\[1200px\\\\]{max-width:1200px}.clcosdk\\\\:max-w-md{max-width:var(--clcosdk-container-md)}.clcosdk\\\\:shrink-0{flex-shrink:0}.clcosdk\\\\:rotate-90{rotate:90deg}.clcosdk\\\\:animate-pulse{animation:var(--clcosdk-animate-pulse)}.clcosdk\\\\:animate-spin{animation:var(--clcosdk-animate-spin)}.clcosdk\\\\:cursor-pointer{cursor:pointer}.clcosdk\\\\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.clcosdk\\\\:grid-rows-\\\\[0fr\\\\]{grid-template-rows:0fr}.clcosdk\\\\:grid-rows-\\\\[1fr\\\\]{grid-template-rows:1fr}.clcosdk\\\\:flex-col{flex-direction:column}.clcosdk\\\\:flex-wrap{flex-wrap:wrap}.clcosdk\\\\:items-center{align-items:center}.clcosdk\\\\:items-start{align-items:flex-start}.clcosdk\\\\:justify-between{justify-content:space-between}.clcosdk\\\\:justify-center{justify-content:center}.clcosdk\\\\:gap-1{gap:calc(var(--clcosdk-spacing) * 1)}.clcosdk\\\\:gap-2{gap:calc(var(--clcosdk-spacing) * 2)}.clcosdk\\\\:gap-3{gap:calc(var(--clcosdk-spacing) * 3)}.clcosdk\\\\:gap-4{gap:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:gap-5{gap:calc(var(--clcosdk-spacing) * 5)}.clcosdk\\\\:gap-6{gap:calc(var(--clcosdk-spacing) * 6)}.clcosdk\\\\:gap-8{gap:calc(var(--clcosdk-spacing) * 8)}.clcosdk\\\\:gap-\\\\[5px\\\\]{gap:5px}:where(.clcosdk\\\\:space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--clcosdk-spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--clcosdk-spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.clcosdk\\\\:space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--clcosdk-spacing) * 4) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--clcosdk-spacing) * 4) * calc(1 - var(--tw-space-y-reverse)))}:where(.clcosdk\\\\:divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.clcosdk\\\\:divide-border>:not(:last-child)){border-color:var(--color-border)}:where(.clcosdk\\\\:divide-divider>:not(:last-child)){border-color:var(--color-divider)}.clcosdk\\\\:self-start{align-self:flex-start}.clcosdk\\\\:overflow-hidden{overflow:hidden}.clcosdk\\\\:overflow-y-auto{overflow-y:auto}.clcosdk\\\\:rounded{border-radius:.25rem}.clcosdk\\\\:rounded-2xl{border-radius:var(--clcosdk-radius-2xl)}.clcosdk\\\\:rounded-btn{border-radius:12px}.clcosdk\\\\:rounded-card{border-radius:24px}.clcosdk\\\\:rounded-full{border-radius:3.40282e38px}.clcosdk\\\\:rounded-lg{border-radius:var(--clcosdk-radius-lg)}.clcosdk\\\\:rounded-md{border-radius:var(--clcosdk-radius-md)}.clcosdk\\\\:border{border-style:var(--tw-border-style);border-width:1px}.clcosdk\\\\:border-2{border-style:var(--tw-border-style);border-width:2px}.clcosdk\\\\:border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.clcosdk\\\\:border-dashed{--tw-border-style:dashed;border-style:dashed}.clcosdk\\\\:border-accent\\\\/50{border-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.clcosdk\\\\:border-accent\\\\/50{border-color:color-mix(in oklab, var(--color-accent) 50%, transparent)}}.clcosdk\\\\:border-accent\\\\/60{border-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.clcosdk\\\\:border-accent\\\\/60{border-color:color-mix(in oklab, var(--color-accent) 60%, transparent)}}.clcosdk\\\\:border-amber-500{border-color:var(--clcosdk-color-amber-500)}.clcosdk\\\\:border-border,.clcosdk\\\\:border-border\\\\/60{border-color:var(--color-border)}@supports (color:color-mix(in lab, red, red)){.clcosdk\\\\:border-border\\\\/60{border-color:color-mix(in oklab, var(--color-border) 60%, transparent)}}.clcosdk\\\\:border-current{border-color:currentColor}.clcosdk\\\\:border-divider{border-color:var(--color-divider)}.clcosdk\\\\:border-error-border{border-color:var(--color-error-border)}.clcosdk\\\\:border-success-border{border-color:var(--color-success-border)}.clcosdk\\\\:border-warning-border{border-color:var(--color-warning-border)}.clcosdk\\\\:border-t-transparent{border-top-color:#0000}.clcosdk\\\\:bg-accent\\\\/10{background-color:var(--color-accent)}@supports (color:color-mix(in lab, red, red)){.clcosdk\\\\:bg-accent\\\\/10{background-color:color-mix(in oklab, var(--color-accent) 10%, transparent)}}.clcosdk\\\\:bg-background{background-color:var(--color-background)}.clcosdk\\\\:bg-black\\\\/50{background-color:var(--clcosdk-color-black)}@supports (color:color-mix(in lab, red, red)){.clcosdk\\\\:bg-black\\\\/50{background-color:color-mix(in oklab, var(--clcosdk-color-black) 50%, transparent)}}.clcosdk\\\\:bg-brand-primary{background-color:var(--color-brand-primary)}.clcosdk\\\\:bg-error-subtle{background-color:var(--color-error-subtle)}.clcosdk\\\\:bg-overlay{background-color:var(--color-overlay)}.clcosdk\\\\:bg-section{background-color:var(--color-section)}.clcosdk\\\\:bg-success-subtle{background-color:var(--color-success-subtle)}.clcosdk\\\\:bg-surface{background-color:var(--color-surface)}.clcosdk\\\\:bg-transparent{background-color:#0000}.clcosdk\\\\:bg-warning-subtle{background-color:var(--color-warning-subtle)}.clcosdk\\\\:bg-gradient-to-b{--tw-gradient-position:to bottom in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.clcosdk\\\\:bg-gradient-to-br{--tw-gradient-position:to bottom right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.clcosdk\\\\:from-surface{--tw-gradient-from:var(--color-surface);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.clcosdk\\\\:from-transparent{--tw-gradient-from:transparent;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.clcosdk\\\\:via-section{--tw-gradient-via:var(--color-section);--tw-gradient-via-stops:var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops)}.clcosdk\\\\:via-transparent{--tw-gradient-via:transparent;--tw-gradient-via-stops:var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops)}.clcosdk\\\\:to-background{--tw-gradient-to:var(--color-background);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.clcosdk\\\\:to-overlay\\\\/35{--tw-gradient-to:var(--color-overlay)}@supports (color:color-mix(in lab, red, red)){.clcosdk\\\\:to-overlay\\\\/35{--tw-gradient-to:color-mix(in oklab, var(--color-overlay) 35%, transparent)}}.clcosdk\\\\:to-overlay\\\\/35{--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.clcosdk\\\\:object-cover{object-fit:cover}.clcosdk\\\\:p-0{padding:calc(var(--clcosdk-spacing) * 0)}.clcosdk\\\\:p-1\\\\.5{padding:calc(var(--clcosdk-spacing) * 1.5)}.clcosdk\\\\:p-3{padding:calc(var(--clcosdk-spacing) * 3)}.clcosdk\\\\:p-4{padding:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:p-6{padding:calc(var(--clcosdk-spacing) * 6)}.clcosdk\\\\:p-8{padding:calc(var(--clcosdk-spacing) * 8)}.clcosdk\\\\:px-2{padding-inline:calc(var(--clcosdk-spacing) * 2)}.clcosdk\\\\:px-3{padding-inline:calc(var(--clcosdk-spacing) * 3)}.clcosdk\\\\:px-4{padding-inline:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:px-5{padding-inline:calc(var(--clcosdk-spacing) * 5)}.clcosdk\\\\:px-6{padding-inline:calc(var(--clcosdk-spacing) * 6)}.clcosdk\\\\:py-2{padding-block:calc(var(--clcosdk-spacing) * 2)}.clcosdk\\\\:pt-4{padding-top:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:pt-14{padding-top:calc(var(--clcosdk-spacing) * 14)}.clcosdk\\\\:pb-4{padding-bottom:calc(var(--clcosdk-spacing) * 4)}.clcosdk\\\\:text-center{text-align:center}.clcosdk\\\\:text-left{text-align:left}.clcosdk\\\\:font-mono{font-family:var(--clcosdk-font-mono)}.clcosdk\\\\:text-base{font-size:var(--clcosdk-text-base);line-height:var(--tw-leading,var(--clcosdk-text-base--line-height))}.clcosdk\\\\:text-sm{font-size:var(--clcosdk-text-sm);line-height:var(--tw-leading,var(--clcosdk-text-sm--line-height))}.clcosdk\\\\:text-xs{font-size:var(--clcosdk-text-xs);line-height:var(--tw-leading,var(--clcosdk-text-xs--line-height))}.clcosdk\\\\:text-\\\\[11px\\\\]{font-size:11px}.clcosdk\\\\:text-\\\\[12px\\\\]{font-size:12px}.clcosdk\\\\:text-\\\\[14px\\\\]{font-size:14px}.clcosdk\\\\:text-\\\\[16px\\\\]{font-size:16px}.clcosdk\\\\:text-\\\\[18px\\\\]{font-size:18px}.clcosdk\\\\:text-\\\\[22px\\\\]{font-size:22px}.clcosdk\\\\:text-\\\\[28px\\\\]{font-size:28px}.clcosdk\\\\:text-\\\\[36px\\\\]{font-size:36px}.clcosdk\\\\:text-\\\\[48px\\\\]{font-size:48px}.clcosdk\\\\:text-\\\\[64px\\\\]{font-size:64px}.clcosdk\\\\:leading-\\\\[110\\\\%\\\\]{--tw-leading:110%;line-height:110%}.clcosdk\\\\:leading-\\\\[120\\\\%\\\\]{--tw-leading:120%;line-height:120%}.clcosdk\\\\:leading-\\\\[125\\\\%\\\\]{--tw-leading:125%;line-height:125%}.clcosdk\\\\:leading-\\\\[130\\\\%\\\\]{--tw-leading:130%;line-height:130%}.clcosdk\\\\:leading-\\\\[135\\\\%\\\\]{--tw-leading:135%;line-height:135%}.clcosdk\\\\:leading-\\\\[140\\\\%\\\\]{--tw-leading:140%;line-height:140%}.clcosdk\\\\:leading-\\\\[150\\\\%\\\\]{--tw-leading:150%;line-height:150%}.clcosdk\\\\:font-medium{--tw-font-weight:var(--clcosdk-font-weight-medium);font-weight:var(--clcosdk-font-weight-medium)}.clcosdk\\\\:font-normal{--tw-font-weight:var(--clcosdk-font-weight-normal);font-weight:var(--clcosdk-font-weight-normal)}.clcosdk\\\\:font-semibold{--tw-font-weight:var(--clcosdk-font-weight-semibold);font-weight:var(--clcosdk-font-weight-semibold)}.clcosdk\\\\:tracking-\\\\[0\\\\.12px\\\\]{--tw-tracking:.12px;letter-spacing:.12px}.clcosdk\\\\:tracking-\\\\[0\\\\.28px\\\\]{--tw-tracking:.28px;letter-spacing:.28px}.clcosdk\\\\:whitespace-nowrap{white-space:nowrap}.clcosdk\\\\:text-error{color:var(--color-error)}.clcosdk\\\\:text-success{color:var(--color-success)}.clcosdk\\\\:text-text-inverse{color:var(--color-text-inverse)}.clcosdk\\\\:text-text-primary{color:var(--color-text-primary)}.clcosdk\\\\:text-text-secondary{color:var(--color-text-secondary)}.clcosdk\\\\:text-warning{color:var(--color-warning)}.clcosdk\\\\:capitalize{text-transform:capitalize}.clcosdk\\\\:underline{text-decoration-line:underline}.clcosdk\\\\:underline-offset-2{text-underline-offset:2px}.clcosdk\\\\:underline-offset-4{text-underline-offset:4px}.clcosdk\\\\:opacity-60{opacity:.6}.clcosdk\\\\:shadow-\\\\[0_0_0_3px_rgba\\\\(59\\\\,130\\\\,246\\\\,0\\\\.2\\\\)\\\\]{--tw-shadow:0 0 0 3px var(--tw-shadow-color,#3b82f633);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.clcosdk\\\\:shadow-\\\\[0_0_0_3px_rgba\\\\(59\\\\,130\\\\,246\\\\,0\\\\.18\\\\)\\\\]{--tw-shadow:0 0 0 3px var(--tw-shadow-color,#3b82f62e);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.clcosdk\\\\:shadow-\\\\[0_0_0_3px_rgba\\\\(59\\\\,130\\\\,246\\\\,0\\\\.25\\\\)\\\\]{--tw-shadow:0 0 0 3px var(--tw-shadow-color,#3b82f640);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.clcosdk\\\\:shadow-\\\\[0_10px_24px_rgba\\\\(0\\\\,0\\\\,0\\\\,0\\\\.18\\\\)\\\\]{--tw-shadow:0 10px 24px var(--tw-shadow-color,#0000002e);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.clcosdk\\\\:shadow-\\\\[0_10px_24px_rgba\\\\(0\\\\,0\\\\,0\\\\,0\\\\.25\\\\)\\\\]{--tw-shadow:0 10px 24px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.clcosdk\\\\:shadow-card{--tw-shadow:0px 4px 6px -2px var(--tw-shadow-color,#0000000d), 0px 12px 24px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.clcosdk\\\\:transition-\\\\[grid-template-rows\\\\]{transition-property:grid-template-rows;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.clcosdk\\\\:transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.clcosdk\\\\:transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.clcosdk\\\\:transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.clcosdk\\\\:duration-200{--tw-duration:.2s;transition-duration:.2s}.clcosdk\\\\:duration-300{--tw-duration:.3s;transition-duration:.3s}.clcosdk\\\\:ease-in-out{--tw-ease:var(--clcosdk-ease-in-out);transition-timing-function:var(--clcosdk-ease-in-out)}@media (hover:hover){.clcosdk\\\\:hover\\\\:-translate-y-0\\\\.5:hover{--tw-translate-y:calc(var(--clcosdk-spacing) * -.5);translate:var(--tw-translate-x) var(--tw-translate-y)}.clcosdk\\\\:hover\\\\:border-divider:hover{border-color:var(--color-divider)}.clcosdk\\\\:hover\\\\:bg-\\\\[\\\\#fcdcd8\\\\]:hover{background-color:#fcdcd8}.clcosdk\\\\:hover\\\\:bg-border:hover{background-color:var(--color-border)}.clcosdk\\\\:hover\\\\:bg-brand-primary:hover{background-color:var(--color-brand-primary)}.clcosdk\\\\:hover\\\\:bg-brand-primary-hover:hover{background-color:var(--color-brand-primary-hover)}.clcosdk\\\\:hover\\\\:bg-section:hover{background-color:var(--color-section)}.clcosdk\\\\:hover\\\\:bg-surface:hover{background-color:var(--color-surface)}.clcosdk\\\\:hover\\\\:text-\\\\[\\\\#8b1a13\\\\]:hover{color:#8b1a13}.clcosdk\\\\:hover\\\\:text-text-primary:hover{color:var(--color-text-primary)}.clcosdk\\\\:hover\\\\:underline:hover{text-decoration-line:underline}.clcosdk\\\\:hover\\\\:shadow-\\\\[0px_14px_32px_-10px_rgba\\\\(0\\\\,0\\\\,0\\\\,0\\\\.35\\\\)\\\\]:hover{--tw-shadow:0px 14px 32px -10px var(--tw-shadow-color,#00000059);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}}.clcosdk\\\\:focus-visible\\\\:ring-2:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.clcosdk\\\\:focus-visible\\\\:ring-accent-focus:focus-visible{--tw-ring-color:var(--color-accent-focus)}.clcosdk\\\\:focus-visible\\\\:ring-gray-400:focus-visible{--tw-ring-color:var(--clcosdk-color-gray-400)}.clcosdk\\\\:focus-visible\\\\:ring-gray-500:focus-visible{--tw-ring-color:var(--clcosdk-color-gray-500)}.clcosdk\\\\:focus-visible\\\\:ring-red-400:focus-visible{--tw-ring-color:var(--clcosdk-color-red-400)}.clcosdk\\\\:focus-visible\\\\:ring-red-500:focus-visible{--tw-ring-color:var(--clcosdk-color-red-500)}.clcosdk\\\\:focus-visible\\\\:ring-offset-2:focus-visible{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color)}.clcosdk\\\\:focus-visible\\\\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.clcosdk\\\\:active\\\\:bg-\\\\[\\\\#d9d9d9\\\\]:active{background-color:#d9d9d9}.clcosdk\\\\:active\\\\:bg-\\\\[\\\\#f9c9c4\\\\]:active{background-color:#f9c9c4}.clcosdk\\\\:active\\\\:bg-border:active{background-color:var(--color-border)}.clcosdk\\\\:active\\\\:bg-brand-primary-active:active{background-color:var(--color-brand-primary-active)}.clcosdk\\\\:active\\\\:text-\\\\[\\\\#6d1510\\\\]:active{color:#6d1510}.clcosdk\\\\:disabled\\\\:pointer-events-none:disabled{pointer-events:none}.clcosdk\\\\:disabled\\\\:opacity-40:disabled{opacity:.4}@media (prefers-color-scheme:dark){@media (hover:hover){.clcosdk\\\\:dark\\\\:hover\\\\:bg-\\\\[rgba\\\\(248\\\\,113\\\\,113\\\\,0\\\\.20\\\\)\\\\]:not(:where(.light,.light *)):hover{background-color:#f8717133}}}@media (hover:hover){.clcosdk\\\\:dark\\\\:hover\\\\:bg-\\\\[rgba\\\\(248\\\\,113\\\\,113\\\\,0\\\\.20\\\\)\\\\]:where(.dark,.dark *):hover{background-color:#f8717133}}@media (prefers-color-scheme:dark){@media (hover:hover){.clcosdk\\\\:dark\\\\:hover\\\\:text-\\\\[\\\\#fca5a5\\\\]:not(:where(.light,.light *)):hover{color:#fca5a5}}}@media (hover:hover){.clcosdk\\\\:dark\\\\:hover\\\\:text-\\\\[\\\\#fca5a5\\\\]:where(.dark,.dark *):hover{color:#fca5a5}}@media (prefers-color-scheme:dark){.clcosdk\\\\:dark\\\\:active\\\\:bg-\\\\[rgba\\\\(248\\\\,113\\\\,113\\\\,0\\\\.30\\\\)\\\\]:not(:where(.light,.light *)):active{background-color:#f871714d}}.clcosdk\\\\:dark\\\\:active\\\\:bg-\\\\[rgba\\\\(248\\\\,113\\\\,113\\\\,0\\\\.30\\\\)\\\\]:where(.dark,.dark *):active{background-color:#f871714d}@media (prefers-color-scheme:dark){.clcosdk\\\\:dark\\\\:active\\\\:bg-divider:not(:where(.light,.light *)):active{background-color:var(--color-divider)}}.clcosdk\\\\:dark\\\\:active\\\\:bg-divider:where(.dark,.dark *):active{background-color:var(--color-divider)}@media (prefers-color-scheme:dark){.clcosdk\\\\:dark\\\\:active\\\\:text-\\\\[\\\\#f87171\\\\]:not(:where(.light,.light *)):active{color:#f87171}}.clcosdk\\\\:dark\\\\:active\\\\:text-\\\\[\\\\#f87171\\\\]:where(.dark,.dark *):active{color:#f87171}.clcosdk\\\\:\\\\[\\\\&_circle\\\\]\\\\:fill-error-subtle circle{fill:var(--color-error-subtle)}.clcosdk\\\\:\\\\[\\\\&_circle\\\\]\\\\:fill-success-subtle circle{fill:var(--color-success-subtle)}.clcosdk\\\\:\\\\[\\\\&_circle\\\\]\\\\:fill-warning-subtle circle{fill:var(--color-warning-subtle)}}@property --tw-space-y-reverse{syntax:\\\"*\\\";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:\\\"*\\\";inherits:false;initial-value:0}@property --tw-border-style{syntax:\\\"*\\\";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:\\\"*\\\";inherits:false}@property --tw-gradient-from{syntax:\\\"<color>\\\";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:\\\"<color>\\\";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:\\\"<color>\\\";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:\\\"*\\\";inherits:false}@property --tw-gradient-via-stops{syntax:\\\"*\\\";inherits:false}@property --tw-gradient-from-position{syntax:\\\"<length-percentage>\\\";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:\\\"<length-percentage>\\\";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:\\\"<length-percentage>\\\";inherits:false;initial-value:100%}@property --tw-leading{syntax:\\\"*\\\";inherits:false}@property --tw-font-weight{syntax:\\\"*\\\";inherits:false}@property --tw-tracking{syntax:\\\"*\\\";inherits:false}@property --tw-shadow{syntax:\\\"*\\\";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:\\\"*\\\";inherits:false}@property --tw-shadow-alpha{syntax:\\\"<percentage>\\\";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:\\\"*\\\";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:\\\"*\\\";inherits:false}@property --tw-inset-shadow-alpha{syntax:\\\"<percentage>\\\";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:\\\"*\\\";inherits:false}@property --tw-ring-shadow{syntax:\\\"*\\\";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:\\\"*\\\";inherits:false}@property --tw-inset-ring-shadow{syntax:\\\"*\\\";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:\\\"*\\\";inherits:false}@property --tw-ring-offset-width{syntax:\\\"<length>\\\";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:\\\"*\\\";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:\\\"*\\\";inherits:false;initial-value:0 0 #0000}@property --tw-duration{syntax:\\\"*\\\";inherits:false}@property --tw-ease{syntax:\\\"*\\\";inherits:false}@property --tw-translate-x{syntax:\\\"*\\\";inherits:false;initial-value:0}@property --tw-translate-y{syntax:\\\"*\\\";inherits:false;initial-value:0}@property --tw-translate-z{syntax:\\\"*\\\";inherits:false;initial-value:0}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}}\";\n","import type { LucideIcon } from 'lucide-react';\nimport { CircleCheck, Info } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\n\nexport type AlertBannerVariant = 'info' | 'success' | 'warning' | 'error';\n\ninterface AlertBannerProps {\n variant: AlertBannerVariant;\n content: ReactNode;\n icon?: boolean;\n className?: string;\n}\n\nconst variantConfig: Record<\n AlertBannerVariant,\n { container: string; text: string; Icon: LucideIcon }\n> = {\n info: {\n container: 'clcosdk:bg-surface clcosdk:border-border',\n text: 'clcosdk:text-text-secondary',\n Icon: Info,\n },\n success: {\n container: 'clcosdk:bg-success-subtle clcosdk:border-success-border',\n text: 'clcosdk:text-success',\n Icon: CircleCheck,\n },\n warning: {\n container: 'clcosdk:bg-warning-subtle clcosdk:border-warning-border',\n text: 'clcosdk:text-warning',\n Icon: Info,\n },\n error: {\n container: 'clcosdk:bg-error-subtle clcosdk:border-error-border',\n text: 'clcosdk:text-error',\n Icon: Info,\n },\n};\n\nexport function AlertBanner({\n variant,\n content,\n icon = false,\n className,\n}: AlertBannerProps) {\n const { container, text, Icon } = variantConfig[variant];\n\n return (\n <div\n className={cn(\n 'clcosdk:flex clcosdk:items-center clcosdk:rounded-btn clcosdk:border clcosdk:p-3',\n icon && 'clcosdk:gap-2',\n container,\n className\n )}\n >\n {icon && (\n <Icon\n className={cn('clcosdk:h-4 clcosdk:w-4 clcosdk:shrink-0', text)}\n aria-hidden=\"true\"\n />\n )}\n <p className={cn(typeClasses.subhead, text)}>{content}</p>\n </div>\n );\n}\n","/**\n * CoinList Sale SDK — Typography Tokens\n *\n * Scale based on design system.\n * fontSize in px, lineHeight as percentage string, fontWeight as number.\n * Use the cn() Tailwind classes where possible, these values\n * are for programmatic access or non-Tailwind contexts.\n */\n\nexport const typeScale = {\n hero: {\n fontSize: 64,\n lineHeight: '110%',\n fontWeight: 600,\n },\n display: {\n fontSize: 48,\n lineHeight: '110%',\n fontWeight: 600,\n },\n h1: {\n fontSize: 36,\n lineHeight: '120%',\n fontWeight: 600,\n },\n h2: {\n fontSize: 28,\n lineHeight: '125%',\n fontWeight: 600,\n },\n h3: {\n fontSize: 22,\n lineHeight: '130%',\n fontWeight: 600,\n },\n h4: {\n fontSize: 18,\n lineHeight: '135%',\n fontWeight: 500,\n },\n body: {\n fontSize: 16,\n lineHeight: '150%',\n fontWeight: 400,\n },\n subhead: {\n fontSize: 14,\n lineHeight: '150%',\n fontWeight: 400,\n },\n caption: {\n fontSize: 12,\n lineHeight: '140%',\n fontWeight: 400,\n },\n label: {\n fontSize: 14,\n lineHeight: '140%',\n fontWeight: 500,\n },\n data: {\n fontSize: 14,\n lineHeight: '140%',\n fontWeight: 400,\n },\n} as const;\n\n/**\n * Tailwind class mappings for each type style.\n * Use these className strings directly in components.\n *\n * e.g. <h1 className={typeClasses.h1}>Hello</h1>\n */\nexport const typeClasses = {\n hero: 'clcosdk:text-[64px] clcosdk:leading-[110%] clcosdk:font-semibold',\n display: 'clcosdk:text-[48px] clcosdk:leading-[110%] clcosdk:font-semibold',\n h1: 'clcosdk:text-[36px] clcosdk:leading-[120%] clcosdk:font-semibold',\n h2: 'clcosdk:text-[28px] clcosdk:leading-[125%] clcosdk:font-semibold',\n h3: 'clcosdk:text-[22px] clcosdk:leading-[130%] clcosdk:font-semibold',\n h4: 'clcosdk:text-[18px] clcosdk:leading-[135%] clcosdk:font-medium',\n body: 'clcosdk:text-[16px] clcosdk:leading-[150%] clcosdk:font-normal',\n subhead: 'clcosdk:text-[14px] clcosdk:leading-[150%] clcosdk:font-normal',\n caption: 'clcosdk:text-[12px] clcosdk:leading-[140%] clcosdk:font-normal',\n label: 'clcosdk:text-[14px] clcosdk:leading-[140%] clcosdk:font-medium',\n data: 'clcosdk:text-[14px] clcosdk:leading-[140%] clcosdk:font-normal',\n} as const;\n\nexport type TypeScale = keyof typeof typeScale;\n","import { type ClassValue, clsx } from 'clsx';\n\n/**\n * Utility function to merge class names using clsx.\n */\nexport function cn(...inputs: ClassValue[]) {\n return clsx(inputs);\n}\n","'use client';\n\nimport { X } from 'lucide-react';\nimport { cn } from '@/client/components/design-system/utils';\n\ninterface CloseButtonProps {\n onClick: () => void;\n 'aria-label'?: string;\n className?: string;\n}\n\nexport function CloseButton({\n onClick,\n 'aria-label': ariaLabel = 'Close',\n className,\n}: CloseButtonProps) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n aria-label={ariaLabel}\n className={cn(\n 'clcosdk:cursor-pointer clcosdk:rounded-full clcosdk:p-1.5 clcosdk:text-text-secondary clcosdk:transition-colors clcosdk:hover:bg-surface clcosdk:hover:text-text-primary clcosdk:focus-visible:outline-none clcosdk:focus-visible:ring-2 clcosdk:focus-visible:ring-gray-400 clcosdk:focus-visible:ring-offset-2',\n className\n )}\n >\n <X className=\"clcosdk:h-5 clcosdk:w-5\" />\n </button>\n );\n}\n","import type { SVGProps } from 'react';\n\nexport function CoinListWordmark(props: SVGProps<SVGSVGElement>) {\n return (\n <svg\n width=\"638\"\n height=\"125\"\n viewBox=\"0 0 638 125\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n {...props}\n >\n <path\n d=\"M68.7724 123.966C74.8226 124.172 80.7696 123.519 86.5104 121.799C97.4076 118.531 106.551 112.58 113.942 103.947C113.942 103.947 113.942 103.947 113.908 103.912C111.879 102.193 109.851 100.507 107.857 98.8218L105.829 97.1363C105.451 96.8268 105.107 96.5172 104.729 96.2076C103.939 95.5197 103.148 94.8662 102.323 94.2126C95.3107 98.8562 87.6104 101.539 79.1196 101.883C74.8569 102.055 70.6287 101.642 66.5036 100.507C59.5252 98.6154 53.2688 95.1757 48.2499 89.7755C39.1059 79.938 35.8745 68.1743 38.2465 55.0348C39.7246 46.9172 43.4373 40.0723 49.1093 34.5C47.9061 34.7408 46.703 35.016 45.5342 35.3943C36.5277 38.2148 29.6181 43.6839 24.6336 51.6639C20.6803 58.0273 18.5834 64.9411 18.3428 72.4739C18.2053 76.7047 18.4803 80.7979 19.4428 84.7879C22.5023 97.2395 29.3087 107.043 39.6903 114.335H39.7934V114.403C40.1372 114.644 40.4809 114.919 40.8247 115.16C49.2812 120.801 58.5971 123.691 68.7724 124.035V123.966Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M72.2101 89.052C68.1881 90.8406 64.0286 91.8725 59.6973 92.2165C64.9912 95.209 70.8007 96.688 77.1259 96.8256C79.1885 96.86 81.251 96.6536 83.4167 96.3097C88.745 95.4841 93.6951 93.5579 98.3015 90.7374C93.9358 87.057 89.6044 83.4109 85.2386 79.7305C81.526 83.6861 77.1946 86.8506 72.2101 89.052Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M66.9848 0.241609C66.4348 0.276006 65.8848 0.344799 65.3691 0.413592C70.663 1.4111 75.7851 3.13093 80.6321 5.71068C90.0511 10.7326 97.3732 17.9215 102.289 27.4494L104.936 25.1448C107.652 22.7714 110.368 20.3981 113.084 18.0247C106.655 11.1797 99.092 6.15784 90.223 3.06214C84.3103 0.998336 78.2601 -0.0335643 72.0381 0.000832319C70.388 0.000832319 68.7036 0.138419 66.9848 0.241609Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M25.4242 107.871C17.4833 97.9988 13.1519 86.7167 13.2207 73.818C13.2207 67.317 14.5614 61.0568 17.1396 55.1062C20.9553 46.2662 26.9711 39.1805 35.4276 34.2962C43.3685 29.687 51.9968 27.8984 61.1752 29.2743C70.5943 30.7189 78.3976 35.2249 84.6541 42.2762C84.6541 42.2762 84.8603 42.5514 84.9634 42.6546C85.8916 41.8291 86.8541 41.0035 87.7823 40.178L88.9167 39.1805C89.8792 38.355 90.8417 37.4951 91.8043 36.6696C94.0043 34.7434 96.17 32.8515 98.3357 30.9253C94.1075 22.223 87.7479 15.55 79.3258 10.8377C69.3911 5.26541 58.7002 3.54557 47.3904 5.02463C41.7528 5.78136 36.3557 7.50119 31.1993 10.0465C13.702 18.7145 1.08597 36.532 0.0546833 58.4771C-0.117196 62.0887 0.123436 65.7348 0.673452 69.3464C2.04849 78.3239 5.34859 86.4759 10.6425 93.8368C14.7676 99.5123 19.6834 104.19 25.3898 107.871H25.4242Z\"\n fill=\"currentColor\"\n />\n <path\n fillRule=\"evenodd\"\n clipRule=\"evenodd\"\n d=\"M366.034 58.1654C366.034 46.8145 375.178 37.665 386.419 37.665C397.66 37.665 406.804 46.8145 406.804 58.1654V99.3727H420.727V58.1654C420.727 39.1785 405.395 23.7344 386.419 23.7344C367.444 23.7344 352.112 39.1785 352.112 58.1654V99.3727H366.034V58.1654ZM278.616 38.1466C265.141 38.1466 254.244 49.0503 254.244 62.5338C254.244 76.0173 265.141 86.9211 278.616 86.9211C292.092 86.9211 302.989 76.0173 302.989 62.5338C302.989 49.0503 292.092 38.1466 278.616 38.1466ZM240.321 62.5338C240.321 41.3799 257.475 24.2159 278.616 24.2159C299.757 24.2159 316.911 41.3799 316.911 62.5338C316.911 83.6878 299.757 100.852 278.616 100.852C257.475 100.852 240.321 83.6878 240.321 62.5338ZM208.386 38.2154C195.082 37.9402 184.048 48.5 183.738 61.8115C183.463 75.123 194.017 86.1643 207.32 86.4739C215.192 86.6459 222.274 82.9998 226.812 77.2212L237.777 85.8204C230.662 94.9011 219.455 100.645 207.011 100.37C186.007 99.923 169.335 82.5183 169.782 61.5019C170.229 40.4856 187.623 23.8032 208.627 24.2503C219.524 24.4911 229.287 29.3066 236.059 36.8051L225.712 46.1266C221.415 41.3455 215.227 38.3186 208.317 38.1466L208.386 38.2154ZM340.527 25.2134V99.3727H326.605V25.2134H340.527ZM508.282 25.2134H494.36V99.8542H508.282V25.2134ZM483.154 99.8542H448.846C439.221 99.8542 431.452 92.0462 431.452 82.4495V25.2134H445.374V82.4495C445.374 84.3757 446.921 85.9236 448.846 85.9236H483.154V99.8542ZM583.772 25.2134H567.856H542.83C530.661 25.2134 520.933 35.1885 520.933 47.2273C520.933 59.2661 530.661 69.2412 542.83 69.2412H552.421C556.821 69.2412 560.396 72.8184 560.396 77.1868V77.9435C560.396 82.3463 556.821 85.8892 552.421 85.8892H520.451V99.8198H552.421C564.522 99.8198 574.319 90.0168 574.319 77.9091V77.1524C574.319 65.0448 564.522 55.2417 552.421 55.2417H542.83C538.499 55.2417 534.855 51.6301 534.855 47.1585C534.855 42.6869 538.499 39.0753 542.83 39.0753H574.319H583.772C591.472 39.0753 597.694 45.3011 597.694 53.0059V99.3039H611.617V53.0059C611.617 37.6306 599.138 25.1446 583.772 25.1446V25.2134ZM637.021 39.1441H609.038V25.2134H637.021V39.1441Z\"\n fill=\"currentColor\"\n />\n </svg>\n );\n}\n","import { CoinListWordmark } from '@/client/components/design-system/logos/CoinListWordmark';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\n\ninterface PoweredByCoinListProps {\n className?: string;\n}\n\nexport function PoweredByCoinList({ className }: PoweredByCoinListProps) {\n return (\n <div\n className={cn(\n 'clcosdk:flex clcosdk:items-center clcosdk:justify-center clcosdk:gap-[5px] clcosdk:text-text-secondary',\n className\n )}\n >\n <span className={cn(typeClasses.caption, 'clcosdk:tracking-[0.12px]')}>\n Powered by\n </span>\n <CoinListWordmark className=\"clcosdk:h-3 clcosdk:w-auto\" />\n </div>\n );\n}\n","'use client';\n\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { type ButtonHTMLAttributes, forwardRef, type ReactNode } from 'react';\nimport { cn } from '@/client/components/design-system/utils';\n\n// Button variants using class-variance-authority for consistent styling\nconst buttonVariants = cva(\n 'clcosdk:inline-flex clcosdk:items-center clcosdk:justify-center clcosdk:gap-3 clcosdk:whitespace-nowrap clcosdk:transition-colors clcosdk:focus-visible:outline-none clcosdk:focus-visible:ring-2 clcosdk:focus-visible:ring-offset-2 clcosdk:disabled:pointer-events-none clcosdk:disabled:opacity-40 clcosdk:cursor-pointer',\n {\n variants: {\n variant: {\n // Primary — tokens auto-switch: dark bg (#171717) → light bg (#f4f4f5) in dark mode\n primary:\n 'clcosdk:bg-brand-primary clcosdk:text-text-inverse clcosdk:font-semibold clcosdk:hover:bg-brand-primary-hover clcosdk:active:bg-brand-primary-active clcosdk:focus-visible:ring-gray-500',\n // Secondary — bg-section, border-border, text-text-primary all auto-switch\n // hover maps to border token value; active has no token so uses dark: override\n secondary:\n 'clcosdk:bg-section clcosdk:border clcosdk:border-border clcosdk:text-text-primary clcosdk:font-medium clcosdk:hover:bg-border clcosdk:active:bg-[#d9d9d9] clcosdk:dark:active:bg-divider clcosdk:focus-visible:ring-gray-400',\n // Destructive — error tokens auto-switch to translucent dark equivalents\n // hover/active have no tokens so use dark: overrides\n destructive:\n 'clcosdk:bg-error-subtle clcosdk:border clcosdk:border-error-border clcosdk:text-error clcosdk:font-semibold clcosdk:hover:bg-[#fcdcd8] clcosdk:active:bg-[#f9c9c4] clcosdk:dark:hover:bg-[rgba(248,113,113,0.20)] clcosdk:dark:active:bg-[rgba(248,113,113,0.30)] clcosdk:focus-visible:ring-red-400',\n // Ghost — transparent base; hover/active use section/border tokens (auto-switch)\n ghost:\n 'clcosdk:bg-transparent clcosdk:text-text-primary clcosdk:font-medium clcosdk:hover:bg-section clcosdk:active:bg-border clcosdk:focus-visible:ring-gray-400',\n // Link — text-text-primary auto-switches light/dark\n link: 'clcosdk:h-auto clcosdk:p-0 clcosdk:text-text-primary clcosdk:font-medium clcosdk:underline-offset-4 clcosdk:hover:underline clcosdk:focus-visible:ring-gray-500',\n // Destructive link — text-error auto-switches (#b42318 → #f87171 in dark)\n destructiveLink:\n 'clcosdk:h-auto clcosdk:p-0 clcosdk:text-error clcosdk:font-medium clcosdk:hover:text-[#8b1a13] clcosdk:active:text-[#6d1510] clcosdk:dark:hover:text-[#fca5a5] clcosdk:dark:active:text-[#f87171] clcosdk:focus-visible:ring-red-500',\n },\n size: {\n sm: 'clcosdk:h-9 clcosdk:px-4 clcosdk:text-sm clcosdk:tracking-[0.28px]',\n default:\n 'clcosdk:h-11 clcosdk:px-5 clcosdk:text-sm clcosdk:tracking-[0.28px]',\n lg: 'clcosdk:h-14 clcosdk:px-6 clcosdk:text-base',\n icon: 'clcosdk:h-12 clcosdk:w-12',\n },\n radius: {\n pill: 'clcosdk:rounded-full',\n // compound variants below handle size-specific radii\n rounded: '',\n },\n fullWidth: {\n true: 'clcosdk:w-full',\n false: '',\n },\n },\n compoundVariants: [\n { size: 'sm', radius: 'rounded', className: 'clcosdk:rounded-lg' },\n { size: 'default', radius: 'rounded', className: 'clcosdk:rounded-2xl' },\n { size: 'lg', radius: 'rounded', className: 'clcosdk:rounded-2xl' },\n { size: 'icon', radius: 'rounded', className: 'clcosdk:rounded-md' },\n ],\n defaultVariants: {\n variant: 'primary',\n size: 'default',\n radius: 'pill',\n fullWidth: false,\n },\n }\n);\n\ninterface ClButtonProps\n extends ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n children?: ReactNode;\n isLoading?: boolean;\n loadingText?: string;\n startIcon?: ReactNode;\n endIcon?: ReactNode;\n}\n\nconst ClButton = forwardRef<HTMLButtonElement, ClButtonProps>(\n (\n {\n className,\n variant,\n size,\n radius,\n fullWidth,\n children,\n isLoading = false,\n loadingText,\n startIcon,\n endIcon,\n disabled,\n ...props\n },\n ref\n ) => {\n const isDisabled = disabled || isLoading;\n\n return (\n <button\n className={cn(\n buttonVariants({ variant, size, radius, fullWidth }),\n className\n )}\n ref={ref}\n disabled={isDisabled}\n {...props}\n >\n {isLoading && (\n <span\n className=\"clcosdk:h-4 clcosdk:w-4 clcosdk:shrink-0 clcosdk:animate-spin clcosdk:rounded-full clcosdk:border-2 clcosdk:border-current clcosdk:border-t-transparent clcosdk:opacity-60\"\n aria-hidden=\"true\"\n />\n )}\n\n {startIcon && !isLoading && (\n <span className=\"clcosdk:shrink-0\">{startIcon}</span>\n )}\n\n <span className={cn(isLoading && 'clcosdk:opacity-60')}>\n {isLoading && loadingText ? loadingText : children}\n </span>\n\n {endIcon && !isLoading && (\n <span className=\"clcosdk:shrink-0\">{endIcon}</span>\n )}\n </button>\n );\n }\n);\n\nClButton.displayName = 'ClButton';\n\nexport type { ClButtonProps };\nexport { buttonVariants, ClButton };\n","import type { SVGProps } from 'react';\n\nexport function CoinListLogomark(props: SVGProps<SVGSVGElement>) {\n return (\n <svg\n width=\"115\"\n height=\"125\"\n viewBox=\"0 0 115 125\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n {...props}\n >\n <path\n d=\"M69.7519 123.966C75.8021 124.172 81.7491 123.519 87.4899 121.799C98.3871 118.531 107.531 112.58 114.922 103.947C114.922 103.947 114.922 103.947 114.888 103.912C112.859 102.193 110.831 100.507 108.837 98.8218L106.809 97.1363C106.431 96.8268 106.087 96.5172 105.709 96.2076C104.919 95.5197 104.128 94.8662 103.303 94.2126C96.2902 98.8562 88.5899 101.539 80.0991 101.883C75.8364 102.055 71.6082 101.642 67.4831 100.507C60.5047 98.6154 54.2483 95.1757 49.2294 89.7755C40.0854 79.938 36.854 68.1743 39.226 55.0348C40.7041 46.9172 44.4168 40.0723 50.0888 34.5C48.8856 34.7408 47.6825 35.016 46.5137 35.3943C37.5072 38.2148 30.5976 43.6839 25.6131 51.6639C21.6598 58.0273 19.5629 64.9411 19.3223 72.4739C19.1848 76.7047 19.4598 80.7979 20.4223 84.7879C23.4818 97.2395 30.2882 107.043 40.6698 114.335H40.7729V114.403C41.1167 114.644 41.4604 114.919 41.8042 115.16C50.2607 120.801 59.5766 123.691 69.7519 124.035V123.966Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M73.1896 89.052C69.1676 90.8406 65.0081 91.8725 60.6768 92.2165C65.9707 95.209 71.7802 96.688 78.1054 96.8256C80.168 96.86 82.2305 96.6536 84.3962 96.3097C89.7245 95.4841 94.6746 93.5579 99.281 90.7374C94.9153 87.057 90.5839 83.4109 86.2181 79.7305C82.5055 83.6861 78.1741 86.8506 73.1896 89.052Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M67.9643 0.241609C67.4143 0.276006 66.8643 0.344799 66.3486 0.413592C71.6425 1.4111 76.7646 3.13093 81.6116 5.71068C91.0306 10.7326 98.3527 17.9215 103.268 27.4494L105.915 25.1448C108.631 22.7714 111.347 20.3981 114.063 18.0247C107.634 11.1797 100.072 6.15784 91.2025 3.06214C85.2898 0.998336 79.2396 -0.0335643 73.0176 0.000832322C71.3675 0.000832322 69.6831 0.138419 67.9643 0.241609Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M26.4037 107.871C18.4628 97.9988 14.1314 86.7167 14.2002 73.818C14.2002 67.317 15.5409 61.0568 18.1191 55.1062C21.9348 46.2662 27.9506 39.1805 36.4071 34.2962C44.348 29.687 52.9763 27.8984 62.1547 29.2743C71.5738 30.7189 79.3771 35.2249 85.6336 42.2762C85.6336 42.2762 85.8398 42.5514 85.9429 42.6546C86.8711 41.8291 87.8336 41.0035 88.7618 40.178L89.8962 39.1805C90.8587 38.355 91.8212 37.4951 92.7838 36.6696C94.9838 34.7434 97.1495 32.8515 99.3152 30.9253C95.087 22.223 88.7274 15.55 80.3053 10.8377C70.3706 5.26541 59.6797 3.54557 48.37 5.02463C42.7323 5.78136 37.3352 7.50119 32.1788 10.0465C14.6815 18.7145 2.06546 36.532 1.03418 58.4771C0.862296 62.0887 1.10293 65.7348 1.65294 69.3464C3.02798 78.3239 6.32808 86.4759 11.622 93.8368C15.7471 99.5123 20.6629 104.19 26.3693 107.871H26.4037Z\"\n fill=\"currentColor\"\n />\n </svg>\n );\n}\n","'use client';\n\nimport {\n ClButton,\n type ClButtonProps,\n} from '@/client/components/design-system/ClButton';\nimport { CoinListLogomark } from '@/client/components/design-system/logos/CoinListLogomark';\n\ninterface CoinListSignInButtonProps\n extends Pick<\n ClButtonProps,\n 'onClick' | 'disabled' | 'fullWidth' | 'isLoading' | 'className'\n > {}\n\nexport function CoinListSignInButton({\n onClick,\n disabled = false,\n fullWidth = false,\n isLoading = false,\n className,\n}: CoinListSignInButtonProps) {\n return (\n <ClButton\n variant=\"primary\"\n size=\"lg\"\n fullWidth={fullWidth}\n onClick={onClick}\n disabled={disabled}\n isLoading={isLoading}\n loadingText=\"Signing in...\"\n startIcon={\n <CoinListLogomark className=\"clcosdk:h-[18px] clcosdk:w-[16px] clcosdk:shrink-0\" />\n }\n className={className}\n >\n Continue with CoinList\n </ClButton>\n );\n}\n","import { useContext } from 'react';\nimport { CoinListContext } from '@/client/CoinListProvider';\nimport type { CoinListClient } from '@/client/core/coinlist-client';\n\nexport interface UseCoinListResult {\n /**\n * Indicates whether the CoinList client has been initialized and ready to use.\n * While isReady is false, then the current user state will be `unknown`.\n */\n isReady: boolean;\n coinlist: CoinListClient;\n}\n\nexport function useCoinList(): UseCoinListResult {\n const context = useContext(CoinListContext);\n if (context === null) {\n throw new CoinListClientInitializationError();\n }\n\n return {\n isReady: context.isReady,\n coinlist: context.coinlist,\n };\n}\n\nexport class CoinListClientInitializationError extends Error {\n constructor(\n message = 'useCoinList() must be used within CoinListProvider. Wrap your app with <CoinListProvider config={...}>.'\n ) {\n super(message);\n this.name = 'CoinListClientInitializationError';\n }\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { AlertBanner } from '@/client/components/design-system/AlertBanner';\nimport { CloseButton } from '@/client/components/design-system/CloseButton';\nimport { PoweredByCoinList } from '@/client/components/design-system/PoweredByCoinList';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport { CoinListSignInButton } from '@/client/components/oauth/CoinListSignInButton';\nimport { useCoinList } from '@/client/hooks/useCoinList';\n\nexport interface CoinListSignInCardProps {\n state?: 'idle' | 'error';\n /**\n * Called when the user clicks the sign-in button. Defaults to\n * {@link CoinListClient#startOAuth}, which redirects to the CoinList\n * authorization page. Pass your own handler to override this behavior.\n */\n onSignIn?: () => void;\n /** Called when the user clicks the close button. When omitted, no close button is rendered. */\n onClose?: () => void;\n className?: string;\n}\n\n/**\n * Sign-in card that prompts the user to authenticate with CoinList.\n *\n * Use this component inside a tree wrapped by {@link CoinListProvider} (for the\n * client context). By default, clicking the sign-in button starts the CoinList\n * OAuth flow via {@link CoinListClient#startOAuth}; pass `onSignIn` to override.\n *\n * Self-scoped: renders fully styled on its own, no `CoinListStyleScope` needed.\n */\nexport function CoinListSignInCard({\n state = 'idle',\n onSignIn,\n onClose,\n className,\n}: CoinListSignInCardProps = {}): ReactNode {\n const { coinlist } = useCoinList();\n const handleSignIn =\n onSignIn ??\n (() => {\n void coinlist.startOAuth();\n });\n\n return (\n <CoinListStyleScope>\n <div\n className={cn(\n 'clcosdk:relative clcosdk:flex clcosdk:w-full clcosdk:max-w-md clcosdk:flex-col clcosdk:rounded-card clcosdk:border clcosdk:border-border clcosdk:bg-background clcosdk:p-6 clcosdk:shadow-card',\n className\n )}\n >\n {onClose && (\n <CloseButton\n onClick={onClose}\n className=\"clcosdk:absolute clcosdk:right-4 clcosdk:top-4\"\n />\n )}\n\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-2\">\n <h3 className={cn(typeClasses.h3, 'clcosdk:text-text-primary')}>\n Sign in to participate\n </h3>\n <p className={cn(typeClasses.body, 'clcosdk:text-text-secondary')}>\n A CoinList account is required to participate in this sale.\n </p>\n </div>\n\n <CoinListSignInButton\n onClick={handleSignIn}\n fullWidth\n className=\"clcosdk:mt-4\"\n />\n\n {state === 'error' && (\n <AlertBanner\n variant=\"error\"\n icon\n content=\"Error signing in. Please try again.\"\n className=\"clcosdk:mt-4\"\n />\n )}\n\n <PoweredByCoinList className=\"clcosdk:mt-4\" />\n </div>\n </CoinListStyleScope>\n );\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport type { Offer } from '@/shared/types/offer';\n\nexport type OfferCardUi = {\n tagline: string | null;\n bannerUrl: string | null;\n logoUrl: string | null;\n formattedStartsAt: string;\n formattedEndsAt: string;\n};\n\nconst monthYearFormatter = new Intl.DateTimeFormat('en-US', {\n month: 'short',\n year: 'numeric',\n});\n\nexport const OfferCardUi = {\n fromDomain: (offer: Offer): OfferCardUi => ({\n tagline: offer.tagline,\n bannerUrl: offer.bannerUrl,\n logoUrl: offer.logoUrl,\n formattedStartsAt: monthYearFormatter.format(offer.startsAt),\n formattedEndsAt: monthYearFormatter.format(offer.endsAt),\n }),\n};\n\nexport interface Props {\n offer: OfferCardUi;\n /** Optional click handler. When provided, the card renders as interactive. */\n onClick?: () => void;\n /** Optional className applied to the card root element. */\n className?: string;\n /** Optional className applied to an outer wrapper element. */\n containerClassName?: string;\n}\n\n/**\n * Offer card. Self-scoped: renders fully styled on its own, with no\n * `CoinListStyleScope` needed. Also composed by {@link OffersGrid}.\n */\nexport function OfferCard({\n offer,\n onClick,\n className,\n containerClassName,\n}: Props): ReactNode {\n const cardLabel = 'Open offer details';\n\n const cardContent = (\n <>\n <div className=\"clcosdk:relative clcosdk:mb-6 clcosdk:h-52 clcosdk:w-full clcosdk:overflow-hidden clcosdk:rounded-2xl clcosdk:border clcosdk:border-border/60 clcosdk:bg-section\">\n {offer.bannerUrl ? (\n <img\n src={offer.bannerUrl}\n alt=\"Offer banner\"\n className=\"clcosdk:h-full clcosdk:w-full clcosdk:object-cover\"\n />\n ) : (\n <div className=\"clcosdk:h-full clcosdk:w-full clcosdk:bg-gradient-to-br clcosdk:from-surface clcosdk:via-section clcosdk:to-background\" />\n )}\n <div className=\"clcosdk:absolute clcosdk:inset-0 clcosdk:bg-gradient-to-b clcosdk:from-transparent clcosdk:via-transparent clcosdk:to-overlay/35\" />\n\n <div className=\"clcosdk:absolute clcosdk:inset-0 clcosdk:flex clcosdk:items-center clcosdk:justify-center clcosdk:p-6\">\n {offer.logoUrl ? (\n <img\n src={offer.logoUrl}\n alt=\"Offer logo\"\n className=\"clcosdk:h-28 clcosdk:w-28 clcosdk:rounded-full clcosdk:border clcosdk:border-border clcosdk:bg-surface clcosdk:object-cover clcosdk:shadow-[0_10px_24px_rgba(0,0,0,0.25)]\"\n />\n ) : (\n <div className=\"clcosdk:h-28 clcosdk:w-28 clcosdk:rounded-full clcosdk:border clcosdk:border-border clcosdk:bg-surface clcosdk:shadow-[0_10px_24px_rgba(0,0,0,0.18)]\" />\n )}\n </div>\n </div>\n\n {offer.tagline && (\n <p\n className={cn(\n typeClasses.h3,\n 'clcosdk:min-h-[2.4rem] clcosdk:text-text-primary'\n )}\n >\n {offer.tagline}\n </p>\n )}\n\n <div className=\"clcosdk:mt-4 clcosdk:grid clcosdk:grid-cols-2 clcosdk:gap-5 clcosdk:border-t clcosdk:border-divider clcosdk:pt-4\">\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-1\">\n <span\n className={cn(typeClasses.subhead, 'clcosdk:text-text-secondary')}\n >\n Starts\n </span>\n <span className={cn(typeClasses.label, 'clcosdk:text-text-primary')}>\n {offer.formattedStartsAt}\n </span>\n </div>\n\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-1\">\n <span\n className={cn(typeClasses.subhead, 'clcosdk:text-text-secondary')}\n >\n Ends\n </span>\n <span className={cn(typeClasses.label, 'clcosdk:text-text-primary')}>\n {offer.formattedEndsAt}\n </span>\n </div>\n </div>\n </>\n );\n\n const baseClasses = cn(\n 'clcosdk:relative clcosdk:flex clcosdk:w-full clcosdk:max-w-[28rem] clcosdk:flex-col clcosdk:rounded-card clcosdk:border clcosdk:border-border clcosdk:bg-background clcosdk:p-6 clcosdk:text-left clcosdk:shadow-card clcosdk:transition-all clcosdk:duration-200',\n className,\n onClick &&\n 'clcosdk:cursor-pointer clcosdk:hover:-translate-y-0.5 clcosdk:hover:border-divider clcosdk:hover:shadow-[0px_14px_32px_-10px_rgba(0,0,0,0.35)] clcosdk:focus-visible:outline-none clcosdk:focus-visible:ring-2 clcosdk:focus-visible:ring-accent-focus clcosdk:focus-visible:ring-offset-2'\n );\n\n let cardNode: ReactNode;\n if (onClick) {\n cardNode = (\n <button\n type=\"button\"\n aria-label={cardLabel}\n className={baseClasses}\n onClick={onClick}\n >\n {cardContent}\n </button>\n );\n } else {\n cardNode = <div className={baseClasses}>{cardContent}</div>;\n }\n\n const card = containerClassName ? (\n <div className={containerClassName}>{cardNode}</div>\n ) : (\n cardNode\n );\n\n return <CoinListStyleScope>{card}</CoinListStyleScope>;\n}\n","import { useEffect, useState } from 'react';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type { Offer } from '@/shared/types/offer';\n\nexport type LoadOffersReason = 'not-authenticated' | 'generic-error';\n\nexport type LoadOffersState =\n | {\n type: 'LOADING';\n }\n | {\n type: 'ERROR';\n reason: LoadOffersReason;\n }\n | {\n type: 'CONTENT';\n offers: Offer[];\n };\n\nexport interface UseOffersOptions {\n /**\n * Offers pre-fetched on the server (e.g. via `CoinListServer.fetchOffers()`).\n * When provided, the hook uses this data as-is and skips the client-side fetch entirely.\n */\n data?: Offer[];\n}\n\nexport interface UseOffersResult {\n offersState: LoadOffersState;\n}\n\nconst LOADING_STATE: LoadOffersState = { type: 'LOADING' };\n\n/**\n * Loads all CoinList offers for the current user and exposes a UI-friendly state.\n *\n * Pass `data` (pre-fetched server-side) to use that data as-is and skip\n * the client-side fetch entirely.\n *\n * Returns `LOADING` while CoinList is initializing or while offers are being fetched.\n * Returns `CONTENT` with all offers when `fetchOffers()` succeeds.\n * Returns `ERROR` with:\n * - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}\n * - `generic-error` for any other failure\n */\nexport function useOffers(options: UseOffersOptions = {}): UseOffersResult {\n const { coinlist, isReady } = useCoinList();\n const { data: serverOffers } = options;\n const [offersState, setOffersState] = useState<LoadOffersState>(\n serverOffers !== undefined\n ? { type: 'CONTENT', offers: serverOffers }\n : LOADING_STATE\n );\n\n useEffect(() => {\n let isCancelled = false;\n\n // Wait until CoinListProvider finishes auth initialization.\n if (!isReady) {\n if (serverOffers === undefined) {\n setOffersState(LOADING_STATE);\n }\n return () => {\n isCancelled = true;\n };\n }\n\n if (serverOffers !== undefined) {\n return () => {\n isCancelled = true;\n };\n }\n\n setOffersState(LOADING_STATE);\n coinlist\n .fetchOffers()\n .then((offers) => {\n if (!isCancelled) {\n setOffersState({ type: 'CONTENT', offers });\n }\n })\n .catch((error: unknown) => {\n if (!isCancelled) {\n const reason: LoadOffersReason =\n error instanceof NotAuthenticatedError\n ? 'not-authenticated'\n : 'generic-error';\n setOffersState({ type: 'ERROR', reason });\n }\n });\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist, isReady, serverOffers]);\n\n return { offersState };\n}\n","'use client';\n\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { AlertBanner } from '@/client/components/design-system/AlertBanner';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport { OfferCard, OfferCardUi } from '@/client/components/offers/OfferCard';\nimport { useOffers } from '@/client/hooks/useOffers';\nimport type { Offer } from '@/shared/types/offer';\n\nconst DEFAULT_MAX_COLUMNS = 3;\n\nexport interface OffersGridProps {\n /** Maximum number of columns to render when horizontal space allows. */\n maxColumns?: number;\n /** Optional className applied to the grid element. */\n className?: string;\n /** Optional className applied to the outer wrapper element. */\n containerClassName?: string;\n /** Optional loading slot shown while offers are being fetched. */\n loading?: ReactNode;\n /** Optional error slot shown when loading offers fails. */\n error?: ReactNode;\n /** Optional empty state slot shown when there are no available offers. */\n emptyState?: ReactNode;\n /** Optional per-offer click handler; when omitted, cards are not clickable. */\n onOfferClick?: (offer: Offer) => void;\n /**\n * Offers pre-fetched on the server (e.g. via `CoinListServer.fetchOffers()`).\n * When provided, the component uses this data as-is and skips the client-side fetch entirely.\n */\n data?: Offer[];\n}\n\nfunction OffersGridBody({\n data,\n maxColumns,\n className,\n containerClassName,\n loading,\n error,\n emptyState,\n onOfferClick,\n}: OffersGridProps = {}): ReactNode {\n const { offersState } = useOffers({ data });\n const cols = Math.max(1, maxColumns ?? DEFAULT_MAX_COLUMNS);\n\n if (offersState.type === 'LOADING') {\n if (loading) {\n return loading;\n }\n\n return (\n <output\n aria-live=\"polite\"\n className=\"clcosdk:flex clcosdk:min-h-40 clcosdk:items-center clcosdk:justify-center clcosdk:rounded-2xl clcosdk:border clcosdk:border-border clcosdk:bg-background clcosdk:p-6\"\n >\n <p className={cn(typeClasses.body, 'clcosdk:text-text-secondary')}>\n Loading offers...\n </p>\n </output>\n );\n }\n\n if (offersState.type === 'ERROR') {\n if (error) {\n return error;\n }\n\n const errorMessage =\n offersState.reason === 'not-authenticated'\n ? 'Sign in to view available offers.'\n : 'Unable to load offers right now. Please try again.';\n\n return (\n <AlertBanner\n variant=\"error\"\n icon\n content={errorMessage}\n className=\"clcosdk:w-full clcosdk:max-w-[28rem]\"\n />\n );\n }\n\n if (offersState.offers.length === 0) {\n if (emptyState) {\n return emptyState;\n }\n\n return (\n <output\n aria-live=\"polite\"\n className=\"clcosdk:flex clcosdk:min-h-40 clcosdk:flex-col clcosdk:items-center clcosdk:justify-center clcosdk:rounded-2xl clcosdk:border clcosdk:border-border clcosdk:bg-background clcosdk:p-6 clcosdk:text-center\"\n >\n <p\n className={cn(\n typeClasses.body,\n 'clcosdk:font-medium clcosdk:text-text-primary'\n )}\n >\n No offers available\n </p>\n <p className={cn(typeClasses.subhead, 'clcosdk:text-text-secondary')}>\n Check back soon for upcoming opportunities.\n </p>\n </output>\n );\n }\n\n const maxGridWidth = `calc(${cols} * 28rem + ${Math.max(cols - 1, 0)} * 1.5rem)`;\n\n return (\n <div\n className={cn(\n 'clcosdk:flex clcosdk:w-full clcosdk:justify-center',\n containerClassName\n )}\n >\n <div\n className={cn('clcosdk:grid clcosdk:w-full clcosdk:gap-6', className)}\n style={{\n gridTemplateColumns:\n 'repeat(auto-fit, minmax(min(100%, 20rem), 1fr))',\n maxWidth: maxGridWidth,\n }}\n >\n {offersState.offers.map((offer) => (\n <OfferCard\n key={offer.id}\n offer={OfferCardUi.fromDomain(offer)}\n onClick={onOfferClick ? () => onOfferClick(offer) : undefined}\n />\n ))}\n </div>\n </div>\n );\n}\n\n/**\n * Displays a responsive grid of offers backed by {@link useOffers}.\n *\n * Pass `data` (pre-fetched server-side) to use that data as-is and skip\n * the client-side fetch entirely.\n *\n * Uses `loading` / `error` slots when provided; otherwise renders standard\n * fallback loading and error states. Offer cards are interactive only when\n * `onOfferClick` is provided.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope` needed.\n */\nexport function OffersGrid(props: OffersGridProps = {}): ReactNode {\n return (\n <CoinListStyleScope>\n <OffersGridBody {...props} />\n </CoinListStyleScope>\n );\n}\n","'use client';\n\nimport { type ReactNode, useState } from 'react';\nimport { AlertBanner } from '@/client/components/design-system/AlertBanner';\nimport { ClButton } from '@/client/components/design-system/ClButton';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\n\n/** Load state of a connected-wallet list. */\nexport type WalletsStatus = 'ready' | 'loading' | 'error';\n\n/** A single connected wallet, shaped for display in {@link ConnectedWalletList}. */\nexport type ConnectedWalletUi = {\n /** Id of the connected wallet, used to remove it. */\n id: string;\n /** Full wallet address (for `title`/`aria`). */\n address: string;\n /** Shortened address for display (e.g. `0x1234…abcd`). */\n shortAddress: string;\n};\n\nexport interface ConnectedWalletListProps {\n wallets: ConnectedWalletUi[];\n /**\n * Removes a connected wallet by id. May return a promise; the row shows a\n * removing state until it settles and surfaces an inline error on rejection.\n * `null`/omitted hides the remove control (read-only list).\n */\n onRemove?: ((id: string) => void | Promise<void>) | null;\n /** Opens the connect flow to add another wallet. Omit to hide the button. */\n onAdd?: (() => void) | null;\n /** Label for the add button. Defaults to \"Add wallet\". */\n addLabel?: string;\n /**\n * Load state of the wallets. `'loading'`/`'error'` render a status message so\n * a failed or in-flight fetch is not mistaken for a genuinely empty list.\n * Defaults to `'ready'`.\n */\n status?: WalletsStatus;\n className?: string;\n}\n\ntype RowState = 'idle' | 'confirming' | 'removing' | 'error';\n\nfunction ConnectedWalletRow({\n wallet,\n onRemove,\n}: {\n wallet: ConnectedWalletUi;\n onRemove?: ((id: string) => void | Promise<void>) | null;\n}): ReactNode {\n const [state, setState] = useState<RowState>('idle');\n\n const remove = async () => {\n if (!onRemove) return;\n setState('removing');\n try {\n await onRemove(wallet.id);\n // On success the list is refetched and this row usually unmounts. Reset to\n // idle anyway so a row that survives the refetch (eventual consistency)\n // isn't stuck showing \"Removing…\" with no way out.\n setState('idle');\n } catch {\n setState('error');\n }\n };\n\n return (\n <div className=\"clcosdk:flex clcosdk:min-h-9 clcosdk:flex-wrap clcosdk:items-center clcosdk:justify-between clcosdk:gap-2\">\n <span\n title={wallet.address}\n className={cn(\n typeClasses.body,\n 'clcosdk:font-mono clcosdk:text-text-primary'\n )}\n >\n {wallet.shortAddress}\n </span>\n\n {onRemove != null &&\n (state === 'confirming' ? (\n <div className=\"clcosdk:flex clcosdk:items-center clcosdk:gap-2\">\n <span\n className={cn(typeClasses.subhead, 'clcosdk:text-text-secondary')}\n >\n Remove?\n </span>\n <ClButton size=\"sm\" variant=\"destructive\" onClick={remove}>\n Remove\n </ClButton>\n <ClButton\n size=\"sm\"\n variant=\"ghost\"\n onClick={() => setState('idle')}\n >\n Cancel\n </ClButton>\n </div>\n ) : state === 'error' ? (\n <div className=\"clcosdk:flex clcosdk:items-center clcosdk:gap-2\">\n <span className={cn(typeClasses.subhead, 'clcosdk:text-error')}>\n Couldn't remove.\n </span>\n <ClButton\n size=\"sm\"\n variant=\"destructiveLink\"\n onClick={() => setState('confirming')}\n >\n Try again\n </ClButton>\n </div>\n ) : (\n <ClButton\n size=\"sm\"\n variant=\"destructiveLink\"\n disabled={state === 'removing'}\n onClick={() => setState('confirming')}\n >\n {state === 'removing' ? 'Removing…' : 'Remove'}\n </ClButton>\n ))}\n </div>\n );\n}\n\n/**\n * Presentational list of a user's connected wallets for a whitelisted-wallet\n * requirement: each row shows the address with an inline two-step remove\n * confirmation, plus an optional \"Add wallet\" button. Self-contained — holds\n * only per-row confirm/removing/error UI state; all data and side effects come\n * from props.\n */\nexport function ConnectedWalletList({\n wallets,\n onRemove,\n onAdd,\n addLabel = 'Add wallet',\n status = 'ready',\n className,\n}: ConnectedWalletListProps): ReactNode {\n return (\n <div\n className={cn('clcosdk:flex clcosdk:flex-col clcosdk:gap-2', className)}\n >\n {status === 'loading' ? (\n <AlertBanner variant=\"info\" content=\"Loading your connected wallets…\" />\n ) : status === 'error' ? (\n <AlertBanner\n variant=\"error\"\n content=\"Couldn't load your connected wallets.\"\n />\n ) : wallets.length === 0 ? (\n <AlertBanner variant=\"info\" content=\"No wallets connected yet.\" />\n ) : (\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:divide-y clcosdk:divide-divider\">\n {wallets.map((wallet) => (\n <ConnectedWalletRow\n key={wallet.id}\n wallet={wallet}\n onRemove={onRemove}\n />\n ))}\n </div>\n )}\n\n {onAdd != null && status !== 'loading' && (\n <ClButton\n size=\"sm\"\n variant=\"secondary\"\n onClick={onAdd}\n className=\"clcosdk:self-start\"\n >\n {addLabel}\n </ClButton>\n )}\n </div>\n );\n}\n","'use client';\n\nimport { useEffect, useId } from 'react';\nimport { AlertBanner } from '@/client/components/design-system/AlertBanner';\nimport { ClButton } from '@/client/components/design-system/ClButton';\nimport { CloseButton } from '@/client/components/design-system/CloseButton';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport type {\n ConnectWallet,\n ConnectWalletSignState,\n} from '@/client/hooks/useConnectWallet';\nimport { useConnectWallet } from '@/client/hooks/useConnectWallet';\nimport { shortenAddress } from '@/shared/core/blockchain/formatters';\nimport type { EvmWalletAddress } from '@/shared/types/blockchain/core';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport type { OfferOptionAddress } from '@/shared/types/offer-option-address';\nimport type { WalletChallengeType } from '@/shared/types/wallet-ownership-challenge';\n\nexport interface ConnectWalletModalProps {\n isOpen: boolean;\n onClose: () => void;\n offerId: OfferId;\n optionId: OfferOptionId;\n /** Host-provided connected wallet, or `null` while none is connected. */\n wallet: ConnectWallet | null;\n /** Called once the wallet is bound to the offer option, right before close. */\n onConnected?: (binding: OfferOptionAddress) => void;\n /**\n * Called when the user asks to connect (or switch) a wallet: the \"Connect\n * wallet\" button when none is connected, and \"Use a different wallet\" when one\n * already is.\n */\n onRequestConnect?: () => void;\n /** Challenge framing; defaults to `'siwe'`. */\n challengeType?: WalletChallengeType;\n /** SIWE statement shown in the signing prompt. */\n statement?: string;\n className?: string;\n}\n\n/**\n * Batteries-included modal for the external-wallet ownership flow. Drives\n * {@link useConnectWallet} (challenge -> host signs -> connect) for one offer\n * option. Signing is delegated to the host-provided {@link ConnectWallet}: the SDK\n * never bundles a wallet stack.\n *\n * No portal is used — rendering stays inside the normal DOM tree so it keeps\n * this SDK's `.clco-sdk-root`-scoped theme tokens without needing its own\n * {@link CoinListStyleScope}.\n */\nexport function ConnectWalletModal({\n isOpen,\n onClose,\n offerId,\n optionId,\n wallet,\n onConnected,\n onRequestConnect,\n challengeType,\n statement,\n className,\n}: ConnectWalletModalProps) {\n const { state, onSign } = useConnectWallet({\n isOpen,\n offerId,\n offerOptionId: optionId,\n wallet,\n challengeType,\n statement,\n });\n // Instance-local so two open modals can't collide on a shared heading id.\n const titleId = useId();\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: only react to a CONNECTED transition, not every state change\n useEffect(() => {\n if (state.type === 'CONNECTED') {\n onConnected?.(state.binding);\n onClose();\n }\n }, [state]);\n\n if (!isOpen || state.type === 'CONNECTED') return null;\n\n return (\n <div className=\"clcosdk:fixed clcosdk:inset-0 clcosdk:z-50 clcosdk:flex clcosdk:items-center clcosdk:justify-center clcosdk:bg-black/50 clcosdk:p-4\">\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n className={cn(\n 'clcosdk:flex clcosdk:w-full clcosdk:max-w-md clcosdk:flex-col clcosdk:gap-6 clcosdk:rounded-2xl clcosdk:bg-background clcosdk:p-6',\n className\n )}\n >\n <div className=\"clcosdk:flex clcosdk:items-start clcosdk:justify-between clcosdk:gap-4\">\n <h3\n id={titleId}\n className={cn(typeClasses.h3, 'clcosdk:text-text-primary')}\n >\n Connect your wallet\n </h3>\n <CloseButton onClick={onClose} />\n </div>\n\n {state.type === 'NEEDS_WALLET' && (\n <NeedsWalletScreen onRequestConnect={onRequestConnect} />\n )}\n {state.type === 'READY' && (\n <ReadyScreen\n address={state.address}\n sign={state.sign}\n onSign={onSign}\n onRequestConnect={onRequestConnect}\n />\n )}\n </div>\n </div>\n );\n}\n\nfunction NeedsWalletScreen({\n onRequestConnect,\n}: {\n onRequestConnect?: () => void;\n}) {\n return (\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-6\">\n <p className={cn(typeClasses.body, 'clcosdk:text-text-secondary')}>\n Connect an external wallet to prove ownership and bind it to this offer.\n </p>\n {onRequestConnect && (\n <ClButton fullWidth onClick={onRequestConnect}>\n Connect wallet\n </ClButton>\n )}\n </div>\n );\n}\n\nfunction ReadyScreen({\n address,\n sign,\n onSign,\n onRequestConnect,\n}: {\n address: EvmWalletAddress;\n sign: ConnectWalletSignState;\n onSign: () => void;\n onRequestConnect?: () => void;\n}) {\n const hasTerminalError =\n sign.type === 'idle' && sign.error !== null && !sign.error.retryable;\n\n return (\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-6\">\n <p className={cn(typeClasses.body, 'clcosdk:text-text-secondary')}>\n Sign a message with your connected wallet to prove you own it. This does\n not cost gas or move any funds.\n </p>\n\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-1 clcosdk:border-t clcosdk:border-divider clcosdk:pt-4\">\n <span className={cn(typeClasses.label, 'clcosdk:text-text-secondary')}>\n Wallet address\n </span>\n <span className={cn(typeClasses.body, 'clcosdk:text-text-primary')}>\n {shortenAddress(address)}\n </span>\n </div>\n\n {sign.type === 'idle' && sign.error && (\n // Live region: the error is inserted async after a failed attempt, so\n // screen readers need it announced rather than silently rendered.\n <div role=\"alert\">\n <AlertBanner variant=\"error\" icon content={sign.error.message} />\n </div>\n )}\n\n <ClButton\n fullWidth\n onClick={onSign}\n isLoading={sign.type === 'signing'}\n loadingText=\"Waiting for signature...\"\n // A terminal failure (e.g. wallet not whitelisted, max wallets) can\n // never succeed by re-signing the same wallet — only switching helps.\n disabled={hasTerminalError}\n >\n Sign & connect\n </ClButton>\n\n {onRequestConnect && (\n <ClButton\n fullWidth\n variant=\"secondary\"\n onClick={onRequestConnect}\n disabled={sign.type === 'signing'}\n >\n Use a different wallet\n </ClButton>\n )}\n </div>\n );\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport {\n type ConnectWallet,\n type ConnectWalletErrorCode,\n connectExternalWalletFlow,\n} from '@/client/core/connect-external-wallet';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport type { EvmWalletAddress } from '@/shared/types/blockchain/core';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport type { OfferOptionAddress } from '@/shared/types/offer-option-address';\nimport type { WalletChallengeType } from '@/shared/types/wallet-ownership-challenge';\n\n// Re-export so consumers importing the hook also get the wallet input type.\nexport type { ConnectWallet } from '@/client/core/connect-external-wallet';\n\n/**\n * A display-ready connect-wallet error: the core flow's machine-readable code\n * and `retryable` flag, plus copy for the UI.\n */\nexport type ConnectWalletError = {\n code: ConnectWalletErrorCode;\n message: string;\n retryable: boolean;\n};\n\n/**\n * Signing-in-flight and the last sign error live inside the READY state (not a\n * separate top-level state) so a failed attempt returns to READY and can be\n * retried without re-opening the modal. Mirrors {@link SignState} in\n * `useTaxDocument`.\n */\nexport type ConnectWalletSignState =\n | { type: 'idle'; error: ConnectWalletError | null }\n | { type: 'signing' };\n\nexport type ConnectWalletState =\n | { type: 'NEEDS_WALLET' } // no wallet connected yet; host must connect one\n | { type: 'READY'; address: EvmWalletAddress; sign: ConnectWalletSignState }\n | { type: 'CONNECTED'; binding: OfferOptionAddress };\n\nexport interface UseConnectWalletOptions {\n /** The hook resets state each time it opens. */\n isOpen: boolean;\n offerId: OfferId;\n offerOptionId: OfferOptionId;\n /** Host-provided connected wallet, or `null` while none is connected. */\n wallet: ConnectWallet | null;\n /** Challenge framing; defaults to `'siwe'`. */\n challengeType?: WalletChallengeType;\n /** SIWE statement shown in the signing prompt. */\n statement?: string;\n}\n\nexport interface UseConnectWalletResult {\n state: ConnectWalletState;\n /** READY.sign: idle -> signing -> (CONNECTED | idle w/ error). No-op otherwise. */\n onSign: () => void;\n}\n\nconst IDLE_SIGN: ConnectWalletSignState = { type: 'idle', error: null };\n\nconst ERROR_COPY: Record<ConnectWalletErrorCode, string> = {\n not_authenticated: 'Sign in to connect your wallet.',\n user_rejected:\n 'Signature request declined. Approve it in your wallet to continue.',\n wallet_not_whitelisted: 'This wallet is not approved for this offer.',\n max_wallets_reached:\n \"You've reached the maximum number of wallets for this option.\",\n unknown: 'Unable to connect your wallet. Please try again.',\n};\n\nfunction displayError(error: {\n code: ConnectWalletErrorCode;\n retryable: boolean;\n}): ConnectWalletError {\n return {\n code: error.code,\n message: ERROR_COPY[error.code],\n retryable: error.retryable,\n };\n}\n\n/**\n * React wrapper over {@link connectExternalWalletFlow}. Owns the modal state\n * machine, the display copy, and generation-token supersession (so a wallet\n * switch, modal close, or unmount cancels an in-flight attempt). The flow logic\n * itself lives in the framework-free core so non-React consumers can drive it.\n */\nexport function useConnectWallet({\n isOpen,\n offerId,\n offerOptionId,\n wallet,\n challengeType,\n statement,\n}: UseConnectWalletOptions): UseConnectWalletResult {\n const { coinlist } = useCoinList();\n const [state, setState] = useState<ConnectWalletState>(() =>\n wallet\n ? { type: 'READY', address: wallet.address, sign: IDLE_SIGN }\n : { type: 'NEEDS_WALLET' }\n );\n\n // Generation token for the in-flight attempt. Each `onSign` bumps it; the\n // reset effect (open / address change) and unmount bump it too, superseding\n // any attempt still in flight so its continuation becomes a no-op.\n const attempt = useRef(0);\n\n // Reset when the modal opens or the connected address changes. Keyed on the\n // address (not the wallet object) so re-creating the adapter with the same\n // address doesn't wipe an in-flight sign or a surfaced error.\n // biome-ignore lint/correctness/useExhaustiveDependencies: reset only on open/address change, not on every wallet-object identity change\n useEffect(() => {\n // Invalidate any in-flight attempt, including on close (isOpen -> false).\n attempt.current += 1;\n if (!isOpen) return;\n setState(\n wallet\n ? { type: 'READY', address: wallet.address, sign: IDLE_SIGN }\n : { type: 'NEEDS_WALLET' }\n );\n }, [isOpen, wallet?.address]);\n\n // Invalidate any in-flight attempt if the hook unmounts. A host can\n // conditionally unmount the exported modal mid-signature; without this the\n // pending flow could bind after the UI is gone.\n useEffect(\n () => () => {\n attempt.current += 1;\n },\n []\n );\n\n const onSign = useCallback(() => {\n if (!wallet || state.type !== 'READY') return;\n\n attempt.current += 1;\n const gen = attempt.current;\n\n setState({\n type: 'READY',\n address: wallet.address,\n sign: { type: 'signing' },\n });\n\n connectExternalWalletFlow({\n coinlist,\n wallet,\n offerId,\n offerOptionId,\n challengeType,\n statement,\n // Cancels the flow before signing / binding if this attempt is superseded.\n isCancelled: () => attempt.current !== gen,\n }).then((result) => {\n // A supersession that lands between the core's last check and here.\n if (attempt.current !== gen) return;\n if (result.type === 'success') {\n setState({ type: 'CONNECTED', binding: result.binding });\n } else if (result.type === 'error') {\n setState({\n type: 'READY',\n address: wallet.address,\n sign: { type: 'idle', error: displayError(result.error) },\n });\n }\n // 'cancelled' -> no-op; a newer attempt owns the state.\n });\n }, [\n wallet,\n state,\n coinlist,\n offerId,\n offerOptionId,\n challengeType,\n statement,\n ]);\n\n return { state, onSign };\n}\n","import type { Hex } from 'viem';\nimport type { EvmSigner } from '@/client/core/blockchain/evm-wallet';\nimport { classifyWalletError } from '@/client/core/blockchain/wallet-error';\nimport type { CoinListClient } from '@/client/core/coinlist-client';\nimport type { EthereumChain } from '@/shared/types/blockchain/core';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport type { OfferOptionAddress } from '@/shared/types/offer-option-address';\nimport type {\n CreateWalletOwnershipChallengeParams,\n WalletChallengeType,\n WalletOwnershipChallenge,\n} from '@/shared/types/wallet-ownership-challenge';\n\n/**\n * The host-provided wallet the ownership flow signs with: the signing-only\n * {@link EvmSigner} plus the {@link EthereumChain} the signature is proven on.\n * `chain` rides on the wallet (not the offer) because the binding is\n * chain-agnostic: it only records which EVM chain signed.\n */\nexport type ConnectWallet = EvmSigner & { readonly chain: EthereumChain };\n\n/**\n * Machine-readable classification of a connect-wallet failure, so consumers can\n * branch on the cause (e.g. hide a retry affordance on a terminal failure)\n * instead of pattern-matching a display string.\n */\nexport type ConnectWalletErrorCode =\n | 'not_authenticated'\n | 'user_rejected'\n | 'wallet_not_whitelisted'\n | 'max_wallets_reached'\n | 'unknown';\n\n/**\n * A classified connect-wallet failure. `retryable` is false when re-signing the\n * same wallet can never succeed (a terminal binding rejection, or no signed-in\n * session). Display copy is the caller's concern, kept out of the core.\n */\nexport type ConnectWalletFlowError = {\n code: ConnectWalletErrorCode;\n retryable: boolean;\n};\n\n/** Progress phases emitted by {@link connectExternalWalletFlow}, in order. */\nexport type ConnectWalletPhase =\n | 'requesting-challenge'\n | 'signing-message'\n | 'submitting-signature';\n\nexport type ConnectWalletFlowResult =\n | { type: 'success'; binding: OfferOptionAddress }\n | { type: 'cancelled' }\n | { type: 'error'; error: ConnectWalletFlowError };\n\n/** The client surface the flow actually depends on, kept narrow on purpose. */\ntype ConnectWalletClient = Pick<\n CoinListClient,\n 'createWalletOwnershipChallenge' | 'connectExternalWallet'\n>;\n\nexport type ConnectWalletFlowParams = {\n coinlist: ConnectWalletClient;\n /** Host-provided connected wallet the flow signs with. */\n wallet: ConnectWallet;\n offerId: OfferId;\n offerOptionId: OfferOptionId;\n /** Challenge framing; defaults to `'siwe'`. */\n challengeType?: WalletChallengeType;\n /** SIWE statement shown in the signing prompt. */\n statement?: string;\n /**\n * Polled before each irreversible step (signing, binding). Return true to\n * abandon a superseded attempt; the flow then resolves `{ type: 'cancelled' }`\n * without prompting the wallet or binding. React hooks pass a generation\n * check here; non-React callers can omit it.\n */\n isCancelled?: () => boolean;\n /** Reports flow progress for consumers rendering loading states. */\n onProgress?: (phase: ConnectWalletPhase) => void;\n};\n\nconst DEFAULT_STATEMENT =\n 'Sign this message to prove you own this wallet. This does not cost gas or move funds.';\n\n// Codes for which re-signing the same wallet can never succeed: no signed-in\n// session, or a terminal binding rejection.\nconst TERMINAL_CODES: ReadonlySet<ConnectWalletErrorCode> = new Set([\n 'not_authenticated',\n 'wallet_not_whitelisted',\n 'max_wallets_reached',\n]);\n\n// The subset the connect endpoint returns as a machine-readable `code` in its\n// 422 ApiErrorDto body.\nconst API_ERROR_CODES: ReadonlySet<ConnectWalletErrorCode> = new Set([\n 'wallet_not_whitelisted',\n 'max_wallets_reached',\n]);\n\nfunction flowError(code: ConnectWalletErrorCode): ConnectWalletFlowError {\n return { code, retryable: !TERMINAL_CODES.has(code) };\n}\n\n/**\n * Returns `{ domain, uri }` for a SIWE challenge, derived from the current page.\n * The flow only runs from a user action, so `window` is present; the\n * empty-string fallback just keeps this total for SSR and is never reached.\n */\nfunction siweContext(): { domain: string; uri: string } {\n if (typeof window === 'undefined') return { domain: '', uri: '' };\n return { domain: window.location.host, uri: window.location.origin };\n}\n\n/**\n * Reads the machine-readable `code` off an HTTP failure's `ApiErrorDto` body.\n * Duck-typed on the response shape rather than `instanceof HttpError`: the core\n * avoids importing the `@/shared/api` layer, so we match the structure instead.\n */\nfunction apiErrorCode(error: unknown): string | undefined {\n if (typeof error !== 'object' || error === null) return undefined;\n const body = (error as { response?: { body?: { code?: unknown } } }).response\n ?.body;\n return typeof body?.code === 'string' ? body.code : undefined;\n}\n\n/**\n * Classifies a challenge/connect API failure (not a wallet-thrown error). The\n * connect endpoint returns a machine-readable `code` in its 422 body for\n * terminal binding failures; everything else (a transient error, or an\n * expired/consumed-challenge 422 a fresh challenge retries) stays `unknown` and\n * retryable.\n */\nfunction classifyApiError(error: unknown): ConnectWalletFlowError {\n if (error instanceof NotAuthenticatedError) {\n return flowError('not_authenticated');\n }\n const code = apiErrorCode(error);\n if (\n code !== undefined &&\n API_ERROR_CODES.has(code as ConnectWalletErrorCode)\n ) {\n return flowError(code as ConnectWalletErrorCode);\n }\n return flowError('unknown');\n}\n\n/**\n * Builds the challenge-request params for the wallet's chain and framing. The\n * exhaustive `switch` makes adding a 3rd challenge type a compile error here\n * rather than a silent wrong branch.\n */\nfunction challengeParams(\n wallet: ConnectWallet,\n challengeType: WalletChallengeType,\n statement: string | undefined\n): CreateWalletOwnershipChallengeParams {\n switch (challengeType) {\n case 'siwe':\n return {\n walletAddress: wallet.address,\n chain: wallet.chain,\n challengeType: 'siwe',\n ...siweContext(),\n statement: statement ?? DEFAULT_STATEMENT,\n };\n case 'plain':\n return {\n walletAddress: wallet.address,\n chain: wallet.chain,\n challengeType: 'plain',\n };\n default: {\n const _exhaustive: never = challengeType;\n return _exhaustive;\n }\n }\n}\n\n/**\n * Drives the external-wallet ownership flow for one offer option:\n * `createWalletOwnershipChallenge` -> host `wallet.signMessage` ->\n * `connectExternalWallet`. Pure and signer-agnostic: signing is delegated to\n * the host-provided {@link ConnectWallet}, and no React is involved so non-hook\n * consumers can drive it directly (mirrors `authorizeWallet` in `swap-flows`).\n * EVM / EOA + SIWE only for now.\n */\nexport async function connectExternalWalletFlow(\n params: ConnectWalletFlowParams\n): Promise<ConnectWalletFlowResult> {\n const {\n coinlist,\n wallet,\n offerId,\n offerOptionId,\n challengeType,\n statement,\n isCancelled,\n onProgress,\n } = params;\n const emit = (phase: ConnectWalletPhase) => onProgress?.(phase);\n const cancelled = () => isCancelled?.() ?? false;\n\n // Step 1: Request a single-use ownership challenge to sign.\n emit('requesting-challenge');\n let challenge: WalletOwnershipChallenge;\n try {\n challenge = await coinlist.createWalletOwnershipChallenge(\n challengeParams(wallet, challengeType ?? 'siwe', statement)\n );\n } catch (error) {\n return { type: 'error', error: classifyApiError(error) };\n }\n\n // Superseded while the challenge was in flight: don't prompt the old wallet.\n if (cancelled()) return { type: 'cancelled' };\n\n // Step 2: Sign the challenge message with the host wallet.\n emit('signing-message');\n let signature: Hex;\n try {\n signature = await wallet.signMessage(challenge.message);\n } catch (error) {\n // Reuse the shared viem/user-rejection classifier for wallet-thrown errors.\n if (classifyWalletError(error).type === 'user_rejected') {\n return { type: 'error', error: flowError('user_rejected') };\n }\n return { type: 'error', error: flowError('unknown') };\n }\n\n // Superseded during signing: don't perform the irreversible bind.\n if (cancelled()) return { type: 'cancelled' };\n\n // Step 3: Submit the signature to bind the wallet to the offer option.\n emit('submitting-signature');\n try {\n const binding = await coinlist.connectExternalWallet(offerId, {\n offerOptionId,\n walletAddress: wallet.address,\n chain: wallet.chain,\n signature,\n });\n return { type: 'success', binding };\n } catch (error) {\n return { type: 'error', error: classifyApiError(error) };\n }\n}\n","'use client';\n\nimport SumsubWebSdk from '@sumsub/websdk-react';\nimport { type ReactNode, useEffect, useRef } from 'react';\nimport { AlertBanner } from '@/client/components/design-system/AlertBanner';\nimport { ClButton } from '@/client/components/design-system/ClButton';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport { useKycToken } from '@/client/hooks/useKycToken';\nimport type { KycLevelName } from '@/shared/types/kyc';\n\nexport interface IdentityVerificationProps {\n /**\n * Sumsub verification level to start. Determines which screens the Sumsub\n * WebSDK shows. Defaults to the backend's standard identity level.\n */\n levelName?: KycLevelName;\n /**\n * Reset the Sumsub applicant before starting the flow, so an\n * already-approved level can be executed again (e.g. to update stale PII).\n * Pass the `kycReset` value from the requirement status. Applies only to\n * the initial token — mid-flow token refreshes never repeat the reset.\n */\n reset?: boolean;\n /** BCP-47 language tag for the Sumsub UI, e.g. `'en'`. */\n locale?: string;\n /**\n * Called when the user submits their data in the Sumsub flow. Verification\n * continues asynchronously on the backend, so the requirement typically moves\n * to a pending state first — refetch requirement statuses to observe it.\n */\n onSubmitted?: () => void;\n /** Called when the Sumsub flow reports an error. */\n onError?: (error: Error) => void;\n className?: string;\n}\n\n/**\n * Inline Sumsub identity verification flow. Fetches a Sumsub WebSDK access\n * token via {@link useKycToken} and renders the Sumsub iframe. Used by\n * `RequirementsChecklist` for `identity_verified` requirements, and can also\n * be rendered standalone.\n */\nexport function IdentityVerification({\n levelName,\n reset,\n locale,\n onSubmitted,\n onError,\n className,\n}: IdentityVerificationProps): ReactNode {\n const { kycTokenState, fetchToken } = useKycToken(levelName, reset);\n const fetchedRef = useRef(false);\n\n useEffect(() => {\n if (fetchedRef.current) return;\n fetchedRef.current = true;\n fetchToken().catch(() => {\n // The failure is surfaced through kycTokenState; swallow the rejection.\n });\n }, [fetchToken]);\n\n const handleMessage = (type: string, payload: unknown) => {\n switch (type) {\n case 'idCheck.onApplicantSubmitted':\n onSubmitted?.();\n break;\n case 'idCheck.onError': {\n const message =\n (payload as { message?: string })?.message ?? 'Verification error';\n onError?.(new Error(message));\n break;\n }\n default:\n break;\n }\n };\n\n const handleError = (error: unknown) => {\n onError?.(error instanceof Error ? error : new Error('Verification error'));\n };\n\n if (kycTokenState.type === 'IDLE' || kycTokenState.type === 'LOADING') {\n return (\n <output\n aria-live=\"polite\"\n className={cn(\n 'clcosdk:flex clcosdk:min-h-40 clcosdk:items-center clcosdk:justify-center',\n className\n )}\n >\n <p className={cn(typeClasses.body, 'clcosdk:text-text-secondary')}>\n Loading identity verification...\n </p>\n </output>\n );\n }\n\n if (kycTokenState.type === 'ERROR') {\n const errorMessage =\n kycTokenState.reason === 'not-authenticated'\n ? 'Sign in to verify your identity.'\n : 'Unable to start identity verification right now. Please try again.';\n return (\n <div\n className={cn('clcosdk:flex clcosdk:flex-col clcosdk:gap-4', className)}\n >\n <AlertBanner variant=\"error\" icon content={errorMessage} />\n {kycTokenState.reason !== 'not-authenticated' && (\n <ClButton\n size=\"sm\"\n onClick={() => {\n fetchToken().catch(() => {\n // The failure is surfaced through kycTokenState.\n });\n }}\n >\n Try again\n </ClButton>\n )}\n </div>\n );\n }\n\n return (\n <div className={cn('clcosdk:w-full', className)}>\n <SumsubWebSdk\n accessToken={kycTokenState.token}\n expirationHandler={fetchToken}\n config={locale === undefined ? {} : { lang: locale }}\n options={{ addViewportTag: false, adaptIframeHeight: true }}\n onMessage={handleMessage}\n onError={handleError}\n />\n </div>\n );\n}\n","import { useCallback, useEffect, useRef, useState } from 'react';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type { KycLevelName } from '@/shared/types/kyc';\n\nexport type KycTokenErrorReason = 'not-authenticated' | 'generic-error';\n\nexport type KycTokenState =\n | {\n type: 'IDLE';\n }\n | {\n type: 'LOADING';\n }\n | {\n type: 'ERROR';\n reason: KycTokenErrorReason;\n }\n | {\n type: 'CONTENT';\n token: string;\n };\n\nexport interface UseKycTokenResult {\n kycTokenState: KycTokenState;\n /**\n * Fetches a fresh Sumsub WebSDK access token and transitions the state to\n * `CONTENT` (or `ERROR`). Resolves with the token so it can also be used\n * imperatively, e.g. as the Sumsub `expirationHandler`. Rejects on failure.\n */\n fetchToken: () => Promise<string>;\n}\n\nconst IDLE_STATE: KycTokenState = { type: 'IDLE' };\nconst LOADING_STATE: KycTokenState = { type: 'LOADING' };\n\n/**\n * Creates Sumsub WebSDK access tokens for the current user via\n * {@link CoinListClient#createKycToken}, exposed as a state machine.\n *\n * Starts in `IDLE`; call `fetchToken()` to request a token. Returns `LOADING`\n * while the request is in flight, then `CONTENT` with the token on success, or\n * `ERROR` with:\n * - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}\n * - `generic-error` for any other failure\n *\n * `reset` (resetting the Sumsub applicant so an already-approved level can be\n * redone) tracks the latest value of the `reset` argument up until a token is\n * first issued; after that, mid-flow token refreshes must never repeat the\n * reset, or the user's in-progress submission would be wiped, so further\n * changes to `reset` are ignored. Failed attempts keep the reset pending, so\n * retrying still requests it — the backend treats resetting an\n * already-pristine applicant as a no-op.\n */\nexport function useKycToken(\n levelName?: KycLevelName,\n reset?: boolean\n): UseKycTokenResult {\n const { coinlist } = useCoinList();\n const [kycTokenState, setKycTokenState] = useState<KycTokenState>(IDLE_STATE);\n const resetPendingRef = useRef(reset === true);\n const tokenIssuedRef = useRef(false);\n\n useEffect(() => {\n if (!tokenIssuedRef.current) {\n resetPendingRef.current = reset === true;\n }\n }, [reset]);\n\n const fetchToken = useCallback(async () => {\n setKycTokenState(LOADING_STATE);\n try {\n const kycToken = await coinlist.createKycToken(\n levelName,\n resetPendingRef.current\n );\n resetPendingRef.current = false;\n tokenIssuedRef.current = true;\n setKycTokenState({ type: 'CONTENT', token: kycToken.token });\n return kycToken.token;\n } catch (error) {\n const reason: KycTokenErrorReason =\n error instanceof NotAuthenticatedError\n ? 'not-authenticated'\n : 'generic-error';\n setKycTokenState({ type: 'ERROR', reason });\n throw error;\n }\n }, [coinlist, levelName]);\n\n return { kycTokenState, fetchToken };\n}\n","'use client';\n\nimport { ChevronRight } from 'lucide-react';\nimport type { ReactNode } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { AlertBanner } from '@/client/components/design-system/AlertBanner';\nimport { ClButton } from '@/client/components/design-system/ClButton';\nimport { StepStatusIcon } from '@/client/components/design-system/StepStatusIcon';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport {\n ConnectedWalletList,\n type ConnectedWalletUi,\n type WalletsStatus,\n} from '@/client/components/requirements/ConnectedWalletList';\nimport { shortenAddress } from '@/shared/core/blockchain/formatters';\nimport type { OfferOptionAddress } from '@/shared/types/offer-option-address';\nimport type {\n Requirement,\n RequirementStatusInfo,\n RequirementStatusValue,\n RequirementType,\n} from '@/shared/types/requirement';\n\nexport type RequirementVariant = 'verification' | 'wallet';\nexport const RequirementVariant = {\n fromType(type: RequirementType): RequirementVariant {\n switch (type) {\n case 'external_wallet':\n case 'whitelisted_wallet':\n return 'wallet';\n default:\n return 'verification';\n }\n },\n};\n\nexport type RequirementStatus =\n | 'required'\n | 'pending'\n | 'completed'\n | 'rejected';\nexport const RequirementStatus = {\n fromStatusValue(status: RequirementStatusValue): RequirementStatus {\n switch (status) {\n case 'not_started':\n case 'action_needed':\n return 'required';\n case 'in_progress':\n return 'pending';\n case 'completed':\n return 'completed';\n case 'rejected':\n return 'rejected';\n }\n },\n};\n\nexport type ChecklistStatus = 'inProgress' | 'eligible' | 'ineligible';\nexport const ChecklistStatus = {\n derive(statuses: RequirementStatusInfo[]): ChecklistStatus {\n if (statuses.some((s) => s.status === 'rejected')) return 'ineligible';\n if (statuses.every((s) => s.status === 'completed')) return 'eligible';\n return 'inProgress';\n },\n};\n\nexport type RequirementItemUi = {\n variant: RequirementVariant;\n status: RequirementStatus;\n label: string;\n description: string;\n /**\n * `true` for `whitelisted_wallet` (a multi-slot list the user can add to and\n * remove from), `false` for the single-slot `external_wallet`.\n */\n multiWallet: boolean;\n /** The user's connected wallets. Single-slot requirements have at most one. */\n connectedWallets: ConnectedWalletUi[];\n};\n\nexport const RequirementItemUi = {\n fromDomain(\n req: Requirement,\n statusInfo: RequirementStatusInfo | undefined,\n label: string,\n description: string,\n addresses: OfferOptionAddress[] = []\n ): RequirementItemUi {\n return {\n variant: RequirementVariant.fromType(req.type),\n status: statusInfo\n ? RequirementStatus.fromStatusValue(statusInfo.status)\n : 'required',\n label,\n description,\n multiWallet: req.type === 'whitelisted_wallet',\n connectedWallets: addresses.map((address) => ({\n id: address.id,\n address: address.address,\n shortAddress: shortenAddress(address.address),\n })),\n };\n },\n};\n\nexport interface RequirementItemProps {\n ui: RequirementItemUi;\n expanded?: boolean;\n onToggle?: () => void;\n className?: string;\n /** Connect / change / add-wallet action (opens the connect flow). */\n onAction?: (() => void) | null;\n /** Removes a bound wallet by id (whitelisted-wallet requirements only). */\n onRemoveWallet?: ((id: string) => void | Promise<void>) | null;\n /**\n * Load state of {@link RequirementItemUi.connectedWallets}. `'loading'` /\n * `'error'` keep a fetch-in-flight or failed fetch from looking like an empty\n * wallet list. Defaults to `'ready'`.\n */\n walletsStatus?: WalletsStatus;\n onContactSupport?: (() => void) | null;\n}\n\nfunction VerificationActionZone({\n status,\n onAction,\n onContactSupport,\n}: {\n status: RequirementStatus;\n onAction?: (() => void) | null;\n onContactSupport?: (() => void) | null;\n}): ReactNode {\n switch (status) {\n case 'required':\n if (onAction === null) return null;\n return (\n <ClButton size=\"sm\" onClick={onAction}>\n Continue\n </ClButton>\n );\n case 'pending':\n return (\n <AlertBanner\n variant=\"warning\"\n content=\"Under review. We'll notify you when complete.\"\n />\n );\n case 'completed':\n return <AlertBanner variant=\"success\" content=\"Identity verified.\" />;\n case 'rejected':\n return (\n <AlertBanner\n variant=\"error\"\n content={\n onContactSupport === null ? (\n 'Verification rejected.'\n ) : (\n <>\n Verification rejected.{' '}\n <button\n type=\"button\"\n onClick={onContactSupport}\n className=\"clcosdk:underline\"\n >\n Contact support\n </button>\n .\n </>\n )\n }\n />\n );\n }\n}\n\nfunction WalletActionZone({\n status,\n multiWallet,\n connectedWallets,\n walletsStatus,\n onAction,\n onRemoveWallet,\n}: {\n status: RequirementStatus;\n multiWallet: boolean;\n connectedWallets: ConnectedWalletUi[];\n walletsStatus?: WalletsStatus;\n onAction?: (() => void) | null;\n onRemoveWallet?: ((id: string) => void | Promise<void>) | null;\n}): ReactNode {\n // Whitelisted-wallet: a list the user adds to (up to the backend cap) and\n // removes from, regardless of completion. The \"Add wallet\" button falls back\n // to `onAction`; the backend enforces the cap and rejects with\n // `max_wallets_reached`.\n if (multiWallet) {\n return (\n <>\n <ConnectedWalletList\n wallets={connectedWallets}\n onRemove={onRemoveWallet}\n onAdd={onAction ?? undefined}\n status={walletsStatus}\n />\n {status === 'rejected' && (\n <AlertBanner\n variant=\"error\"\n content=\"One of these wallets is not eligible for this sale.\"\n />\n )}\n </>\n );\n }\n\n // Single-slot external_wallet.\n if (status === 'completed') {\n const connected = connectedWallets[0];\n return (\n <>\n {onAction !== null && (\n <ClButton size=\"sm\" variant=\"secondary\" onClick={onAction}>\n Change wallet\n </ClButton>\n )}\n {/* A failed/in-flight address fetch must not hide behind the success\n banner, which would mask the error the way the multi-slot list\n already guards against. */}\n {walletsStatus === 'loading' ? (\n <AlertBanner\n variant=\"info\"\n content=\"Loading your connected wallet…\"\n />\n ) : walletsStatus === 'error' ? (\n <AlertBanner\n variant=\"error\"\n content=\"Couldn't load your connected wallet.\"\n />\n ) : (\n <AlertBanner\n variant=\"success\"\n content={connected ? connected.shortAddress : 'Wallet connected.'}\n />\n )}\n </>\n );\n }\n\n if (status === 'rejected') {\n return (\n <>\n {onAction !== null && (\n <ClButton size=\"sm\" onClick={onAction}>\n Connect wallet\n </ClButton>\n )}\n <AlertBanner\n variant=\"error\"\n content=\"This wallet is not eligible for this sale.\"\n />\n </>\n );\n }\n\n if (onAction === null) return null;\n return (\n <ClButton size=\"sm\" onClick={onAction}>\n Connect wallet\n </ClButton>\n );\n}\n\n/**\n * A single requirement row (label, status, expandable action zone). Self-scoped:\n * renders fully styled on its own, with no `CoinListStyleScope` needed. Also composed\n * by {@link RequirementsChecklist}.\n */\nexport function RequirementItem({\n ui,\n expanded = false,\n onToggle,\n className,\n onAction,\n onRemoveWallet,\n walletsStatus,\n onContactSupport,\n}: RequirementItemProps) {\n return (\n <CoinListStyleScope>\n <div\n className={cn(\n 'clcosdk:flex clcosdk:w-full clcosdk:flex-col',\n className\n )}\n >\n <button\n type=\"button\"\n onClick={onToggle}\n aria-expanded={expanded}\n className=\"clcosdk:flex clcosdk:h-14 clcosdk:w-full clcosdk:cursor-pointer clcosdk:items-center clcosdk:justify-between clcosdk:rounded-2xl clcosdk:px-2 clcosdk:transition-colors clcosdk:hover:bg-surface\"\n >\n <div className=\"clcosdk:flex clcosdk:items-center clcosdk:gap-3\">\n <StepStatusIcon status={ui.status} />\n <span\n className={cn(\n typeClasses.body,\n 'clcosdk:whitespace-nowrap clcosdk:font-medium clcosdk:text-text-primary'\n )}\n >\n {ui.label}\n </span>\n </div>\n <ChevronRight\n className={cn(\n 'clcosdk:h-6 clcosdk:w-6 clcosdk:shrink-0 clcosdk:text-text-secondary clcosdk:transition-transform clcosdk:duration-300',\n expanded && 'clcosdk:rotate-90'\n )}\n aria-hidden=\"true\"\n />\n </button>\n\n <div\n className={cn(\n 'clcosdk:grid clcosdk:transition-[grid-template-rows] clcosdk:duration-300 clcosdk:ease-in-out',\n expanded ? 'clcosdk:grid-rows-[1fr]' : 'clcosdk:grid-rows-[0fr]'\n )}\n >\n {/* min-h-0 lets the grid item collapse to 0 when grid-rows is 0fr */}\n <div className=\"clcosdk:min-h-0 clcosdk:overflow-hidden\">\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-4 clcosdk:px-2 clcosdk:pb-4\">\n <p\n className={cn(\n typeClasses.subhead,\n 'clcosdk:text-text-secondary'\n )}\n >\n {ui.description}\n </p>\n {ui.variant === 'verification' ? (\n <VerificationActionZone\n status={ui.status}\n onAction={onAction}\n onContactSupport={onContactSupport}\n />\n ) : (\n <WalletActionZone\n status={ui.status}\n multiWallet={ui.multiWallet}\n connectedWallets={ui.connectedWallets}\n walletsStatus={walletsStatus}\n onAction={onAction}\n onRemoveWallet={onRemoveWallet}\n />\n )}\n </div>\n </div>\n </div>\n </div>\n </CoinListStyleScope>\n );\n}\n","import type { LucideIcon } from 'lucide-react';\nimport { CircleCheck, CircleX, Info } from 'lucide-react';\nimport { cn } from '@/client/components/design-system/utils';\n\nexport type StepStatus = 'required' | 'pending' | 'completed' | 'rejected';\n\ninterface StepStatusIconProps {\n status: StepStatus;\n className?: string;\n}\n\nconst statusConfig: Record<\n StepStatus,\n { Icon: LucideIcon; colorClass: string; fillClass: string }\n> = {\n required: {\n Icon: Info,\n colorClass: 'clcosdk:text-warning',\n fillClass: 'clcosdk:[&_circle]:fill-warning-subtle',\n },\n pending: {\n Icon: Info,\n colorClass: 'clcosdk:text-warning',\n fillClass: 'clcosdk:[&_circle]:fill-warning-subtle',\n },\n completed: {\n Icon: CircleCheck,\n colorClass: 'clcosdk:text-success',\n fillClass: 'clcosdk:[&_circle]:fill-success-subtle',\n },\n rejected: {\n Icon: CircleX,\n colorClass: 'clcosdk:text-error',\n fillClass: 'clcosdk:[&_circle]:fill-error-subtle',\n },\n};\n\nexport function StepStatusIcon({ status, className }: StepStatusIconProps) {\n const { Icon, colorClass, fillClass } = statusConfig[status];\n return (\n <Icon\n className={cn(\n 'clcosdk:h-6 clcosdk:w-6 clcosdk:shrink-0',\n colorClass,\n fillClass,\n className\n )}\n aria-hidden=\"true\"\n />\n );\n}\n","'use client';\n\nimport { type ReactNode, useEffect, useRef, useState } from 'react';\nimport { CoinListStyleScope } from '@/client/CoinListStyleScope';\nimport { AlertBanner } from '@/client/components/design-system/AlertBanner';\nimport { ClButton } from '@/client/components/design-system/ClButton';\nimport { CloseButton } from '@/client/components/design-system/CloseButton';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport { CoinListSignInCard } from '@/client/components/oauth/CoinListSignInCard';\nimport type { WalletsStatus } from '@/client/components/requirements/ConnectedWalletList';\nimport { ConnectWalletModal } from '@/client/components/requirements/ConnectWalletModal';\nimport { IdentityVerification } from '@/client/components/requirements/IdentityVerification';\nimport {\n ChecklistStatus,\n RequirementItem,\n RequirementItemUi,\n RequirementVariant,\n} from '@/client/components/requirements/RequirementItem';\nimport { TaxDocumentModal } from '@/client/components/requirements/TaxDocumentModal';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport type { ConnectWallet } from '@/client/hooks/useConnectWallet';\nimport { useOptionAddresses } from '@/client/hooks/useOptionAddresses';\nimport type { RequirementsData } from '@/client/hooks/useRequirements';\nimport { useRequirements } from '@/client/hooks/useRequirements';\nimport type { KycLevelName } from '@/shared/types/kyc';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport { OfferOptionAddressId } from '@/shared/types/offer-option-address';\nimport type {\n Requirement,\n RequirementId,\n RequirementStatusValue,\n RequirementType,\n} from '@/shared/types/requirement';\n\nconst isWalletRequirement = (requirement: Requirement): boolean =>\n RequirementVariant.fromType(requirement.type) === 'wallet';\n\nconst DEFAULT_LABELS: Record<RequirementType, string> = {\n kyc_approved: 'KYC Verification',\n identity_verified: 'Identity Verification',\n proof_of_address: 'Proof of Address',\n source_of_funds: 'Source of Funds',\n external_wallet: 'External Wallet',\n whitelisted_wallet: 'Whitelisted Wallet',\n jurisdiction: 'Jurisdiction Check',\n accreditation: 'Accreditation',\n document: 'Document',\n};\n\nconst DEFAULT_DESCRIPTIONS: Record<RequirementType, string> = {\n kyc_approved: 'Complete Know Your Customer verification.',\n identity_verified: 'Verify your identity.',\n proof_of_address: 'Provide proof of your residential address.',\n source_of_funds: 'Provide documentation for your source of funds.',\n external_wallet: 'Connect an external wallet.',\n whitelisted_wallet: 'Connect a whitelisted wallet.',\n jurisdiction: 'Confirm your jurisdiction eligibility.',\n accreditation: 'Verify your accreditation status.',\n document: 'Confirm your Tax Documents.',\n};\n\nexport interface RequirementsChecklistProps {\n offerId: OfferId;\n optionId: OfferOptionId;\n title: string;\n description: string;\n onContinue?: () => void;\n /**\n * Called when the user clicks a requirement's action button (e.g. \"Continue\", \"Connect wallet\").\n * Defaults to {@link CoinListClient#handleRequirement}, which opens the corresponding CoinList\n * page in a new tab — except for `document` requirements, which default to opening a built-in\n * {@link TaxDocumentModal} instead. Pass your own handler to override this behavior for all\n * requirement types, or pass `null` to disable the action button entirely.\n */\n onRequirementActionOverride?: ((requirement: Requirement) => void) | null;\n /**\n * Called when the user clicks \"Contact support\" on a rejected requirement.\n * Defaults to {@link CoinListClient#contactSupport}, which opens the CoinList support ticket\n * page in a new tab. Pass your own handler to override this behavior, or pass `null` to disable\n * the contact support button entirely.\n */\n onContactSupportOverride?: ((requirement: Requirement) => void) | null;\n /**\n * Host-provided connected wallet used to satisfy `external_wallet` /\n * `whitelisted_wallet` requirements in-app via {@link ConnectWalletModal}.\n * Pass a connected {@link ConnectWallet}, or `null` while none is connected\n * (then also pass {@link onRequestConnect} so the modal can prompt to\n * connect). When this prop is omitted entirely — or is `null` without an\n * {@link onRequestConnect} to act on — wallet requirements fall back to\n * {@link CoinListClient#handleRequirement} (opening CoinList in a new tab).\n */\n wallet?: ConnectWallet | null;\n /** Called when the user asks to connect a wallet and none is connected yet. */\n onRequestConnect?: () => void;\n /** Override the default label for a requirement type. */\n getLabel?: (requirement: Requirement) => string;\n /** Override the default description for a requirement type. */\n getDescription?: (requirement: Requirement) => string | null;\n /** Optional loading slot. */\n loading?: ReactNode;\n /**\n * Rendered when the user is not authenticated. Defaults to\n * {@link CoinListSignInCard}, which prompts the user to sign in and starts\n * the CoinList OAuth flow. Pass `null` to render nothing.\n */\n unauthenticatedState?: ReactNode;\n /** Optional error slot. */\n error?: ReactNode;\n className?: string;\n /**\n * Requirements data pre-fetched on the server (e.g. via\n * `CoinListServer.fetchOfferRequirements()` + `fetchRequirementStatuses()`).\n * When provided, the component uses this data as-is and skips the client-side\n * requirements fetch. Connected-wallet addresses for wallet requirements are\n * not part of `RequirementsData` and are always fetched client-side.\n */\n data?: RequirementsData;\n /**\n * Options for the inline Sumsub verification flow shown for KYC-backed\n * requirements (`identity_verified`, `kyc_approved`, `accreditation`) when\n * `onRequirementActionOverride` is not provided. The flow starts whenever\n * the requirement's status carries a `kycLevel` — the backend prescribes\n * both the level and whether the applicant must be reset first.\n */\n identityVerificationOptions?: {\n /** Override the backend-prescribed Sumsub verification level. */\n levelName?: KycLevelName;\n /** BCP-47 language tag for the Sumsub UI, e.g. `'en'`. */\n locale?: string;\n };\n}\n\n/** How often to check requirement statuses after the Sumsub flow is submitted. */\nconst VERIFICATION_POLL_INTERVAL_MS = 5_000;\n/** How long to keep checking before giving up and refreshing the checklist anyway. */\nconst VERIFICATION_POLL_TIMEOUT_MS = 120_000;\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Full-screen overlay hosting the Sumsub identity verification flow — mirrors\n * frontline-web, where verification runs on a dedicated full page rather than\n * inside the requirement row.\n */\nfunction VerificationOverlay({\n onClose,\n children,\n}: {\n onClose: () => void;\n children: ReactNode;\n}): ReactNode {\n return (\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Identity verification\"\n className=\"clcosdk:fixed clcosdk:inset-0 clcosdk:z-50 clcosdk:flex clcosdk:items-center clcosdk:justify-center clcosdk:bg-overlay clcosdk:p-4\"\n >\n <div className=\"clcosdk:relative clcosdk:flex clcosdk:max-h-[92vh] clcosdk:w-full clcosdk:max-w-[760px] clcosdk:flex-col clcosdk:overflow-y-auto clcosdk:rounded-2xl clcosdk:bg-background clcosdk:p-6 clcosdk:pt-14\">\n <CloseButton\n onClick={onClose}\n className=\"clcosdk:absolute clcosdk:top-4 clcosdk:right-4\"\n />\n {children}\n </div>\n </div>\n );\n}\n\nfunction RequirementsChecklistBody({\n offerId,\n optionId,\n title,\n description,\n onContinue,\n onRequirementActionOverride,\n onContactSupportOverride,\n wallet,\n onRequestConnect,\n getLabel,\n getDescription,\n loading,\n unauthenticatedState,\n error,\n className,\n data,\n identityVerificationOptions,\n}: RequirementsChecklistProps): ReactNode {\n const { coinlist } = useCoinList();\n const { requirementsState, refetch } = useRequirements(offerId, { data });\n const [expandedIndex, setExpandedIndex] = useState<number | null>(null);\n const [taxDocumentOpen, setTaxDocumentOpen] = useState(false);\n const [walletConnectOpen, setConnectWalletOpen] = useState(false);\n const [verifyingRequirementId, setVerifyingRequirementId] =\n useState<RequirementId | null>(null);\n const isMountedRef = useRef(true);\n\n useEffect(() => {\n isMountedRef.current = true;\n return () => {\n isMountedRef.current = false;\n };\n }, []);\n\n // The connected wallets are per-option, so fetch them once for this option and\n // only when it actually has a wallet requirement to display them against.\n // Latch on the last known CONTENT: a requirements refetch (remove / connect /\n // tax / verify) dips requirementsState to LOADING, and reading the flag off\n // that dip would flip the fetch off and on, churning the wallet list.\n const [hasWalletRequirement, setHasWalletRequirement] = useState(false);\n useEffect(() => {\n if (requirementsState.type === 'CONTENT') {\n setHasWalletRequirement(\n (requirementsState.requirements[optionId] ?? []).some(\n isWalletRequirement\n )\n );\n }\n }, [requirementsState, optionId]);\n const {\n addressesState,\n refetch: refetchAddresses,\n disconnect,\n } = useOptionAddresses(offerId, optionId, {\n enabled: hasWalletRequirement,\n });\n const optionAddresses =\n addressesState.type === 'CONTENT' ? addressesState.addresses : [];\n // A failed/in-flight wallet fetch must not read as \"no wallets connected\", so\n // surface its load state to the wallet UI rather than an empty list.\n const walletsStatus: WalletsStatus =\n addressesState.type === 'ERROR'\n ? 'error'\n : addressesState.type === 'LOADING'\n ? 'loading'\n : 'ready';\n\n const onRemoveWallet = async (id: string) => {\n await disconnect(OfferOptionAddressId(id));\n // Removing a wallet can flip the requirement back to actionable, so refresh\n // the requirement statuses too (disconnect already refetched the wallets).\n refetch();\n };\n\n const onRequirementAction =\n onRequirementActionOverride !== undefined\n ? onRequirementActionOverride\n : (requirement: Requirement) => {\n if (requirement.type === 'document') {\n setTaxDocumentOpen(true);\n return;\n }\n // Only drive the in-app modal when it can actually complete the\n // requirement: a connected wallet to sign with, or a way to connect\n // one (`onRequestConnect`). A bare `wallet={null}` with no\n // `onRequestConnect` would strand the user on a dead-end screen, so\n // fall through to `handleRequirement` instead.\n if (\n (requirement.type === 'external_wallet' ||\n requirement.type === 'whitelisted_wallet') &&\n wallet !== undefined &&\n (wallet !== null || onRequestConnect !== undefined)\n ) {\n setConnectWalletOpen(true);\n return;\n }\n coinlist.handleRequirement(requirement);\n };\n const onContactSupport =\n onContactSupportOverride !== undefined\n ? onContactSupportOverride\n : () => coinlist.contactSupport();\n\n // After the user submits the Sumsub flow, the verification result arrives\n // asynchronously (Sumsub webhook -> backend). Poll requirement statuses\n // until this requirement's status moves off its pre-submit value, then\n // refresh the checklist.\n const awaitVerificationResult = (\n requirementId: RequirementId,\n statusBeforeSubmit: RequirementStatusValue\n ) => {\n void (async () => {\n const deadline = Date.now() + VERIFICATION_POLL_TIMEOUT_MS;\n while (Date.now() < deadline) {\n await sleep(VERIFICATION_POLL_INTERVAL_MS);\n if (!isMountedRef.current) return;\n try {\n const statuses = await coinlist.fetchRequirementStatuses(offerId);\n const current = statuses.find((s) => s.id === requirementId)?.status;\n if (current !== undefined && current !== statusBeforeSubmit) break;\n } catch (_) {\n // Transient fetch errors: keep polling until the deadline.\n }\n }\n if (isMountedRef.current) {\n setVerifyingRequirementId(null);\n refetch();\n }\n })();\n };\n\n if (requirementsState.type === 'LOADING') {\n if (loading) return loading;\n return (\n <output\n aria-live=\"polite\"\n className=\"clcosdk:flex clcosdk:min-h-40 clcosdk:items-center clcosdk:justify-center clcosdk:rounded-2xl clcosdk:border clcosdk:border-border clcosdk:bg-background clcosdk:p-6\"\n >\n <p className={cn(typeClasses.body, 'clcosdk:text-text-secondary')}>\n Loading requirements...\n </p>\n </output>\n );\n }\n\n if (requirementsState.type === 'ERROR') {\n if (requirementsState.reason === 'not-authenticated') {\n return unauthenticatedState !== undefined ? (\n unauthenticatedState\n ) : (\n <CoinListSignInCard />\n );\n }\n if (error) return error;\n return (\n <AlertBanner\n variant=\"error\"\n icon\n content=\"Unable to load requirements right now. Please try again.\"\n className=\"clcosdk:w-full clcosdk:max-w-[28rem]\"\n />\n );\n }\n\n const { requirements: requirementsByOptionId, statuses } = requirementsState;\n const requirements = requirementsByOptionId[optionId] ?? [];\n const requirementIds = new Set(requirements.map((r) => r.id));\n const optionStatuses = statuses.filter((s) => requirementIds.has(s.id));\n const statusByRequirementId = new Map(optionStatuses.map((s) => [s.id, s]));\n const checklistStatus: ChecklistStatus =\n ChecklistStatus.derive(optionStatuses);\n\n return (\n <div\n className={cn(\n 'clcosdk:flex clcosdk:w-full clcosdk:flex-col clcosdk:gap-4',\n className\n )}\n >\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-2\">\n <h3 className={cn(typeClasses.h3, 'clcosdk:text-text-primary')}>\n {title}\n </h3>\n <p className={cn(typeClasses.body, 'clcosdk:text-text-secondary')}>\n {description}\n </p>\n </div>\n\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:divide-y clcosdk:divide-divider\">\n {requirements.map((req, index) => {\n const statusInfo = statusByRequirementId.get(req.id);\n const label = getLabel ? getLabel(req) : DEFAULT_LABELS[req.type];\n const itemDescription =\n (getDescription ? getDescription(req) : null) ??\n DEFAULT_DESCRIPTIONS[req.type];\n\n // Inline Sumsub flow whenever the backend prescribed one for this\n // status (kycLevel present) — identity_verified, kyc_approved, and\n // accreditation.\n const inlineVerification =\n statusInfo?.kycLevel !== undefined &&\n onRequirementActionOverride === undefined;\n\n let onActionBound: (() => void) | null | undefined;\n if (onRequirementAction === null) {\n onActionBound = null;\n } else if (inlineVerification) {\n onActionBound = () => setVerifyingRequirementId(req.id);\n } else if (onRequirementAction) {\n onActionBound = () => onRequirementAction(req);\n }\n\n let onContactSupportBound: (() => void) | null | undefined;\n if (onContactSupport === null) {\n onContactSupportBound = null;\n } else if (onContactSupport) {\n onContactSupportBound = () => onContactSupport(req);\n }\n\n // Wallet requirements show the user's real connected wallet(s) fetched\n // from the partner API. Non-wallet requirements get no addresses.\n const walletRequirement = isWalletRequirement(req);\n return (\n <RequirementItem\n key={req.id}\n ui={RequirementItemUi.fromDomain(\n req,\n statusInfo,\n label,\n itemDescription,\n walletRequirement ? optionAddresses : []\n )}\n expanded={expandedIndex === index}\n onToggle={() =>\n setExpandedIndex((prev) => (prev === index ? null : index))\n }\n onAction={onActionBound}\n onRemoveWallet={walletRequirement ? onRemoveWallet : undefined}\n walletsStatus={walletRequirement ? walletsStatus : undefined}\n onContactSupport={onContactSupportBound}\n />\n );\n })}\n </div>\n\n {checklistStatus === 'ineligible' && (\n <AlertBanner\n variant=\"error\"\n icon\n content=\"You are not eligible to participate.\"\n />\n )}\n\n {onContinue && (\n <ClButton\n fullWidth\n disabled={checklistStatus !== 'eligible'}\n onClick={onContinue}\n >\n Continue\n </ClButton>\n )}\n\n <TaxDocumentModal\n isOpen={taxDocumentOpen}\n onClose={() => setTaxDocumentOpen(false)}\n onSubmitted={() => refetch()}\n />\n\n {verifyingRequirementId !== null && (\n <VerificationOverlay onClose={() => setVerifyingRequirementId(null)}>\n <IdentityVerification\n levelName={\n identityVerificationOptions?.levelName ??\n statusByRequirementId.get(verifyingRequirementId)?.kycLevel\n }\n reset={\n statusByRequirementId.get(verifyingRequirementId)?.kycReset ??\n false\n }\n locale={identityVerificationOptions?.locale}\n onSubmitted={() =>\n awaitVerificationResult(\n verifyingRequirementId,\n statusByRequirementId.get(verifyingRequirementId)?.status ??\n 'not_started'\n )\n }\n />\n </VerificationOverlay>\n )}\n\n <ConnectWalletModal\n isOpen={walletConnectOpen}\n onClose={() => setConnectWalletOpen(false)}\n offerId={offerId}\n optionId={optionId}\n wallet={wallet ?? null}\n onRequestConnect={onRequestConnect}\n onConnected={() => {\n refetch();\n refetchAddresses();\n }}\n />\n </div>\n );\n}\n\n/**\n * Connected requirements checklist that fetches requirements and statuses\n * via {@link useRequirements} and renders requirement items for the\n * specified option.\n *\n * Pass `data` (pre-fetched server-side) to use that data as-is and skip\n * the initial client-side fetch.\n *\n * When the user is not authenticated, renders a sign-in card instead of the\n * checklist — without fetching. Pass `unauthenticatedState` to customize\n * that state, or `null` to render nothing.\n *\n * By default, clicking a requirement's action button opens the corresponding\n * CoinList page in a new tab via {@link CoinListClient#handleRequirement}. It is\n * recommended to omit `onRequirementActionOverride` and rely on this default.\n * Pass your own handler only if you need custom navigation behavior, or `null`\n * to disable the action button entirely.\n *\n * Self-scoped: renders fully styled on its own, with no `CoinListStyleScope` needed.\n */\nexport function RequirementsChecklist(\n props: RequirementsChecklistProps\n): ReactNode {\n return (\n <CoinListStyleScope>\n <RequirementsChecklistBody {...props} />\n </CoinListStyleScope>\n );\n}\n","'use client';\n\nimport { useEffect } from 'react';\nimport { AlertBanner } from '@/client/components/design-system/AlertBanner';\nimport { ClButton } from '@/client/components/design-system/ClButton';\nimport { CloseButton } from '@/client/components/design-system/CloseButton';\nimport { typeClasses } from '@/client/components/design-system/tokens/typography';\nimport { cn } from '@/client/components/design-system/utils';\nimport type { TaxDocumentFields } from '@/client/hooks/useTaxDocument';\nimport { useTaxDocument } from '@/client/hooks/useTaxDocument';\nimport type { DocumentSubmission } from '@/shared/types/document-submission';\n\nconst FIELD_ROWS: ReadonlyArray<{\n field: keyof TaxDocumentFields;\n label: string;\n placeholder?: string;\n}> = [\n { field: 'fullLegalName', label: 'Full legal name' },\n { field: 'dob', label: 'Date of birth', placeholder: 'MM/DD/YYYY' },\n { field: 'countryOfCitizenship', label: 'Country of citizenship' },\n { field: 'taxId', label: 'Tax ID' },\n { field: 'permanentAddress', label: 'Permanent address' },\n];\n\nexport interface TaxDocumentModalProps {\n isOpen: boolean;\n onClose: () => void;\n /** Called once the document is successfully signed, right before the modal closes. */\n onSubmitted?: (submission: DocumentSubmission) => void;\n className?: string;\n}\n\n/**\n * Batteries-included modal for the tax document (W-8BEN / W-8BEN-E) signing\n * flow. Fetches the current user's PII via {@link useTaxDocument}, lets\n * individuals review/edit it before signing; company/trust entities see a\n * plain sign screen with no fields.\n *\n * No portal is used — rendering stays inside the normal DOM tree so it keeps\n * this SDK's `.clco-sdk-root`-scoped theme tokens without needing its own\n * {@link CoinListStyleScope}.\n */\nexport function TaxDocumentModal({\n isOpen,\n onClose,\n onSubmitted,\n className,\n}: TaxDocumentModalProps) {\n const { state, onEditField, onStartEdit, onSaveEdit, onCancelEdit, onSign } =\n useTaxDocument({ isOpen });\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: only react to a SUBMITTED transition, not every state change\n useEffect(() => {\n if (state.type === 'SUBMITTED') {\n onSubmitted?.(state.submission);\n onClose();\n }\n }, [state]);\n\n if (!isOpen || state.type === 'SUBMITTED') return null;\n\n return (\n <div className=\"clcosdk:fixed clcosdk:inset-0 clcosdk:z-50 clcosdk:flex clcosdk:items-center clcosdk:justify-center clcosdk:bg-black/50 clcosdk:p-4\">\n <div\n className={cn(\n 'clcosdk:flex clcosdk:w-full clcosdk:max-w-md clcosdk:flex-col clcosdk:gap-6 clcosdk:rounded-2xl clcosdk:bg-background clcosdk:p-6',\n className\n )}\n >\n <div className=\"clcosdk:flex clcosdk:items-start clcosdk:justify-between clcosdk:gap-4\">\n <TaxDocumentModalHeading state={state} />\n <CloseButton onClick={onClose} />\n </div>\n\n {state.type === 'LOADING' && <LoadingScreen />}\n {state.type === 'ERROR' && <ErrorScreen reason={state.reason} />}\n {state.type === 'REVIEW' && (\n <ReviewScreen\n fields={state.fields}\n piiUnavailable={state.piiUnavailable}\n sign={state.sign}\n onStartEdit={onStartEdit}\n onSign={onSign}\n />\n )}\n {state.type === 'EDITING' && (\n <EditScreen\n fields={state.fields}\n onEditField={onEditField}\n onSaveEdit={onSaveEdit}\n onCancelEdit={onCancelEdit}\n />\n )}\n {state.type === 'SIGN_ONLY' && (\n <SignOnlyScreen sign={state.sign} onSign={onSign} />\n )}\n </div>\n </div>\n );\n}\n\nfunction TaxDocumentModalHeading({\n state,\n}: {\n state: ReturnType<typeof useTaxDocument>['state'];\n}) {\n const title =\n state.type === 'EDITING'\n ? 'Edit your W-8BEN'\n : state.type === 'REVIEW'\n ? 'Confirm your W-8BEN'\n : state.type === 'SIGN_ONLY'\n ? 'Confirm your W-8BEN-E'\n : 'Tax document';\n\n return (\n <h3 className={cn(typeClasses.h3, 'clcosdk:text-text-primary')}>{title}</h3>\n );\n}\n\nfunction LoadingScreen() {\n return (\n <output\n aria-live=\"polite\"\n className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-4\"\n >\n {FIELD_ROWS.map(({ field }) => (\n <div\n key={field}\n className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-1\"\n >\n <div className=\"clcosdk:h-3 clcosdk:w-28 clcosdk:animate-pulse clcosdk:rounded clcosdk:bg-surface\" />\n <div className=\"clcosdk:h-5 clcosdk:w-48 clcosdk:animate-pulse clcosdk:rounded clcosdk:bg-surface\" />\n </div>\n ))}\n </output>\n );\n}\n\nfunction ErrorScreen({\n reason,\n}: {\n reason: 'not-authenticated' | 'generic-error';\n}) {\n return (\n <AlertBanner\n variant=\"error\"\n icon\n content={\n reason === 'not-authenticated'\n ? 'Sign in to complete your tax document.'\n : 'Unable to load your tax information right now. Please try again.'\n }\n />\n );\n}\n\nfunction ReviewScreen({\n fields,\n piiUnavailable,\n sign,\n onStartEdit,\n onSign,\n}: {\n fields: TaxDocumentFields;\n piiUnavailable: boolean;\n sign: { type: 'idle'; error: string | null } | { type: 'signing' };\n onStartEdit: () => void;\n onSign: () => void;\n}) {\n return (\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-6\">\n <p className={cn(typeClasses.body, 'clcosdk:text-text-secondary')}>\n Review your information below. If anything looks incorrect, edit before\n signing.\n </p>\n\n {piiUnavailable && (\n <AlertBanner\n variant=\"info\"\n icon\n content=\"We don't have this information on file yet — please fill it in below.\"\n />\n )}\n\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-4 clcosdk:border-t clcosdk:border-divider clcosdk:pt-4\">\n {FIELD_ROWS.map(({ field, label }) => (\n <div\n key={field}\n className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-1\"\n >\n <span\n className={cn(typeClasses.label, 'clcosdk:text-text-secondary')}\n >\n {label}\n </span>\n <span className={cn(typeClasses.body, 'clcosdk:text-text-primary')}>\n {fields[field] || '—'}\n </span>\n </div>\n ))}\n </div>\n\n <p className={cn(typeClasses.caption, 'clcosdk:text-text-secondary')}>\n By signing, you certify that the information above is accurate and that\n you are the beneficial owner of the income this form relates to. This\n document cannot be edited once signed.\n </p>\n\n {sign.type === 'idle' && sign.error && (\n <AlertBanner variant=\"error\" icon content={sign.error} />\n )}\n\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-2\">\n <ClButton\n fullWidth\n onClick={onSign}\n isLoading={sign.type === 'signing'}\n loadingText=\"Signing...\"\n >\n Sign W-8BEN\n </ClButton>\n <ClButton\n fullWidth\n variant=\"secondary\"\n onClick={onStartEdit}\n disabled={sign.type === 'signing'}\n >\n Edit information\n </ClButton>\n </div>\n </div>\n );\n}\n\nfunction EditScreen({\n fields,\n onEditField,\n onSaveEdit,\n onCancelEdit,\n}: {\n fields: TaxDocumentFields;\n onEditField: (field: keyof TaxDocumentFields, value: string) => void;\n onSaveEdit: () => void;\n onCancelEdit: () => void;\n}) {\n return (\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-6\">\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-4 clcosdk:border-t clcosdk:border-divider clcosdk:pt-4\">\n {FIELD_ROWS.map(({ field, label, placeholder }) => (\n <label\n key={field}\n className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-1\"\n >\n <span\n className={cn(typeClasses.label, 'clcosdk:text-text-secondary')}\n >\n {label}\n </span>\n <input\n type=\"text\"\n value={fields[field]}\n placeholder={placeholder}\n onChange={(e) => onEditField(field, e.target.value)}\n className={cn(\n typeClasses.body,\n 'clcosdk:rounded-lg clcosdk:border clcosdk:border-border clcosdk:bg-background clcosdk:px-3 clcosdk:py-2 clcosdk:text-text-primary clcosdk:focus-visible:outline-none clcosdk:focus-visible:ring-2 clcosdk:focus-visible:ring-gray-400'\n )}\n />\n </label>\n ))}\n </div>\n\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-2\">\n <ClButton fullWidth onClick={onSaveEdit}>\n Save & review\n </ClButton>\n <ClButton fullWidth variant=\"secondary\" onClick={onCancelEdit}>\n Cancel\n </ClButton>\n </div>\n </div>\n );\n}\n\nfunction SignOnlyScreen({\n sign,\n onSign,\n}: {\n sign: { type: 'idle'; error: string | null } | { type: 'signing' };\n onSign: () => void;\n}) {\n return (\n <div className=\"clcosdk:flex clcosdk:flex-col clcosdk:gap-6\">\n <p className={cn(typeClasses.body, 'clcosdk:text-text-secondary')}>\n As an entity investor, you must complete a W-8BEN-E to confirm your\n foreign tax status and claim applicable treaty benefits. You'll receive\n an email to complete the signing.\n </p>\n\n {sign.type === 'idle' && sign.error && (\n <AlertBanner variant=\"error\" icon content={sign.error} />\n )}\n\n <ClButton\n fullWidth\n onClick={onSign}\n isLoading={sign.type === 'signing'}\n loadingText=\"Signing...\"\n >\n Sign W-8BEN-E\n </ClButton>\n </div>\n );\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport type { DocumentSubmission } from '@/shared/types/document-submission';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type { Pii } from '@/shared/types/pii';\n\nexport type TaxDocumentFields = {\n fullLegalName: string;\n dob: string;\n countryOfCitizenship: string;\n taxId: string;\n permanentAddress: string;\n};\n\n/**\n * Structured address pieces sent split in the payload (`City` / `Country`).\n * Kept separate from the single editable `permanentAddress` display string\n * and never shown or edited in the form.\n */\nexport type TaxDocumentAddressParts = {\n city: string;\n country: string;\n};\n\n/**\n * Signing-in-flight and the last sign error live inside the REVIEW/SIGN_ONLY\n * state (not a separate top-level state) so a failed sign never loses the\n * user's fields.\n */\nexport type SignState =\n | { type: 'idle'; error: string | null }\n | { type: 'signing' };\n\nexport type TaxDocumentState =\n | { type: 'LOADING' } // always fetches PII first, solely to read `kind`\n | {\n type: 'REVIEW';\n fields: TaxDocumentFields;\n addressParts: TaxDocumentAddressParts;\n piiUnavailable: boolean;\n sign: SignState;\n } // person only\n | {\n type: 'EDITING';\n fields: TaxDocumentFields;\n original: TaxDocumentFields;\n addressParts: TaxDocumentAddressParts;\n piiUnavailable: boolean;\n } // person only\n | { type: 'SIGN_ONLY'; sign: SignState } // company/trust only — no fields shown, ever\n | { type: 'ERROR'; reason: 'not-authenticated' | 'generic-error' } // fetchPii() failure only\n | { type: 'SUBMITTED'; submission: DocumentSubmission };\n\nexport interface UseTaxDocumentOptions {\n /** The hook only fetches PII while open; state resets each time it opens. */\n isOpen: boolean;\n}\n\nexport interface UseTaxDocumentResult {\n state: TaxDocumentState;\n onEditField: (field: keyof TaxDocumentFields, value: string) => void;\n onStartEdit: () => void; // REVIEW -> EDITING\n onSaveEdit: () => void; // EDITING -> REVIEW, local only, not submitted\n onCancelEdit: () => void; // EDITING -> REVIEW, discards changes\n onSign: () => void; // REVIEW.sign or SIGN_ONLY.sign: idle -> signing -> (SUBMITTED | idle w/ error)\n}\n\nconst IDLE_SIGN: SignState = { type: 'idle', error: null };\nconst LOADING_STATE: TaxDocumentState = { type: 'LOADING' };\nconst SIGN_FAILED_MESSAGE = 'Unable to sign document. Please try again.';\nconst DOB_INVALID_MESSAGE = 'Enter your date of birth as MM/DD/YYYY.';\n\n/**\n * Maps each editable field to its DocuSeal field name for the\n * `tax_certification` template. Values are forwarded verbatim to\n * Passport/DocuSeal by Frontline — see POST\n * /v1/documents/:document_type/submission. Keys must match the template's\n * field names exactly; unknown keys are silently ignored by DocuSeal.\n */\nconst FIELD_KEYS: Record<keyof TaxDocumentFields, string> = {\n fullLegalName: 'Full Name',\n dob: 'DOB',\n countryOfCitizenship: 'Country Of Citizenship',\n taxId: 'Foreign Tax Number',\n permanentAddress: 'Permanent Address',\n};\n\n/** Formats a `Date` as US `MM/DD/YYYY`. */\nfunction formatUsDate(date: Date): string {\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n const year = String(date.getFullYear()).padStart(4, '0');\n return `${month}/${day}/${year}`;\n}\n\n/**\n * Converts a date-only ISO string (`YYYY-MM-DD`) to US `MM/DD/YYYY`.\n *\n * Reorders the parts as strings rather than going through `new Date()`, which\n * would interpret a bare date as UTC midnight and can shift the day in\n * negative timezones. Returns `''` for empty or malformed input.\n */\nfunction formatIsoDateOnly(isoDate: string): string {\n const match = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(isoDate);\n if (!match) return '';\n const [, year, month, day] = match;\n return `${month}/${day}/${year}`;\n}\n\n/**\n * Returns `true` when `value` is a real calendar date in US `MM/DD/YYYY`\n * form. Rejects bad formats (`\"ABC\"`) and impossible dates (`\"02/30/2024\"`).\n */\nfunction isValidUsDate(value: string): boolean {\n const match = /^(\\d{2})\\/(\\d{2})\\/(\\d{4})$/.exec(value);\n if (!match) return false;\n const [, mm, dd, yyyy] = match;\n const month = Number(mm);\n const day = Number(dd);\n const year = Number(yyyy);\n const date = new Date(year, month - 1, day);\n return (\n date.getFullYear() === year &&\n date.getMonth() === month - 1 &&\n date.getDate() === day\n );\n}\n\nfunction mapPiiToFields(pii: Pii): TaxDocumentFields {\n const { street, city, state, postalCode } = pii.permanentAddress;\n const cityLine = [postalCode, city].filter(Boolean).join(' ');\n const permanentAddress = [street, cityLine, state].filter(Boolean).join(', ');\n\n return {\n fullLegalName: pii.fullLegalName ?? '',\n // Date-only ISO from the backend, shown as MM/DD/YYYY. Blank until the\n // backend has a date of birth (the field is editable in the meantime).\n dob: formatIsoDateOnly(pii.dateOfBirth ?? ''),\n countryOfCitizenship: pii.jurisdiction?.name ?? '',\n taxId: pii.taxId ?? '',\n permanentAddress,\n };\n}\n\nfunction addressPartsFromPii(pii: Pii): TaxDocumentAddressParts {\n return {\n city: pii.permanentAddress.city ?? '',\n country: pii.permanentAddress.country ?? '',\n };\n}\n\nfunction hasAnyFieldValue(fields: TaxDocumentFields): boolean {\n return Object.values(fields).some((value) => value.trim() !== '');\n}\n\n/**\n * `Signature` echoes the full name (DocuSeal renders it as a font signature\n * on the template's signature field — required for Passport's auto-sign to\n * produce a signed document) and `Date` is the signing date.\n */\nfunction toSubmissionFields(\n fields: TaxDocumentFields,\n addressParts: TaxDocumentAddressParts\n): Record<string, string> {\n return {\n [FIELD_KEYS.fullLegalName]: fields.fullLegalName,\n [FIELD_KEYS.dob]: fields.dob,\n [FIELD_KEYS.countryOfCitizenship]: fields.countryOfCitizenship,\n [FIELD_KEYS.taxId]: fields.taxId,\n [FIELD_KEYS.permanentAddress]: fields.permanentAddress,\n City: addressParts.city,\n Country: addressParts.country,\n Signature: fields.fullLegalName,\n Date: formatUsDate(new Date()),\n };\n}\n\n/**\n * Loads the current user's PII and drives the tax document (W-8BEN /\n * W-8BEN-E) signing flow.\n *\n * Always fetches PII once per open — it's the only way to learn the\n * entity's `kind`. For company/trust entities the fetched values are\n * discarded (only `kind` is used) and the form is skipped entirely\n * (`SIGN_ONLY`); for individuals they seed the review screen (`REVIEW`).\n */\nexport function useTaxDocument({\n isOpen,\n}: UseTaxDocumentOptions): UseTaxDocumentResult {\n const { coinlist, isReady } = useCoinList();\n const [state, setState] = useState<TaxDocumentState>(LOADING_STATE);\n\n useEffect(() => {\n let isCancelled = false;\n\n if (!isOpen) {\n return () => {\n isCancelled = true;\n };\n }\n\n if (!isReady) {\n setState(LOADING_STATE);\n return () => {\n isCancelled = true;\n };\n }\n\n setState(LOADING_STATE);\n coinlist\n .fetchPii()\n .then((pii) => {\n if (isCancelled) return;\n if (pii.kind === 'company') {\n setState({ type: 'SIGN_ONLY', sign: IDLE_SIGN });\n return;\n }\n const fields = mapPiiToFields(pii);\n setState({\n type: 'REVIEW',\n fields,\n addressParts: addressPartsFromPii(pii),\n piiUnavailable: !hasAnyFieldValue(fields),\n sign: IDLE_SIGN,\n });\n })\n .catch((error: unknown) => {\n if (isCancelled) return;\n setState({\n type: 'ERROR',\n reason:\n error instanceof NotAuthenticatedError\n ? 'not-authenticated'\n : 'generic-error',\n });\n });\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist, isReady, isOpen]);\n\n const onEditField = useCallback(\n (field: keyof TaxDocumentFields, value: string) => {\n setState((prev) =>\n prev.type === 'EDITING'\n ? { ...prev, fields: { ...prev.fields, [field]: value } }\n : prev\n );\n },\n []\n );\n\n const onStartEdit = useCallback(() => {\n setState((prev) =>\n prev.type === 'REVIEW'\n ? {\n type: 'EDITING',\n fields: prev.fields,\n original: prev.fields,\n addressParts: prev.addressParts,\n piiUnavailable: prev.piiUnavailable,\n }\n : prev\n );\n }, []);\n\n const onSaveEdit = useCallback(() => {\n setState((prev) =>\n prev.type === 'EDITING'\n ? {\n type: 'REVIEW',\n fields: prev.fields,\n addressParts: prev.addressParts,\n piiUnavailable: prev.piiUnavailable,\n sign: IDLE_SIGN,\n }\n : prev\n );\n }, []);\n\n const onCancelEdit = useCallback(() => {\n setState((prev) =>\n prev.type === 'EDITING'\n ? {\n type: 'REVIEW',\n fields: prev.original,\n addressParts: prev.addressParts,\n piiUnavailable: prev.piiUnavailable,\n sign: IDLE_SIGN,\n }\n : prev\n );\n }, []);\n\n const onSign = useCallback(() => {\n if (state.type !== 'REVIEW' && state.type !== 'SIGN_ONLY') return;\n\n // Light validation: a blank DOB is allowed (the backend may not have one\n // yet); a non-blank DOB must be a real MM/DD/YYYY date.\n if (\n state.type === 'REVIEW' &&\n state.fields.dob.trim() !== '' &&\n !isValidUsDate(state.fields.dob)\n ) {\n setState({\n ...state,\n sign: { type: 'idle', error: DOB_INVALID_MESSAGE },\n });\n return;\n }\n\n setState({ ...state, sign: { type: 'signing' } });\n\n coinlist\n .submitDocument(\n 'tax_certification',\n state.type === 'REVIEW'\n ? toSubmissionFields(state.fields, state.addressParts)\n : {}\n )\n .then((submission) => {\n setState({ type: 'SUBMITTED', submission });\n })\n .catch(() => {\n setState((prev) =>\n prev.type === 'REVIEW' || prev.type === 'SIGN_ONLY'\n ? { ...prev, sign: { type: 'idle', error: SIGN_FAILED_MESSAGE } }\n : prev\n );\n });\n }, [state, coinlist]);\n\n return { state, onEditField, onStartEdit, onSaveEdit, onCancelEdit, onSign };\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport type {\n OfferOptionAddress,\n OfferOptionAddressId,\n} from '@/shared/types/offer-option-address';\n\nexport type LoadOptionAddressesReason = 'not-authenticated' | 'generic-error';\n\nexport type LoadOptionAddressesState =\n | { type: 'LOADING' }\n | { type: 'ERROR'; reason: LoadOptionAddressesReason }\n | { type: 'CONTENT'; addresses: OfferOptionAddress[] };\n\nexport interface UseOptionAddressesOptions {\n /**\n * Bound wallets pre-fetched on the server (e.g. via\n * `CoinListServer.listOptionAddresses()`). When provided, the hook uses this\n * data as-is and skips the initial client-side fetch. Calling `refetch()`\n * (or `disconnect()`) will still trigger a fresh fetch.\n */\n data?: OfferOptionAddress[];\n /**\n * When `false`, the hook stays in a benign empty `CONTENT` state and sends no\n * request. Use it to avoid fetching bindings for options with no wallet\n * requirement. Defaults to `true`.\n */\n enabled?: boolean;\n}\n\nexport interface UseOptionAddressesResult {\n addressesState: LoadOptionAddressesState;\n /** Triggers a re-fetch of the bound wallets. */\n refetch: () => void;\n /**\n * Removes a bound wallet, then refetches the list. Rejects (without\n * refetching) if the removal fails, so callers can surface the error.\n */\n disconnect: (addressId: OfferOptionAddressId) => Promise<void>;\n}\n\nconst LOADING_STATE: LoadOptionAddressesState = { type: 'LOADING' };\nconst EMPTY_STATE: LoadOptionAddressesState = {\n type: 'CONTENT',\n addresses: [],\n};\n\n/**\n * Loads the user's proven wallet bindings for a single offer option, then\n * exposes them via a state machine plus `refetch`/`disconnect` actions.\n *\n * Returns `LOADING` while CoinList is initializing or data is being fetched,\n * `CONTENT` with the bindings on success, and `ERROR` with `not-authenticated`\n * (logged-out, or a {@link NotAuthenticatedError}) or `generic-error` otherwise.\n */\nexport function useOptionAddresses(\n offerId: OfferId,\n offerOptionId: OfferOptionId,\n options: UseOptionAddressesOptions = {}\n): UseOptionAddressesResult {\n const { coinlist, isReady } = useCoinList();\n const { data, enabled = true } = options;\n const [addressesState, setAddressesState] =\n useState<LoadOptionAddressesState>(\n data !== undefined ? { type: 'CONTENT', addresses: data } : LOADING_STATE\n );\n const [fetchKey, setFetchKey] = useState(0);\n const refetch = useCallback(() => setFetchKey((k) => k + 1), []);\n\n const disconnect = useCallback(\n async (addressId: OfferOptionAddressId): Promise<void> => {\n await coinlist.removeOptionAddress(offerId, addressId);\n refetch();\n },\n [coinlist, offerId, refetch]\n );\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: fetchKey is an intentional refetch trigger\n useEffect(() => {\n let isCancelled = false;\n\n if (!enabled) {\n // Disabled means \"don't fetch\", not \"discard seeded data\" — keep any\n // server-provided bindings instead of blanking them to empty.\n setAddressesState(\n data !== undefined ? { type: 'CONTENT', addresses: data } : EMPTY_STATE\n );\n return () => {\n isCancelled = true;\n };\n }\n\n if (!isReady) {\n if (data === undefined) {\n setAddressesState(LOADING_STATE);\n }\n return () => {\n isCancelled = true;\n };\n }\n\n if (data !== undefined && fetchKey === 0) {\n return () => {\n isCancelled = true;\n };\n }\n\n if (coinlist.getAuthState() === 'logged-out') {\n setAddressesState({ type: 'ERROR', reason: 'not-authenticated' });\n return () => {\n isCancelled = true;\n };\n }\n\n setAddressesState(LOADING_STATE);\n coinlist\n .listOptionAddresses(offerId, offerOptionId)\n .then((addresses) => {\n if (!isCancelled) {\n setAddressesState({ type: 'CONTENT', addresses });\n }\n })\n .catch((error: unknown) => {\n if (!isCancelled) {\n const reason: LoadOptionAddressesReason =\n error instanceof NotAuthenticatedError\n ? 'not-authenticated'\n : 'generic-error';\n setAddressesState({ type: 'ERROR', reason });\n }\n });\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist, isReady, enabled, offerId, offerOptionId, fetchKey]);\n\n return { addressesState, refetch, disconnect };\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferOptionId } from '@/shared/types/offer-detail';\nimport type {\n Requirement,\n RequirementStatusInfo,\n} from '@/shared/types/requirement';\n\nexport type LoadRequirementsReason = 'not-authenticated' | 'generic-error';\n\nexport type LoadRequirementsState =\n | {\n type: 'LOADING';\n }\n | {\n type: 'ERROR';\n reason: LoadRequirementsReason;\n }\n | {\n type: 'CONTENT';\n requirements: Record<OfferOptionId, Requirement[]>;\n statuses: RequirementStatusInfo[];\n };\n\nexport type RequirementsData = {\n requirements: Record<OfferOptionId, Requirement[]>;\n statuses: RequirementStatusInfo[];\n};\n\nexport interface UseRequirementsOptions {\n /**\n * Requirements data pre-fetched on the server (e.g. via\n * `CoinListServer.fetchOfferRequirements()` + `fetchRequirementStatuses()`).\n * When provided, the hook uses this data as-is and skips the initial client-side fetch.\n * Calling `refetch()` will still trigger a fresh fetch.\n */\n data?: RequirementsData;\n}\n\nexport interface UseRequirementsResult {\n requirementsState: LoadRequirementsState;\n /** Triggers a re-fetch of requirements and statuses. */\n refetch: () => void;\n}\n\nconst LOADING_STATE: LoadRequirementsState = { type: 'LOADING' };\n\n/**\n * Loads requirements (grouped by option ID) and requirement statuses for a\n * given offer, then exposes them via a state machine.\n *\n * Pass `data` (pre-fetched server-side) to use that data as-is and skip\n * the initial client-side fetch. Calling `refetch()` will still trigger a fresh fetch.\n *\n * Returns `LOADING` while CoinList is initializing or while data is being fetched.\n * Returns `CONTENT` with requirements and statuses on success.\n * Returns `ERROR` with:\n * - `not-authenticated` immediately (no request is sent) when the client's\n * auth state is logged-out, or when fetching fails with\n * {@link NotAuthenticatedError}\n * - `generic-error` for any other failure\n */\nexport function useRequirements(\n offerId: OfferId,\n options: UseRequirementsOptions = {}\n): UseRequirementsResult {\n const { coinlist, isReady } = useCoinList();\n const { data } = options;\n const [requirementsState, setRequirementsState] =\n useState<LoadRequirementsState>(\n data !== undefined ? { type: 'CONTENT', ...data } : LOADING_STATE\n );\n const [fetchKey, setFetchKey] = useState(0);\n const refetch = useCallback(() => setFetchKey((k) => k + 1), []);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: fetchKey is an intentional refetch trigger\n useEffect(() => {\n let isCancelled = false;\n\n if (!isReady) {\n if (data === undefined) {\n setRequirementsState(LOADING_STATE);\n }\n return () => {\n isCancelled = true;\n };\n }\n\n if (data !== undefined && fetchKey === 0) {\n return () => {\n isCancelled = true;\n };\n }\n\n if (coinlist.getAuthState() === 'logged-out') {\n setRequirementsState({ type: 'ERROR', reason: 'not-authenticated' });\n return () => {\n isCancelled = true;\n };\n }\n\n setRequirementsState(LOADING_STATE);\n Promise.all([\n coinlist.fetchOfferRequirements(offerId),\n coinlist.fetchRequirementStatuses(offerId),\n ])\n .then(([requirementsByOptionId, statuses]) => {\n if (!isCancelled) {\n setRequirementsState({\n type: 'CONTENT',\n requirements: requirementsByOptionId,\n statuses,\n });\n }\n })\n .catch((error: unknown) => {\n if (!isCancelled) {\n const reason: LoadRequirementsReason =\n error instanceof NotAuthenticatedError\n ? 'not-authenticated'\n : 'generic-error';\n setRequirementsState({ type: 'ERROR', reason });\n }\n });\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist, isReady, offerId, fetchKey]);\n\n return { requirementsState, refetch };\n}\n","import { useEffect, useRef, useState } from 'react';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport type {\n Erc20Asset,\n EthereumChain,\n EvmContractAddress,\n} from '@/shared/types/blockchain/core';\n\n/**\n * The state of the swap's output-token fetch.\n *\n * - `LOADING`: no result yet (initial, or provider still initializing).\n * - `ERROR`: the fetch failed.\n * - `CONTENT`: the output token was fetched successfully.\n *\n * A stale `CONTENT`/`ERROR` is preserved while a re-fetch (e.g. after a chain\n * change) is in flight, rather than flipping back to `LOADING`.\n */\nexport type SwapOutputTokenState =\n | { type: 'LOADING' }\n | { type: 'ERROR' }\n | { type: 'CONTENT'; outputToken: Erc20Asset };\n\nexport interface UseSwapOutputTokenOptions {\n /** The swap contract whose output token to read. */\n contractAddress: EvmContractAddress;\n chain: EthereumChain;\n /** When false, the hook does not fetch. */\n enabled: boolean;\n}\n\nexport interface UseSwapOutputTokenResult {\n outputTokenState: SwapOutputTokenState;\n}\n\nconst LOADING_STATE: SwapOutputTokenState = { type: 'LOADING' };\n\n/**\n * Fetches the ERC-20 output token a swap contract pays out. Re-fetches when the\n * contract or chain changes, and once when `enabled` flips to true.\n *\n * The fetch runs once (no polling); a failure resolves to `ERROR` and is not\n * retried until a dependency changes.\n */\nexport function useSwapOutputToken(\n options: UseSwapOutputTokenOptions\n): UseSwapOutputTokenResult {\n const { contractAddress, chain, enabled } = options;\n const { coinlist, isReady } = useCoinList();\n\n const [outputTokenState, setOutputTokenState] =\n useState<SwapOutputTokenState>(LOADING_STATE);\n\n const fetchIdRef = useRef(0);\n\n useEffect(() => {\n if (!enabled || !isReady) return;\n const currentFetchId = ++fetchIdRef.current;\n\n const load = async () => {\n try {\n const outputToken = await coinlist.swap.getOutputToken({\n contractAddress,\n chain,\n });\n if (currentFetchId !== fetchIdRef.current) return;\n setOutputTokenState({ type: 'CONTENT', outputToken });\n } catch {\n if (currentFetchId !== fetchIdRef.current) return;\n setOutputTokenState({ type: 'ERROR' });\n }\n };\n\n load();\n\n return () => {\n ++fetchIdRef.current;\n };\n }, [coinlist, isReady, contractAddress, chain, enabled]);\n\n return { outputTokenState };\n}\n","import { useEffect, useRef, useState } from 'react';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { SWAP_POLL_INTERVAL_MS } from '@/shared/core/blockchain/swap/constants';\nimport { SwapQuote } from '@/shared/core/blockchain/swap/quote';\nimport type {\n AssetDecimals,\n BlockchainAmount,\n EthereumChain,\n EvmContractAddress,\n} from '@/shared/types/blockchain/core';\n\nexport interface UseSwapQuoteOptions {\n /** The swap contract to quote against. */\n contractAddress: EvmContractAddress;\n chain: EthereumChain;\n /** The gross amount the user wants to swap, in the input token. */\n inputAmount: BlockchainAmount;\n inputTokenAddress: EvmContractAddress;\n /**\n * Decimals of the swap's output token. Quoting is skipped until this is\n * known (e.g. while {@link useSwapOutputToken} is still loading).\n */\n outputTokenDecimals: AssetDecimals | null;\n /** How often to refresh the quote. Defaults to {@link SWAP_POLL_INTERVAL_MS}. */\n pollIntervalMs?: number;\n /** When false, the hook neither fetches nor polls. */\n enabled: boolean;\n}\n\nexport interface UseSwapQuoteResult {\n /** The latest quote, or `null` until the first successful fetch. */\n quote: SwapQuote | null;\n /** True until the first quote arrives; false while the hook is disabled. */\n isLoading: boolean;\n /** True while a background poll refreshes an existing quote. */\n isRefreshing: boolean;\n}\n\n/**\n * Polls a read-only swap quote for `inputAmount` of `inputTokenAddress` against\n * the given swap contract, refreshing every `pollIntervalMs`.\n *\n * A failed fetch is swallowed: the last quote stays visible and the next poll\n * tick retries. Quoting is skipped while `outputTokenDecimals` is `null` or\n * `enabled` is false, and until the CoinList provider finishes initializing.\n */\nexport function useSwapQuote(options: UseSwapQuoteOptions): UseSwapQuoteResult {\n const {\n contractAddress,\n chain,\n inputAmount,\n inputTokenAddress,\n outputTokenDecimals,\n pollIntervalMs = SWAP_POLL_INTERVAL_MS,\n enabled,\n } = options;\n const { coinlist, isReady } = useCoinList();\n\n const [quote, setQuote] = useState<SwapQuote | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [isRefreshing, setIsRefreshing] = useState(false);\n\n const isFetchingRef = useRef(false);\n const hasQuoteRef = useRef(false);\n const fetchIdRef = useRef(0);\n\n useEffect(() => {\n if (!isReady) return;\n if (!enabled) {\n setIsLoading(false);\n return;\n }\n const currentFetchId = ++fetchIdRef.current;\n isFetchingRef.current = false;\n\n const loadQuote = async () => {\n if (outputTokenDecimals === null) return;\n if (isFetchingRef.current) return;\n isFetchingRef.current = true;\n\n if (hasQuoteRef.current) {\n setIsRefreshing(true);\n }\n\n try {\n const preview = await coinlist.swap.getPreview({\n contractAddress,\n chain,\n inputToken: inputTokenAddress,\n amount: inputAmount.raw,\n });\n if (currentFetchId !== fetchIdRef.current) return;\n\n setQuote(\n SwapQuote.fromPreview(\n preview,\n inputAmount.decimals,\n outputTokenDecimals\n )\n );\n if (!hasQuoteRef.current) {\n hasQuoteRef.current = true;\n setIsLoading(false);\n }\n } catch {\n // Swallow: keep the last quote and let the next poll tick retry.\n } finally {\n if (currentFetchId === fetchIdRef.current) {\n isFetchingRef.current = false;\n setIsRefreshing(false);\n }\n }\n };\n\n loadQuote();\n const interval = setInterval(loadQuote, pollIntervalMs);\n return () => {\n clearInterval(interval);\n ++fetchIdRef.current;\n setIsRefreshing(false);\n };\n }, [\n coinlist,\n isReady,\n contractAddress,\n chain,\n inputAmount.raw,\n inputAmount.decimals,\n inputTokenAddress,\n outputTokenDecimals,\n pollIntervalMs,\n enabled,\n ]);\n\n return { quote, isLoading, isRefreshing };\n}\n","import { useEffect, useRef, useState } from 'react';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { SWAP_POLL_INTERVAL_MS } from '@/shared/core/blockchain/swap/constants';\nimport { TOKEN_REGISTRY } from '@/shared/core/blockchain/token-registry';\nimport type {\n EthereumChain,\n EvmWalletAddress,\n StablecoinSymbol,\n} from '@/shared/types/blockchain/core';\nimport type { NonEmptyArray } from '@/shared/types/collections';\n\nexport interface UseSwapTokenBalancesOptions {\n address: EvmWalletAddress;\n chain: EthereumChain;\n /** The assets to read balances for. */\n assets: NonEmptyArray<StablecoinSymbol>;\n /** How often to refresh balances. Defaults to {@link SWAP_POLL_INTERVAL_MS}. */\n pollIntervalMs?: number;\n /** When false, the hook neither fetches nor polls. */\n enabled: boolean;\n}\n\nexport interface UseSwapTokenBalancesResult {\n /**\n * Raw on-chain balances keyed by the requested assets. Each requested asset\n * has an entry once a fetch settles (`bigint` on success, `null` on failure).\n * Assets that were not requested are absent.\n */\n balances: Map<StablecoinSymbol, bigint | null>;\n isLoading: boolean;\n}\n\n/**\n * Polls the raw ERC-20 balances of `assets` for `address`, refreshing every\n * `pollIntervalMs`. Each asset settles independently: a failed read maps to\n * `null` while the others still resolve. A poll tick is skipped while the\n * previous fetch is still in flight. `assets` is compared by contents, so\n * passing an inline array does not restart the poll.\n *\n * `isLoading` is true only until the first poll settles; background polls do\n * not toggle it. Disabled (or before the provider is ready) the hook does not\n * fetch.\n */\nexport function useSwapTokenBalances(\n options: UseSwapTokenBalancesOptions\n): UseSwapTokenBalancesResult {\n const {\n address,\n chain,\n assets,\n pollIntervalMs = SWAP_POLL_INTERVAL_MS,\n enabled,\n } = options;\n const { coinlist, isReady } = useCoinList();\n\n const [balances, setBalances] = useState<\n Map<StablecoinSymbol, bigint | null>\n >(new Map());\n const [isLoading, setIsLoading] = useState(true);\n\n const fetchIdRef = useRef(0);\n const isFetchingRef = useRef(false);\n\n // Compare `assets` by contents, not reference, so callers may pass an\n // inline array without restarting the poll every render.\n const assetsKey = assets.join(',');\n\n useEffect(() => {\n if (!isReady) return;\n if (!enabled) {\n setIsLoading(false);\n return;\n }\n const symbols = assetsKey.split(',') as NonEmptyArray<StablecoinSymbol>;\n const currentFetchId = ++fetchIdRef.current;\n isFetchingRef.current = false;\n let isFirstFetch = true;\n\n async function fetchBalances() {\n // Skip a poll tick while the previous fetch is still in flight so a\n // slow earlier read cannot resolve last and overwrite fresher balances.\n if (isFetchingRef.current) return;\n isFetchingRef.current = true;\n if (isFirstFetch) {\n setIsLoading(true);\n }\n const results = await Promise.allSettled(\n symbols.map((symbol) =>\n coinlist.swap.getTokenBalance({\n tokenAddress: TOKEN_REGISTRY.contractAddress(symbol, chain),\n owner: address,\n chain,\n })\n )\n );\n if (currentFetchId !== fetchIdRef.current) return;\n isFetchingRef.current = false;\n\n const next = new Map<StablecoinSymbol, bigint | null>();\n symbols.forEach((symbol, i) => {\n const result = results[i];\n next.set(\n symbol,\n result.status === 'fulfilled' ? result.value.balance : null\n );\n });\n setBalances(next);\n setIsLoading(false);\n isFirstFetch = false;\n }\n\n fetchBalances();\n const interval = setInterval(fetchBalances, pollIntervalMs);\n return () => {\n clearInterval(interval);\n ++fetchIdRef.current;\n };\n }, [coinlist, isReady, address, chain, assetsKey, pollIntervalMs, enabled]);\n\n return { balances, isLoading };\n}\n","import { useEffect, useRef } from 'react';\nimport type { OauthClientErrorReason } from '@/client/core/types/client-types';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport type { AuthorizationCode, CodeVerifier } from '@/shared/types/oauth';\n\n/**\n * Reasons passed to {@link UseCompleteOAuthOptions.onFailure} when the\n * OAuth callback cannot be completed. Includes PKCE / redirect validation\n * errors from {@link CoinListClient.completeOAuth} and a dedicated value when\n * {@link UseCompleteOAuthOptions.postOAuthComplete} fails or rejects.\n */\nexport type CompleteOAuthFailureReason =\n | OauthClientErrorReason\n | 'complete_request_failed';\n\nexport interface UseCompleteOAuthOptions {\n /**\n * Exchange the authorization code on your backend (e.g. POST to your API).\n * Return `true` when the session was established successfully, `false` when\n * the request completed but signing in failed. Rejections are treated like\n * `false` and reported as {@link CompleteOAuthFailureReason}\n * `\"complete_request_failed\"`.\n */\n postOAuthComplete: (payload: {\n code: AuthorizationCode;\n codeVerifier: CodeVerifier;\n }) => Promise<boolean>;\n /**\n * Called when the user denied access (`error` query parameter), when\n * {@link CoinListClient.completeOAuth} fails PKCE/state validation, or when\n * {@link UseCompleteOAuthOptions.postOAuthComplete} fails.\n */\n onFailure: (reason: CompleteOAuthFailureReason) => void | Promise<void>;\n /** Invoked after {@link UseCompleteOAuthOptions.postOAuthComplete} succeeds and {@link CoinListClient.init} has refreshed the client session. */\n onSuccess: () => void | Promise<void>;\n}\n\n/**\n * Runs the CoinList OAuth callback once on mount: validates the redirect URL via\n * {@link CoinListClient.completeOAuth}, exchanges the code via {@link UseCompleteOAuthOptions.postOAuthComplete},\n * refreshes tokens with {@link CoinListClient.init}, then calls {@link UseCompleteOAuthOptions.onSuccess}.\n *\n * Framework-agnostic: reads `window.location` like {@link CoinListClient.completeOAuth}. Supply\n * {@link UseCompleteOAuthOptions.postOAuthComplete}, {@link UseCompleteOAuthOptions.onFailure},\n * and {@link UseCompleteOAuthOptions.onSuccess} to perform redirects or routing in your app.\n *\n * Must be used within {@link CoinListProvider}.\n */\nexport function useCompleteOAuth(options: UseCompleteOAuthOptions): void {\n const { coinlist } = useCoinList();\n\n const postOAuthCompleteRef = useRef(options.postOAuthComplete);\n const onFailureRef = useRef(options.onFailure);\n const onSuccessRef = useRef(options.onSuccess);\n\n postOAuthCompleteRef.current = options.postOAuthComplete;\n onFailureRef.current = options.onFailure;\n onSuccessRef.current = options.onSuccess;\n\n const hasStartedExchangeRef = useRef(false);\n\n useEffect(() => {\n if (typeof window === 'undefined') return;\n\n const params = new URLSearchParams(window.location.search);\n if (!params.has('code') && !params.has('error')) return;\n\n if (hasStartedExchangeRef.current) return;\n\n const oauthResult = coinlist.completeOAuth();\n if (oauthResult.type === 'error') {\n void Promise.resolve(onFailureRef.current(oauthResult.reason)).catch(\n () => {}\n );\n return;\n }\n\n hasStartedExchangeRef.current = true;\n let cancelled = false;\n\n void (async () => {\n try {\n const ok = await postOAuthCompleteRef.current({\n code: oauthResult.code,\n codeVerifier: oauthResult.codeVerifier,\n });\n\n if (cancelled) return;\n\n if (!ok) {\n hasStartedExchangeRef.current = false;\n await onFailureRef.current('complete_request_failed');\n return;\n }\n\n await coinlist.init();\n\n if (cancelled) return;\n\n await onSuccessRef.current();\n } catch {\n if (cancelled) return;\n hasStartedExchangeRef.current = false;\n await onFailureRef.current('complete_request_failed');\n }\n })();\n\n return () => {\n cancelled = true;\n hasStartedExchangeRef.current = false;\n };\n }, [coinlist]);\n}\n","import { useEffect, useState } from 'react';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferDetail } from '@/shared/types/offer-detail';\n\nexport type LoadOfferDetailsReason = 'not-authenticated' | 'generic-error';\n\nexport type LoadOfferDetailsState =\n | {\n type: 'LOADING';\n }\n | {\n type: 'ERROR';\n reason: LoadOfferDetailsReason;\n }\n | {\n type: 'CONTENT';\n offerDetail: OfferDetail;\n };\n\nexport interface UseOfferDetailsOptions {\n /**\n * Offer detail pre-fetched on the server (e.g. via `CoinListServer.fetchOfferDetails()`).\n * When provided, the hook uses this data as-is and skips the client-side fetch entirely.\n */\n data?: OfferDetail;\n}\n\nexport interface UseOfferDetailsResult {\n offerDetailsState: LoadOfferDetailsState;\n}\n\nconst LOADING_STATE: LoadOfferDetailsState = { type: 'LOADING' };\n\n/**\n * Loads CoinList offer details for a given offer id and exposes a UI-friendly state.\n *\n * Pass `data` (pre-fetched server-side) to use that data as-is and skip\n * the client-side fetch entirely.\n *\n * Returns `LOADING` while CoinList is initializing or while details are being fetched.\n * Returns `CONTENT` with the offer when `fetchOfferDetails()` succeeds.\n * Returns `ERROR` with:\n * - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}\n * - `generic-error` for any other failure\n */\nexport function useOfferDetails(\n offerId: OfferId,\n options: UseOfferDetailsOptions = {}\n): UseOfferDetailsResult {\n const { coinlist, isReady } = useCoinList();\n const { data } = options;\n const [offerDetailsState, setOfferDetailsState] =\n useState<LoadOfferDetailsState>(\n data !== undefined\n ? { type: 'CONTENT', offerDetail: data }\n : LOADING_STATE\n );\n\n useEffect(() => {\n let isCancelled = false;\n\n if (!isReady) {\n if (data === undefined) {\n setOfferDetailsState(LOADING_STATE);\n }\n return () => {\n isCancelled = true;\n };\n }\n\n if (data !== undefined) {\n return () => {\n isCancelled = true;\n };\n }\n\n setOfferDetailsState(LOADING_STATE);\n coinlist\n .fetchOfferDetails(offerId)\n .then((offerDetail) => {\n if (!isCancelled) {\n setOfferDetailsState({ type: 'CONTENT', offerDetail });\n }\n })\n .catch((error: unknown) => {\n if (!isCancelled) {\n const reason: LoadOfferDetailsReason =\n error instanceof NotAuthenticatedError\n ? 'not-authenticated'\n : 'generic-error';\n setOfferDetailsState({ type: 'ERROR', reason });\n }\n });\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist, isReady, offerId, data]);\n\n return { offerDetailsState };\n}\n","import { useEffect, useState } from 'react';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { Participation } from '@/shared/types/participation';\n\nexport type LoadParticipationsReason = 'not-authenticated' | 'generic-error';\n\nexport type LoadParticipationsState =\n | {\n type: 'LOADING';\n }\n | {\n type: 'ERROR';\n reason: LoadParticipationsReason;\n }\n | {\n type: 'CONTENT';\n participations: Participation[];\n };\n\nexport interface UseParticipationsOptions {\n /**\n * Participations pre-fetched on the server (e.g. via `CoinListServer.fetchParticipations()`).\n * When provided, the hook uses this data as-is and skips the client-side fetch entirely.\n */\n data?: Participation[];\n}\n\nexport interface UseParticipationsResult {\n participationsState: LoadParticipationsState;\n}\n\nconst LOADING_STATE: LoadParticipationsState = { type: 'LOADING' };\n\n/**\n * Loads all CoinList participations for the current user and exposes a UI-friendly state.\n * Optionally filters by offer when `offerId` is provided.\n *\n * Pass `data` (pre-fetched server-side) to use that data as-is and skip\n * the client-side fetch entirely.\n *\n * Returns `LOADING` while CoinList is initializing or while participations are being fetched.\n * Returns `CONTENT` with all participations when `fetchParticipations()` succeeds.\n * Returns `ERROR` with:\n * - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}\n * - `generic-error` for any other failure\n */\nexport function useParticipations(\n offerId?: OfferId,\n options: UseParticipationsOptions = {}\n): UseParticipationsResult {\n const { coinlist, isReady } = useCoinList();\n const { data } = options;\n const [participationsState, setParticipationsState] =\n useState<LoadParticipationsState>(\n data !== undefined\n ? { type: 'CONTENT', participations: data }\n : LOADING_STATE\n );\n\n useEffect(() => {\n let isCancelled = false;\n\n // Wait until CoinListProvider finishes auth initialization.\n if (!isReady) {\n if (data === undefined) {\n setParticipationsState(LOADING_STATE);\n }\n return () => {\n isCancelled = true;\n };\n }\n\n if (data !== undefined) {\n return () => {\n isCancelled = true;\n };\n }\n\n setParticipationsState(LOADING_STATE);\n coinlist\n .fetchParticipations(offerId)\n .then((participations) => {\n if (!isCancelled) {\n setParticipationsState({ type: 'CONTENT', participations });\n }\n })\n .catch((error: unknown) => {\n if (!isCancelled) {\n const reason: LoadParticipationsReason =\n error instanceof NotAuthenticatedError\n ? 'not-authenticated'\n : 'generic-error';\n setParticipationsState({ type: 'ERROR', reason });\n }\n });\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist, isReady, offerId, data]);\n\n return { participationsState };\n}\n"],"mappings":"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","names":["createContext","jsx","createContext","jsx","jsxs","jsx","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","useContext","useContext","jsx","jsxs","Fragment","jsx","jsxs","useEffect","useState","useState","useEffect","jsx","jsxs","useState","jsx","jsxs","useState","useEffect","useEffect","useState","useState","useEffect","jsx","jsxs","useEffect","useEffect","useRef","useCallback","useEffect","useRef","useState","LOADING_STATE","useState","useRef","useEffect","useCallback","jsx","jsxs","useRef","useEffect","CircleCheck","Info","jsx","Info","CircleCheck","Fragment","jsx","jsxs","useEffect","useRef","useState","useEffect","useCallback","useEffect","useState","IDLE_SIGN","LOADING_STATE","useState","useEffect","useCallback","jsx","jsxs","useEffect","useCallback","useEffect","useState","LOADING_STATE","useState","useCallback","useEffect","useCallback","useEffect","useState","LOADING_STATE","useState","useCallback","useEffect","jsx","jsxs","useState","useRef","useEffect","statuses","useEffect","useRef","useState","LOADING_STATE","useState","useRef","useEffect","useEffect","useRef","useState","useState","useRef","useEffect","useEffect","useRef","useState","useState","useRef","useEffect","useEffect","useRef","useRef","useEffect","useEffect","useState","LOADING_STATE","useState","useEffect","useEffect","useState","LOADING_STATE","useState","useEffect"]}