@mesub/react 0.0.0-stage → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +340 -2
- package/dist/index.cjs +2974 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +152 -0
- package/dist/index.d.ts +152 -0
- package/dist/index.js +2955 -0
- package/dist/index.js.map +1 -0
- package/package.json +99 -4
- package/styles.css +2764 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/provider.tsx","../src/errors.ts","../src/api.ts","../src/checkout.tsx","../src/context.ts","../src/dialog.tsx","../src/brand.tsx","../src/format.ts","../src/screens.tsx","../src/wallet.ts","../src/manage.tsx","../src/detail.tsx","../src/detail-logic.ts","../src/subscriptions.tsx","../src/subscribe-button.tsx"],"sourcesContent":["/**\n * `@mesub/react`: the wallet part of subscribing, in the browser. It calls the\n * routes `@mesub/node` mounts on your own server, never Mesub, and holds no key.\n */\nexport { MesubProvider, type MesubProviderProps } from './provider';\nexport type { MesubTheme, SubscribeState } from './context';\nexport type { FetchLike } from './api';\nexport {\n SubscribeButton,\n useSubscribe,\n type SubscribeButtonProps,\n type UseSubscribeOptions,\n type UseSubscribeResult,\n} from './subscribe-button';\nexport {\n ManageButton,\n ManageSubscriptions,\n useSubscriptions,\n type ManageButtonProps,\n type ManageSubscriptionsProps,\n type MesubHeldSubscription,\n type PayNowResult,\n type UseSubscriptionsResult,\n} from './subscriptions';\nexport type { SolanaChain } from './wallet';\nexport type {\n MesubAction,\n MesubBlockedReason,\n MesubPlan,\n MesubStopReason,\n MesubSubscription,\n MesubSubscriptionStatus,\n MesubToken,\n} from './types';\n","import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from 'react';\nimport { createApi, type FetchLike } from './api';\nimport { Checkout } from './checkout';\nimport {\n MesubContext,\n type ManageRequest,\n type MesubInternal,\n type MesubTheme,\n type SubscribeRequest,\n} from './context';\nimport { Manage } from './manage';\nimport { SubscriptionDialog } from './detail';\nimport type { MesubPlan, MesubSubscription } from './types';\nimport type { SolanaChain } from './wallet';\n\nexport interface MesubProviderProps {\n // Where your server mounts the routes of @mesub/node: \"/api/mesub\".\n endpoint: string;\n // The network the wallet signs for and sends on. solana:mainnet by default, where Mesub runs.\n chain?: SolanaChain | undefined;\n // To add your own headers or credentials. By default, credentials: 'include'.\n fetch?: FetchLike | undefined;\n // data-mesub-theme on the widget. Leave it out to inherit it from an ancestor.\n theme?: MesubTheme | undefined;\n // Where \"Cancel any time\" leads once subscribed: your own page (\"/account\"), Mesub's by\n // default, null for no button.\n manageUrl?: string | null | undefined;\n children?: ReactNode;\n}\n\ntype Open =\n { kind: 'subscribe'; request: SubscribeRequest } | { kind: 'manage'; request: ManageRequest };\n\ninterface Pending {\n promise: Promise<MesubSubscription | null>;\n resolve(result: MesubSubscription | null): void;\n // What the dialog settled on, handed over when it closes.\n result: MesubSubscription | null;\n}\n\n/** Says where the merchant's routes are, and renders the one dialog the hooks open. */\nexport function MesubProvider({\n endpoint,\n chain = 'solana:mainnet',\n fetch,\n theme,\n manageUrl,\n children,\n}: MesubProviderProps) {\n const api = useMemo(() => createApi({ endpoint, fetch }), [endpoint, fetch]);\n const plans = useMemo(() => new Map<string, Promise<MesubPlan>>(), [api]);\n const [open, setOpen] = useState<Open | null>(null);\n const [revision, setRevision] = useState(0);\n const pending = useRef<Pending | null>(null);\n // The subscription's own window, up behind whatever its action opens.\n const [managed, setManaged] = useState<{ plan: string | undefined } | null>(null);\n const openSubscription = useCallback((plan: string | undefined) => setManaged({ plan }), []);\n\n // Unmounted with a dialog up: whoever waits on it is answered.\n useEffect(\n () => () => {\n pending.current?.resolve(null);\n pending.current = null;\n },\n [],\n );\n\n const plan = useCallback(\n (slug: string) => {\n let read = plans.get(slug);\n if (!read) {\n read = api.plan(slug);\n plans.set(slug, read);\n read.catch(() => plans.delete(slug));\n }\n return read;\n },\n [api, plans],\n );\n\n // One dialog at a time: a second click gets the first one's answer.\n const start = useCallback((next: Open) => {\n if (pending.current) return pending.current.promise;\n let resolve!: Pending['resolve'];\n const promise = new Promise<MesubSubscription | null>((done) => {\n resolve = done;\n });\n pending.current = { promise, resolve, result: null };\n setOpen(next);\n return promise;\n }, []);\n\n const subscribe = useCallback(\n (request: SubscribeRequest) => start({ kind: 'subscribe', request }),\n [start],\n );\n const manage = useCallback(\n (request: ManageRequest) => start({ kind: 'manage', request }),\n [start],\n );\n\n const settled = useCallback((subscription: MesubSubscription | null) => {\n if (pending.current && subscription) pending.current.result = subscription;\n setRevision((current) => current + 1);\n }, []);\n\n const close = useCallback(() => {\n pending.current?.resolve(pending.current.result);\n pending.current = null;\n setOpen(null);\n }, []);\n\n const value = useMemo<MesubInternal>(\n () => ({\n api,\n chain,\n theme,\n manageUrl,\n plan,\n revision,\n subscribe,\n manage,\n openSubscription,\n }),\n [api, chain, theme, manageUrl, plan, revision, subscribe, manage, openSubscription],\n );\n\n return (\n <MesubContext.Provider value={value}>\n {children}\n {open?.kind === 'subscribe' ? (\n <Checkout\n plan={open.request.plan}\n onState={open.request.onState}\n onSubscribed={(subscription, signature) => {\n settled(subscription);\n open.request.onSubscribed(subscription, signature);\n }}\n onClose={close}\n />\n ) : null}\n {/* One native dialog at a time: it steps aside while its action runs. */}\n {managed && !open ? (\n <SubscriptionDialog plan={managed.plan} onClose={() => setManaged(null)} />\n ) : null}\n {open?.kind === 'manage' ? (\n <Manage\n subscription={open.request.subscription}\n action={open.request.action}\n onChanged={settled}\n onClose={close}\n />\n ) : null}\n </MesubContext.Provider>\n );\n}\n","/**\n * A call to the merchant's server that failed. `status` is null when nothing\n * answered (network, timeout); `code` is the server's own, as `@mesub/node` names it.\n */\nexport class MesubClientError extends Error {\n override readonly name = 'MesubClientError';\n readonly status: number | null;\n readonly code: string | null;\n // Seconds, from Retry-After: on a 429, and on a 503 `unavailable` (Mesub-io/backend#505).\n readonly retryAfter: number | null;\n\n constructor(\n message: string,\n status: number | null,\n code: string | null = null,\n options: ErrorOptions & { retryAfter?: number | null } = {},\n ) {\n super(message, options);\n this.status = status;\n this.code = code;\n this.retryAfter = options.retryAfter ?? null;\n }\n}\n","import { MesubClientError } from './errors';\nimport type {\n MesubAction,\n MesubPayment,\n MesubPlan,\n MesubSubscription,\n MesubSubscriptionDetail,\n MesubUpcoming,\n PreparedSubscription,\n Settled,\n WalletTransaction,\n} from './types';\n\n// Reads and builds answer at once.\nexport const REQUEST_TIMEOUT_MS = 15_000;\n// Submit and the confirms wait for the chain: about a minute.\nexport const CHAIN_TIMEOUT_MS = 90_000;\n\nexport type FetchLike = (input: string, init: RequestInit) => Promise<Response>;\n\nexport interface ApiOptions {\n // Where the merchant mounted the routes of @mesub/node: \"/api/mesub\".\n endpoint: string;\n fetch?: FetchLike | undefined;\n}\n\n/** The routes `@mesub/node` mounts on the merchant's server. Nothing here reaches Mesub. */\nexport interface MesubApi {\n plan(slug: string): Promise<MesubPlan>;\n subscriptions(): Promise<MesubSubscription[]>;\n // One of them with its latest charges.\n subscription(id: string): Promise<MesubSubscriptionDetail>;\n prepare(plan: string, wallet: string): Promise<PreparedSubscription>;\n // A fresh transaction for a checkout still to sign (Mesub-io/backend#427), with the terms it names.\n transaction(id: string): Promise<PreparedSubscription>;\n submit(id: string, signed: { transaction: string; terms_signature: string }): Promise<Settled>;\n build(action: MesubAction, id: string): Promise<WalletTransaction>;\n confirm(action: MesubAction, id: string, signature: string): Promise<Settled>;\n // Pays a late payment now (Mesub-io/backend#354): nothing to sign, the outcome comes with the pull.\n payNow(id: string): Promise<MesubSubscription>;\n}\n\n/**\n * When each transaction answered dies, on this browser's clock: from its\n * `transaction_expires_at` (Mesub-io/backend#471), held beside the answer.\n */\nconst deadlines = new WeakMap<object, number>();\n\n/** When that answer's transaction stops landing, on this clock. Null when nobody said. */\nexport function deadlineOf(answer: object): number | null {\n return deadlines.get(answer) ?? null;\n}\n\n/**\n * `transaction_expires_at` on this clock. A visitor's clock can be off by\n * minutes, so the time left is counted against the server's `Date` when the\n * browser may read it, minus the second that header rounds away: it errs\n * early, as Mesub's estimate does. Without it, this clock is trusted unless it\n * says the transaction was dead on arrival: then the clock is wrong, and the\n * chain will say when it expires.\n */\nfunction dyingAt(expiresAt: unknown, served: string | null, received: number): number | null {\n const at = typeof expiresAt === 'string' ? Date.parse(expiresAt) : Number.NaN;\n if (Number.isNaN(at)) return null;\n const now = served === null ? Number.NaN : Date.parse(served);\n const until = Number.isNaN(now) ? at : received + (at - now) - 1000;\n return until > received ? until : null;\n}\n\nconst isObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\n/** The fewest charges a server lists when it lists them all: under it, the list is whole. */\nconst LISTED_AT_MOST = 5;\n\n/**\n * What was paid since the subscription began. `paid` is the server's own\n * total. A server that predates it only sums the charges it lists\n * (`listed_paid`): that is the total only while the list is whole.\n */\nfunction paidOf(answer: Record<string, unknown>): MesubSubscriptionDetail['paid'] {\n const read = (value: unknown) =>\n isObject(value) && typeof value.count === 'number'\n ? { count: value.count, amount: typeof value.amount === 'string' ? value.amount : null }\n : null;\n const total = read(answer.paid);\n if (total) return total;\n\n const whole = Array.isArray(answer.payments) && answer.payments.length < LISTED_AT_MOST;\n return whole ? read(answer.listed_paid) : null;\n}\n\nexport function createApi(options: ApiOptions): MesubApi {\n const base = options.endpoint.replace(/\\/+$/, '');\n // Read at call time, so a fetch stubbed after the client is built is still used.\n const doFetch: FetchLike = options.fetch ?? ((input, init) => globalThis.fetch(input, init));\n\n async function request(\n method: 'GET' | 'POST',\n path: string,\n body: unknown,\n timeout: number,\n ): Promise<Record<string, unknown>> {\n const headers: Record<string, string> = { Accept: 'application/json' };\n // The routes refuse a POST that is not JSON, even one with nothing to say.\n if (method === 'POST') headers['Content-Type'] = 'application/json';\n\n const late = `No answer within ${timeout / 1000} seconds.`;\n const controller = new AbortController();\n let timer: ReturnType<typeof setTimeout> | undefined;\n // Raced too, since a custom fetch may ignore the signal.\n const deadline = new Promise<never>((_, reject) => {\n timer = setTimeout(() => {\n reject(new MesubClientError(late, null, 'timeout'));\n controller.abort();\n }, timeout);\n });\n\n async function send(): Promise<Record<string, unknown>> {\n let response: Response;\n try {\n response = await doFetch(`${base}${path}`, {\n method,\n headers,\n ...(method === 'POST' && { body: JSON.stringify(body ?? {}) }),\n // The merchant's own session cookie says who is asking.\n credentials: 'include',\n signal: controller.signal,\n });\n } catch (error) {\n if (controller.signal.aborted) throw new MesubClientError(late, null, 'timeout');\n throw new MesubClientError('Could not reach the server.', null, 'network', {\n cause: error,\n });\n }\n\n let answer: unknown;\n try {\n answer = await response.json();\n } catch {\n answer = undefined;\n }\n\n if (!response.ok) throw refusal(response, answer);\n if (!isObject(answer)) {\n // A page instead of JSON: the routes are not mounted at `endpoint`.\n throw new MesubClientError(\n `${base}${path} did not answer as the @mesub/node routes do.`,\n response.status,\n 'bad_response',\n );\n }\n const until = dyingAt(\n answer.transaction_expires_at,\n response.headers.get('Date'),\n Date.now(),\n );\n if (until !== null) deadlines.set(answer, until);\n return answer;\n }\n\n try {\n // The body is read inside the race: a hung body times out too.\n return await Promise.race([send(), deadline]);\n } finally {\n clearTimeout(timer);\n }\n }\n\n const at = (id: string) => `/subscriptions/${encodeURIComponent(id)}`;\n\n return {\n plan: async (slug) =>\n (await request(\n 'GET',\n `/plans/${encodeURIComponent(slug)}`,\n undefined,\n REQUEST_TIMEOUT_MS,\n )) as unknown as MesubPlan,\n subscriptions: async () => {\n const answer = await request('GET', '/subscriptions', undefined, REQUEST_TIMEOUT_MS);\n return Array.isArray(answer.subscriptions)\n ? (answer.subscriptions as MesubSubscription[])\n : [];\n },\n subscription: async (id) => {\n const answer = await request('GET', at(id), undefined, REQUEST_TIMEOUT_MS);\n return {\n subscription: answer.subscription as MesubSubscription,\n upcoming: Array.isArray(answer.upcoming)\n ? (answer.upcoming as MesubUpcoming[])\n : [],\n payments: Array.isArray(answer.payments)\n ? (answer.payments as MesubPayment[])\n : null,\n paid: paidOf(answer),\n };\n },\n prepare: async (plan, wallet) =>\n (await request(\n 'POST',\n '/subscriptions',\n { plan, wallet },\n REQUEST_TIMEOUT_MS,\n )) as unknown as PreparedSubscription,\n transaction: async (id) =>\n (await request(\n 'POST',\n `${at(id)}/transaction`,\n {},\n REQUEST_TIMEOUT_MS,\n )) as unknown as PreparedSubscription,\n submit: async (id, signed) =>\n (await request(\n 'POST',\n `${at(id)}/submit`,\n { transaction: signed.transaction, terms_signature: signed.terms_signature },\n CHAIN_TIMEOUT_MS,\n )) as unknown as Settled,\n build: async (action, id) =>\n (await request(\n 'POST',\n `${at(id)}/${action}`,\n {},\n REQUEST_TIMEOUT_MS,\n )) as unknown as WalletTransaction,\n payNow: async (id) => {\n const answer = await request('POST', `${at(id)}/retry`, {}, REQUEST_TIMEOUT_MS);\n return answer.subscription as MesubSubscription;\n },\n confirm: async (action, id, signature) =>\n (await request(\n 'POST',\n `${at(id)}/${action}/confirm`,\n { signature },\n CHAIN_TIMEOUT_MS,\n )) as unknown as Settled,\n };\n}\n\n/** `{ error: { code, message } }`, as the routes refuse. */\nfunction refusal(response: Response, answer: unknown): MesubClientError {\n const error = isObject(answer) && isObject(answer.error) ? answer.error : null;\n const message =\n typeof error?.message === 'string' && error.message !== ''\n ? error.message\n : `The server answered ${response.status}.`;\n const seconds = Number(response.headers.get('Retry-After'));\n\n return new MesubClientError(\n message,\n response.status,\n typeof error?.code === 'string' ? error.code : null,\n { retryAfter: Number.isFinite(seconds) && seconds > 0 ? seconds : null },\n );\n}\n\n/** Nothing answered: the network failed or the wait ran out. */\nexport function unreachable(error: unknown): boolean {\n return error instanceof MesubClientError && error.status === null;\n}\n\n/**\n * Mesub is busy, said with a wait: a 503 `unavailable` with `Retry-After`\n * (Mesub-io/backend#505). Too many submits at once (2 s) or a Pay now the\n * queue refused (20 s): nothing was signed, sent or queued. The seconds to\n * wait, or null for any other error.\n */\nexport function busyFor(error: unknown): number | null {\n if (!(error instanceof MesubClientError)) return null;\n if (error.status !== 503 || error.code !== 'unavailable') return null;\n return error.retryAfter;\n}\n\n/** The merchant's server says nobody is signed in on its site. */\nexport function signedOut(error: unknown): boolean {\n return error instanceof MesubClientError && error.status === 401;\n}\n\n/** No such route: a server whose `@mesub/node` predates it. An unknown subscription names its code. */\nexport function routeMissing(error: unknown): boolean {\n if (!(error instanceof MesubClientError)) return false;\n return (\n error.status === 405 || (error.status === 404 && error.code !== 'subscription_not_found')\n );\n}\n","import { useWallets, type UiWallet } from '@wallet-standard/react';\nimport { useEffect, useId, useRef, useState } from 'react';\nimport { busyFor, deadlineOf, routeMissing, signedOut, unreachable } from './api';\nimport { useMesubInternal, type SubscribeState } from './context';\nimport { MesubDialog, type DialogScreen } from './dialog';\nimport { MesubClientError } from './errors';\nimport {\n briefPrice,\n cadence,\n chargedOnce,\n fit,\n moment,\n planEnd,\n manageLink,\n planUsd,\n shortAddress,\n termsCancelUrl,\n termsFacts,\n termsSingleCharge,\n} from './format';\nimport {\n Explorer,\n failureScreen,\n Hero,\n Merchant,\n Price,\n rememberWallet,\n signedOutScreen,\n walletScreen,\n type Failure,\n type WalletView,\n} from './screens';\nimport type { MesubPlan, MesubSubscription, PreparedSubscription } from './types';\nimport {\n connectAccounts,\n signOnly,\n signText,\n WalletError,\n type Signer,\n type SolanaChain,\n} from './wallet';\n\nexport interface CheckoutProps {\n plan: string;\n onClose(): void;\n // Each state reached, for the button underneath.\n onState(state: SubscribeState): void;\n onSubscribed(subscription: MesubSubscription, signature: string | null): void;\n}\n\ntype PlanState =\n { name: 'loading' } | { name: 'loaded'; plan: MesubPlan } | { name: 'failed'; error: unknown };\n\n/** Where the checkout is. Everything after the wallet carries who signs. */\ntype View =\n | { name: 'plan' }\n | { name: 'wallet'; pick: WalletView }\n | { name: 'preparing'; signer: Signer }\n | { name: 'review'; signer: Signer; prepared: PreparedSubscription; notice: string | null }\n | {\n name: 'signing';\n signer: Signer;\n // `fresh`: the terms are signed, the transaction to sign is being built.\n what: 'terms' | 'fresh' | 'transaction';\n single: boolean;\n notice: string | null;\n }\n | { name: 'submitting'; signer: Signer; signature: string | null; notice?: string }\n | {\n name: 'subscribed';\n signer: Signer;\n subscription: MesubSubscription;\n signature: string | null;\n cancelUrl: string | null;\n single: boolean;\n }\n | { name: 'failed'; failure: Failure; signer: Signer | null; signature: string | null }\n | { name: 'signed-out' };\n\nconst SAFE = 'Nothing was charged.';\nconst PENDING = 'Payment may be pending.';\nconst FRESH_TERMS = 'The terms had expired. These are fresh: check them again.';\nconst EXPIRED =\n 'The transaction expired before it was sent. Nothing was charged: approve this one.';\nconst EXPIRED_TERMS =\n 'The transaction expired before it was sent, and its terms with it. Nothing was charged: check these.';\nconst NOT_LANDED =\n 'The transaction has not landed yet. Wait a moment, then check again: nothing is paid twice.';\n\nconst STATES: Partial<Record<View['name'], SubscribeState>> = {\n signing: 'signing',\n submitting: 'confirming',\n subscribed: 'subscribed',\n};\n\n/** The longest Mesub's busy wait at submit is waited out on its own, in seconds: it asks 2. */\nconst BUSY_WAIT_MAX_S = 10;\n\nconst seconds = (n: number) => `${n} ${n === 1 ? 'second' : 'seconds'}`;\n\n/** A few seconds: what a request to the server and its answer take, at worst. */\nconst MARGIN_MS = 5_000;\n\n/** Past `expires_at`, or within a few seconds of it: not worth asking the wallet. */\nfunction expired(prepared: PreparedSubscription): boolean {\n const until = Date.parse(prepared.terms.expires_at);\n return !Number.isNaN(until) && until - Date.now() < MARGIN_MS;\n}\n\n/**\n * Its transaction dies before Mesub could send it, by `transaction_expires_at`:\n * one signed then is replaced rather than submitted dead. False from a server\n * that does not say: the submit's `transaction_expired` still catches it.\n */\nfunction dying(prepared: PreparedSubscription): boolean {\n const until = deadlineOf(prepared);\n return until !== null && until - Date.now() < MARGIN_MS;\n}\n\n/**\n * Whether this is one charge and no more. What the subscriber signs says it\n * once it exists; before, and for terms that name no amount, the plan's end\n * against its period does.\n */\nfunction singleCharge(plan: MesubPlan, terms?: string): boolean {\n return (terms === undefined ? null : termsSingleCharge(terms)) ?? chargedOnce(plan);\n}\n\nconst messageOf = (error: unknown) =>\n error instanceof MesubClientError ? error.message : 'Something went wrong.';\n\n/** `POST /subscriptions` refused, or never answered: nothing was signed yet. */\nfunction notPrepared(error: unknown): Failure {\n const base = { step: 'review', moved: 'safe', icon: 'merchant' } as const;\n if (unreachable(error)) {\n return { ...base, title: 'No answer', message: messageOf(error), action: 'retry' };\n }\n const status = error instanceof MesubClientError ? error.status : null;\n if (status === 403) {\n return { ...base, title: 'Wrong wallet', message: messageOf(error), action: 'wallet' };\n }\n if (status === 404) {\n // The checkout itself is gone, not the plan: another one can be made.\n return error instanceof MesubClientError && error.code === 'subscription_not_found'\n ? { ...base, title: 'Could not subscribe', message: messageOf(error), action: 'retry' }\n : { ...base, title: 'Plan not found', message: messageOf(error), action: 'close' };\n }\n // A return asked while its billing period turns: a wait, not a no.\n if (error instanceof MesubClientError && error.code === 'comeback_period_rolling') {\n return {\n ...base,\n title: 'Almost there',\n message: error.retryAfter\n ? `Your billing period is turning over. Try again in ${error.retryAfter} seconds.`\n : messageOf(error),\n action: 'retry',\n };\n }\n // Mesub's own refusal (already subscribed, plan closed): its words, as written.\n if (status === 409) {\n return { ...base, title: 'Cannot subscribe', message: messageOf(error), action: 'close' };\n }\n const busy = busyFor(error);\n if (busy !== null) {\n return {\n ...base,\n title: 'Busy right now',\n message: `Too many requests at once. Try again in ${seconds(busy)}.`,\n action: 'retry',\n };\n }\n if (status === 429) {\n const wait = error instanceof MesubClientError ? error.retryAfter : null;\n return {\n ...base,\n title: 'Too many requests',\n message: wait ? `Try again in ${wait} seconds.` : messageOf(error),\n action: 'retry',\n };\n }\n return { ...base, title: 'Could not subscribe', message: messageOf(error), action: 'retry' };\n}\n\n/**\n * The window `useSubscribe` opens: the plan, a wallet, what it costs, the two\n * signatures, then Mesub sends. One dialog from the click to \"Done\".\n */\nexport function Checkout({ plan: slug, onClose, onState, onSubscribed }: CheckoutProps) {\n const { api, chain, manageUrl } = useMesubInternal();\n const wallets = useWallets();\n const titleId = useId();\n\n const [loaded, setLoaded] = useState<PlanState>({ name: 'loading' });\n const [view, setViewState] = useState<View>({ name: 'plan' });\n const [checking, setChecking] = useState(false);\n\n const alive = useRef(true);\n // Bumped by each step taken: a late answer from the one before is dropped.\n const attempt = useRef(0);\n // The view as of now, not as of the last render: what a double click is checked against.\n const shown = useRef<View>(view);\n const checkingNow = useRef(false);\n // What was handed to submit: \"Check again\" sends exactly that, never a new payment.\n const sent = useRef<{\n id: string;\n signed: { transaction: string; terms_signature: string };\n signer: Signer;\n signature: string | null;\n // Where the terms said it can be stopped, for the done screen.\n cancelUrl: string | null;\n // Whether the terms signed were for one charge: the receipt says the same.\n single: boolean;\n // The message `terms_signature` is over: other terms need another signature.\n terms: string;\n } | null>(null);\n // Transactions that expired at submit, in a row: the first is replaced, the second stops.\n const expiries = useRef(0);\n const latest = useRef({ onState, onSubscribed });\n latest.current = { onState, onSubscribed };\n\n function setView(next: View) {\n shown.current = next;\n setViewState(next);\n latest.current.onState(STATES[next.name] ?? 'open');\n }\n\n function begin() {\n const id = ++attempt.current;\n return () => alive.current && id === attempt.current;\n }\n\n function loadPlan() {\n setLoaded({ name: 'loading' });\n api.plan(slug).then(\n (served) => alive.current && setLoaded({ name: 'loaded', plan: served }),\n (error: unknown) => alive.current && setLoaded({ name: 'failed', error }),\n );\n }\n\n useEffect(() => {\n alive.current = true;\n latest.current.onState('open');\n loadPlan();\n return () => {\n alive.current = false;\n };\n // Once per opening: the provider mounts a new Checkout each time.\n }, []);\n\n function fail(failure: Failure, signer: Signer | null, signature: string | null = null) {\n setView({ name: 'failed', failure, signer, signature });\n }\n\n // The server refused to build anything: nothing was paid, whatever was signed.\n function refused(error: unknown, signer: Signer) {\n if (signedOut(error)) setView({ name: 'signed-out' });\n else fail(notPrepared(error), signer);\n }\n\n function notSigned(signer: Signer, title: string, error: unknown) {\n fail(\n {\n step: 'approve',\n title,\n message:\n error instanceof WalletError\n ? error.message\n : `${signer.wallet.name} did not sign.`,\n moved: 'safe',\n action: 'retry',\n icon: 'wallet',\n },\n signer,\n );\n }\n\n async function prepare(signer: Signer, notice: string | null = null) {\n const current = begin();\n expiries.current = 0;\n setView({ name: 'preparing', signer });\n try {\n const prepared = await api.prepare(slug, signer.account.address);\n if (current()) setView({ name: 'review', signer, prepared, notice });\n } catch (error) {\n if (current()) refused(error, signer);\n }\n }\n\n /** A fresh transaction for that checkout. Null from a server whose routes predate it. */\n async function fresh(id: string): Promise<PreparedSubscription | null> {\n try {\n return await api.transaction(id);\n } catch (error) {\n if (routeMissing(error)) return null;\n throw error;\n }\n }\n\n async function pick(wallet: UiWallet) {\n // A second click on the row: the first one is already asking the wallet.\n if (shown.current.name !== 'wallet' || shown.current.pick.name === 'waiting') return;\n const current = begin();\n const refused = (message: string) =>\n current() && setView({ name: 'wallet', pick: { name: 'rejected', wallet, message } });\n setView({ name: 'wallet', pick: { name: 'waiting', wallet } });\n\n let account;\n try {\n [account] = await connectAccounts(wallet);\n } catch (refusal) {\n refused(\n `${wallet.name} said: ${refusal instanceof Error ? refusal.message : 'it did not connect.'}`,\n );\n return;\n }\n if (!current()) return;\n if (!account) {\n refused(`${wallet.name} shared no Solana account.`);\n return;\n }\n rememberWallet(wallet.name);\n await prepare({ wallet, account });\n }\n\n async function sign(signer: Signer, prepared: PreparedSubscription, plan: MesubPlan) {\n // A second click finds the review gone: nothing is prepared or signed twice.\n if (shown.current.name !== 'review' || shown.current.prepared !== prepared) return;\n const single = singleCharge(plan, prepared.terms.message);\n const current = begin();\n // Never sign stale terms: ask the server again, and show what it answers.\n if (expired(prepared)) {\n await prepare(signer, FRESH_TERMS);\n return;\n }\n\n setView({ name: 'signing', signer, what: 'terms', single, notice: null });\n let termsSignature;\n try {\n termsSignature = await signText(signer, prepared.terms.message);\n } catch (error) {\n if (current()) notSigned(signer, 'Terms not signed', error);\n return;\n }\n if (!current()) return;\n // The wallet's window stayed open past the terms' life.\n if (expired(prepared)) {\n await prepare(signer, FRESH_TERMS);\n return;\n }\n\n // A transaction lives 150 blocks from when it is built: built now, not while the terms were read.\n setView({ name: 'signing', signer, what: 'fresh', single, notice: null });\n let latest;\n try {\n // An older server has no such route: the transaction held is signed.\n latest = (await fresh(prepared.subscription.id)) ?? prepared;\n } catch (error) {\n if (current()) refused(error, signer);\n return;\n }\n if (!current()) return;\n // It names other terms than the ones just signed: shown, then signed again.\n if (latest.terms.message !== prepared.terms.message) {\n setView({ name: 'review', signer, prepared: latest, notice: FRESH_TERMS });\n return;\n }\n await pay(signer, latest, termsSignature, single, null);\n }\n\n /** Has the transaction signed, and submits it with the terms signature held. */\n async function pay(\n signer: Signer,\n held: PreparedSubscription,\n termsSignature: string,\n single: boolean,\n notice: string | null,\n ) {\n const current = begin();\n setView({ name: 'signing', signer, what: 'transaction', single, notice });\n let signed;\n try {\n // Signed, not sent: Mesub co-signs and sends it.\n signed = await signOnly(signer, chain, held.transaction);\n } catch (error) {\n if (current()) notSigned(signer, 'Transaction not signed', error);\n return;\n }\n if (!current()) return;\n\n sent.current = {\n id: held.subscription.id,\n signed: { transaction: signed.transaction, terms_signature: termsSignature },\n signer,\n signature: signed.signature,\n cancelUrl: termsCancelUrl(held.terms.message),\n single,\n terms: held.terms.message,\n };\n // The wallet's window stayed open past the transaction's life: replaced, never sent dead.\n if (dying(held)) {\n await renew(sent.current, current);\n return;\n }\n await submit();\n }\n\n // Its blockhash died before Mesub sent it: a new transaction for the same subscription, never a new one.\n async function renew(handed: NonNullable<typeof sent.current>, current: () => boolean) {\n const { id, signer, single } = handed;\n const stop = (message: string) =>\n fail(\n {\n step: 'confirming',\n title: 'Transaction expired',\n message,\n moved: 'safe',\n action: 'retry',\n icon: 'merchant',\n },\n signer,\n );\n if (++expiries.current > 1) {\n stop('The transaction expired again before it could be sent. Try again in a moment.');\n return;\n }\n\n setView({ name: 'signing', signer, what: 'fresh', single, notice: EXPIRED });\n let latest;\n try {\n latest = await fresh(id);\n } catch (error) {\n if (current()) refused(error, signer);\n return;\n }\n if (!current()) return;\n // An older server builds one with a new checkout only: asked for, not started here.\n if (!latest) {\n stop('The transaction expired before it could be sent.');\n return;\n }\n if (latest.terms.message !== handed.terms) {\n setView({ name: 'review', signer, prepared: latest, notice: EXPIRED_TERMS });\n return;\n }\n await pay(signer, latest, handed.signed.terms_signature, single, EXPIRED);\n }\n\n // Also \"Check again\": Mesub recognises what it already co-signed and answers from the chain.\n async function submit(waited = false) {\n const handed = sent.current;\n if (!handed) return;\n const { id, signed, signer, signature, cancelUrl, single } = handed;\n const current = begin();\n setView({ name: 'submitting', signer, signature });\n try {\n const settled = await api.submit(id, signed);\n if (settled.reason) {\n if (!current()) return;\n // Not a failed payment: its blockhash ran out before it landed, and it never will.\n if (settled.reason_code === 'transaction_expired') {\n await renew(handed, current);\n return;\n }\n // Not yet on chain: the same transaction may still land, so it is checked, not replaced.\n if (settled.reason_code === 'nothing_landed') {\n fail(\n {\n step: 'confirming',\n title: 'Still confirming',\n message: NOT_LANDED,\n moved: 'pending',\n action: 'check',\n icon: 'merchant',\n },\n signer,\n signature,\n );\n return;\n }\n fail(\n {\n step: 'confirming',\n title: 'Payment did not go through',\n message: settled.reason,\n moved: 'safe',\n action: 'retry',\n icon: 'merchant',\n },\n signer,\n );\n return;\n }\n // Told even once closed: the subscription exists.\n latest.current.onSubscribed(settled.subscription, signature);\n if (current()) {\n setView({\n name: 'subscribed',\n signer,\n subscription: settled.subscription,\n signature,\n cancelUrl,\n single,\n });\n }\n } catch (error) {\n if (!current()) return;\n if (signedOut(error)) {\n setView({ name: 'signed-out' });\n return;\n }\n if (error instanceof MesubClientError && error.code === 'transaction_expired') {\n await renew(handed, current);\n return;\n }\n // Too many submits at once (Mesub-io/backend#505): the same bytes, once more after the\n // wait, as \"Check again\" sends them. Never a new signature nor a new transaction.\n const busy = busyFor(error);\n if (busy !== null) {\n if (!waited && busy <= BUSY_WAIT_MAX_S) {\n setView({\n name: 'submitting',\n signer,\n signature,\n notice: `Busy right now: sending again in ${seconds(busy)}.`,\n });\n await new Promise((resolve) => setTimeout(resolve, busy * 1000));\n if (current()) await submit(true);\n return;\n }\n fail(\n {\n step: 'confirming',\n title: 'Busy right now',\n message: `Too many payments are being sent at once. Wait ${seconds(busy)}, then check again: the same payment is sent, never a second one.`,\n // The server's own replays may have lost a send before: no way to a second payment.\n moved: 'pending',\n action: 'check',\n icon: 'merchant',\n },\n signer,\n signature,\n );\n return;\n }\n const status = error instanceof MesubClientError ? error.status : null;\n // No word on what became of it: Mesub may have sent it.\n if (status === null || status >= 500 || !(error instanceof MesubClientError)) {\n fail(\n {\n step: 'confirming',\n title: 'Still confirming',\n message:\n 'No answer yet on what became of the transaction. Wait a minute, then check again: nothing is paid twice.',\n moved: 'pending',\n action: 'check',\n icon: 'merchant',\n },\n signer,\n signature,\n );\n return;\n }\n // A refusal: Mesub sent nothing.\n fail(\n {\n step: 'confirming',\n title: 'Could not subscribe',\n message: error.message,\n moved: 'safe',\n action: 'retry',\n icon: 'merchant',\n },\n signer,\n );\n }\n }\n\n async function checkAgain() {\n if (checkingNow.current) return;\n checkingNow.current = true;\n setChecking(true);\n try {\n await submit();\n } finally {\n checkingNow.current = false;\n if (alive.current) setChecking(false);\n }\n }\n\n function toWallets() {\n attempt.current++;\n setView({ name: 'wallet', pick: { name: 'list' } });\n }\n\n function toPlan() {\n attempt.current++;\n setView({ name: 'plan' });\n }\n\n function act(action: Failure['action'], signer: Signer | null) {\n if (action === 'close') onClose();\n else if (action === 'check') void checkAgain();\n else if (action === 'wallet' || !signer) toWallets();\n // Again from the server: a fresh transaction, and the review of what it costs.\n else void prepare(signer);\n }\n\n let screen: DialogScreen;\n if (view.name === 'signed-out') {\n screen = signedOutScreen({\n titleId,\n step: 'review',\n message:\n 'You are not signed in on this site. Sign in here first, then subscribe again.',\n safe: SAFE,\n onClose,\n });\n } else if (loaded.name !== 'loaded') {\n screen = planScreen(loaded, titleId, loadPlan, onClose);\n } else if (view.name === 'wallet') {\n screen = walletScreen({\n titleId,\n view: view.pick,\n wallets,\n purpose: 'subscribe',\n lead: 'It pays the subscription. Nothing is signed yet.',\n setView: (pickView) => {\n attempt.current++;\n setView({ name: 'wallet', pick: pickView });\n },\n pick: (wallet) => void pick(wallet),\n onBack: toPlan,\n });\n } else {\n screen = stageScreen({\n view,\n plan: loaded.plan,\n chain,\n manageUrl,\n titleId,\n checking,\n onContinue: toWallets,\n onSign: (signer, prepared) => void sign(signer, prepared, loaded.plan),\n onAct: act,\n onWallets: toWallets,\n onClose,\n });\n }\n\n return <MesubDialog screen={screen} titleId={titleId} onClose={onClose} />;\n}\n\n/** While the plan loads, or when it could not be read. */\nfunction planScreen(\n loaded: Exclude<PlanState, { name: 'loaded' }>,\n titleId: string,\n reload: () => void,\n close: () => void,\n): DialogScreen {\n if (loaded.name === 'loading') {\n return {\n step: 'plan',\n view: 'plan-loading',\n body: (\n <>\n <Hero kind=\"wait\" />\n <h2 id={titleId}>Subscribe</h2>\n <p data-mesub-notice=\"\" role=\"status\" aria-busy=\"true\">\n Loading the plan\n </p>\n </>\n ),\n };\n }\n const silent = unreachable(loaded.error);\n return {\n step: 'plan',\n view: 'plan-failed',\n body: (\n <>\n <Hero kind=\"error\" />\n <h2 id={titleId}>{silent ? 'No answer' : 'Plan not found'}</h2>\n <p role=\"alert\" data-mesub-error=\"\">\n {loaded.error instanceof MesubClientError\n ? loaded.error.message\n : 'Could not read this plan.'}\n </p>\n <p data-mesub-funds=\"safe\">{SAFE}</p>\n {silent ? (\n <button type=\"button\" data-mesub-submit=\"\" onClick={reload}>\n Try again\n </button>\n ) : (\n <button type=\"button\" data-mesub-done=\"\" onClick={close}>\n Close\n </button>\n )}\n </>\n ),\n };\n}\n\nfunction stageScreen(props: {\n view: Exclude<View, { name: 'wallet' } | { name: 'signed-out' }>;\n plan: MesubPlan;\n chain: SolanaChain;\n manageUrl: string | null | undefined;\n titleId: string;\n checking: boolean;\n onContinue(): void;\n onSign(signer: Signer, prepared: PreparedSubscription): void;\n onAct(action: Failure['action'], signer: Signer | null): void;\n onWallets(): void;\n onClose(): void;\n}): DialogScreen {\n const { view, plan, chain, titleId } = props;\n // Short where it is read fast; the terms keep the exact amount.\n const { text: price, title: exact } = briefPrice(plan);\n // A plan with an end date stops charging there: said before anything is signed.\n const ends = planEnd(plan.ends_at);\n // The terms once they are on screen or signed, the plan before.\n const single =\n view.name === 'review'\n ? singleCharge(plan, view.prepared.terms.message)\n : view.name === 'signing' || view.name === 'subscribed'\n ? view.single\n : singleCharge(plan);\n const every = single ? 'once' : cadence(plan.period_hours);\n const merchant = (\n <Merchant\n name={plan.project_name}\n logoUrl={plan.logo_url}\n testNetwork={plan.network !== 'mainnet-beta'}\n />\n );\n\n if (view.name === 'failed') {\n const { failure, signer } = view;\n return failureScreen({\n failure,\n titleId,\n icon: failure.icon === 'wallet' ? signer?.wallet.icon : plan.logo_url,\n safe: SAFE,\n pending: PENDING,\n signature: view.signature,\n chain,\n busy: props.checking,\n onAct: (action) => props.onAct(action, signer),\n onBack: props.onWallets,\n backLabel: 'Use another wallet',\n });\n }\n\n if (view.name === 'plan') {\n if (!plan.available) {\n return {\n step: 'plan',\n view: 'plan-closed',\n body: (\n <>\n <Hero kind=\"error\" icon={plan.logo_url} />\n <h2 id={titleId}>Plan closed</h2>\n <p role=\"alert\" data-mesub-error=\"\">\n This plan is not taking new subscribers right now.\n </p>\n <p data-mesub-funds=\"safe\">{SAFE}</p>\n <button type=\"button\" data-mesub-done=\"\" onClick={props.onClose}>\n Close\n </button>\n </>\n ),\n };\n }\n return {\n step: 'plan',\n view: 'plan',\n body: (\n <>\n {merchant}\n <h2 id={titleId}>{plan.name}</h2>\n <Price plan={plan} every={every} single={single} />\n {ends ? (\n <p data-mesub-ends=\"\">\n {single\n ? `Access until ${ends}, when the plan ends. Nothing more is charged.`\n : `Ends on ${ends}`}\n </p>\n ) : null}\n {plan.description ? <p data-mesub-description=\"\">{plan.description}</p> : null}\n <button type=\"button\" data-mesub-submit=\"\" onClick={props.onContinue}>\n Continue with a wallet\n </button>\n <button type=\"button\" data-mesub-cancel=\"\" onClick={props.onClose}>\n Cancel\n </button>\n </>\n ),\n };\n }\n\n const { wallet, account } = view.signer;\n\n if (view.name === 'preparing') {\n return {\n step: 'wallet',\n view: 'preparing',\n onBack: props.onWallets,\n body: (\n <>\n <Hero kind=\"wait\" icon={wallet.icon} />\n <h2 id={titleId}>Preparing your subscription</h2>\n <p data-mesub-notice=\"\" role=\"status\" aria-busy=\"true\">\n Nothing to sign yet\n </p>\n </>\n ),\n };\n }\n\n if (view.name === 'review') {\n const { terms } = view.prepared;\n const nextCharge = new Date(Date.now() + plan.period_hours * 3_600_000);\n // Nor a date past the plan's end, whatever the terms say: the row would promise a charge.\n const chargedAgain = !single && !chargedOnce(plan);\n return {\n step: 'review',\n view: 'review',\n onBack: props.onWallets,\n body: (\n <>\n {merchant}\n <h2 id={titleId}>{plan.name}</h2>\n <Price plan={plan} every={every} single={single} />\n {view.notice ? (\n <p data-mesub-notice=\"\" role=\"status\">\n {view.notice}\n </p>\n ) : null}\n {/* Two facts only: the price is above, and the wallet shows the SOL it costs. */}\n <dl data-mesub-summary=\"\">\n <div data-mesub-row=\"\">\n <dt>Pays from</dt>\n <dd title={account.address}>\n <img src={wallet.icon} alt=\"\" width={16} height={16} />\n {shortAddress(account.address)}\n </dd>\n </div>\n {chargedAgain ? (\n <div data-mesub-row=\"\">\n <dt>Next charge</dt>\n <dd>{moment(nextCharge.toISOString())}</dd>\n </div>\n ) : null}\n {ends ? (\n <div data-mesub-row=\"\">\n {/* One charge: the plan's end is where the access bought stops. */}\n <dt>{single ? 'Access until' : 'Plan ends'}</dt>\n <dd>{ends}</dd>\n </div>\n ) : null}\n </dl>\n <details data-mesub-terms=\"\">\n <summary>The terms you sign</summary>\n {/* A plain list, the rows of the one above: what a person needs of the terms. */}\n <dl data-mesub-summary=\"\">\n {termsFacts(terms.message, plan).map((fact) => (\n <div data-mesub-row=\"\" key={fact.label}>\n <dt>{fact.label}</dt>\n <dd title={fact.full}>\n {fact.href ? (\n <a\n data-mesub-token=\"\"\n href={fact.href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {fact.value}\n </a>\n ) : (\n fact.value\n )}\n {fact.note ? <small> {fact.note}</small> : null}\n </dd>\n </div>\n ))}\n </dl>\n </details>\n {/* Last before the button: what clicking it starts. */}\n <p data-mesub-footnote=\"\">\n Two approvals in {wallet.name}: the terms, then the payment.{' '}\n {single ? 'Nothing more is charged.' : 'Cancel anytime.'}\n </p>\n <button\n type=\"button\"\n data-mesub-submit=\"\"\n title={exact}\n data-mesub-fit={fit(price)}\n onClick={() => props.onSign(view.signer, view.prepared)}\n >\n Sign and pay {price}\n </button>\n <button type=\"button\" data-mesub-cancel=\"\" onClick={props.onClose}>\n Cancel\n </button>\n </>\n ),\n };\n }\n\n if (view.name === 'signing') {\n const terms = view.what === 'terms';\n const notice = view.notice ? (\n <p data-mesub-notice=\"\" role=\"status\">\n {view.notice}\n </p>\n ) : null;\n if (view.what === 'fresh') {\n return {\n step: 'approve',\n view: 'approve-fresh',\n onBack: props.onWallets,\n body: (\n <>\n <Hero kind=\"wait\" icon={wallet.icon} />\n <h2 id={titleId}>Preparing the payment</h2>\n {notice}\n <p data-mesub-notice=\"\" role=\"status\" aria-busy=\"true\">\n Nothing to approve yet\n </p>\n <button type=\"button\" data-mesub-cancel=\"\" onClick={props.onClose}>\n Cancel\n </button>\n </>\n ),\n };\n }\n return {\n step: 'approve',\n view: `approve-${view.what}`,\n onBack: props.onWallets,\n body: (\n <>\n <Hero kind=\"wait\" icon={wallet.icon} />\n <h2 id={titleId}>\n {terms ? 'Sign the terms' : 'Approve the payment'} in {wallet.name}\n </h2>\n <p title={terms ? undefined : exact}>\n {terms\n ? 'Step 1 of 2: a message, it moves nothing.'\n : single\n ? `Step 2 of 2: ${price} now, a single charge.`\n : `Step 2 of 2: ${price} now, then ${price} ${every}.`}\n </p>\n {notice}\n <button type=\"button\" data-mesub-cancel=\"\" onClick={props.onClose}>\n Cancel\n </button>\n </>\n ),\n };\n }\n\n if (view.name === 'submitting') {\n return {\n step: 'confirming',\n view: 'confirming',\n body: (\n <>\n <Hero kind=\"wait\" icon={plan.logo_url} />\n <h2 id={titleId}>Confirming on Solana</h2>\n <p>This can take up to a minute.</p>\n {view.notice ? (\n <p data-mesub-notice=\"\" role=\"status\">\n {view.notice}\n </p>\n ) : null}\n {view.signature ? (\n <Explorer\n signature={view.signature}\n chain={chain}\n label=\"View transaction\"\n />\n ) : null}\n </>\n ),\n };\n }\n\n // Signed as one charge: no next one is announced, whatever came back.\n const nextCharge = view.single ? null : moment(view.subscription.next_charge_at);\n // One charge: access stops at the plan's end, written as it was before signing.\n const accessUntil = view.single ? (ends ?? moment(view.subscription.access_until)) : null;\n const manage = manageLink(props.manageUrl, view.cancelUrl);\n\n return {\n step: 'subscribed',\n view: 'subscribed',\n body: (\n <>\n <Hero kind=\"check\" />\n <h2 id={titleId}>You are subscribed</h2>\n <p title={exact}>\n {plan.name}, {price} {every}\n </p>\n <dl data-mesub-summary=\"\">\n <div data-mesub-row=\"\">\n <dt>Paid today</dt>\n <dd title={exact}>\n {price}\n {planUsd(plan) ? <small>{planUsd(plan)}</small> : null}\n </dd>\n </div>\n {nextCharge ? (\n <div data-mesub-row=\"\">\n <dt>Next charge</dt>\n <dd>{nextCharge}</dd>\n </div>\n ) : null}\n {accessUntil ? (\n <div data-mesub-row=\"\">\n <dt>Access until</dt>\n <dd>{accessUntil}</dd>\n </div>\n ) : null}\n <div data-mesub-row=\"\">\n <dt>Pays from</dt>\n <dd title={account.address}>\n <img src={wallet.icon} alt=\"\" width={16} height={16} />\n {shortAddress(account.address)}\n </dd>\n </div>\n {view.signature ? (\n <div data-mesub-row=\"\">\n <dt>Receipt</dt>\n <dd>\n <Explorer signature={view.signature} chain={chain} label=\"View\" />\n </dd>\n </div>\n ) : null}\n </dl>\n <button type=\"button\" data-mesub-done=\"\" onClick={props.onClose}>\n Done\n </button>\n {/* Only once it runs: where it is stopped is of no use before. */}\n {manage ? (\n <a\n data-mesub-manage=\"\"\n data-mesub-external={manage.external ? '' : undefined}\n href={manage.href}\n // The merchant's own page opens in place; Mesub's, in a tab of its own.\n {...(manage.external && { target: '_blank', rel: 'noopener noreferrer' })}\n >\n Cancel any time\n </a>\n ) : null}\n </>\n ),\n };\n}\n","import { createContext, useContext } from 'react';\nimport type { MesubApi } from './api';\nimport type { MesubAction, MesubPlan, MesubSubscription } from './types';\nimport type { SolanaChain } from './wallet';\n\nexport type MesubTheme = 'light' | 'dark' | 'auto';\n\n/** Where a subscribe stands: `open` is the dialog up with nothing being signed. */\nexport type SubscribeState = 'idle' | 'open' | 'signing' | 'confirming' | 'subscribed';\n\nexport interface SubscribeRequest {\n plan: string;\n onState(state: SubscribeState): void;\n // `signature` is the transaction's id, when the wallet is its first signer.\n onSubscribed(subscription: MesubSubscription, signature: string | null): void;\n}\n\nexport interface ManageRequest {\n subscription: MesubSubscription;\n action: MesubAction;\n}\n\n/** What the provider hands to the hooks and the dialogs. Not part of the public API. */\nexport interface MesubInternal {\n api: MesubApi;\n chain: SolanaChain;\n // Set on the widget as data-mesub-theme; undefined leaves it to an ancestor.\n theme: MesubTheme | undefined;\n // Where \"Cancel any time\" leads: the merchant's own page, null for no button, undefined for Mesub's.\n manageUrl: string | null | undefined;\n // One read per slug, shared: a failed one is asked again next time.\n plan(slug: string): Promise<MesubPlan>;\n // Bumped when a subscription was made or changed: the lists read again.\n revision: number;\n // Opens the checkout. Resolves on close, with the subscription if it went through.\n subscribe(request: SubscribeRequest): Promise<MesubSubscription | null>;\n // Opens the cancel, resume or close dialog. Resolves on close.\n manage(request: ManageRequest): Promise<MesubSubscription | null>;\n // Opens the customer's subscription to that plan in a dialog: what the Manage button does.\n openSubscription(plan: string | undefined): void;\n}\n\nexport const MesubContext = createContext<MesubInternal | null>(null);\n\nexport function useMesubInternal(): MesubInternal {\n const value = useContext(MesubContext);\n if (!value) throw new Error('@mesub/react must be used inside <MesubProvider>');\n return value;\n}\n","import { Fragment, useEffect, useLayoutEffect, useRef, type ReactNode } from 'react';\nimport { MesubMark } from './brand';\nimport { useMesubInternal } from './context';\n\n// The first control of a screen: its first choice, or its primary button.\nconst FIRST_CONTROL =\n '[data-mesub-wallets] button:not(:disabled), [data-mesub-submit], [data-mesub-done], [data-mesub-install], [data-mesub-reload], [data-mesub-cancel]';\n\nexport interface DialogScreen {\n // data-mesub-step: what the CSS keys the progress line and layout on.\n step: string;\n // One per screen: a new one remounts the body, which replays its enter animation.\n view: string;\n // Draws the icon back, top left.\n onBack?: (() => void) | undefined;\n body: ReactNode;\n}\n\n/**\n * The native dialog every Mesub window is. Stays mounted across steps, so the\n * progress line animates between them; only the body is remounted.\n */\nexport function MesubDialog({\n screen,\n titleId,\n onClose,\n}: {\n screen: DialogScreen;\n titleId: string;\n onClose(): void;\n}) {\n const { theme } = useMesubInternal();\n const dialog = useRef<HTMLDialogElement>(null);\n\n // Layout effect: runs before the focus effect below, so showModal() does\n // not take the focus back from the first control.\n useLayoutEffect(() => {\n const node = dialog.current;\n if (node && !node.open) {\n if (typeof node.showModal === 'function') node.showModal();\n else node.setAttribute('open', '');\n }\n }, []);\n\n useEffect(() => {\n const node = dialog.current;\n const control = node?.querySelector<HTMLElement>(FIRST_CONTROL);\n (control ?? node?.querySelector<HTMLElement>('[data-mesub-close]'))?.focus();\n }, [screen.view]);\n\n return (\n <dialog\n ref={dialog}\n aria-labelledby={titleId}\n aria-modal=\"true\"\n data-mesub-dialog=\"\"\n data-mesub-step={screen.step}\n data-mesub-theme={theme}\n onCancel={(event) => {\n // Escape: the owner unmounts the dialog, not the browser.\n event.preventDefault();\n onClose();\n }}\n onClick={(event) => {\n // The backdrop is the dialog itself: a click outside its box landed on it.\n if (event.target !== event.currentTarget) return;\n const box = event.currentTarget.getBoundingClientRect();\n const inside =\n event.clientX >= box.left &&\n event.clientX <= box.right &&\n event.clientY >= box.top &&\n event.clientY <= box.bottom;\n if (!inside) onClose();\n }}\n onKeyDown={(event) => {\n if (event.key === 'Escape') {\n event.preventDefault();\n onClose();\n }\n }}\n >\n {/* Empty on purpose: the CSS draws both icons with :empty. */}\n {screen.onBack ? (\n <button\n type=\"button\"\n data-mesub-back=\"\"\n aria-label=\"Back\"\n onClick={screen.onBack}\n />\n ) : null}\n <button type=\"button\" data-mesub-close=\"\" aria-label=\"Close\" onClick={onClose} />\n <div data-mesub-brand=\"\">\n <MesubMark width={27} height={18} />\n mesub.io\n </div>\n <Fragment key={screen.view}>{screen.body}</Fragment>\n </dialog>\n );\n}\n","// The Mesub mark, traced from its artwork row by row: one path in currentColor.\nconst MARK =\n 'M68 0h12v1h-12zM64 1h19v1h-19zM62 2h24v1h-24zM60 3h28v1h-28zM58 4h32v1h-32zM56 5h35v1h-35zM55 6h38v1h-38zM54 7h40v1h-40zM52 8h43v1h-43zM51 9h18v1h-18zM78 9h18v1h-18zM50 10h16v1h-16zM82 10h15v1h-15zM50 11h13v1h-13zM84 11h14v1h-14zM49 12h13v1h-13zM86 12h12v1h-12zM48 13h12v1h-12zM87 13h12v1h-12zM47 14h12v1h-12zM88 14h12v1h-12zM47 15h11v1h-11zM89 15h11v1h-11zM46 16h11v1h-11zM90 16h11v1h-11zM46 17h10v1h-10zM91 17h10v1h-10zM45 18h10v1h-10zM92 18h10v1h-10zM45 19h10v1h-10zM92 19h10v1h-10zM44 20h10v1h-10zM93 20h10v1h-10zM44 21h9v1h-9zM93 21h10v1h-10zM43 22h10v1h-10zM94 22h10v1h-10zM43 23h9v1h-9zM94 23h11v1h-11zM27 24h4v1h-4zM43 24h9v1h-9zM72 24h2v1h-2zM95 24h10v1h-10zM22 25h15v1h-15zM43 25h9v1h-9zM70 25h6v1h-6zM96 25h10v1h-10zM19 26h20v1h-20zM43 26h8v1h-8zM69 26h8v1h-8zM96 26h10v1h-10zM17 27h24v1h-24zM42 27h9v1h-9zM69 27h8v1h-8zM97 27h10v1h-10zM15 28h36v1h-36zM69 28h9v1h-9zM97 28h10v1h-10zM14 29h37v1h-37zM69 29h9v1h-9zM98 29h10v1h-10zM12 30h39v1h-39zM69 30h10v1h-10zM98 30h10v1h-10zM11 31h40v1h-40zM69 31h10v1h-10zM99 31h10v1h-10zM10 32h41v1h-41zM70 32h10v1h-10zM99 32h10v1h-10zM9 33h19v1h-19zM31 33h20v1h-20zM70 33h10v1h-10zM100 33h10v1h-10zM8 34h15v1h-15zM35 34h16v1h-16zM71 34h10v1h-10zM101 34h10v1h-10zM7 35h14v1h-14zM38 35h13v1h-13zM71 35h11v1h-11zM101 35h10v1h-10zM6 36h13v1h-13zM39 36h13v1h-13zM72 36h10v1h-10zM102 36h10v1h-10zM6 37h12v1h-12zM40 37h12v1h-12zM73 37h10v1h-10zM102 37h10v1h-10zM5 38h11v1h-11zM42 38h10v1h-10zM73 38h10v1h-10zM103 38h10v1h-10zM4 39h11v1h-11zM43 39h10v1h-10zM74 39h10v1h-10zM103 39h10v1h-10zM4 40h10v1h-10zM43 40h10v1h-10zM74 40h10v1h-10zM104 40h10v1h-10zM3 41h11v1h-11zM44 41h10v1h-10zM75 41h10v1h-10zM104 41h10v1h-10zM3 42h10v1h-10zM45 42h10v1h-10zM75 42h10v1h-10zM105 42h10v1h-10zM2 43h10v1h-10zM45 43h10v1h-10zM76 43h10v1h-10zM106 43h9v1h-9zM2 44h10v1h-10zM46 44h10v1h-10zM76 44h10v1h-10zM106 44h10v1h-10zM2 45h9v1h-9zM46 45h10v1h-10zM77 45h10v1h-10zM107 45h10v1h-10zM1 46h10v1h-10zM47 46h10v1h-10zM78 46h9v1h-9zM107 46h10v1h-10zM1 47h9v1h-9zM47 47h10v1h-10zM78 47h10v1h-10zM108 47h10v1h-10zM1 48h9v1h-9zM48 48h10v1h-10zM79 48h10v1h-10zM108 48h10v1h-10zM0 49h10v1h-10zM48 49h10v1h-10zM79 49h10v1h-10zM109 49h10v1h-10zM0 50h9v1h-9zM27 50h4v1h-4zM49 50h10v1h-10zM80 50h10v1h-10zM109 50h10v1h-10zM0 51h9v1h-9zM25 51h7v1h-7zM49 51h10v1h-10zM80 51h10v1h-10zM110 51h10v1h-10zM0 52h9v1h-9zM25 52h8v1h-8zM50 52h10v1h-10zM81 52h10v1h-10zM111 52h9v1h-9zM0 53h9v1h-9zM25 53h8v1h-8zM51 53h10v1h-10zM81 53h10v1h-10zM111 53h10v1h-10zM0 54h9v1h-9zM25 54h9v1h-9zM51 54h10v1h-10zM82 54h10v1h-10zM112 54h9v1h-9zM0 55h9v1h-9zM25 55h10v1h-10zM52 55h10v1h-10zM82 55h10v1h-10zM112 55h10v1h-10zM0 56h9v1h-9zM25 56h10v1h-10zM52 56h10v1h-10zM83 56h10v1h-10zM113 56h10v1h-10zM0 57h9v1h-9zM26 57h10v1h-10zM53 57h10v1h-10zM84 57h9v1h-9zM113 57h10v1h-10zM0 58h9v1h-9zM26 58h10v1h-10zM53 58h10v1h-10zM84 58h10v1h-10zM114 58h10v1h-10zM1 59h9v1h-9zM27 59h10v1h-10zM54 59h10v1h-10zM85 59h10v1h-10zM114 59h10v1h-10zM1 60h9v1h-9zM27 60h10v1h-10zM54 60h10v1h-10zM85 60h10v1h-10zM115 60h10v1h-10zM1 61h9v1h-9zM28 61h10v1h-10zM55 61h10v1h-10zM86 61h10v1h-10zM115 61h10v1h-10zM1 62h10v1h-10zM28 62h10v1h-10zM56 62h9v1h-9zM86 62h10v1h-10zM116 62h10v1h-10zM2 63h9v1h-9zM29 63h10v1h-10zM56 63h10v1h-10zM87 63h10v1h-10zM116 63h10v1h-10zM2 64h10v1h-10zM29 64h10v1h-10zM57 64h9v1h-9zM87 64h10v1h-10zM117 64h10v1h-10zM2 65h10v1h-10zM30 65h10v1h-10zM57 65h10v1h-10zM88 65h10v1h-10zM118 65h9v1h-9zM3 66h10v1h-10zM30 66h10v1h-10zM58 66h10v1h-10zM88 66h10v1h-10zM118 66h10v1h-10zM3 67h10v1h-10zM31 67h10v1h-10zM58 67h10v1h-10zM89 67h10v1h-10zM119 67h9v1h-9zM4 68h10v1h-10zM32 68h9v1h-9zM59 68h10v1h-10zM89 68h10v1h-10zM119 68h10v1h-10zM5 69h10v1h-10zM32 69h10v1h-10zM59 69h10v1h-10zM90 69h10v1h-10zM120 69h10v1h-10zM5 70h10v1h-10zM33 70h10v1h-10zM60 70h10v1h-10zM91 70h9v1h-9zM120 70h10v1h-10zM6 71h10v1h-10zM33 71h10v1h-10zM60 71h10v1h-10zM91 71h10v1h-10zM121 71h10v1h-10zM6 72h10v1h-10zM34 72h10v1h-10zM61 72h10v1h-10zM92 72h9v1h-9zM121 72h10v1h-10zM7 73h10v1h-10zM34 73h10v1h-10zM61 73h10v1h-10zM92 73h10v1h-10zM122 73h10v1h-10zM7 74h10v1h-10zM35 74h10v1h-10zM62 74h10v1h-10zM93 74h10v1h-10zM123 74h9v1h-9zM8 75h10v1h-10zM35 75h10v1h-10zM63 75h9v1h-9zM93 75h10v1h-10zM123 75h10v1h-10zM8 76h10v1h-10zM36 76h10v1h-10zM63 76h10v1h-10zM94 76h10v1h-10zM124 76h9v1h-9zM9 77h10v1h-10zM36 77h10v1h-10zM64 77h9v1h-9zM94 77h10v1h-10zM124 77h10v1h-10zM9 78h10v1h-10zM37 78h10v1h-10zM64 78h10v1h-10zM95 78h10v1h-10zM125 78h9v1h-9zM10 79h10v1h-10zM37 79h10v1h-10zM65 79h10v1h-10zM95 79h10v1h-10zM125 79h10v1h-10zM11 80h10v1h-10zM38 80h10v1h-10zM65 80h10v1h-10zM96 80h10v1h-10zM126 80h10v1h-10zM11 81h10v1h-10zM39 81h9v1h-9zM66 81h10v1h-10zM97 81h9v1h-9zM126 81h10v1h-10zM12 82h10v1h-10zM39 82h10v1h-10zM66 82h10v1h-10zM97 82h10v1h-10zM127 82h10v1h-10zM12 83h10v1h-10zM40 83h9v1h-9zM67 83h10v1h-10zM98 83h9v1h-9zM127 83h10v1h-10zM13 84h10v1h-10zM40 84h10v1h-10zM67 84h10v1h-10zM98 84h10v1h-10zM128 84h10v1h-10zM13 85h10v1h-10zM41 85h9v1h-9zM68 85h10v1h-10zM99 85h9v1h-9zM129 85h9v1h-9zM14 86h10v1h-10zM41 86h10v1h-10zM68 86h10v1h-10zM99 86h10v1h-10zM129 86h10v1h-10zM14 87h10v1h-10zM42 87h10v1h-10zM69 87h10v1h-10zM99 87h10v1h-10zM130 87h9v1h-9zM15 88h37v1h-37zM70 88h40v1h-40zM130 88h10v1h-10zM16 89h37v1h-37zM70 89h40v1h-40zM131 89h9v1h-9zM16 90h37v1h-37zM71 90h40v1h-40zM131 90h10v1h-10zM17 91h37v1h-37zM71 91h40v1h-40zM132 91h10v1h-10zM17 92h37v1h-37zM72 92h40v1h-40zM132 92h10v1h-10zM18 93h37v1h-37zM72 93h40v1h-40zM133 93h10v1h-10zM18 94h37v1h-37zM73 94h40v1h-40zM133 94h10v1h-10zM19 95h37v1h-37zM73 95h40v1h-40zM134 95h10v1h-10z';\n\n/** The Mesub mark in currentColor: one asset for both themes. */\nexport function MesubMark({ width, height }: { width: number; height: number }) {\n return (\n <svg\n width={width}\n height={height}\n viewBox=\"0 0 144 96\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path d={MARK} />\n </svg>\n );\n}\n\n// Placeholders for wallets that are not installed: no adapter hands us their icon.\nexport const INSTALL_ICONS = {\n Phantom:\n 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cmVjdCB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHJ4PSI2IiBmaWxsPSIjM2EzZDQ3Ii8+PHBhdGggZD0iTTggMTZWOGg0LjVhMi41IDIuNSAwIDAgMSAwIDVIOCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjEuNiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+PC9zdmc+',\n Solflare:\n 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cmVjdCB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHJ4PSI2IiBmaWxsPSIjNWE1ZjZiIi8+PHBhdGggZD0iTTE1LjUgOS4yQzE1IDguNSAxMy45IDggMTIuNSA4IDEwLjggOCA5LjUgOC44IDkuNSAxMHMxLjIgMS43IDMgMiAzIC44IDMgMi0xLjMgMi0zIDJjLTEuNCAwLTIuNS0uNS0zLTEuMiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjEuNiIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+PC9zdmc+',\n} as const;\n","import type { MesubPlan } from './types';\nimport type { SolanaChain } from './wallet';\n\n/** `2000000` at 6 decimals is `2`, `2500000` is `2.5`: exact, no float. */\nexport function formatAmount(amount: string, decimals: number): string {\n const units = BigInt(amount);\n const scale = 10n ** BigInt(decimals);\n const whole = (units / scale).toString();\n const fraction = (units % scale).toString().padStart(decimals, '0').replace(/0+$/, '');\n return fraction ? `${whole}.${fraction}` : whole;\n}\n\n/** `30000` is `30,000`, `1234.5` is `1,234.5`: one grouping, whatever the browser's locale. */\nexport function grouped(display: string): string {\n const [whole = '', fraction] = display.split('.');\n if (!/^\\d+$/.test(whole)) return display;\n const spaced = whole.replace(/\\B(?=(\\d{3})+$)/g, ',');\n return fraction === undefined ? spaced : `${spaced}.${fraction}`;\n}\n\n/** Decimal dollars as `$0.10` or `$1,234.50`; under a cent, `less than $0.01`. Null when unreadable. */\nexport function formatUsd(value: string | null | undefined): string | null {\n if (typeof value !== 'string' || !/^\\d+(\\.\\d+)?$/.test(value)) return null;\n const dollars = Number(value);\n if (!Number.isFinite(dollars) || dollars >= 1e15) return null;\n if (dollars < 0.01) return 'less than $0.01';\n return `$${grouped(dollars.toFixed(2))}`;\n}\n\n/** An estimate says so: `about $0.10`. */\nexport function aboutUsd(value: string | null | undefined): string | null {\n const usd = formatUsd(value);\n if (!usd) return null;\n return usd.startsWith('less') ? usd : `about ${usd}`;\n}\n\nconst SYMBOL_MAX = 12;\nconst NAME_MAX = 32;\n/** The stablecoins Mesub vouches for: an unverified token never reads as one. */\nconst VOUCHED = new Set(['USDC', 'USDT', 'PYUSD']);\n\n/** A token's own text, untrusted: no control or invisible character, one line, cut short. */\nfunction clean(text: unknown, max: number): string | null {\n if (typeof text !== 'string') return null;\n const plain = text\n .replace(/[\\p{Cc}\\p{Cf}]/gu, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n if (!plain) return null;\n const letters = Array.from(plain);\n return letters.length > max ? `${letters.slice(0, max).join('')}…` : plain;\n}\n\n/** How a plan's token reads on screen. */\nexport interface TokenText {\n // The symbol, or the short mint when it has none.\n unit: string;\n // Whether `unit` is a symbol.\n named: boolean;\n name: string | null;\n // An https image of a verified token, else null.\n logo: string | null;\n // Said by Mesub, not guessed: false against a server that predates `token`.\n unverified: boolean;\n // Its amount is its dollar value: no estimate beside it.\n vouched: boolean;\n shortMint: string;\n}\n\ntype Priced = Pick<MesubPlan, 'symbol' | 'mint' | 'token'>;\n\nfunction httpsUrl(value: unknown): string | null {\n if (typeof value !== 'string') return null;\n try {\n return new URL(value).protocol === 'https:' ? value : null;\n } catch {\n return null;\n }\n}\n\n/** The token of a plan: `token.symbol`, else the vouched `symbol`, else the short mint. */\nexport function tokenOf(plan: Priced): TokenText {\n const token = typeof plan.token === 'object' && plan.token !== null ? plan.token : null;\n const vouched = typeof plan.symbol === 'string' && plan.symbol !== '';\n const verified = vouched || token?.verified === true;\n const unverified = token !== null && !verified;\n const shortMint = shortAddress(plan.mint);\n\n let symbol =\n clean(token?.symbol, SYMBOL_MAX) ?? (vouched ? clean(plan.symbol, SYMBOL_MAX) : null);\n let name = clean(token?.name, NAME_MAX);\n // Mesub already drops these: said again here, the widget trusts no unverified text.\n if (unverified && symbol && VOUCHED.has(symbol.toUpperCase())) symbol = null;\n if (unverified && name && VOUCHED.has(name.toUpperCase())) name = null;\n\n return {\n unit: symbol ?? shortMint,\n named: symbol !== null,\n name,\n logo: verified ? httpsUrl(token?.logo_url) : null,\n unverified,\n vouched,\n shortMint,\n };\n}\n\n/** The one way an amount is written: `30,000 Bonk`, `1 USDC`, `30,000 DezX…B263`. */\nexport function priceOf(plan: Priced & Pick<MesubPlan, 'amount_display'>): string {\n return `${grouped(plan.amount_display)} ${tokenOf(plan).unit}`;\n}\n\nconst UNITS = ['K', 'M', 'B', 'T'];\n\n/**\n * `30000` is `30K`, `30500` is `30.5K`, `6000000000` is `6B`: from 10,000 up,\n * under 1e15, and only when nothing is lost at two decimals. Null when the\n * amount stays in full. On the digits as text: never rounded, never a float.\n */\nexport function short(display: string): string | null {\n if (!/^\\d+$/.test(display)) return null;\n const digits = display.replace(/^0+(?=\\d)/, '');\n if (digits.length < 5 || digits.length > 15) return null;\n\n // The largest unit it reaches: K for 5 or 6 digits, T for 13 to 15.\n const unit = Math.floor((digits.length - 1) / 3);\n const cut = digits.length - unit * 3;\n const rest = digits.slice(cut);\n if (/[1-9]/.test(rest.slice(2))) return null;\n\n const decimals = rest.slice(0, 2).replace(/0+$/, '');\n return `${digits.slice(0, cut)}${decimals ? `.${decimals}` : ''}${UNITS[unit - 1]}`;\n}\n\n/** An amount where it is read fast. `title` is the exact one, set only when `text` is short. */\nexport interface Brief {\n text: string;\n title: string | undefined;\n}\n\n/** Short when the rule allows and the token is no vouched stablecoin, in full otherwise. */\nexport function brief(display: string, vouched: boolean, unit = ''): Brief {\n const full = `${grouped(display)}${unit}`;\n const cut = vouched ? null : short(display);\n\n return cut ? { text: `${cut}${unit}`, title: full } : { text: full, title: undefined };\n}\n\n/** `priceOf` where it is read fast: `30K Bonk`, `1,500 USDC`, `30,512 Bonk`. */\nexport function briefPrice(plan: Priced & Pick<MesubPlan, 'amount_display'>): Brief {\n const token = tokenOf(plan);\n\n return brief(plan.amount_display, token.vouched, ` ${token.unit}`);\n}\n\n/** How far a long amount shrinks to stay in its box, for `data-mesub-fit`. None at ordinary lengths. */\nexport function fit(text: string): '2' | '3' | '4' | undefined {\n const length = Array.from(text).length;\n if (length > 30) return '4';\n if (length > 18) return '3';\n return length > 14 ? '2' : undefined;\n}\n\n/** The plan's dollar value as an estimate, or null: never beside a vouched stablecoin. */\nexport function planUsd(plan: Priced & Pick<MesubPlan, 'amount_usd'>): string | null {\n return tokenOf(plan).vouched ? null : aboutUsd(plan.amount_usd);\n}\n\n/** The one line an unverified token gets, with the mint to check it against. Null otherwise. */\nexport function unverifiedNote(plan: Priced): string | null {\n const token = tokenOf(plan);\n if (!token.unverified) return null;\n return token.name\n ? `Unverified token: ${token.name}, mint ${token.shortMint}`\n : `Unverified token, mint ${token.shortMint}`;\n}\n\nconst NAMED: Record<number, string> = { 24: 'day', 168: 'week', 720: 'month', 8760: 'year' };\n\n/** `every month`, `every 3 days`, `every 6 hours`: the dashboard's own names. */\nexport function cadence(hours: number): string {\n const named = NAMED[hours];\n if (named) return `every ${named}`;\n if (hours % 24 === 0) return `every ${hours / 24} days`;\n return hours === 1 ? 'every hour' : `every ${hours} hours`;\n}\n\n/** Lamports as SOL: `2039280` is `0.00203928 SOL`. */\nexport function formatSol(lamports: string): string {\n return `${formatAmount(lamports, 9)} SOL`;\n}\n\n/** `Oct 4, 2026`, in the subscriber's own locale. */\nexport function formatDate(date: Date): string {\n return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' });\n}\n\n/** `Oct 4`: a date in a list of them, where the year is not in doubt. Null when there is none. */\nexport function shortDay(iso: string | null | undefined): string | null {\n if (!iso) return null;\n const date = new Date(iso);\n return Number.isNaN(date.getTime())\n ? null\n : date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n}\n\n/** An ISO date as `formatDate` writes it, or null when there is none to show. */\nexport function day(iso: string | null | undefined): string | null {\n if (!iso) return null;\n const date = new Date(iso);\n return Number.isNaN(date.getTime()) ? null : formatDate(date);\n}\n\n/** Within two days either way, the hour matters: an hourly plan's dates all fall on one day. */\nconst CLOSE_MS = 48 * 3_600_000;\n\nfunction written(\n iso: string | null | undefined,\n far: Intl.DateTimeFormatOptions,\n now: number,\n): string | null {\n if (!iso) return null;\n const date = new Date(iso);\n if (Number.isNaN(date.getTime())) return null;\n if (Math.abs(date.getTime() - now) >= CLOSE_MS) return date.toLocaleDateString(undefined, far);\n\n return date.toLocaleString(undefined, {\n ...far,\n hour: 'numeric',\n minute: '2-digit',\n // The subscriber's own zone, named: an hour alone could be anyone's.\n timeZoneName: 'short',\n });\n}\n\n/** A charge or an end as `day` writes it, with its hour when it is close: `Oct 5, 2026, 3:00 PM GMT+2`. */\nexport function moment(iso: string | null | undefined, now = Date.now()): string | null {\n return written(iso, { month: 'short', day: 'numeric', year: 'numeric' }, now);\n}\n\n/** `shortDay` with the hour when it is close: `Oct 5, 3:00 PM GMT+2`. */\nexport function shortMoment(iso: string | null | undefined, now = Date.now()): string | null {\n return written(iso, { month: 'short', day: 'numeric' }, now);\n}\n\nconst MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\nconst two = (n: number) => String(n).padStart(2, '0');\n\n/**\n * A plan's end, always with its time and in UTC: `Oct 20, 2026, 23:59 UTC`.\n * A plan ends on any second, not on a day, and the same words for everyone,\n * whatever their zone. Seconds are dropped: 23:59:59 reads 23:59.\n */\nexport function planEnd(iso: string | null | undefined): string | null {\n if (!iso) return null;\n const date = new Date(iso);\n if (Number.isNaN(date.getTime())) return null;\n\n return (\n `${MONTHS[date.getUTCMonth()]} ${date.getUTCDate()}, ${date.getUTCFullYear()}, ` +\n `${two(date.getUTCHours())}:${two(date.getUTCMinutes())} UTC`\n );\n}\n\nexport function shortAddress(address: string): string {\n return `${address.slice(0, 4)}…${address.slice(-4)}`;\n}\n\n/** The transaction on Solana Explorer, on the network it was sent to. */\nexport function explorerUrl(signature: string, chain: SolanaChain): string {\n const cluster = chain === 'solana:mainnet' ? '' : `?cluster=${chain.slice('solana:'.length)}`;\n return `https://explorer.solana.com/tx/${signature}${cluster}`;\n}\n\n/** One line of the terms the wallet signs: a fact with its name, or a plain sentence. */\nexport interface TermsLine {\n label: string | null;\n value: string;\n}\n\n/**\n * The terms message, line by line, for a list rather than a block of text.\n * Nothing is dropped nor reworded: it is what the wallet is about to sign. The\n * first line is its heading, and a line with no `Name: value` shape stays a\n * sentence.\n */\nexport function termsLines(message: string): TermsLine[] {\n return message\n .split('\\n')\n .filter((line) => line.trim() !== '')\n .map((line, index) => {\n const named = index === 0 ? null : /^([A-Za-z][A-Za-z ]{0,30}): (.+)$/.exec(line);\n\n return named ? { label: named[1]!, value: named[2]! } : { label: null, value: line };\n });\n}\n\n/** The line that says where a subscription is stopped: a link, not a fact to read. */\nconst CANCEL_LABEL = 'Cancel any time';\n\n/** Where the terms say the subscription can be cancelled, when it is a web address. */\nexport function termsCancelUrl(message: string): string | null {\n const line = termsLines(message).find((each) => each.label === CANCEL_LABEL);\n\n return line && /^https?:\\/\\/\\S+$/.test(line.value) ? line.value : null;\n}\n\n/**\n * Whether the terms say the first charge is the only one, as Mesub writes it:\n * `Amount: 2 USDC, a single charge`. Null when they name no amount at all.\n */\nexport function termsSingleCharge(message: string): boolean | null {\n const lines = termsLines(message);\n const amount = lines.find((each) => each.label === 'Amount');\n if (amount) return amount.value.endsWith(', a single charge');\n\n return lines.some((each) => each.label === 'Single charge') ? true : null;\n}\n\n/** Mesub runs no charge this close to a plan's end: the margin its clock keeps against the chain's. */\nconst END_MARGIN_MS = 120_000;\n\n/** Whether a plan ending at `endsAt` rules out a charge due at `dueMs`. Never on a plan with no end. */\nexport function noChargeAt(dueMs: number, endsAt: string | null | undefined): boolean {\n const end = endsAt ? Date.parse(endsAt) : NaN;\n\n return !Number.isNaN(end) && dueMs + END_MARGIN_MS > end;\n}\n\n/**\n * Whether subscribing now leaves one charge only: the period paid starts when\n * the transaction lands, the margin before now at the earliest, and no charge\n * runs at its end once the plan's is that close.\n */\nexport function chargedOnce(\n plan: { period_hours: number; ends_at: string | null },\n now = Date.now(),\n): boolean {\n return noChargeAt(now - END_MARGIN_MS + plan.period_hours * 3_600_000, plan.ends_at);\n}\n\n/** Where \"Cancel any time\" leads, and whether it leaves the site. */\nexport interface ManageLink {\n href: string;\n external: boolean;\n}\n\n/**\n * Where a subscriber goes to stop: your own page when you named one, a path\n * on your site or a full address; Mesub's, as the terms give it, otherwise.\n * `null` shows no button at all. An address that is neither falls back to\n * Mesub's rather than become a link to anything.\n */\nexport function manageLink(\n yours: string | null | undefined,\n fromTerms: string | null,\n): ManageLink | null {\n if (yours === null) return null;\n if (typeof yours === 'string') {\n if (/^\\/(?!\\/)\\S*$/.test(yours)) return { href: yours, external: false };\n if (/^https?:\\/\\/\\S+$/.test(yours)) return { href: yours, external: true };\n }\n\n return fromTerms ? { href: fromTerms, external: true } : null;\n}\n\n/** Lines of the terms a person does not read: said elsewhere on the screen, or for machines. */\nconst NOT_SHOWN = new Set([\n // Also on a single charge: its own line says it, in full.\n 'Amount',\n 'Plan',\n 'Plan details',\n 'Wallet',\n 'Nonce',\n 'Expires',\n // The merchant may change where it is paid: not a term a subscriber holds them to.\n 'Paid to',\n // Shown as a button under the list.\n CANCEL_LABEL,\n]);\n\nconst ADDRESS = /[1-9A-HJ-NP-Za-km-z]{32,44}/;\n\n/** One fact of the terms, as the review lists it. `full` is the whole value when it was shortened. */\nexport interface TermsFact {\n label: string;\n value: string;\n full?: string;\n /** Where the value leads, when it is worth a click: the token's page on Jupiter. */\n href?: string;\n /** A short line under the value: \"Unverified token\". */\n note?: string;\n}\n\nconst escaped = (text: string) => text.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n/** The plan's amount where a term states it (`30000 tokens`, `2 USDC`), as the screen writes it. */\nfunction repriced(value: string, plan: TermsPlan): string {\n const units = ['tokens', ...(plan.symbol ? [escaped(plan.symbol)] : [])].join('|');\n const said = new RegExp(\n `(^|[^\\\\d.,])${escaped(plan.amount_display)} (?:${units})(?![\\\\w.])`,\n 'g',\n );\n // A token with no symbol stays \"tokens\": its mint is on the Token line.\n const price = tokenOf(plan).named ? priceOf(plan) : `${grouped(plan.amount_display)} tokens`;\n\n return value.replace(said, (_, before: string) => `${before}${price}`);\n}\n\ntype TermsPlan = Pick<MesubPlan, 'symbol' | 'mint' | 'token' | 'amount_display'>;\n\n/** The token's page on Jupiter, where it is bought or swapped. */\nexport function jupiterUrl(mint: string): string {\n return `https://jup.ag/tokens/${mint}`;\n}\n\n/**\n * The terms as a short list a person reads: the first charge, what follows\n * or that nothing does, when access stops on a plan that ends, which\n * subscription and in which token. The price, the wallet and the\n * lines meant for machines (the plan's address, the nonce, the expiry) are\n * left out, and addresses are shortened: the wallet shows the full text when\n * it asks to sign. With the plan, amounts and the token read as on the rest\n * of the screen; `full` stays the line as signed.\n */\nexport function termsFacts(message: string, plan?: TermsPlan): TermsFact[] {\n const token = plan ? tokenOf(plan) : null;\n const note = token?.unverified ? { note: 'Unverified token' } : {};\n\n return termsLines(message)\n .filter((line): line is { label: string; value: string } => line.label !== null)\n .filter((line) => !NOT_SHOWN.has(line.label))\n .map(({ label, value }) => {\n // \"USDC, mint 4zMM...\" is the token's name; a mint alone stays, shortened.\n const named = /^(.+), mint ([1-9A-HJ-NP-Za-km-z]{32,44})$/.exec(value);\n if (named) {\n return {\n label,\n value: named[1]!,\n full: value,\n href: jupiterUrl(named[2]!),\n ...(label === 'Token' && note),\n };\n }\n\n const address = ADDRESS.exec(value)?.[0];\n if (address) {\n const short = value.replace(address, shortAddress(address));\n // The plan's own mint, unnamed in the terms: Mesub's symbol beside it.\n const known = label === 'Token' && token?.named && address === plan?.mint;\n return {\n label,\n value: known ? `${token.unit}, ${short}` : short,\n full: value,\n // A mint with no name is still a token to get.\n ...(label === 'Token' && { href: jupiterUrl(address), ...note }),\n };\n }\n\n // The transaction comes right after: the screen's own button says so.\n const trimmed = value\n .replace(/, in the transaction you sign next$/, '')\n .replace(/^https?:\\/\\//, '');\n\n const shown = plan ? repriced(trimmed, plan) : trimmed;\n\n return shown === value ? { label, value } : { label, value: shown, full: value };\n });\n}\n","import type { UiWallet } from '@wallet-standard/react';\nimport { useState, type ReactNode } from 'react';\nimport { INSTALL_ICONS } from './brand';\nimport type { DialogScreen } from './dialog';\nimport { briefPrice, explorerUrl, fit, planUsd, tokenOf, unverifiedNote } from './format';\nimport type { MesubPlan } from './types';\nimport { isSolanaWallet, lacking, usable, type Purpose, type SolanaChain } from './wallet';\n\nconst LAST_WALLET_KEY = 'mesub:last-wallet';\n\nfunction lastWallet(): string | null {\n try {\n return localStorage.getItem(LAST_WALLET_KEY);\n } catch {\n return null;\n }\n}\n\nexport function rememberWallet(name: string) {\n try {\n localStorage.setItem(LAST_WALLET_KEY, name);\n } catch {\n // Storage refused: the badge is a nicety.\n }\n}\n\nexport function Hero({ kind, icon }: { kind: string; icon?: string | null | undefined }) {\n return (\n <div data-mesub-hero={kind} aria-hidden=\"true\">\n {icon ? <img src={icon} alt=\"\" width={56} height={56} /> : null}\n </div>\n );\n}\n\nexport function Explorer({\n signature,\n chain,\n label,\n}: {\n signature: string;\n chain: SolanaChain;\n label: string;\n}) {\n return (\n <a\n data-mesub-explorer=\"\"\n href={explorerUrl(signature, chain)}\n target=\"_blank\"\n rel=\"noopener\"\n >\n {label}\n </a>\n );\n}\n\ntype Token = Pick<MesubPlan, 'symbol' | 'mint' | 'token'>;\n\n/**\n * The token's image, before an amount: a verified token's only, over https.\n * Its box is fixed by the stylesheet, and one that fails to load is taken out.\n */\nexport function TokenLogo({ plan }: { plan: Token }) {\n const { logo } = tokenOf(plan);\n const [failed, setFailed] = useState<string | null>(null);\n if (!logo || failed === logo) return null;\n\n return (\n <img\n data-mesub-token-logo=\"\"\n src={logo}\n alt=\"\"\n width={20}\n height={20}\n loading=\"lazy\"\n decoding=\"async\"\n referrerPolicy=\"no-referrer\"\n onError={() => setFailed(logo)}\n />\n );\n}\n\n/** The price of a plan, on the checkout: the amount, how often, then what is worth knowing of the token. */\nexport function Price({\n plan,\n every,\n single,\n}: {\n plan: Token & Pick<MesubPlan, 'amount_display' | 'amount_usd'>;\n every: string;\n single: boolean;\n}) {\n const usd = planUsd(plan);\n const note = unverifiedNote(plan);\n const price = briefPrice(plan);\n\n return (\n <p data-mesub-price=\"\">\n {/* Short where it can be, the exact amount on hover; a long one shrinks. */}\n <strong title={price.title} data-mesub-fit={fit(price.text)}>\n <TokenLogo plan={plan} />\n {price.text}\n </strong>\n <span>{every}</span>\n {usd ? <small data-mesub-usd=\"\">{single ? usd : `${usd} ${every}`}</small> : null}\n {note ? (\n <small data-mesub-unverified=\"\" title={plan.mint}>\n {note}\n </small>\n ) : null}\n </p>\n );\n}\n\n/** Whose plan it is, above its name. */\nexport function Merchant({\n name,\n logoUrl,\n testNetwork,\n}: {\n name: string;\n logoUrl: string | null;\n testNetwork: boolean;\n}) {\n return (\n <div data-mesub-merchant=\"\">\n {logoUrl ? <img src={logoUrl} alt=\"\" width={56} height={56} /> : null}\n <strong>{name}</strong>\n {testNetwork ? <span data-mesub-network=\"devnet\">Test network</span> : null}\n </div>\n );\n}\n\nexport type WalletView =\n | { name: 'list' }\n | { name: 'waiting'; wallet: UiWallet }\n | { name: 'rejected'; wallet: UiWallet; message: string };\n\n/** The wallet step: the installed wallets, then waiting on one, or its refusal. */\nexport function walletScreen({\n titleId,\n view,\n wallets,\n purpose,\n lead,\n step = 'wallet',\n setView,\n pick,\n onBack,\n}: {\n titleId: string;\n view: WalletView;\n // Every installed wallet: the ones that cannot do it are named, not hidden.\n wallets: readonly UiWallet[];\n purpose: Purpose;\n lead: string;\n step?: string;\n setView(view: WalletView): void;\n pick(wallet: UiWallet): void;\n onBack(): void;\n}): DialogScreen {\n const toList = () => setView({ name: 'list' });\n\n if (view.name === 'waiting') {\n return {\n step,\n view: 'wallet-waiting',\n onBack: toList,\n body: (\n <>\n <Hero kind=\"wait\" icon={view.wallet.icon} />\n <h2 id={titleId}>Approve in {view.wallet.name}</h2>\n <p>Check the {view.wallet.name} window.</p>\n <button type=\"button\" data-mesub-back=\"\" onClick={toList}>\n Use another wallet\n </button>\n </>\n ),\n };\n }\n\n if (view.name === 'rejected') {\n return {\n step,\n view: 'wallet-rejected',\n onBack: toList,\n body: (\n <>\n <Hero kind=\"error\" icon={view.wallet.icon} />\n <h2 id={titleId}>Request rejected</h2>\n <p role=\"alert\" data-mesub-error=\"\">\n {view.message}\n </p>\n <button type=\"button\" data-mesub-submit=\"\" onClick={() => pick(view.wallet)}>\n Try again\n </button>\n <button type=\"button\" data-mesub-back=\"\" onClick={toList}>\n Use another wallet\n </button>\n </>\n ),\n };\n }\n\n const solana = wallets.filter(isSolanaWallet);\n const capable = solana.filter((wallet) => usable(wallet, purpose));\n const unable = solana.filter((wallet) => !usable(wallet, purpose));\n const reload = (\n <button type=\"button\" data-mesub-reload=\"\" onClick={() => window.location.reload()}>\n Reload\n </button>\n );\n\n if (solana.length === 0) {\n return {\n step,\n view: 'wallet-none',\n onBack,\n body: (\n <>\n <Hero kind=\"empty\" />\n <h2 id={titleId}>No Solana wallet found</h2>\n <p>Install one, then reload this page.</p>\n <div data-mesub-no-wallet=\"\">\n <a\n data-mesub-install=\"\"\n href=\"https://phantom.com\"\n target=\"_blank\"\n rel=\"noopener\"\n >\n <img src={INSTALL_ICONS.Phantom} alt=\"\" width={28} height={28} />\n Phantom<span>Install</span>\n </a>\n <a\n data-mesub-install=\"\"\n href=\"https://solflare.com\"\n target=\"_blank\"\n rel=\"noopener\"\n >\n <img src={INSTALL_ICONS.Solflare} alt=\"\" width={28} height={28} />\n Solflare<span>Install</span>\n </a>\n </div>\n {reload}\n </>\n ),\n };\n }\n\n // Installed, but missing what this takes: say which, and what it lacks.\n const cannot = unable.map(\n (wallet) => `${wallet.name} cannot ${lacking(wallet, purpose).join(' or ')}.`,\n );\n\n if (capable.length === 0) {\n return {\n step,\n view: 'wallet-unable',\n onBack,\n body: (\n <>\n <Hero kind=\"empty\" />\n <h2 id={titleId}>This wallet cannot do it</h2>\n <p>Use a wallet that can, such as Phantom or Solflare, then reload.</p>\n <p role=\"alert\" data-mesub-error=\"\">\n {cannot.join(' ')}\n </p>\n {reload}\n </>\n ),\n };\n }\n\n const last = lastWallet();\n return {\n step,\n view: 'wallet-list',\n onBack,\n body: (\n <>\n <h2 id={titleId}>Connect a wallet</h2>\n <p>{lead}</p>\n <ul data-mesub-wallets=\"\" aria-label=\"Wallets in this browser\">\n {capable.map((wallet) => (\n <li key={wallet.name}>\n <button\n type=\"button\"\n data-mesub-wallet={wallet.name}\n onClick={() => pick(wallet)}\n >\n <img src={wallet.icon} alt=\"\" width={28} height={28} />\n {wallet.name}\n {wallet.name === last ? (\n <span data-mesub-badge=\"\">Last used</span>\n ) : null}\n </button>\n </li>\n ))}\n </ul>\n {cannot.length > 0 ? (\n <p data-mesub-notice=\"\" role=\"note\">\n {cannot.join(' ')}\n </p>\n ) : null}\n </>\n ),\n };\n}\n\n/**\n * What went wrong, on the step it happened on. `moved` is the line that says\n * whether anything left the wallet: `safe` only when nothing can have landed.\n */\nexport interface Failure {\n step: string;\n title: string;\n message: ReactNode;\n moved: 'safe' | 'pending' | null;\n // The one primary action.\n action: 'retry' | 'check' | 'close' | 'wallet';\n // The wallet's icon where the wallet failed, the merchant's elsewhere.\n icon: 'wallet' | 'merchant';\n}\n\nconst PRIMARY: Record<Exclude<Failure['action'], 'close'>, string> = {\n retry: 'Try again',\n check: 'Check again',\n wallet: 'Use another wallet',\n};\n\nexport function failureScreen({\n failure,\n titleId,\n icon,\n safe,\n pending,\n signature,\n chain,\n busy,\n onAct,\n onBack,\n backLabel,\n}: {\n failure: Failure;\n titleId: string;\n icon: string | null | undefined;\n // The two money lines, in the flow's own words.\n safe: string;\n pending: string;\n signature: string | null;\n chain: SolanaChain;\n busy: boolean;\n onAct(action: Failure['action']): void;\n // Leaves the failure for the screen before it. None while something may still land.\n onBack?: (() => void) | undefined;\n backLabel: string;\n}): DialogScreen {\n const back = failure.moved === 'pending' ? undefined : onBack;\n return {\n step: failure.step,\n view: `${failure.step}-failed-${failure.title}`,\n onBack: back,\n body: (\n <>\n <Hero kind={failure.moved === 'pending' ? 'pending' : 'error'} icon={icon} />\n <h2 id={titleId}>{failure.title}</h2>\n <p role=\"alert\" data-mesub-error=\"\">\n {failure.message}\n </p>\n {failure.moved === 'safe' ? (\n <p data-mesub-funds=\"safe\">{safe}</p>\n ) : failure.moved === 'pending' ? (\n <p data-mesub-funds=\"pending\">{pending}</p>\n ) : null}\n {failure.moved === 'pending' && signature ? (\n <Explorer signature={signature} chain={chain} label=\"View transaction\" />\n ) : null}\n {failure.action === 'close' ? (\n <button type=\"button\" data-mesub-done=\"\" onClick={() => onAct('close')}>\n Close\n </button>\n ) : (\n <button\n type=\"button\"\n data-mesub-submit=\"\"\n disabled={busy}\n aria-busy={busy || undefined}\n onClick={() => onAct(failure.action)}\n >\n {PRIMARY[failure.action]}\n </button>\n )}\n {back && failure.action === 'retry' ? (\n <button type=\"button\" data-mesub-back=\"\" onClick={back}>\n {backLabel}\n </button>\n ) : null}\n </>\n ),\n };\n}\n\n/** A 401: nobody is signed in on the merchant's site, so there is nothing to sign. */\nexport function signedOutScreen({\n titleId,\n step,\n message,\n safe,\n onClose,\n}: {\n titleId: string;\n step: string;\n message: string;\n safe: string;\n onClose(): void;\n}): DialogScreen {\n return {\n step,\n view: 'signed-out',\n body: (\n <>\n <Hero kind=\"error\" />\n <h2 id={titleId}>Sign in first</h2>\n <p role=\"alert\" data-mesub-error=\"\">\n {message}\n </p>\n <p data-mesub-funds=\"safe\">{safe}</p>\n <button type=\"button\" data-mesub-done=\"\" onClick={onClose}>\n Close\n </button>\n </>\n ),\n };\n}\n","import { getBase58Decoder } from '@solana/kit';\nimport { getWalletFeature, type UiWallet } from '@wallet-standard/react';\n\n// The few Wallet Standard shapes used here, read off the wallet itself.\nexport interface WalletAccount {\n readonly address: string;\n readonly chains: readonly string[];\n}\n\ninterface ConnectFeature {\n connect(input?: { silent?: boolean }): Promise<{ accounts: readonly WalletAccount[] }>;\n}\n\ninterface SignMessageFeature {\n signMessage(\n ...inputs: { account: WalletAccount; message: Uint8Array }[]\n ): Promise<readonly { signedMessage: Uint8Array; signature: Uint8Array }[]>;\n}\n\ninterface SignTransactionFeature {\n signTransaction(\n ...inputs: { account: WalletAccount; chain: string; transaction: Uint8Array }[]\n ): Promise<readonly { signedTransaction: Uint8Array }[]>;\n}\n\ninterface SignAndSendFeature {\n signAndSendTransaction(\n ...inputs: { account: WalletAccount; chain: string; transaction: Uint8Array }[]\n ): Promise<readonly { signature: Uint8Array }[]>;\n}\n\n/** A Wallet Standard chain, such as `solana:mainnet` or `solana:devnet`. */\nexport type SolanaChain = `solana:${string}`;\n\n/** The wallet and the account of it that signs. */\nexport interface Signer {\n wallet: UiWallet;\n account: WalletAccount;\n}\n\n/**\n * Subscribing signs the terms, then the transaction without sending it: Mesub\n * co-signs and sends. Managing sends one transaction from the wallet itself.\n */\nexport type Purpose = 'subscribe' | 'manage';\n\nconst NEEDS: Record<Purpose, readonly string[]> = {\n subscribe: ['solana:signMessage', 'solana:signTransaction'],\n manage: ['solana:signAndSendTransaction'],\n};\n\nconst IN_WORDS: Record<string, string> = {\n 'solana:signMessage': 'sign a message',\n 'solana:signTransaction': 'sign a transaction without sending it',\n 'solana:signAndSendTransaction': 'send a transaction',\n};\n\nconst isSolana = (chain: string) => chain.startsWith('solana:');\n\n/** A wallet that can hand over a Solana account. */\nexport function isSolanaWallet(wallet: UiWallet): boolean {\n return wallet.chains.some(isSolana) && wallet.features.includes('standard:connect');\n}\n\n/** What the wallet cannot do for that purpose, in words. Empty when it can do it all. */\nexport function lacking(wallet: UiWallet, purpose: Purpose): string[] {\n return NEEDS[purpose]\n .filter((feature) => !(wallet.features as readonly string[]).includes(feature))\n .map((feature) => IN_WORDS[feature]!);\n}\n\nexport function usable(wallet: UiWallet, purpose: Purpose): boolean {\n return isSolanaWallet(wallet) && lacking(wallet, purpose).length === 0;\n}\n\n/** The wallet said no, or answered nothing: shown in its own words. */\nexport class WalletError extends Error {\n constructor(\n message: string,\n readonly wallet: string,\n ) {\n super(message);\n }\n}\n\nconst said = (wallet: UiWallet, refusal: unknown) =>\n `${wallet.name} said: ${refusal instanceof Error ? refusal.message : String(refusal)}`;\n\nconst fromBase64 = (text: string) => Uint8Array.from(atob(text), (char) => char.charCodeAt(0));\n\nfunction toBase64(bytes: Uint8Array): string {\n let binary = '';\n for (const byte of bytes) binary += String.fromCharCode(byte);\n return btoa(binary);\n}\n\n/**\n * The wallet's Solana accounts. Never `standard:disconnect` first: on a dApp it\n * would also end the merchant's own wallet connection, which shares this origin.\n * Called as a method: a wallet may rely on `this`.\n */\nexport async function connectAccounts(\n wallet: UiWallet,\n silent = false,\n): Promise<readonly WalletAccount[]> {\n const feature = getWalletFeature(wallet, 'standard:connect') as ConnectFeature;\n const { accounts } = await feature.connect(silent ? { silent: true } : undefined);\n return accounts.filter((account) => account.chains.some(isSolana));\n}\n\n/**\n * The installed wallet already showing `address` to this site, asked silently:\n * a wallet that is not authorised here shows no prompt. Null when none does.\n */\nexport async function findConnected(\n wallets: readonly UiWallet[],\n address: string,\n purpose: Purpose,\n): Promise<Signer | null> {\n const shows = (wallet: UiWallet) => wallet.accounts.some((entry) => entry.address === address);\n const capable = wallets\n .filter((wallet) => usable(wallet, purpose))\n .sort((a, b) => Number(shows(b)) - Number(shows(a)));\n\n for (const wallet of capable) {\n const accounts = await connectAccounts(wallet, true).catch(() => []);\n const account = accounts.find((entry) => entry.address === address);\n if (account) return { wallet, account };\n }\n return null;\n}\n\n/** Signs the text's UTF-8 bytes and returns the signature in base58. */\nexport async function signText({ wallet, account }: Signer, text: string): Promise<string> {\n const feature = getWalletFeature(wallet, 'solana:signMessage') as SignMessageFeature;\n let output;\n try {\n [output] = await feature.signMessage({ account, message: new TextEncoder().encode(text) });\n } catch (refusal) {\n throw new WalletError(said(wallet, refusal), wallet.name);\n }\n if (!output) throw new WalletError(`${wallet.name} returned no signature.`, wallet.name);\n return getBase58Decoder().decode(output.signature);\n}\n\n/**\n * Has the wallet sign the base64 transaction WITHOUT sending it, and returns\n * it signed, in base64, with its id when the wallet is its first signer.\n */\nexport async function signOnly(\n { wallet, account }: Signer,\n chain: SolanaChain,\n transaction: string,\n): Promise<{ transaction: string; signature: string | null }> {\n const feature = getWalletFeature(wallet, 'solana:signTransaction') as SignTransactionFeature;\n let output;\n try {\n [output] = await feature.signTransaction({\n account,\n chain,\n transaction: fromBase64(transaction),\n });\n } catch (refusal) {\n throw new WalletError(said(wallet, refusal), wallet.name);\n }\n if (!output) throw new WalletError(`${wallet.name} returned no transaction.`, wallet.name);\n return {\n transaction: toBase64(output.signedTransaction),\n signature: firstSignature(output.signedTransaction),\n };\n}\n\n/** Has the wallet sign AND send the base64 transaction, and returns its signature in base58. */\nexport async function signAndSend(\n { wallet, account }: Signer,\n chain: SolanaChain,\n transaction: string,\n): Promise<string> {\n const feature = getWalletFeature(wallet, 'solana:signAndSendTransaction') as SignAndSendFeature;\n let output;\n try {\n [output] = await feature.signAndSendTransaction({\n account,\n chain,\n transaction: fromBase64(transaction),\n });\n } catch (refusal) {\n throw new WalletError(said(wallet, refusal), wallet.name);\n }\n if (!output) throw new WalletError(`${wallet.name} returned no signature.`, wallet.name);\n return getBase58Decoder().decode(output.signature);\n}\n\n/**\n * A transaction's id is its first signature: one count byte, then 64 bytes.\n * Null while that slot is empty, which is Mesub's to fill when it pays the fee.\n */\nfunction firstSignature(wire: Uint8Array): string | null {\n const signature = wire.subarray(1, 65);\n if (signature.length < 64 || signature.every((byte) => byte === 0)) return null;\n return getBase58Decoder().decode(signature);\n}\n","import { useWallets, type UiWallet } from '@wallet-standard/react';\nimport { useEffect, useId, useRef, useState } from 'react';\nimport { signedOut } from './api';\nimport { useMesubInternal } from './context';\nimport { MesubDialog, type DialogScreen } from './dialog';\nimport { MesubClientError } from './errors';\nimport { moment, noChargeAt, planEnd, shortAddress } from './format';\nimport {\n Explorer,\n failureScreen,\n Hero,\n rememberWallet,\n signedOutScreen,\n walletScreen,\n type Failure,\n type WalletView,\n} from './screens';\nimport type { MesubAction, MesubSubscription, Settled } from './types';\nimport { connectAccounts, findConnected, signAndSend, WalletError, type Signer } from './wallet';\n\nexport interface ManageProps {\n subscription: MesubSubscription;\n action: MesubAction;\n onClose(): void;\n // Something was sent or settled: the lists read again. Null when only the outcome is unknown.\n onChanged(subscription: MesubSubscription | null): void;\n}\n\ntype View =\n | { name: 'confirm' }\n | { name: 'finding' }\n | { name: 'wallet'; pick: WalletView }\n | { name: 'building'; signer: Signer }\n | { name: 'approve'; signer: Signer }\n | { name: 'confirming'; signer: Signer; signature: string }\n | { name: 'done'; subscription: MesubSubscription; signature: string }\n | {\n name: 'failed';\n failure: Failure;\n signer: Signer | null;\n signature: string | null;\n icon: string | undefined;\n }\n | { name: 'signed-out' };\n\nconst FIND_TIMEOUT_MS = 4_000;\nconst SAFE = 'Nothing changed.';\nconst PENDING = 'The transaction may still land.';\n\nconst WORDS: Record<MesubAction, { ask: string; go: string; keep: string; done: string }> = {\n cancel: {\n ask: 'Cancel',\n go: 'Cancel subscription',\n keep: 'Keep it',\n done: 'Subscription cancelled',\n },\n resume: {\n ask: 'Resume',\n go: 'Resume subscription',\n keep: 'Not now',\n done: 'Subscription resumed',\n },\n close: { ask: 'Close', go: 'Close subscription', keep: 'Not now', done: 'Subscription closed' },\n};\n\nconst messageOf = (error: unknown) =>\n error instanceof MesubClientError ? error.message : 'Something went wrong.';\n\n/** The confirms' `reason_code` for a transaction the chain may still take: checked, not rebuilt. */\nconst NOT_YET = ['cancellation_not_landed', 'resume_not_landed', 'close_not_landed'];\n\n/**\n * What a confirm that settled nothing comes to, by its `reason_code`, never by\n * its sentence. A code this version does not know is Mesub's sentence, and Try again.\n */\nfunction unsettled(action: MesubAction, settled: Settled): Failure {\n const code = settled.reason_code;\n // Its blockhash ran out before it landed: nothing changed, and a new one is built.\n if (code === 'transaction_expired') {\n return {\n step: 'confirming',\n title: 'Transaction expired',\n message: 'The transaction expired before it landed. Try again with a new one.',\n moved: 'safe',\n action: 'retry',\n icon: 'wallet',\n };\n }\n if (code && NOT_YET.includes(code)) {\n return {\n step: 'confirming',\n title: 'Still confirming',\n message: `The ${action} has not landed yet. Wait a moment, then check again.`,\n moved: 'pending',\n action: 'check',\n icon: 'wallet',\n };\n }\n return {\n step: 'confirming',\n title: 'It did not go through',\n message: settled.reason,\n moved: 'safe',\n action: 'retry',\n icon: 'wallet',\n };\n}\n\n/** What the action does, before anything is signed. */\nfunction consequence(\n action: MesubAction,\n subscription: MesubSubscription,\n planEndsAt: string | null,\n): string {\n const end = subscription.access_until ?? subscription.current_period_end;\n const until = moment(end);\n if (action === 'cancel') {\n return subscription.access && until\n ? `You keep access until ${until}. Nothing more is charged.`\n : 'It stops now. Nothing more is charged.';\n }\n if (action === 'resume') {\n // The plan ends before a charge can run: resuming brings none back.\n if (end && until && noChargeAt(Date.parse(end), planEndsAt)) {\n return `It runs again until ${planEnd(planEndsAt)}, when the plan ends. Nothing more is charged.`;\n }\n return until\n ? `Charges start again on ${until}, as before.`\n : 'Charges start again, as before.';\n }\n return 'It is over. Closing it returns its deposit to your wallet.';\n}\n\n/** What it became, once Mesub confirmed. */\nfunction outcome(action: MesubAction, subscription: MesubSubscription): string {\n const until = moment(subscription.access_until ?? subscription.current_period_end);\n if (action === 'cancel') {\n return subscription.access && until\n ? `You keep access until ${until}.`\n : 'Nothing more is charged.';\n }\n if (action === 'resume') {\n const next = moment(subscription.next_charge_at);\n if (next) return `Next charge ${next}.`;\n return subscription.access && until ? `You keep access until ${until}.` : 'It runs again.';\n }\n return 'Its deposit is back in your wallet.';\n}\n\n/**\n * The window that cancels, resumes or closes one subscription: the wallet that\n * pays it signs and sends one transaction, then the server confirms it.\n */\nexport function Manage({ subscription, action, onClose, onChanged }: ManageProps) {\n const { api, chain, plan: readPlan } = useMesubInternal();\n const wallets = useWallets();\n const titleId = useId();\n const words = WORDS[action];\n const payer = subscription.wallet;\n\n const [view, setViewState] = useState<View>({ name: 'confirm' });\n const [checking, setChecking] = useState(false);\n // The plan's name, when it can be read: its slug stands in until then.\n const [planName, setPlanName] = useState(subscription.plan ?? 'this subscription');\n // Its end date, which decides whether resuming brings a charge back.\n const [planEndsAt, setPlanEndsAt] = useState<string | null>(null);\n\n const alive = useRef(true);\n const attempt = useRef(0);\n const shown = useRef<View>(view);\n const checkingNow = useRef(false);\n const latest = useRef({ wallets, onChanged });\n latest.current = { wallets, onChanged };\n\n function setView(next: View) {\n shown.current = next;\n setViewState(next);\n }\n\n function begin() {\n const id = ++attempt.current;\n return () => alive.current && id === attempt.current;\n }\n\n useEffect(() => {\n alive.current = true;\n if (subscription.plan) {\n readPlan(subscription.plan).then(\n (served) => {\n if (!alive.current) return;\n setPlanName(served.name);\n setPlanEndsAt(served.ends_at);\n },\n () => undefined,\n );\n }\n return () => {\n alive.current = false;\n };\n // Once per opening.\n }, []);\n\n function fail(\n failure: Failure,\n signer: Signer | null,\n signature: string | null = null,\n icon = signer?.wallet.icon,\n ) {\n setView({ name: 'failed', failure, signer, signature, icon });\n }\n\n // The wallet already showing the paying account signs; else the subscriber picks one.\n async function start() {\n if (shown.current.name !== 'confirm') return;\n const current = begin();\n setView({ name: 'finding' });\n // A wallet that never answers a silent connect must not hold the dialog.\n const signer = await Promise.race([\n findConnected(latest.current.wallets, payer, 'manage'),\n new Promise<null>((resolve) => setTimeout(() => resolve(null), FIND_TIMEOUT_MS)),\n ]);\n if (!current()) return;\n if (signer) await run(signer);\n else setView({ name: 'wallet', pick: { name: 'list' } });\n }\n\n async function pick(wallet: UiWallet) {\n if (shown.current.name !== 'wallet' || shown.current.pick.name === 'waiting') return;\n const current = begin();\n setView({ name: 'wallet', pick: { name: 'waiting', wallet } });\n\n let accounts;\n try {\n accounts = await connectAccounts(wallet);\n } catch (refusal) {\n if (!current()) return;\n const message = `${wallet.name} said: ${refusal instanceof Error ? refusal.message : 'it did not connect.'}`;\n setView({ name: 'wallet', pick: { name: 'rejected', wallet, message } });\n return;\n }\n if (!current()) return;\n const account = accounts.find((entry) => entry.address === payer);\n if (!account) {\n // Not the wallet that pays this one: nothing is built, nothing is signed.\n const on = accounts[0]\n ? `${wallet.name} is on ${shortAddress(accounts[0].address)}`\n : `${wallet.name} shared no Solana account`;\n fail(\n {\n step: 'wallet',\n title: 'Wrong wallet',\n message: `${on}, and this subscription is paid from ${shortAddress(payer)}. Switch to that account in your wallet, then try again.`,\n moved: 'safe',\n action: 'wallet',\n icon: 'wallet',\n },\n null,\n null,\n wallet.icon,\n );\n return;\n }\n rememberWallet(wallet.name);\n await run({ wallet, account });\n }\n\n async function run(signer: Signer) {\n const current = begin();\n setView({ name: 'building', signer });\n let transaction;\n try {\n ({ transaction } = await api.build(action, subscription.id));\n } catch (error) {\n if (!current()) return;\n if (signedOut(error)) {\n setView({ name: 'signed-out' });\n return;\n }\n const refused = error instanceof MesubClientError && error.status !== null;\n fail(\n {\n step: 'approve',\n title: refused ? `Cannot ${action} it` : 'No answer',\n message: messageOf(error),\n moved: 'safe',\n // Mesub's refusal is final for now; a silence is worth another try.\n action: refused && error.status !== 429 ? 'close' : 'retry',\n icon: 'wallet',\n },\n signer,\n );\n return;\n }\n if (!current()) return;\n\n setView({ name: 'approve', signer });\n let signature;\n try {\n // The wallet signs AND sends this one: Mesub signs nothing of it.\n signature = await signAndSend(signer, chain, transaction);\n } catch (error) {\n if (!current()) return;\n fail(\n {\n step: 'approve',\n title: 'Not approved',\n message:\n error instanceof WalletError\n ? error.message\n : `${signer.wallet.name} did not send it.`,\n moved: 'safe',\n action: 'retry',\n icon: 'wallet',\n },\n signer,\n );\n return;\n }\n // Sent: whatever the dialog does next, the lists are out of date.\n latest.current.onChanged(null);\n if (!current()) return;\n await confirm(signer, signature);\n }\n\n // Also \"Check again\": the same confirm is answered the same, and sends nothing.\n async function confirm(signer: Signer, signature: string) {\n const current = begin();\n setView({ name: 'confirming', signer, signature });\n try {\n const settled = await api.confirm(action, subscription.id, signature);\n latest.current.onChanged(settled.reason ? null : settled.subscription);\n if (!current()) return;\n if (settled.reason) {\n const failure = unsettled(action, settled);\n fail(failure, signer, failure.moved === 'pending' ? signature : null);\n return;\n }\n setView({ name: 'done', subscription: settled.subscription, signature });\n } catch (error) {\n if (!current()) return;\n if (signedOut(error)) {\n setView({ name: 'signed-out' });\n return;\n }\n const status = error instanceof MesubClientError ? error.status : null;\n const refused = status !== null && status < 500;\n fail(\n refused\n ? {\n step: 'confirming',\n title: `Cannot ${action} it`,\n message: messageOf(error),\n moved: null,\n action: 'close',\n icon: 'wallet',\n }\n : {\n step: 'confirming',\n title: 'Still confirming',\n message: `If ${signer.wallet.name} shows the transaction as sent, wait a minute, then check again.`,\n moved: 'pending',\n action: 'check',\n icon: 'wallet',\n },\n signer,\n signature,\n );\n }\n }\n\n async function checkAgain(signer: Signer, signature: string) {\n if (checkingNow.current) return;\n checkingNow.current = true;\n setChecking(true);\n try {\n await confirm(signer, signature);\n } finally {\n checkingNow.current = false;\n if (alive.current) setChecking(false);\n }\n }\n\n function toWallets() {\n attempt.current++;\n setView({ name: 'wallet', pick: { name: 'list' } });\n }\n\n function toConfirm() {\n attempt.current++;\n setView({ name: 'confirm' });\n }\n\n let screen: DialogScreen;\n if (view.name === 'signed-out') {\n screen = signedOutScreen({\n titleId,\n step: 'confirm',\n message: 'You are not signed in on this site. Sign in here first, then try again.',\n safe: SAFE,\n onClose,\n });\n } else if (view.name === 'wallet') {\n screen = walletScreen({\n titleId,\n view: view.pick,\n wallets,\n purpose: 'manage',\n lead: `The one that pays this subscription: ${shortAddress(payer)}.`,\n setView: (pickView) => {\n attempt.current++;\n setView({ name: 'wallet', pick: pickView });\n },\n pick: (wallet) => void pick(wallet),\n onBack: toConfirm,\n });\n } else if (view.name === 'failed') {\n const { failure, signer, signature } = view;\n screen = failureScreen({\n failure,\n titleId,\n icon: view.icon,\n safe: SAFE,\n pending: PENDING,\n signature,\n chain,\n busy: checking,\n onAct: (next) => {\n if (next === 'close') onClose();\n else if (next === 'check' && signer && signature) {\n void checkAgain(signer, signature);\n } else if (next === 'wallet' || !signer) toWallets();\n else void run(signer);\n },\n onBack: toConfirm,\n backLabel: 'Back',\n });\n } else if (view.name === 'confirm') {\n screen = {\n step: 'confirm',\n view: 'confirm',\n body: (\n <>\n <h2 id={titleId}>\n {words.ask} {planName}?\n </h2>\n <p>{consequence(action, subscription, planEndsAt)}</p>\n <dl data-mesub-summary=\"\">\n <div data-mesub-row=\"\">\n <dt>Signed by</dt>\n <dd title={payer}>{shortAddress(payer)}</dd>\n </div>\n </dl>\n <button type=\"button\" data-mesub-submit=\"\" onClick={() => void start()}>\n {words.go}\n </button>\n <button type=\"button\" data-mesub-cancel=\"\" onClick={onClose}>\n {words.keep}\n </button>\n </>\n ),\n };\n } else if (view.name === 'finding' || view.name === 'building') {\n screen = {\n step: 'wallet',\n view: view.name,\n onBack: toConfirm,\n body: (\n <>\n <Hero\n kind=\"wait\"\n icon={view.name === 'building' ? view.signer.wallet.icon : null}\n />\n <h2 id={titleId}>\n {view.name === 'finding' ? 'Looking for your wallet' : 'Preparing'}\n </h2>\n <p data-mesub-notice=\"\" role=\"status\" aria-busy=\"true\">\n Nothing to sign yet\n </p>\n </>\n ),\n };\n } else if (view.name === 'approve') {\n screen = {\n step: 'approve',\n view: 'approve',\n onBack: toConfirm,\n body: (\n <>\n <Hero kind=\"wait\" icon={view.signer.wallet.icon} />\n <h2 id={titleId}>Approve in {view.signer.wallet.name}</h2>\n <p>\n One transaction, sent by your wallet. It pays nothing but the network fee.\n </p>\n <button type=\"button\" data-mesub-cancel=\"\" onClick={onClose}>\n Cancel\n </button>\n </>\n ),\n };\n } else if (view.name === 'confirming') {\n screen = {\n step: 'confirming',\n view: 'confirming',\n body: (\n <>\n <Hero kind=\"wait\" icon={view.signer.wallet.icon} />\n <h2 id={titleId}>Confirming on Solana</h2>\n <p>This can take up to a minute.</p>\n <Explorer signature={view.signature} chain={chain} label=\"View transaction\" />\n </>\n ),\n };\n } else {\n screen = {\n step: 'done',\n view: 'done',\n body: (\n <>\n <Hero kind=\"check\" />\n <h2 id={titleId}>{words.done}</h2>\n <p>{outcome(action, view.subscription)}</p>\n <Explorer signature={view.signature} chain={chain} label=\"View transaction\" />\n <button type=\"button\" data-mesub-done=\"\" onClick={onClose}>\n Done\n </button>\n </>\n ),\n };\n }\n\n return <MesubDialog screen={screen} titleId={titleId} onClose={onClose} />;\n}\n","import { useEffect, useId, useState } from 'react';\nimport { useMesubInternal } from './context';\nimport {\n paidBrief,\n paidIn,\n paymentSaid,\n pickSubscription,\n retryOf,\n symbolOf,\n} from './detail-logic';\nimport { MesubDialog } from './dialog';\nimport {\n cadence,\n day,\n explorerUrl,\n formatAmount,\n formatUsd,\n grouped,\n planEnd,\n briefPrice,\n fit,\n shortAddress,\n shortMoment,\n tokenOf,\n} from './format';\nimport { TokenLogo } from './screens';\nimport {\n closeFrom,\n fact,\n noteOf,\n PayNow,\n STATUS,\n useSubscriptions,\n type MesubHeldSubscription,\n} from './subscriptions';\nimport type { MesubAction, MesubPlan, MesubSubscriptionDetail } from './types';\n\nconst ACTION: Record<MesubAction, string> = {\n cancel: 'Cancel subscription',\n resume: 'Resume subscription',\n close: 'Close and get the deposit back',\n};\n\nconst UPCOMING: Record<string, string> = { charge: 'Next charge', retry: 'Next try' };\n\n/** The plan a row names, read best effort: its slug stands in until then. */\nfunction usePlan(slug: string | null | undefined): MesubPlan | undefined {\n const { plan } = useMesubInternal();\n const [read, setRead] = useState<MesubPlan | undefined>(undefined);\n\n useEffect(() => {\n if (!slug) return;\n let live = true;\n plan(slug).then(\n (served) => live && setRead(served),\n () => undefined,\n );\n return () => {\n live = false;\n };\n }, [plan, slug]);\n\n return slug && read?.slug === slug ? read : undefined;\n}\n\n/** What comes next and what was charged, read once the row is known. Null while unknown. */\nfunction useDetail(row: MesubHeldSubscription | null): MesubSubscriptionDetail | null {\n const { api, revision } = useMesubInternal();\n const [detail, setDetail] = useState<MesubSubscriptionDetail | null>(null);\n const id = row?.id;\n\n useEffect(() => {\n if (!id) return;\n let live = true;\n api.subscription(id).then(\n (served) => live && setDetail(served),\n // An older server has no such route: the view stands without its payments.\n () => undefined,\n );\n return () => {\n live = false;\n };\n }, [api, id, revision]);\n\n return detail?.subscription.id === id ? detail : null;\n}\n\n/**\n * The customer's subscription to a plan, in the Mesub window: what it is, how\n * it stands, what comes next, what was charged, and the one thing it allows.\n * One subscription, never a list: what the Manage button opens.\n */\n/** Past payments listed at first, and how many more each request adds. */\nconst PAST_SHOWN = 5;\nconst PAST_STEP = 10;\n\nexport function SubscriptionDialog({\n plan: slug,\n onClose,\n}: {\n plan: string | undefined;\n onClose(): void;\n}) {\n // How many past payments are listed: a few, then more on request, never a list that scrolls.\n const [shown, setShown] = useState(PAST_SHOWN);\n const titleId = useId();\n const { chain } = useMesubInternal();\n const { state, subscriptions, error, reload, payNow, manage } = useSubscriptions();\n const row = (pickSubscription(subscriptions, slug) as MesubHeldSubscription | null) ?? null;\n const plan = usePlan(row?.plan);\n const detail = useDetail(row);\n\n let body;\n if (state === 'loading') {\n body = (\n <>\n <h2 id={titleId}>Your subscription</h2>\n <p data-mesub-notice=\"\" role=\"status\" aria-busy=\"true\">\n Reading your subscription\n </p>\n </>\n );\n } else if (state === 'signed-out') {\n body = (\n <>\n <h2 id={titleId}>Sign in first</h2>\n <p>Sign in on this site to see your subscription.</p>\n </>\n );\n } else if (state === 'error') {\n body = (\n <>\n <h2 id={titleId}>Your subscription</h2>\n <p role=\"alert\" data-mesub-error=\"\">\n {error}\n </p>\n <button type=\"button\" data-mesub-retry=\"\" onClick={() => void reload()}>\n Try again\n </button>\n </>\n );\n } else if (!row) {\n body = (\n <>\n <h2 id={titleId}>No subscription yet</h2>\n <p>You are not subscribed to this plan.</p>\n </>\n );\n } else {\n const name = plan?.name ?? row.plan ?? 'Subscription';\n const dated = fact(row);\n const since = day(row.confirmed_at);\n const note = noteOf(row);\n const upcoming = detail?.upcoming ?? [];\n const past = detail?.payments ?? [];\n // In the plan's token; left out while the plan or the total is unknown, never guessed.\n const total = detail?.paid?.amount\n ? paidBrief(detail.paid.amount, plan, formatAmount)\n : null;\n const rate = plan ? briefPrice(plan) : null;\n const due = (display: string | null | undefined) =>\n display ? `${grouped(display)}${symbolOf(plan)}` : '';\n // What comes next is told once: on its own line when the server serves it, as a fact otherwise.\n const facts = upcoming.length > 0 && dated?.term !== 'Access until' ? null : dated;\n\n body = (\n <>\n <div data-mesub-identity=\"\">\n {plan?.logo_url ? (\n <img data-mesub-logo=\"\" src={plan.logo_url} alt=\"\" />\n ) : (\n <span data-mesub-logo=\"\" aria-hidden=\"true\">\n {name.slice(0, 1).toUpperCase()}\n </span>\n )}\n <div>\n <h2 id={titleId}>{name}</h2>\n {plan ? <span>by {plan.project_name}</span> : null}\n </div>\n <span data-mesub-status={row.paused ? 'paused' : row.status}>\n {row.paused ? 'Parked' : (STATUS[row.status] ?? row.status)}\n </span>\n </div>\n\n {plan && rate ? (\n <p data-mesub-rate=\"\">\n <strong title={rate.title} data-mesub-fit={fit(rate.text)}>\n <TokenLogo plan={plan} />\n {rate.text}\n </strong>{' '}\n {cadence(plan.period_hours)}\n </p>\n ) : null}\n\n {note ? <p data-mesub-state-note=\"\">{note}</p> : null}\n\n <dl data-mesub-summary=\"\">\n {facts ? (\n <div data-mesub-row=\"\">\n <dt>{facts.term}</dt>\n <dd>{facts.date}</dd>\n </div>\n ) : null}\n {since ? (\n <div data-mesub-row=\"\">\n <dt>Since</dt>\n <dd>{since}</dd>\n </div>\n ) : null}\n {total ? (\n <div data-mesub-row=\"\">\n <dt>Total paid</dt>\n <dd title={total.title}>{total.text}</dd>\n </div>\n ) : null}\n {planEnd(plan?.ends_at) ? (\n <div data-mesub-row=\"\">\n <dt>Plan ends</dt>\n <dd>{planEnd(plan?.ends_at)}</dd>\n </div>\n ) : null}\n {closeFrom(row) ? (\n <div data-mesub-row=\"\">\n <dt>Close from</dt>\n <dd>{closeFrom(row)}</dd>\n </div>\n ) : null}\n <div data-mesub-row=\"\">\n <dt>Pays from</dt>\n <dd title={row.wallet}>{shortAddress(row.wallet)}</dd>\n </div>\n </dl>\n\n {upcoming.length > 0 || past.length > 0 ? (\n // Closed until asked for, as the terms are on the checkout: same toggle.\n <details data-mesub-terms=\"\" data-mesub-payments=\"\">\n <summary>Payments</summary>\n {upcoming.length > 0 ? (\n <section aria-label=\"Incoming payments\">\n <h3>Incoming</h3>\n <ul>\n {upcoming.map((next) => (\n <li\n key={`next-${next.due_at}`}\n data-mesub-payment=\"upcoming\"\n >\n <span>{shortMoment(next.due_at)}</span>\n <span>\n {UPCOMING[next.kind] ?? next.kind}\n {retryOf(next) ? (\n <small title=\"Retry\">{retryOf(next)}</small>\n ) : null}\n </span>\n {/* Each payment in full: where one checks. */}\n <span data-mesub-fit={fit(due(next.amount_display))}>\n {due(next.amount_display)}\n </span>\n </li>\n ))}\n </ul>\n </section>\n ) : null}\n {past.length > 0 ? (\n <section aria-label=\"Past payments\">\n <h3>Past</h3>\n <ul>\n {past.slice(0, shown).map((payment) => {\n const said = paymentSaid(payment);\n const amount = paidIn(payment.amount, plan, formatAmount);\n // The price at the charge: not for a stablecoin, whose amount says it.\n const usd =\n plan && amount && !tokenOf(plan).vouched\n ? formatUsd(payment.amount_usd)\n : null;\n return (\n <li\n key={`${payment.attempted_at}-${payment.signature ?? ''}`}\n data-mesub-payment={said.tone}\n >\n <span>{shortMoment(payment.attempted_at)}</span>\n <span>\n {said.label}\n {retryOf(payment) ? (\n <small title=\"Retry\">\n {retryOf(payment)}\n </small>\n ) : null}\n </span>\n <span data-mesub-fit={fit(amount ?? '')}>\n {payment.signature &&\n payment.outcome === 'paid' ? (\n <a\n href={explorerUrl(\n payment.signature,\n chain,\n )}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n title=\"See the transaction\"\n >\n {amount ?? 'Receipt'}\n </a>\n ) : (\n amount\n )}\n {usd ? <small>{usd}</small> : null}\n </span>\n </li>\n );\n })}\n </ul>\n {past.length > shown ? (\n <button\n type=\"button\"\n data-mesub-more=\"\"\n onClick={() => setShown(shown + PAST_STEP)}\n >\n Show more\n </button>\n ) : null}\n </section>\n ) : null}\n </details>\n ) : null}\n\n {row.payable ? <PayNow pay={() => payNow(row.id)} /> : null}\n {row.action ? (\n <button\n type=\"button\"\n data-mesub-action={row.action}\n onClick={() => void manage(row.id)}\n >\n {ACTION[row.action]}\n </button>\n ) : null}\n </>\n );\n }\n\n return (\n <MesubDialog\n titleId={titleId}\n onClose={onClose}\n screen={{\n step: 'subscription',\n view: `subscription-${state}-${row?.id ?? 'none'}`,\n body: (\n <>\n {body}\n <button type=\"button\" data-mesub-cancel=\"\" onClick={onClose}>\n Done\n </button>\n </>\n ),\n }}\n />\n );\n}\n","import { brief, grouped, tokenOf, type Brief } from './format';\nimport type { MesubPayment, MesubPlan, MesubSubscription } from './types';\n\n/** Statuses of a subscription worth opening first: something is still running or owed. */\nconst LIVE = ['active', 'unpaid', 'cancelled', 'stopped'];\n\n/** Nothing to manage: checkouts nobody signed, and rows a newer one replaced. */\nconst NOT_ONE = ['pending', 'expired', 'failed', 'superseded'];\n\n/**\n * The one subscription the Manage window is about: the customer's to that\n * plan, or to any when none is named. A live one before an ended one, the\n * newest first within each. Null when there is none.\n */\nexport function pickSubscription(\n rows: readonly MesubSubscription[],\n plan?: string | undefined,\n): MesubSubscription | null {\n const theirs = rows\n .filter((row) => !NOT_ONE.includes(row.status))\n .filter((row) => plan === undefined || row.plan === plan)\n .sort((a, b) => Date.parse(b.created_at) - Date.parse(a.created_at));\n\n return theirs.find((row) => LIVE.includes(row.status)) ?? theirs[0] ?? null;\n}\n\n/** How one charge reads: a word, and whether it went well, badly, or neither. */\nexport interface PaymentSaid {\n label: string;\n tone: 'good' | 'bad' | 'none';\n}\n\nconst REASONS: Record<string, string> = {\n insufficient_balance: 'low balance',\n // The token program's OwnerMismatch: the wallet revoked Mesub's approval, or gave it to another app.\n program_4: 'approval was removed',\n};\n\n/**\n * A reason in the spelling Mesub serves: `insufficient_balance`, `program_4`.\n * An older server says `insufficient-balance`, `program:4`; read as the same\n * until Mesub-io/backend#476 is deployed, then this can go.\n */\nconst snake = (reason: string) => reason.replace(/[-:]/g, '_');\n\n/** A charge in words. An outcome this version does not know is shown as Mesub named it. */\nexport function paymentSaid(payment: Pick<MesubPayment, 'outcome' | 'reason'>): PaymentSaid {\n const why = payment.reason ? REASONS[snake(payment.reason)] : undefined;\n\n switch (payment.outcome) {\n case 'paid':\n return { label: 'Paid', tone: 'good' };\n case 'rejected':\n return { label: why ? `Missed, ${why}` : 'Missed', tone: 'bad' };\n case 'skipped':\n return { label: 'Skipped', tone: 'none' };\n case 'blocked':\n return { label: 'Not charged', tone: 'none' };\n default:\n return { label: payment.outcome.toLowerCase().replace(/_/g, ' '), tone: 'none' };\n }\n}\n\n/** An amount in the plan's token, or null when the plan could not be read: never a guess. */\nexport function paidIn(\n amount: string,\n plan: (Pick<MesubPlan, 'decimals' | 'symbol'> & Partial<Pick<MesubPlan, 'token'>>) | undefined,\n format: (amount: string, decimals: number) => string,\n): string | null {\n if (!plan || !/^\\d+$/.test(amount)) return null;\n\n return `${grouped(format(amount, plan.decimals))}${symbolOf(plan)}`;\n}\n\n/** `paidIn` where it is read fast: short when the rule allows, the exact amount as `title`. */\nexport function paidBrief(\n amount: string,\n plan: (Pick<MesubPlan, 'decimals' | 'symbol'> & Partial<Pick<MesubPlan, 'token'>>) | undefined,\n format: (amount: string, decimals: number) => string,\n): Brief | null {\n if (!plan || !/^\\d+$/.test(amount)) return null;\n const { vouched } = tokenOf({ mint: '', ...plan });\n\n return brief(format(amount, plan.decimals), vouched, symbolOf(plan));\n}\n\n/** ` Bonk` after an amount in a list, or nothing: a short mint has no room there. */\nexport function symbolOf(\n plan: (Pick<MesubPlan, 'symbol'> & Partial<Pick<MesubPlan, 'token'>>) | undefined,\n): string {\n if (!plan) return '';\n const token = tokenOf({ mint: '', ...plan });\n\n return token.named ? ` ${token.unit}` : '';\n}\n\n/** `2 / 3`: which retry, out of how many the plan allows. Null when it is not one, or not said. */\nexport function retryOf(of: {\n retry_number?: number | null | undefined;\n retries_allowed?: number | null | undefined;\n}): string | null {\n const { retry_number: number, retries_allowed: allowed } = of;\n if (!Number.isInteger(number) || !Number.isInteger(allowed)) return null;\n return number! > 0 && allowed! > 0 ? `${number} / ${allowed}` : null;\n}\n","import {\n forwardRef,\n useCallback,\n useEffect,\n useRef,\n useState,\n type ButtonHTMLAttributes,\n type HTMLAttributes,\n} from 'react';\nimport { busyFor, signedOut } from './api';\nimport { useMesubInternal } from './context';\nimport { MesubClientError } from './errors';\nimport { briefPrice, cadence, day, moment, fit, shortAddress } from './format';\nimport { TokenLogo } from './screens';\nimport type { MesubAction, MesubPlan, MesubSubscription } from './types';\n\n/** A subscription the customer holds, with what it allows now. */\nexport interface MesubHeldSubscription extends MesubSubscription {\n // Cancel a running one, resume a cancellation still running, close one that is over.\n action: MesubAction | null;\n // A late payment the customer can pay now (Mesub-io/backend#354), see `payNow`.\n payable: boolean;\n}\n\n/** What a \"Pay now\" came to, in the words the widget shows. */\nexport interface PayNowResult {\n // Sent: the outcome comes with the pull, and the list reads again.\n ok: boolean;\n message: string;\n // Mesub was busy (Mesub-io/backend#499): the seconds before paying again can work.\n retryAfter?: number;\n}\n\n/** What `useSubscriptions()` returns. */\nexport interface UseSubscriptionsResult {\n // `signed-out`: the merchant's server answered 401, nobody is signed in on the site.\n state: 'loading' | 'ready' | 'signed-out' | 'error';\n // Newest first. Checkouts never signed are left out.\n subscriptions: MesubHeldSubscription[];\n // The server's message, in the error state.\n error: string | null;\n reload(): Promise<void>;\n // Pays that late payment now: nothing to sign. Never throws: a refusal is its `message`.\n payNow(id: string): Promise<PayNowResult>;\n // Opens the dialog for what that subscription allows. Resolves when it closes: the\n // subscription as it is now, or null if nothing changed.\n manage(id: string): Promise<MesubSubscription | null>;\n}\n\n// A checkout nobody signed, one that failed, one a newer row replaced: not held.\nconst HELD = new Set(['active', 'cancelled', 'unpaid', 'stopped', 'ended']);\n\n/** When a cancelled one can be closed: as the server says, else at the end of its access. */\nfunction closesAt(subscription: MesubSubscription): number {\n return Date.parse(\n subscription.closable_from ??\n subscription.access_until ??\n subscription.current_period_end ??\n '',\n );\n}\n\nfunction actionOf(subscription: MesubSubscription, now: number): MesubAction | null {\n const { status } = subscription;\n // Mesub says whether the chain lets it close now (Mesub-io/backend#402): an ended one, a\n // cancellation past its end, one stopped because its wallet closed Mesub's access for good.\n if (subscription.closable === true) return 'close';\n // Nobody can charge it again, nor bring it back: nothing to cancel.\n if (status === 'stopped' && subscription.stop_reason === 'authority_closed') return null;\n if (status === 'active' || status === 'unpaid' || status === 'stopped') return 'cancel';\n if (status === 'cancelled') {\n const end = closesAt(subscription);\n // Past its end with the page still open: the server will say `ended` next read.\n if (!Number.isNaN(end) && end <= now) return 'close';\n // Cancelled with a payment missed: it cannot be resumed, only closed once it ends.\n return subscription.access ? 'resume' : null;\n }\n if (status === 'ended') {\n // A server that says it: not closable means its account is gone, or Mesub cannot close it.\n if (subscription.closable === false) return null;\n // Its account is gone already: closed here, or outside Mesub (`closed_elsewhere`,\n // `authority_closed` before Mesub-io/backend#476).\n const closed = ['closed', 'closed_elsewhere', 'authority_closed'].includes(\n subscription.end_reason ?? '',\n );\n return closed ? null : 'close';\n }\n return null;\n}\n\n/**\n * Whether paying a late payment now can succeed (Mesub-io/backend#354): late,\n * not paused, still approved by the wallet, and before `retry_deadline` when\n * there is one. Mesub refuses the rest anyway; the button is not offered.\n */\nexport function payableOf(row: MesubSubscription, now: number): boolean {\n // Held back for a cause that is not theirs: paying now would meet the same block.\n if (row.status !== 'unpaid' || row.paused || row.blocked_since) return false;\n if (row.late_reason === 'approval_revoked' || row.late_reason === 'authority_closed') {\n return false;\n }\n const deadline = Date.parse(row.retry_deadline ?? '');\n return Number.isNaN(deadline) || deadline > now;\n}\n\nexport const PAY_NOW_SENT = 'Payment sent. It shows here once the network confirms it.';\n\n/** Why paying now was refused, as the canonical table words it; Mesub's own message otherwise. */\nexport function payNowRefusal(failure: unknown): string {\n if (!(failure instanceof MesubClientError)) return 'Something went wrong.';\n switch (failure.code) {\n case 'insufficient_balance':\n return `${failure.message} Add funds, then pay again: no retry was spent.`;\n case 'retry_too_soon': {\n const minutes = failure.retryAfter === null ? null : Math.ceil(failure.retryAfter / 60);\n return minutes === null\n ? failure.message\n : `You can pay again in ${minutes} ${minutes === 1 ? 'minute' : 'minutes'}.`;\n }\n case 'unavailable': {\n // The queue refused it (Mesub-io/backend#499): nothing was queued, pay again after the wait.\n return busyFor(failure) === null\n ? failure.message\n : \"Mesub can't take the payment right now. Nothing was charged.\";\n }\n case 'retries_spent':\n return 'No retries are left for this period.';\n case 'retry_deadline_passed':\n return 'It is too late to pay this period: the subscription stops at its end.';\n default:\n return failure.message;\n }\n}\n\n/** The signed-in customer's subscriptions, read from the merchant's server, and what each allows. */\nexport function useSubscriptions(): UseSubscriptionsResult {\n const { api, revision, manage: open } = useMesubInternal();\n\n const [state, setState] = useState<UseSubscriptionsResult['state']>('loading');\n const [rows, setRows] = useState<MesubSubscription[]>([]);\n const [error, setError] = useState<string | null>(null);\n const [now, setNow] = useState(() => Date.now());\n\n // The latest read wins: an older answer arriving late is dropped.\n const read = useRef(0);\n const alive = useRef(true);\n useEffect(() => {\n alive.current = true;\n return () => {\n alive.current = false;\n };\n }, []);\n\n const reload = useCallback(async () => {\n const id = ++read.current;\n try {\n const served = await api.subscriptions();\n if (!alive.current || id !== read.current) return;\n setRows(served.filter((row) => HELD.has(row.status)));\n setNow(Date.now());\n setError(null);\n setState('ready');\n } catch (failure) {\n if (!alive.current || id !== read.current) return;\n if (signedOut(failure)) {\n setRows([]);\n setError(null);\n setState('signed-out');\n return;\n }\n setError(\n failure instanceof MesubClientError ? failure.message : 'Something went wrong.',\n );\n setState('error');\n }\n }, [api]);\n\n // On mount, and each time a subscription was made or changed through the widget.\n useEffect(() => {\n void reload();\n }, [reload, revision]);\n\n // A cancellation reaching its end turns closable: weigh the dates again then.\n useEffect(() => {\n const ends = rows\n .filter((row) => row.status === 'cancelled')\n .map(closesAt)\n .filter((end) => !Number.isNaN(end) && end > now);\n if (ends.length === 0) return;\n // setTimeout overflows past 24 days: nobody keeps the page open that long.\n const wait = Math.min(Math.min(...ends) - now + 1000, 2_000_000_000);\n const timer = setTimeout(() => setNow(Date.now()), wait);\n return () => clearTimeout(timer);\n }, [rows, now]);\n\n const subscriptions = rows.map((row) => ({\n ...row,\n action: actionOf(row, now),\n payable: payableOf(row, now),\n }));\n\n const latest = useRef(subscriptions);\n latest.current = subscriptions;\n const manage = useCallback(\n async (id: string): Promise<MesubSubscription | null> => {\n const held = latest.current.find((row) => row.id === id);\n if (!held?.action) return null;\n const { action, payable: _, ...subscription } = held;\n return open({ subscription, action });\n },\n [open],\n );\n\n const payNow = useCallback(\n async (id: string): Promise<PayNowResult> => {\n try {\n await api.payNow(id);\n } catch (failure) {\n const wait = busyFor(failure);\n return {\n ok: false,\n message: payNowRefusal(failure),\n ...(wait === null ? {} : { retryAfter: wait }),\n };\n }\n // Still late until the pull lands: read again for what it says now.\n void reload();\n return { ok: true, message: PAY_NOW_SENT };\n },\n [api, reload],\n );\n\n return { state, subscriptions, error, reload, payNow, manage };\n}\n\nexport const STATUS: Record<string, string> = {\n active: 'Active',\n unpaid: 'Payment late',\n cancelled: 'Cancelled',\n stopped: 'Stopped',\n ended: 'Ended',\n};\n\nconst ACTION: Record<MesubAction, string> = { cancel: 'Cancel', resume: 'Resume', close: 'Close' };\n\n/** The one date that matters now: the next charge, the next try, or when access ends. */\nexport function fact(row: MesubHeldSubscription): { term: string; date: string } | null {\n const pick = (term: string, iso: string | null) => {\n const date = moment(iso);\n return date ? { term, date } : null;\n };\n if (row.status === 'cancelled') {\n return pick('Access until', row.access_until ?? row.current_period_end);\n }\n // On Free no try of Mesub's comes: what is left is the date to pay by.\n if (row.status === 'unpaid') {\n return pick('Next try', row.next_retry_at) ?? pick('Pay by', row.retry_deadline);\n }\n if (row.status === 'active') {\n // No charge to come, in the last period of a plan that ends: what is left is its access.\n return pick('Next charge', row.next_charge_at) ?? pick('Access until', row.access_until);\n }\n return null;\n}\n\n/**\n * When it can be closed, when not yet: the date Mesub serves (Mesub-io/backend#402),\n * the end of the period a cancellation set. Null once it can be, or with no date known.\n */\nexport function closeFrom(row: MesubHeldSubscription): string | null {\n if (row.closable !== false || row.action === 'close') return null;\n return moment(row.closable_from);\n}\n\n/** Why it stopped, by `stop_reason`, in the words the subscriber reads. */\nfunction stoppedNote(row: MesubHeldSubscription): string {\n const open =\n \"Its subscription account stays open on your wallet, so the plan's owner could still charge it: cancel it if you are not coming back.\";\n switch (row.stop_reason) {\n case 'out_of_retries':\n return `Stopped: every retry of the missed payment failed, and your access has ended. ${open}`;\n case 'retry_deadline_passed':\n return `Stopped: the missed payment was not paid by the date to pay by, and your access has ended. ${open}`;\n case 'authority_closed':\n return `Stopped: your wallet's approval for this token was closed for good, so no payment can go through any more, and your access has ended.${\n row.action === 'close' ? ' Close it to get its deposit back.' : ''\n }`;\n default:\n return 'Stopped after missed payments. Nothing more is charged.';\n }\n}\n\n/** What to do or expect, in a sentence, when the status alone does not say. Null on a healthy one. */\nexport function noteOf(row: MesubHeldSubscription): string | null {\n if (row.paused) return 'Parked: nothing is charged while it is.';\n // Never whose cause it is: the merchant's setup is not the subscriber's to read.\n if (row.blocked_since && (row.status === 'active' || row.status === 'unpaid')) {\n const until = moment(row.access_until);\n return `Payments are on hold for now. There is nothing for you to do${\n until ? `, and your access runs until ${until}` : ''\n }.`;\n }\n if (row.status === 'unpaid') {\n // Adding funds only fixes a low balance: said for that, and when Mesub names no reason.\n if (row.late_reason === 'approval_revoked') {\n return 'The last payment did not go through. This wallet no longer lets Mesub charge it: adding funds will not fix it.';\n }\n if (row.late_reason === 'authority_closed') {\n return 'The last payment did not go through. This wallet closed its authorisation: it can no longer be charged.';\n }\n if (row.next_retry_at) {\n return 'The last payment did not go through. Add funds to the wallet, then pay now, with nothing to sign; otherwise Mesub tries again at the next try.';\n }\n return row.retry_deadline\n ? 'The last payment did not go through, so access is off. Add funds to the wallet, then pay now, with nothing to sign, before the date to pay by.'\n : 'The last payment did not go through. Add funds to the wallet, then pay now.';\n }\n if (row.status === 'cancelled') {\n if (row.action === 'close') return 'Cancelled, and over. Close it to get its deposit back.';\n // Cancelled with a payment missed: no resume, and the payment is not collected.\n if (!row.access) {\n return 'Cancelled. Your last payment was missed, so you have no access, and Mesub will not collect it. Close it once it ends to get its deposit back.';\n }\n return 'Cancelled. Resume before the end to keep it.';\n }\n if (row.status === 'stopped') return stoppedNote(row);\n if (row.status === 'ended') {\n return row.action === 'close'\n ? 'Ended. Close it to get its deposit back.'\n : 'Ended. Nothing more is charged.';\n }\n return null;\n}\n\n/** The plans named by the rows, read best effort: a slug stands in for one that cannot be read. */\nfunction usePlans(slugs: string[]): Record<string, MesubPlan> {\n const { plan } = useMesubInternal();\n const [plans, setPlans] = useState<Record<string, MesubPlan>>({});\n const key = [...new Set(slugs)].sort().join(',');\n\n useEffect(() => {\n let live = true;\n for (const slug of key ? key.split(',') : []) {\n plan(slug).then(\n (served) => live && setPlans((known) => ({ ...known, [slug]: served })),\n () => undefined,\n );\n }\n return () => {\n live = false;\n };\n }, [key, plan]);\n\n return plans;\n}\n\n/** \"Pay now\", and what came of it, read out where it was clicked. */\nexport function PayNow({ pay }: { pay(): Promise<PayNowResult> }) {\n const [busy, setBusy] = useState(false);\n const [said, setSaid] = useState<PayNowResult | null>(null);\n // Mesub was busy: the button waits this many seconds, then can be pressed again.\n const [wait, setWait] = useState(0);\n\n useEffect(() => {\n if (wait <= 0) return;\n const timer = setTimeout(() => {\n setWait(wait - 1);\n if (wait === 1) setSaid(null);\n }, 1000);\n return () => clearTimeout(timer);\n }, [wait]);\n\n async function click() {\n setBusy(true);\n try {\n const result = await pay();\n setSaid(result);\n setWait(result.retryAfter ?? 0);\n } finally {\n setBusy(false);\n }\n }\n\n const tone = said?.ok ? 'sent' : wait > 0 ? 'wait' : 'refused';\n return (\n <div data-mesub-pay-now=\"\">\n <button\n type=\"button\"\n data-mesub-action=\"pay-now\"\n disabled={busy || wait > 0}\n aria-busy={busy || undefined}\n onClick={() => void click()}\n >\n {wait > 0 ? `Pay again in ${wait} s` : 'Pay now'}\n </button>\n {said ? (\n <p role={said.ok ? 'status' : 'alert'} data-mesub-pay-now-said={tone}>\n {said.message}\n </p>\n ) : null}\n </div>\n );\n}\n\nexport interface ManageSubscriptionsProps extends HTMLAttributes<HTMLDivElement> {\n // Called when one was cancelled, resumed or closed.\n onChanged?: ((subscription: MesubSubscription) => void) | undefined;\n}\n\n/**\n * The signed-in customer's subscriptions, each with its status, its next date\n * and the one thing it allows now. Styled by its data-mesub-* attributes.\n */\nexport function ManageSubscriptions({ onChanged, ...rest }: ManageSubscriptionsProps) {\n const { theme } = useMesubInternal();\n const { state, subscriptions, error, reload, payNow, manage } = useSubscriptions();\n const plans = usePlans(subscriptions.flatMap((row) => (row.plan ? [row.plan] : [])));\n const [retrying, setRetrying] = useState(false);\n\n async function act(id: string) {\n const changed = await manage(id);\n if (changed) onChanged?.(changed);\n }\n\n async function retry() {\n setRetrying(true);\n try {\n await reload();\n } finally {\n setRetrying(false);\n }\n }\n\n let body;\n if (state === 'loading') {\n body = (\n <p data-mesub-notice=\"\" role=\"status\" aria-busy=\"true\">\n Loading your subscriptions\n </p>\n );\n } else if (state === 'signed-out') {\n body = <p data-mesub-empty=\"signed-out\">Sign in on this site to see your subscriptions.</p>;\n } else if (state === 'error') {\n body = (\n <>\n <p role=\"alert\" data-mesub-error=\"\">\n {error}\n </p>\n <button\n type=\"button\"\n data-mesub-retry=\"\"\n disabled={retrying}\n aria-busy={retrying || undefined}\n onClick={() => void retry()}\n >\n Try again\n </button>\n </>\n );\n } else if (subscriptions.length === 0) {\n body = <p data-mesub-empty=\"none\">You have no subscription yet.</p>;\n } else {\n body = (\n <ul data-mesub-subscription-list=\"\" aria-label=\"Your subscriptions\">\n {subscriptions.map((row) => {\n const plan = row.plan ? plans[row.plan] : undefined;\n const dated = fact(row);\n const name = plan?.name ?? row.plan ?? 'Subscription';\n const since = day(row.confirmed_at);\n const note = noteOf(row);\n const price = plan ? briefPrice(plan) : null;\n return (\n <li key={row.id} data-mesub-subscription={row.id}>\n <div data-mesub-subscription-head=\"\">\n {plan?.logo_url ? (\n <img data-mesub-logo=\"\" src={plan.logo_url} alt=\"\" />\n ) : (\n <span data-mesub-logo=\"\" aria-hidden=\"true\">\n {name.slice(0, 1).toUpperCase()}\n </span>\n )}\n <div data-mesub-subscription-name=\"\">\n <strong>{name}</strong>\n {plan ? <span>by {plan.project_name}</span> : null}\n </div>\n <span data-mesub-status={row.paused ? 'paused' : row.status}>\n {row.paused ? 'Parked' : (STATUS[row.status] ?? row.status)}\n </span>\n </div>\n {plan && price ? (\n <p data-mesub-subscription-price=\"\">\n <strong title={price.title} data-mesub-fit={fit(price.text)}>\n <TokenLogo plan={plan} />\n {price.text}\n </strong>{' '}\n {cadence(plan.period_hours)}\n </p>\n ) : null}\n <dl data-mesub-summary=\"\">\n {dated ? (\n <div data-mesub-row=\"\">\n <dt>{dated.term}</dt>\n <dd>{dated.date}</dd>\n </div>\n ) : null}\n {since ? (\n <div data-mesub-row=\"\">\n <dt>Since</dt>\n <dd>{since}</dd>\n </div>\n ) : null}\n {closeFrom(row) ? (\n <div data-mesub-row=\"\">\n <dt>Close from</dt>\n <dd>{closeFrom(row)}</dd>\n </div>\n ) : null}\n <div data-mesub-row=\"\">\n <dt>Paid from</dt>\n <dd title={row.wallet}>{shortAddress(row.wallet)}</dd>\n </div>\n </dl>\n {note ? <p data-mesub-subscription-note=\"\">{note}</p> : null}\n {row.payable ? <PayNow pay={() => payNow(row.id)} /> : null}\n {row.action ? (\n <button\n type=\"button\"\n data-mesub-action={row.action}\n onClick={() => void act(row.id)}\n >\n {ACTION[row.action]}\n </button>\n ) : null}\n </li>\n );\n })}\n </ul>\n );\n }\n\n return (\n <div\n {...rest}\n data-mesub-subscriptions=\"\"\n data-mesub-state={state}\n data-mesub-theme={theme}\n >\n {body}\n </div>\n );\n}\n\nexport interface ManageButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n // The plan whose subscription it opens. Left out: the customer's live one, whatever the plan.\n plan?: string | undefined;\n}\n\n/**\n * Opens the customer's subscription to a plan in the Mesub window: how it\n * stands, what comes next, what was charged, and cancel, resume or close.\n */\nexport const ManageButton = forwardRef<HTMLButtonElement, ManageButtonProps>(function ManageButton(\n { plan, children, onClick, ...rest },\n ref,\n) {\n const { openSubscription, theme } = useMesubInternal();\n\n return (\n <button\n type=\"button\"\n {...rest}\n ref={ref}\n data-mesub-manage-button=\"\"\n data-mesub-theme={theme}\n onClick={(event) => {\n onClick?.(event);\n if (!event.defaultPrevented) openSubscription(plan);\n }}\n >\n {children ?? 'Manage subscription'}\n </button>\n );\n});\n","import {\n forwardRef,\n useCallback,\n useEffect,\n useRef,\n useState,\n type ButtonHTMLAttributes,\n type MouseEvent,\n} from 'react';\nimport { useMesubInternal, type SubscribeState } from './context';\nimport { explorerUrl, moment } from './format';\nimport type { MesubSubscription } from './types';\n\nexport interface UseSubscribeOptions {\n // Called once Mesub confirmed it, even if the dialog was closed meanwhile.\n onSubscribed?: ((subscription: MesubSubscription) => void) | undefined;\n}\n\n/** What `useSubscribe()` returns. */\nexport interface UseSubscribeResult {\n // `open` while the dialog is up and nothing is being signed.\n state: SubscribeState;\n subscription: MesubSubscription | null;\n // The transaction that paid the first period, base58, when the wallet is its first signer.\n signature: string | null;\n // Opens the checkout. Resolves when it closes: the subscription, or null if it did not go through.\n subscribe(): Promise<MesubSubscription | null>;\n}\n\n/** The subscribe flow, for a button of your own: `subscribe()` opens the Mesub checkout. */\nexport function useSubscribe(plan: string, options: UseSubscribeOptions = {}): UseSubscribeResult {\n const { subscribe: open } = useMesubInternal();\n\n const [state, setState] = useState<SubscribeState>('idle');\n const [subscription, setSubscription] = useState<MesubSubscription | null>(null);\n const [signature, setSignature] = useState<string | null>(null);\n\n // Read at call time: the latest render's callback, without a new `subscribe`.\n const latest = useRef(options);\n latest.current = options;\n const alive = useRef(true);\n useEffect(() => {\n alive.current = true;\n return () => {\n alive.current = false;\n };\n }, []);\n\n const subscribe = useCallback(async (): Promise<MesubSubscription | null> => {\n let done = false;\n const result = await open({\n plan,\n onState: (next) => alive.current && setState(next),\n onSubscribed: (confirmed, paid) => {\n done = true;\n if (alive.current) {\n setSubscription(confirmed);\n setSignature(paid);\n // It may land after the dialog was closed: the button says so all the same.\n setState('subscribed');\n }\n latest.current.onSubscribed?.(confirmed);\n },\n });\n // Closed before the end: back to where it was.\n if (alive.current) setState(done ? 'subscribed' : 'idle');\n return result;\n }, [open, plan]);\n\n return { state, subscription, signature, subscribe };\n}\n\nexport interface SubscribeButtonProps\n extends UseSubscribeOptions, ButtonHTMLAttributes<HTMLButtonElement> {\n // The plan's slug, as set in the Mesub dashboard.\n plan: string;\n}\n\nconst LABELS: Partial<Record<SubscribeState, string>> = {\n signing: 'Approve in your wallet',\n confirming: 'Confirming',\n subscribed: 'Subscribed',\n};\n\n/**\n * Opens the Mesub checkout for a plan. Busy is aria-disabled, not disabled, so\n * the keyboard focus stays on it; only subscribed disables it.\n */\nexport const SubscribeButton = forwardRef<HTMLButtonElement, SubscribeButtonProps>(\n function SubscribeButton(\n { plan, onSubscribed, children, onClick, disabled, type, ...rest },\n ref,\n ) {\n const { chain, theme } = useMesubInternal();\n const { state, subscription, signature, subscribe } = useSubscribe(plan, { onSubscribed });\n const busy = state === 'signing' || state === 'confirming';\n const due = moment(subscription?.next_charge_at);\n\n function click(event: MouseEvent<HTMLButtonElement>) {\n if (busy) return;\n onClick?.(event);\n if (!event.defaultPrevented) void subscribe();\n }\n\n return (\n <>\n <button\n {...rest}\n ref={ref}\n type={type ?? 'button'}\n disabled={Boolean(disabled) || state === 'subscribed'}\n aria-busy={busy || undefined}\n aria-disabled={busy || undefined}\n onClick={click}\n data-mesub-subscribe=\"\"\n data-mesub-state={state}\n data-mesub-theme={theme}\n >\n {LABELS[state] ?? children ?? 'Subscribe'}\n </button>\n {state === 'subscribed' && (due || signature) ? (\n <span data-mesub-receipt=\"\" data-mesub-theme={theme}>\n {due ? `Next charge ${due}` : null}\n {due && signature ? ' · ' : null}\n {signature ? (\n <a href={explorerUrl(signature, chain)} target=\"_blank\" rel=\"noopener\">\n Receipt\n </a>\n ) : null}\n </span>\n ) : null}\n </>\n );\n },\n);\n"],"mappings":"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","names":["import_react","seconds","import_react","import_react","import_jsx_runtime","said","short","import_react","import_react","refusal","import_jsx_runtime","import_jsx_runtime","refused","refusal","latest","nextCharge","fact","import_react","import_jsx_runtime","SAFE","PENDING","messageOf","refusal","import_react","import_react","import_jsx_runtime","said","ManageButton","import_jsx_runtime","ACTION","said","import_jsx_runtime","plan","import_react","import_jsx_runtime","SubscribeButton"]}
|