@usethrottle/auth 0.12.1 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +10 -0
  2. package/dist/{AccountModal-KA54WUFW.js → AccountModal-4GF7X5X4.js} +2 -2
  3. package/dist/{chunk-6WN3J5MM.js → chunk-37RG635A.js} +4 -17
  4. package/dist/{chunk-6WN3J5MM.js.map → chunk-37RG635A.js.map} +1 -1
  5. package/dist/chunk-PTREZIKS.js +31 -0
  6. package/dist/chunk-PTREZIKS.js.map +1 -0
  7. package/dist/{chunk-VDK23T6L.js → chunk-X4IZ7RC6.js} +2 -2
  8. package/dist/{chunk-RCNUWITB.js → chunk-YRJFGH6J.js} +2 -2
  9. package/dist/{client-7LVKfuXO.d.ts → client-BripyQad.d.ts} +5 -3
  10. package/dist/{hooks-DkpLrEiC.d.ts → hooks-q2sYQa7f.d.ts} +1 -1
  11. package/dist/index.cjs +38 -2
  12. package/dist/index.cjs.map +1 -1
  13. package/dist/index.d.cts +8 -3
  14. package/dist/index.d.ts +8 -3
  15. package/dist/index.js +27 -1
  16. package/dist/index.js.map +1 -1
  17. package/dist/react/components/account/index.d.ts +3 -2
  18. package/dist/react/components/account/index.js +1 -1
  19. package/dist/react/components/auth/index.js +2 -2
  20. package/dist/react/components/index.cjs +55 -35
  21. package/dist/react/components/index.cjs.map +1 -1
  22. package/dist/react/components/index.d.cts +12 -4
  23. package/dist/react/components/index.d.ts +14 -6
  24. package/dist/react/components/index.js +25 -4
  25. package/dist/react/components/index.js.map +1 -1
  26. package/dist/react/components/provider.d.ts +2 -1
  27. package/dist/react/components/provider.js +1 -1
  28. package/dist/react/index.cjs +36 -0
  29. package/dist/react/index.cjs.map +1 -1
  30. package/dist/react/index.d.cts +7 -3
  31. package/dist/react/index.d.ts +7 -4
  32. package/dist/react/index.js +24 -1
  33. package/package.json +4 -1
  34. package/dist/chunk-ETYOOYYV.js +0 -2
  35. package/dist/chunk-ETYOOYYV.js.map +0 -1
  36. /package/dist/{AccountModal-KA54WUFW.js.map → AccountModal-4GF7X5X4.js.map} +0 -0
  37. /package/dist/{chunk-VDK23T6L.js.map → chunk-X4IZ7RC6.js.map} +0 -0
  38. /package/dist/{chunk-RCNUWITB.js.map → chunk-YRJFGH6J.js.map} +0 -0
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/request.ts","../src/session.ts","../src/storage.ts","../src/client.ts","../src/account.ts"],"sourcesContent":["export class ThrottleAuthError extends Error {\n readonly code: string;\n readonly statusCode: number;\n readonly retryAfter?: number;\n readonly details?: unknown;\n\n constructor(args: { code: string; message: string; statusCode: number; retryAfter?: number; details?: unknown }) {\n super(args.message);\n this.name = 'ThrottleAuthError';\n this.code = args.code;\n this.statusCode = args.statusCode;\n this.retryAfter = args.retryAfter;\n this.details = args.details;\n }\n}\n","import { ThrottleAuthError } from './errors';\n\nexport interface RequestInput {\n method: string;\n path: string;\n baseUrl: string;\n publishableKey: string;\n accessToken?: string;\n stepUpToken?: string;\n body?: unknown;\n}\n\n/** Returns the UNWRAPPED `data` from the `{ data: … }` envelope. Throws ThrottleAuthError otherwise. */\nexport async function request(input: RequestInput): Promise<any> {\n const headers: Record<string, string> = { 'X-API-Key': input.publishableKey };\n if (input.body !== undefined) headers['Content-Type'] = 'application/json';\n if (input.accessToken) headers.Authorization = `Bearer ${input.accessToken}`;\n if (input.stepUpToken) headers['X-Step-Up'] = input.stepUpToken;\n\n const res = await fetch(`${input.baseUrl}/v1/storefront${input.path}`, {\n method: input.method,\n headers,\n ...(input.body !== undefined ? { body: JSON.stringify(input.body) } : {}),\n });\n\n const text = await res.text();\n let parsed: any = {};\n try {\n parsed = text ? JSON.parse(text) : {};\n } catch {\n // Non-JSON body — an HTML gateway page, say. Leave parsed empty so the\n // branch below still throws a typed error rather than a raw SyntaxError.\n }\n\n if (!res.ok) {\n const e = parsed?.error ?? {};\n // `Retry-After` is server-controlled but not trusted: Number('soon') is\n // NaN, and a NaN reaches the UI as \"wait NaN seconds\".\n const ra = Number(res.headers.get('retry-after'));\n throw new ThrottleAuthError({\n code: e.code ?? 'request_failed',\n message: e.message ?? `Request failed with ${res.status}`,\n statusCode: res.status,\n retryAfter: Number.isFinite(ra) && ra >= 0 ? ra : undefined,\n details: e.details,\n });\n }\n\n // `'data' in parsed`, not `parsed?.data ?? parsed`: a legitimate\n // `{ \"data\": null }` is nullish, and `??` would fall through and hand the\n // caller the whole envelope instead of the null the API actually sent.\n return parsed && typeof parsed === 'object' && 'data' in parsed ? parsed.data : (parsed ?? {});\n}\n","import type { Customer, Session } from './types';\n\nexport type AuthStatus = 'loading' | 'authenticated' | 'unauthenticated';\n\nexport interface AuthSnapshot {\n status: AuthStatus;\n customer: Customer | null;\n /**\n * False here does NOT only mean \"we emailed them and they have not clicked\".\n * While it is false the API may also be withholding pre-existing account\n * data behind the claim cutoff — empty order lists and a 403 on `PATCH /me`\n * are expected, not broken. See the plan header.\n */\n emailVerified: boolean;\n}\n\ntype Listener = (snapshot: AuthSnapshot) => void;\n\nexport class SessionState {\n #snapshot: AuthSnapshot = { status: 'loading', customer: null, emailVerified: false };\n #accessToken: string | null = null;\n #expiresAt: number | null = null;\n #listeners = new Set<Listener>();\n\n get(): AuthSnapshot { return this.#snapshot; }\n accessToken(): string | null { return this.#accessToken; }\n expiresAt(): number | null { return this.#expiresAt; }\n\n setSession(session: Session): void {\n this.#accessToken = session.accessToken;\n this.#expiresAt = Date.parse(session.expiresAt);\n this.#publish({\n status: 'authenticated',\n customer: session.customer,\n emailVerified: Boolean(session.customer?.emailVerified),\n });\n }\n\n setStatus(status: AuthStatus): void {\n this.#publish({ ...this.#snapshot, status });\n }\n\n clear(): void {\n this.#accessToken = null;\n this.#expiresAt = null;\n this.#publish({ status: 'unauthenticated', customer: null, emailVerified: false });\n }\n\n subscribe(fn: Listener): () => void {\n this.#listeners.add(fn);\n return () => { this.#listeners.delete(fn); };\n }\n\n #publish(next: AuthSnapshot): void {\n // Identity matters: React's useSyncExternalStore re-renders on reference\n // change, and a token refresh every ten minutes must not re-render the\n // whole account area when nothing visible changed.\n const same =\n next.status === this.#snapshot.status &&\n next.emailVerified === this.#snapshot.emailVerified &&\n customerEquals(next.customer, this.#snapshot.customer);\n if (same) return;\n this.#snapshot = next;\n for (const fn of [...this.#listeners]) {\n // A merchant's subscriber throwing must not stop the rest from hearing.\n try { fn(next); } catch { /* merchant callback */ }\n }\n }\n}\n\nfunction customerEquals(a: Customer | null, b: Customer | null): boolean {\n if (a === b) return true;\n if (!a || !b) return false;\n const keys = new Set([...Object.keys(a), ...Object.keys(b)]) as Set<keyof Customer>;\n for (const k of keys) if (a[k] !== b[k]) return false;\n return true;\n}\n","import type { AuthStorage } from './types';\n\nexport type { AuthStorage };\n\nexport function memoryStorage(): AuthStorage {\n const map = new Map<string, string>();\n return {\n get: (k) => map.get(k) ?? null,\n set: (k, v) => void map.set(k, v),\n remove: (k) => void map.delete(k),\n };\n}\n\n/**\n * localStorage when it works, memory when it does not. Safari private mode,\n * hardened browser settings and server-side rendering all make localStorage\n * either absent or throwing; none of them may take the storefront down.\n */\nexport function localStorageAdapter(): AuthStorage {\n const fallback = memoryStorage();\n const ls = (): Storage | null => {\n try {\n return typeof localStorage !== 'undefined' ? localStorage : null;\n } catch {\n return null;\n }\n };\n return {\n get(k) {\n try {\n const v = ls()?.getItem(k);\n if (v != null) return v;\n } catch { /* fall through */ }\n return fallback.get(k);\n },\n set(k, v) {\n fallback.set(k, v);\n try { ls()?.setItem(k, v); } catch { /* memory-only this session */ }\n },\n remove(k) {\n fallback.remove(k);\n try { ls()?.removeItem(k); } catch { /* already gone */ }\n },\n };\n}\n","import { request } from './request';\nimport { ThrottleAuthError } from './errors';\nimport { SessionState, type AuthSnapshot } from './session';\nimport { localStorageAdapter, type AuthStorage } from './storage';\nimport type { Customer, Session, ThrottleAuthConfig } from './types';\n\nconst DEFAULT_BASE_URL = 'https://api.usethrottle.dev';\n/** Refresh this far before expiry so ordinary calls rarely see a 401 at all. */\nconst REFRESH_SKEW_MS = 30_000;\n\nexport interface DeviceSession {\n id: string;\n userAgent: string | null;\n ipPrefix: string | null;\n createdAt: string;\n lastUsedAt: string;\n current: boolean;\n}\n\nexport interface ThrottleAuth {\n register(email: string, password: string): Promise<{ status: 'active' | 'pending' }>;\n signIn(email: string, password: string): Promise<void>;\n signOut(): Promise<void>;\n signOutEverywhere(): Promise<void>;\n restore(): Promise<void>;\n getSnapshot(): AuthSnapshot;\n /**\n * The current access token, refreshed first when it is about to expire\n * (single-flight, shared with every other caller), or null when signed out.\n * Rejects when a refresh fails without ending the session (a 5xx, a 429 or\n * a network error); the buyer stays signed in. `@usethrottle/catalog`\n * treats a rejection as signed out for that request.\n * Pass it to `@usethrottle/catalog`'s `customerToken`.\n */\n getAccessToken(): Promise<string | null>;\n subscribe(fn: (s: AuthSnapshot) => void): () => void;\n stepUp(password: string): Promise<void>;\n call<T = any>(method: string, path: string, body?: unknown): Promise<T>;\n verifyEmail(token: string): Promise<void>;\n resendVerification(): Promise<void>;\n forgotPassword(email: string): Promise<void>;\n resetPassword(token: string, password: string): Promise<void>;\n changePassword(password: string): Promise<void>;\n listSessions(): Promise<DeviceSession[]>;\n revokeSession(id: string): Promise<void>;\n /**\n * Resolves once any sign-in or registration claim in flight has settled.\n * `createThrottleAuth` always supplies it (it resolves at once there);\n * `ThrottleProvider` supplies one that tracks its cart claim. Optional so a\n * hand-made `ThrottleAuth` written against 0.11 still compiles.\n */\n whenClaimSettled?(): Promise<void>;\n}\n\nexport function createThrottleAuth(\n config: ThrottleAuthConfig,\n): ThrottleAuth & Required<Pick<ThrottleAuth, 'whenClaimSettled'>> {\n const baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, '');\n const storage: AuthStorage = config.storage ?? localStorageAdapter();\n // Namespaced by key so two Throttle applications on one origin cannot read\n // each other's refresh token out of shared localStorage.\n const storageKey = `throttle_auth_rt:${config.publishableKey}`;\n const lockName = `throttle_auth_refresh:${config.publishableKey}`;\n\n const state = new SessionState();\n let refreshInFlight: Promise<void> | null = null;\n let stepUpToken: string | null = null;\n let stepUpExpiresAt = 0;\n\n const base = { baseUrl, publishableKey: config.publishableKey };\n\n async function persist(session: Session): Promise<void> {\n state.setSession(session);\n await storage.set(storageKey, session.refreshToken);\n }\n\n async function forget(): Promise<void> {\n stepUpToken = null;\n state.clear();\n await storage.remove(storageKey);\n }\n\n /**\n * Cross-tab single flight. Two tabs refreshing at once would each present the\n * same stored token; the second is a replay, and the server kills the family.\n * Web Locks serialises them; where it is unavailable the in-process guard\n * below still covers the common single-tab case.\n */\n function withLock<T>(fn: () => Promise<T>): Promise<T> {\n const locks = (globalThis as any).navigator?.locks;\n return locks?.request ? locks.request(lockName, fn) : fn();\n }\n\n async function doRefresh(): Promise<void> {\n await withLock(async () => {\n // Re-read INSIDE the lock: another tab may have rotated while we waited,\n // and presenting the token we read before the lock would be a replay.\n const refreshToken = await storage.get(storageKey);\n if (!refreshToken) {\n await forget();\n throw new ThrottleAuthError({ code: 'session_revoked', message: 'No session', statusCode: 401 });\n }\n try {\n const data = await request({ ...base, method: 'POST', path: '/auth/refresh', body: { refreshToken } });\n await persist(data as Session);\n } catch (err) {\n // Drop the stored token ONLY when the server actually refused the\n // session: 401 session_revoked, or 403 environment_mismatch. Those are\n // the two the refresh route returns, and there is nothing left to\n // retry with in either case.\n //\n // Everything else keeps the token. `request()` throws a\n // ThrottleAuthError for EVERY non-2xx, so testing the error class\n // alone also caught a 502 with an HTML gateway body — a buyer whose\n // tab refreshed during a rolling deploy was permanently signed out\n // client-side even though their session was never invalidated. A 429\n // is the same shape: \"try later\", not \"you are logged out\". And a\n // fetch() that rejects outright never produces a ThrottleAuthError,\n // so it was already handled.\n const refused =\n err instanceof ThrottleAuthError && (err.statusCode === 401 || err.statusCode === 403);\n if (refused) await forget();\n throw err;\n }\n });\n }\n\n function refresh(): Promise<void> {\n if (!refreshInFlight) {\n refreshInFlight = doRefresh().finally(() => { refreshInFlight = null; });\n }\n return refreshInFlight;\n }\n\n async function accessToken(): Promise<string | null> {\n const expires = state.expiresAt();\n if (state.accessToken() && expires && expires - Date.now() > REFRESH_SKEW_MS) {\n return state.accessToken();\n }\n if (await storage.get(storageKey)) {\n await refresh();\n return state.accessToken();\n }\n return state.accessToken();\n }\n\n async function ensureStepUp(): Promise<boolean> {\n if (stepUpToken && stepUpExpiresAt > Date.now()) return true;\n if (!config.onStepUpRequired) return false;\n const password = await config.onStepUpRequired();\n if (!password) return false;\n await stepUp(password);\n return true;\n }\n\n async function stepUp(password: string): Promise<void> {\n const data = await request({\n ...base, method: 'POST', path: '/auth/step-up',\n accessToken: await accessToken() ?? undefined, body: { password },\n });\n stepUpToken = data.stepUpToken;\n stepUpExpiresAt = Date.now() + (Number(data.expiresIn) || 300) * 1000 - 5_000;\n }\n\n async function call<T = any>(method: string, path: string, body?: unknown): Promise<T> {\n let retriedAuth = false;\n let retriedStepUp = false;\n // Only true on the retry that follows a `step_up_required` 403 — never\n // attached speculatively. Sending an authorization-grade header on every\n // request once minted meant it rode along on unrelated calls too, and\n // cross-origin each of those then failed CORS preflight. The cost is one\n // extra round trip per gated call, which is how the server signals\n // step-up in the first place.\n let sendStepUp = false;\n\n for (;;) {\n const token = await accessToken();\n try {\n return await request({\n ...base, method, path, body,\n accessToken: token ?? undefined,\n stepUpToken: sendStepUp ? (stepUpToken ?? undefined) : undefined,\n });\n } catch (err) {\n const e = err as ThrottleAuthError;\n // `session_revoked` belongs here too. The server returns it for a\n // stale session EPOCH as well as for a genuinely dead session, and a\n // changed password bumps the epoch while deliberately sparing the\n // current session — so one refresh recovers it. When the session\n // really is dead the refresh fails and forget() runs, which is the\n // same outcome, one request later.\n const expired = e.statusCode === 401 &&\n (e.code === 'unauthorized' || e.code === 'token_expired' || e.code === 'session_revoked');\n if (expired && !retriedAuth) {\n retriedAuth = true;\n await refresh(); // shared — ten callers here produce ONE request\n continue;\n }\n if (e.code === 'step_up_required' && !retriedStepUp) {\n retriedStepUp = true;\n // ensureStepUp() reuses the cached token when it's still within its\n // 300s validity (no re-prompt); it was never sent above, so this is\n // the first the server has seen of it for this call.\n if (await ensureStepUp()) { sendStepUp = true; continue; }\n }\n throw err;\n }\n }\n }\n\n return {\n async register(email, password) {\n const data = await request({ ...base, method: 'POST', path: '/auth/register', body: { email, password } });\n if (data?.status === 'pending') return { status: 'pending' };\n await persist(data as Session);\n return { status: 'active' };\n },\n\n async signIn(email, password) {\n const data = await request({ ...base, method: 'POST', path: '/auth/login', body: { email, password } });\n await persist(data as Session);\n },\n\n async signOut() {\n try { await call('POST', '/auth/logout'); } catch { /* local state still goes */ }\n await forget();\n },\n\n async signOutEverywhere() {\n try { await call('POST', '/auth/logout-all'); } catch { /* local state still goes */ }\n await forget();\n },\n\n async restore() {\n if (!(await storage.get(storageKey))) { state.setStatus('unauthenticated'); return; }\n try { await refresh(); } catch { /* forget() already ran */ }\n },\n\n getSnapshot: () => state.get(),\n\n async getAccessToken() {\n try {\n return await accessToken();\n } catch (err) {\n // A refused refresh already ran forget(): the buyer is signed out.\n // Anything else (a 502, a network error) keeps the session; rethrow.\n if (state.get().status === 'unauthenticated') return null;\n throw err;\n }\n },\n\n subscribe: (fn) => state.subscribe(fn),\n stepUp,\n call,\n\n async verifyEmail(token) {\n await request({ ...base, method: 'POST', path: '/auth/verify-email', body: { token } });\n // `ver` is a claim baked into the access token, and the claim cutoff is\n // read from the session row. Without a new token the buyer stays gated —\n // and their own order history stays hidden — for the rest of this\n // token's ten minutes.\n if (await storage.get(storageKey)) {\n try { await refresh(); } catch { /* verification still succeeded */ }\n }\n },\n\n async resendVerification() {\n await call('POST', '/auth/verify-email/resend');\n },\n\n async forgotPassword(email) {\n // Always 202, whether or not the address has an account. Do not infer\n // anything from it and do not tell the buyer whether it existed.\n await request({ ...base, method: 'POST', path: '/auth/forgot-password', body: { email } });\n },\n\n async resetPassword(token, password) {\n await request({ ...base, method: 'POST', path: '/auth/reset-password', body: { token, password } });\n // The server revokes every session on reset, this one included.\n await forget();\n },\n\n async changePassword(password) {\n await call('POST', '/me/change-password', { password });\n // The change bumps the session epoch. This session was deliberately\n // spared, but the access token in hand now carries a stale epoch and the\n // next write would 401. Rotate now rather than on the buyer's next click\n // — and do not let a failed rotation report a change that already\n // succeeded server-side as a failure.\n try { await refresh(); } catch { /* the password change already succeeded */ }\n },\n\n async listSessions() {\n return call<DeviceSession[]>('GET', '/me/sessions');\n },\n\n async revokeSession(id) {\n const mine = await call<DeviceSession[]>('GET', '/me/sessions');\n const current = mine.find((s) => s.current);\n await call('DELETE', `/me/sessions/${encodeURIComponent(id)}`);\n if (current?.id === id) await forget();\n },\n\n // The core never claims a cart; `ThrottleProvider` overrides this with one\n // that tracks its sign-in claim.\n whenClaimSettled: () => Promise.resolve(),\n };\n}\n\nexport type { AuthSnapshot, Customer, Session, ThrottleAuthConfig };\n","import type { ThrottleAuth } from './client';\nimport { ThrottleAuthError } from './errors';\nimport type {\n Address, AddressInput, Customer, Invoice, OpenCart, Order, OrderDetail,\n PaymentMethod, ProfilePatch, Subscription, SubscriptionShippingAddress,\n} from './types';\n\nexport interface Page { cursor?: string; limit?: number }\n\n/** What the payment widget needs to render a card form. Passed through from\n * the processor — `buyerExternalIdentifier` in particular must reach the\n * widget unchanged, because the session token pins it and the processor\n * refuses a mismatch by rendering nothing at all. */\nexport interface CardSetupSession {\n embedToken: string;\n checkoutSessionId: string;\n amount: number;\n currency: string;\n merchantAccountId?: string;\n environment?: string;\n buyerExternalIdentifier: string;\n country: string;\n /** A ready-made page that hosts the card form, if you would rather redirect\n * or iframe than embed the widget yourself. */\n hostedUrl: string;\n embedUrl: string;\n}\n\nexport interface ThrottleAccount {\n getProfile(): Promise<Customer>;\n updateProfile(patch: ProfilePatch): Promise<Customer>;\n listAddresses(): Promise<Address[]>;\n createAddress(input: AddressInput): Promise<Address>;\n updateAddress(id: string, patch: Partial<AddressInput>): Promise<Address>;\n deleteAddress(id: string): Promise<void>;\n listPaymentMethods(): Promise<PaymentMethod[]>;\n setDefaultPaymentMethod(id: string): Promise<PaymentMethod>;\n deletePaymentMethod(id: string): Promise<void>;\n /** Opens a processor-hosted session the buyer types their card into. The\n * returned values are handed straight to the payment widget. */\n startCardSetup(): Promise<CardSetupSession>;\n /** Records the card the widget just vaulted, identified by the transaction\n * the widget returns. Safe to call twice with the same id. */\n confirmCardSetup(transactionId: string): Promise<PaymentMethod>;\n listOrders(page?: Page): Promise<Order[]>;\n getOrder(id: string): Promise<OrderDetail>;\n listInvoices(page?: Page): Promise<Invoice[]>;\n getInvoice(id: string): Promise<Invoice>;\n /** A 600-second signed URL. Fetch it on click — it expires. */\n getInvoicePdfUrl(id: string): Promise<{ url: string }>;\n listSubscriptions(page?: Page): Promise<Subscription[]>;\n getSubscription(id: string): Promise<Subscription>;\n /**\n * Voids an unpaid order. Refused once money has been captured — that is a\n * return, not a cancellation, and only the merchant may move money back.\n */\n cancelOrder(id: string, opts?: { reason?: string }): Promise<Order>;\n /** Opens an RMA the merchant approves. Changes no order state by itself. */\n requestOrderReturn(\n id: string,\n input: { items: Array<{ lineItemId: string; quantity: number }>; reason?: string },\n ): Promise<{ id: string; status: string }>;\n cancelSubscription(id: string, opts?: { atPeriodEnd?: boolean }): Promise<Subscription>;\n pauseSubscription(id: string): Promise<Subscription>;\n resumeSubscription(id: string): Promise<Subscription>;\n /**\n * Where a physical subscription's box goes, from the next renewal. Needs a\n * fresh sign-in (step-up), like cancelling. A subscription that ships\n * nothing answers `subscription_not_physical`.\n */\n updateSubscriptionShippingAddress(id: string, address: SubscriptionShippingAddress): Promise<Subscription>;\n claimCart(cartId: string): Promise<{ cartId: string; customerId: string }>;\n /**\n * The buyer's newest open or idle-abandoned cart in `currency` (see `status`), or null. Answers null as well\n * when the API predates the route (404). Always present on the account that\n * `createAccount` and `ThrottleProvider` build; optional here so a hand-made\n * `ThrottleAccount` written against 0.11 still compiles.\n */\n getOpenCart?(input: { currency: string }): Promise<OpenCart | null>;\n}\n\nconst seg = (v: string) => encodeURIComponent(v);\n\nfunction query(page?: Page): string {\n const params = new URLSearchParams();\n if (page?.cursor) params.set('cursor', page.cursor);\n if (page?.limit != null) params.set('limit', String(page.limit));\n const s = params.toString();\n return s ? `?${s}` : '';\n}\n\nexport function createAccount(\n auth: ThrottleAuth,\n): ThrottleAccount & Required<Pick<ThrottleAccount, 'getOpenCart'>> {\n const { call } = auth;\n return {\n getProfile: () => call('GET', '/me'),\n updateProfile: (patch) => call('PATCH', '/me', patch),\n\n listAddresses: () => call('GET', '/me/addresses'),\n createAddress: (input) => call('POST', '/me/addresses', input),\n updateAddress: (id, patch) => call('PATCH', `/me/addresses/${seg(id)}`, patch),\n deleteAddress: (id) => call('DELETE', `/me/addresses/${seg(id)}`),\n\n listPaymentMethods: () => call('GET', '/me/payment-methods'),\n // The platform has no \"change this subscription's card\" capability, so\n // this is how a buyer changes what they are billed on: move the default.\n setDefaultPaymentMethod: (id) => call('PATCH', `/me/payment-methods/${seg(id)}`, { isDefault: true }),\n deletePaymentMethod: (id) => call('DELETE', `/me/payment-methods/${seg(id)}`),\n\n // Saving a card is two calls because the card number never reaches us: the\n // first mints a processor-hosted embed session, the buyer types their card\n // into that, and the second records what the processor vaulted. Everything\n // about the saved card is read back from the processor, so nothing here\n // trusts what the browser claims the card was.\n startCardSetup: () => call('POST', '/me/payment-methods/embed-token'),\n confirmCardSetup: (transactionId) =>\n call('POST', '/me/payment-methods/confirm', { transactionId }),\n\n listOrders: (page) => call('GET', `/me/orders${query(page)}`),\n getOrder: (id) => call('GET', `/me/orders/${seg(id)}`),\n listInvoices: (page) => call('GET', `/me/invoices${query(page)}`),\n getInvoice: (id) => call('GET', `/me/invoices/${seg(id)}`),\n getInvoicePdfUrl: (id) => call('GET', `/me/invoices/${seg(id)}/pdf`),\n listSubscriptions: (page) => call('GET', `/me/subscriptions${query(page)}`),\n getSubscription: (id) => call('GET', `/me/subscriptions/${seg(id)}`),\n\n cancelOrder: (id, opts) => call('POST', `/me/orders/${seg(id)}/cancel`, opts),\n requestOrderReturn: (id, input) => call('POST', `/me/orders/${seg(id)}/return-request`, input),\n cancelSubscription: (id, opts) => call('POST', `/me/subscriptions/${seg(id)}/cancel`, opts),\n pauseSubscription: (id) => call('POST', `/me/subscriptions/${seg(id)}/pause`),\n resumeSubscription: (id) => call('POST', `/me/subscriptions/${seg(id)}/resume`),\n updateSubscriptionShippingAddress: (id, address) =>\n call('PATCH', `/me/subscriptions/${seg(id)}/shipping-address`, address),\n\n claimCart: (cartId) => call('POST', `/me/carts/${seg(cartId)}/claim`),\n\n async getOpenCart({ currency }) {\n if (typeof currency !== 'string' || !/^[A-Za-z]{3}$/.test(currency)) {\n throw new TypeError('getOpenCart: currency must be a 3-letter ISO code');\n }\n try {\n return await call<OpenCart | null>('GET', `/me/cart?currency=${currency.toUpperCase()}`);\n } catch (err) {\n // An API that predates the route: no cart to follow, not a failure.\n if (err instanceof ThrottleAuthError && err.statusCode === 404) return null;\n throw err;\n }\n },\n };\n}\n"],"mappings":";AAAO,IAAM,oBAAN,cAAgC,MAAM;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,MAAqG;AAC/G,UAAM,KAAK,OAAO;AAClB,SAAK,OAAO;AACZ,SAAK,OAAO,KAAK;AACjB,SAAK,aAAa,KAAK;AACvB,SAAK,aAAa,KAAK;AACvB,SAAK,UAAU,KAAK;AAAA,EACtB;AACF;;;ACDA,eAAsB,QAAQ,OAAmC;AAC/D,QAAM,UAAkC,EAAE,aAAa,MAAM,eAAe;AAC5E,MAAI,MAAM,SAAS,OAAW,SAAQ,cAAc,IAAI;AACxD,MAAI,MAAM,YAAa,SAAQ,gBAAgB,UAAU,MAAM,WAAW;AAC1E,MAAI,MAAM,YAAa,SAAQ,WAAW,IAAI,MAAM;AAEpD,QAAM,MAAM,MAAM,MAAM,GAAG,MAAM,OAAO,iBAAiB,MAAM,IAAI,IAAI;AAAA,IACrE,QAAQ,MAAM;AAAA,IACd;AAAA,IACA,GAAI,MAAM,SAAS,SAAY,EAAE,MAAM,KAAK,UAAU,MAAM,IAAI,EAAE,IAAI,CAAC;AAAA,EACzE,CAAC;AAED,QAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,MAAI,SAAc,CAAC;AACnB,MAAI;AACF,aAAS,OAAO,KAAK,MAAM,IAAI,IAAI,CAAC;AAAA,EACtC,QAAQ;AAAA,EAGR;AAEA,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,IAAI,QAAQ,SAAS,CAAC;AAG5B,UAAM,KAAK,OAAO,IAAI,QAAQ,IAAI,aAAa,CAAC;AAChD,UAAM,IAAI,kBAAkB;AAAA,MAC1B,MAAM,EAAE,QAAQ;AAAA,MAChB,SAAS,EAAE,WAAW,uBAAuB,IAAI,MAAM;AAAA,MACvD,YAAY,IAAI;AAAA,MAChB,YAAY,OAAO,SAAS,EAAE,KAAK,MAAM,IAAI,KAAK;AAAA,MAClD,SAAS,EAAE;AAAA,IACb,CAAC;AAAA,EACH;AAKA,SAAO,UAAU,OAAO,WAAW,YAAY,UAAU,SAAS,OAAO,OAAQ,UAAU,CAAC;AAC9F;;;AClCO,IAAM,eAAN,MAAmB;AAAA,EACxB,YAA0B,EAAE,QAAQ,WAAW,UAAU,MAAM,eAAe,MAAM;AAAA,EACpF,eAA8B;AAAA,EAC9B,aAA4B;AAAA,EAC5B,aAAa,oBAAI,IAAc;AAAA,EAE/B,MAAoB;AAAE,WAAO,KAAK;AAAA,EAAW;AAAA,EAC7C,cAA6B;AAAE,WAAO,KAAK;AAAA,EAAc;AAAA,EACzD,YAA2B;AAAE,WAAO,KAAK;AAAA,EAAY;AAAA,EAErD,WAAW,SAAwB;AACjC,SAAK,eAAe,QAAQ;AAC5B,SAAK,aAAa,KAAK,MAAM,QAAQ,SAAS;AAC9C,SAAK,SAAS;AAAA,MACZ,QAAQ;AAAA,MACR,UAAU,QAAQ;AAAA,MAClB,eAAe,QAAQ,QAAQ,UAAU,aAAa;AAAA,IACxD,CAAC;AAAA,EACH;AAAA,EAEA,UAAU,QAA0B;AAClC,SAAK,SAAS,EAAE,GAAG,KAAK,WAAW,OAAO,CAAC;AAAA,EAC7C;AAAA,EAEA,QAAc;AACZ,SAAK,eAAe;AACpB,SAAK,aAAa;AAClB,SAAK,SAAS,EAAE,QAAQ,mBAAmB,UAAU,MAAM,eAAe,MAAM,CAAC;AAAA,EACnF;AAAA,EAEA,UAAU,IAA0B;AAClC,SAAK,WAAW,IAAI,EAAE;AACtB,WAAO,MAAM;AAAE,WAAK,WAAW,OAAO,EAAE;AAAA,IAAG;AAAA,EAC7C;AAAA,EAEA,SAAS,MAA0B;AAIjC,UAAM,OACJ,KAAK,WAAW,KAAK,UAAU,UAC/B,KAAK,kBAAkB,KAAK,UAAU,iBACtC,eAAe,KAAK,UAAU,KAAK,UAAU,QAAQ;AACvD,QAAI,KAAM;AACV,SAAK,YAAY;AACjB,eAAW,MAAM,CAAC,GAAG,KAAK,UAAU,GAAG;AAErC,UAAI;AAAE,WAAG,IAAI;AAAA,MAAG,QAAQ;AAAA,MAA0B;AAAA,IACpD;AAAA,EACF;AACF;AAEA,SAAS,eAAe,GAAoB,GAA6B;AACvE,MAAI,MAAM,EAAG,QAAO;AACpB,MAAI,CAAC,KAAK,CAAC,EAAG,QAAO;AACrB,QAAM,OAAO,oBAAI,IAAI,CAAC,GAAG,OAAO,KAAK,CAAC,GAAG,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC;AAC3D,aAAW,KAAK,KAAM,KAAI,EAAE,CAAC,MAAM,EAAE,CAAC,EAAG,QAAO;AAChD,SAAO;AACT;;;ACxEO,SAAS,gBAA6B;AAC3C,QAAM,MAAM,oBAAI,IAAoB;AACpC,SAAO;AAAA,IACL,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK;AAAA,IAC1B,KAAK,CAAC,GAAG,MAAM,KAAK,IAAI,IAAI,GAAG,CAAC;AAAA,IAChC,QAAQ,CAAC,MAAM,KAAK,IAAI,OAAO,CAAC;AAAA,EAClC;AACF;AAOO,SAAS,sBAAmC;AACjD,QAAM,WAAW,cAAc;AAC/B,QAAM,KAAK,MAAsB;AAC/B,QAAI;AACF,aAAO,OAAO,iBAAiB,cAAc,eAAe;AAAA,IAC9D,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AAAA,IACL,IAAI,GAAG;AACL,UAAI;AACF,cAAM,IAAI,GAAG,GAAG,QAAQ,CAAC;AACzB,YAAI,KAAK,KAAM,QAAO;AAAA,MACxB,QAAQ;AAAA,MAAqB;AAC7B,aAAO,SAAS,IAAI,CAAC;AAAA,IACvB;AAAA,IACA,IAAI,GAAG,GAAG;AACR,eAAS,IAAI,GAAG,CAAC;AACjB,UAAI;AAAE,WAAG,GAAG,QAAQ,GAAG,CAAC;AAAA,MAAG,QAAQ;AAAA,MAAiC;AAAA,IACtE;AAAA,IACA,OAAO,GAAG;AACR,eAAS,OAAO,CAAC;AACjB,UAAI;AAAE,WAAG,GAAG,WAAW,CAAC;AAAA,MAAG,QAAQ;AAAA,MAAqB;AAAA,IAC1D;AAAA,EACF;AACF;;;ACtCA,IAAM,mBAAmB;AAEzB,IAAM,kBAAkB;AA8CjB,SAAS,mBACd,QACiE;AACjE,QAAM,WAAW,OAAO,WAAW,kBAAkB,QAAQ,OAAO,EAAE;AACtE,QAAM,UAAuB,OAAO,WAAW,oBAAoB;AAGnE,QAAM,aAAa,oBAAoB,OAAO,cAAc;AAC5D,QAAM,WAAW,yBAAyB,OAAO,cAAc;AAE/D,QAAM,QAAQ,IAAI,aAAa;AAC/B,MAAI,kBAAwC;AAC5C,MAAI,cAA6B;AACjC,MAAI,kBAAkB;AAEtB,QAAM,OAAO,EAAE,SAAS,gBAAgB,OAAO,eAAe;AAE9D,iBAAe,QAAQ,SAAiC;AACtD,UAAM,WAAW,OAAO;AACxB,UAAM,QAAQ,IAAI,YAAY,QAAQ,YAAY;AAAA,EACpD;AAEA,iBAAe,SAAwB;AACrC,kBAAc;AACd,UAAM,MAAM;AACZ,UAAM,QAAQ,OAAO,UAAU;AAAA,EACjC;AAQA,WAAS,SAAY,IAAkC;AACrD,UAAM,QAAS,WAAmB,WAAW;AAC7C,WAAO,OAAO,UAAU,MAAM,QAAQ,UAAU,EAAE,IAAI,GAAG;AAAA,EAC3D;AAEA,iBAAe,YAA2B;AACxC,UAAM,SAAS,YAAY;AAGzB,YAAM,eAAe,MAAM,QAAQ,IAAI,UAAU;AACjD,UAAI,CAAC,cAAc;AACjB,cAAM,OAAO;AACb,cAAM,IAAI,kBAAkB,EAAE,MAAM,mBAAmB,SAAS,cAAc,YAAY,IAAI,CAAC;AAAA,MACjG;AACA,UAAI;AACF,cAAM,OAAO,MAAM,QAAQ,EAAE,GAAG,MAAM,QAAQ,QAAQ,MAAM,iBAAiB,MAAM,EAAE,aAAa,EAAE,CAAC;AACrG,cAAM,QAAQ,IAAe;AAAA,MAC/B,SAAS,KAAK;AAcZ,cAAM,UACJ,eAAe,sBAAsB,IAAI,eAAe,OAAO,IAAI,eAAe;AACpF,YAAI,QAAS,OAAM,OAAO;AAC1B,cAAM;AAAA,MACR;AAAA,IACF,CAAC;AAAA,EACH;AAEA,WAAS,UAAyB;AAChC,QAAI,CAAC,iBAAiB;AACpB,wBAAkB,UAAU,EAAE,QAAQ,MAAM;AAAE,0BAAkB;AAAA,MAAM,CAAC;AAAA,IACzE;AACA,WAAO;AAAA,EACT;AAEA,iBAAe,cAAsC;AACnD,UAAM,UAAU,MAAM,UAAU;AAChC,QAAI,MAAM,YAAY,KAAK,WAAW,UAAU,KAAK,IAAI,IAAI,iBAAiB;AAC5E,aAAO,MAAM,YAAY;AAAA,IAC3B;AACA,QAAI,MAAM,QAAQ,IAAI,UAAU,GAAG;AACjC,YAAM,QAAQ;AACd,aAAO,MAAM,YAAY;AAAA,IAC3B;AACA,WAAO,MAAM,YAAY;AAAA,EAC3B;AAEA,iBAAe,eAAiC;AAC9C,QAAI,eAAe,kBAAkB,KAAK,IAAI,EAAG,QAAO;AACxD,QAAI,CAAC,OAAO,iBAAkB,QAAO;AACrC,UAAM,WAAW,MAAM,OAAO,iBAAiB;AAC/C,QAAI,CAAC,SAAU,QAAO;AACtB,UAAM,OAAO,QAAQ;AACrB,WAAO;AAAA,EACT;AAEA,iBAAe,OAAO,UAAiC;AACrD,UAAM,OAAO,MAAM,QAAQ;AAAA,MACzB,GAAG;AAAA,MAAM,QAAQ;AAAA,MAAQ,MAAM;AAAA,MAC/B,aAAa,MAAM,YAAY,KAAK;AAAA,MAAW,MAAM,EAAE,SAAS;AAAA,IAClE,CAAC;AACD,kBAAc,KAAK;AACnB,sBAAkB,KAAK,IAAI,KAAK,OAAO,KAAK,SAAS,KAAK,OAAO,MAAO;AAAA,EAC1E;AAEA,iBAAe,KAAc,QAAgB,MAAc,MAA4B;AACrF,QAAI,cAAc;AAClB,QAAI,gBAAgB;AAOpB,QAAI,aAAa;AAEjB,eAAS;AACP,YAAM,QAAQ,MAAM,YAAY;AAChC,UAAI;AACF,eAAO,MAAM,QAAQ;AAAA,UACnB,GAAG;AAAA,UAAM;AAAA,UAAQ;AAAA,UAAM;AAAA,UACvB,aAAa,SAAS;AAAA,UACtB,aAAa,aAAc,eAAe,SAAa;AAAA,QACzD,CAAC;AAAA,MACH,SAAS,KAAK;AACZ,cAAM,IAAI;AAOV,cAAM,UAAU,EAAE,eAAe,QAC9B,EAAE,SAAS,kBAAkB,EAAE,SAAS,mBAAmB,EAAE,SAAS;AACzE,YAAI,WAAW,CAAC,aAAa;AAC3B,wBAAc;AACd,gBAAM,QAAQ;AACd;AAAA,QACF;AACA,YAAI,EAAE,SAAS,sBAAsB,CAAC,eAAe;AACnD,0BAAgB;AAIhB,cAAI,MAAM,aAAa,GAAG;AAAE,yBAAa;AAAM;AAAA,UAAU;AAAA,QAC3D;AACA,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM,SAAS,OAAO,UAAU;AAC9B,YAAM,OAAO,MAAM,QAAQ,EAAE,GAAG,MAAM,QAAQ,QAAQ,MAAM,kBAAkB,MAAM,EAAE,OAAO,SAAS,EAAE,CAAC;AACzG,UAAI,MAAM,WAAW,UAAW,QAAO,EAAE,QAAQ,UAAU;AAC3D,YAAM,QAAQ,IAAe;AAC7B,aAAO,EAAE,QAAQ,SAAS;AAAA,IAC5B;AAAA,IAEA,MAAM,OAAO,OAAO,UAAU;AAC5B,YAAM,OAAO,MAAM,QAAQ,EAAE,GAAG,MAAM,QAAQ,QAAQ,MAAM,eAAe,MAAM,EAAE,OAAO,SAAS,EAAE,CAAC;AACtG,YAAM,QAAQ,IAAe;AAAA,IAC/B;AAAA,IAEA,MAAM,UAAU;AACd,UAAI;AAAE,cAAM,KAAK,QAAQ,cAAc;AAAA,MAAG,QAAQ;AAAA,MAA+B;AACjF,YAAM,OAAO;AAAA,IACf;AAAA,IAEA,MAAM,oBAAoB;AACxB,UAAI;AAAE,cAAM,KAAK,QAAQ,kBAAkB;AAAA,MAAG,QAAQ;AAAA,MAA+B;AACrF,YAAM,OAAO;AAAA,IACf;AAAA,IAEA,MAAM,UAAU;AACd,UAAI,CAAE,MAAM,QAAQ,IAAI,UAAU,GAAI;AAAE,cAAM,UAAU,iBAAiB;AAAG;AAAA,MAAQ;AACpF,UAAI;AAAE,cAAM,QAAQ;AAAA,MAAG,QAAQ;AAAA,MAA6B;AAAA,IAC9D;AAAA,IAEA,aAAa,MAAM,MAAM,IAAI;AAAA,IAE7B,MAAM,iBAAiB;AACrB,UAAI;AACF,eAAO,MAAM,YAAY;AAAA,MAC3B,SAAS,KAAK;AAGZ,YAAI,MAAM,IAAI,EAAE,WAAW,kBAAmB,QAAO;AACrD,cAAM;AAAA,MACR;AAAA,IACF;AAAA,IAEA,WAAW,CAAC,OAAO,MAAM,UAAU,EAAE;AAAA,IACrC;AAAA,IACA;AAAA,IAEA,MAAM,YAAY,OAAO;AACvB,YAAM,QAAQ,EAAE,GAAG,MAAM,QAAQ,QAAQ,MAAM,sBAAsB,MAAM,EAAE,MAAM,EAAE,CAAC;AAKtF,UAAI,MAAM,QAAQ,IAAI,UAAU,GAAG;AACjC,YAAI;AAAE,gBAAM,QAAQ;AAAA,QAAG,QAAQ;AAAA,QAAqC;AAAA,MACtE;AAAA,IACF;AAAA,IAEA,MAAM,qBAAqB;AACzB,YAAM,KAAK,QAAQ,2BAA2B;AAAA,IAChD;AAAA,IAEA,MAAM,eAAe,OAAO;AAG1B,YAAM,QAAQ,EAAE,GAAG,MAAM,QAAQ,QAAQ,MAAM,yBAAyB,MAAM,EAAE,MAAM,EAAE,CAAC;AAAA,IAC3F;AAAA,IAEA,MAAM,cAAc,OAAO,UAAU;AACnC,YAAM,QAAQ,EAAE,GAAG,MAAM,QAAQ,QAAQ,MAAM,wBAAwB,MAAM,EAAE,OAAO,SAAS,EAAE,CAAC;AAElG,YAAM,OAAO;AAAA,IACf;AAAA,IAEA,MAAM,eAAe,UAAU;AAC7B,YAAM,KAAK,QAAQ,uBAAuB,EAAE,SAAS,CAAC;AAMtD,UAAI;AAAE,cAAM,QAAQ;AAAA,MAAG,QAAQ;AAAA,MAA8C;AAAA,IAC/E;AAAA,IAEA,MAAM,eAAe;AACnB,aAAO,KAAsB,OAAO,cAAc;AAAA,IACpD;AAAA,IAEA,MAAM,cAAc,IAAI;AACtB,YAAM,OAAO,MAAM,KAAsB,OAAO,cAAc;AAC9D,YAAM,UAAU,KAAK,KAAK,CAAC,MAAM,EAAE,OAAO;AAC1C,YAAM,KAAK,UAAU,gBAAgB,mBAAmB,EAAE,CAAC,EAAE;AAC7D,UAAI,SAAS,OAAO,GAAI,OAAM,OAAO;AAAA,IACvC;AAAA;AAAA;AAAA,IAIA,kBAAkB,MAAM,QAAQ,QAAQ;AAAA,EAC1C;AACF;;;AClOA,IAAM,MAAM,CAAC,MAAc,mBAAmB,CAAC;AAE/C,SAAS,MAAM,MAAqB;AAClC,QAAM,SAAS,IAAI,gBAAgB;AACnC,MAAI,MAAM,OAAQ,QAAO,IAAI,UAAU,KAAK,MAAM;AAClD,MAAI,MAAM,SAAS,KAAM,QAAO,IAAI,SAAS,OAAO,KAAK,KAAK,CAAC;AAC/D,QAAM,IAAI,OAAO,SAAS;AAC1B,SAAO,IAAI,IAAI,CAAC,KAAK;AACvB;AAEO,SAAS,cACd,MACkE;AAClE,QAAM,EAAE,KAAK,IAAI;AACjB,SAAO;AAAA,IACL,YAAY,MAAM,KAAK,OAAO,KAAK;AAAA,IACnC,eAAe,CAAC,UAAU,KAAK,SAAS,OAAO,KAAK;AAAA,IAEpD,eAAe,MAAM,KAAK,OAAO,eAAe;AAAA,IAChD,eAAe,CAAC,UAAU,KAAK,QAAQ,iBAAiB,KAAK;AAAA,IAC7D,eAAe,CAAC,IAAI,UAAU,KAAK,SAAS,iBAAiB,IAAI,EAAE,CAAC,IAAI,KAAK;AAAA,IAC7E,eAAe,CAAC,OAAO,KAAK,UAAU,iBAAiB,IAAI,EAAE,CAAC,EAAE;AAAA,IAEhE,oBAAoB,MAAM,KAAK,OAAO,qBAAqB;AAAA;AAAA;AAAA,IAG3D,yBAAyB,CAAC,OAAO,KAAK,SAAS,uBAAuB,IAAI,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,CAAC;AAAA,IACpG,qBAAqB,CAAC,OAAO,KAAK,UAAU,uBAAuB,IAAI,EAAE,CAAC,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAO5E,gBAAgB,MAAM,KAAK,QAAQ,iCAAiC;AAAA,IACpE,kBAAkB,CAAC,kBACjB,KAAK,QAAQ,+BAA+B,EAAE,cAAc,CAAC;AAAA,IAE/D,YAAY,CAAC,SAAS,KAAK,OAAO,aAAa,MAAM,IAAI,CAAC,EAAE;AAAA,IAC5D,UAAU,CAAC,OAAO,KAAK,OAAO,cAAc,IAAI,EAAE,CAAC,EAAE;AAAA,IACrD,cAAc,CAAC,SAAS,KAAK,OAAO,eAAe,MAAM,IAAI,CAAC,EAAE;AAAA,IAChE,YAAY,CAAC,OAAO,KAAK,OAAO,gBAAgB,IAAI,EAAE,CAAC,EAAE;AAAA,IACzD,kBAAkB,CAAC,OAAO,KAAK,OAAO,gBAAgB,IAAI,EAAE,CAAC,MAAM;AAAA,IACnE,mBAAmB,CAAC,SAAS,KAAK,OAAO,oBAAoB,MAAM,IAAI,CAAC,EAAE;AAAA,IAC1E,iBAAiB,CAAC,OAAO,KAAK,OAAO,qBAAqB,IAAI,EAAE,CAAC,EAAE;AAAA,IAEnE,aAAa,CAAC,IAAI,SAAS,KAAK,QAAQ,cAAc,IAAI,EAAE,CAAC,WAAW,IAAI;AAAA,IAC5E,oBAAoB,CAAC,IAAI,UAAU,KAAK,QAAQ,cAAc,IAAI,EAAE,CAAC,mBAAmB,KAAK;AAAA,IAC7F,oBAAoB,CAAC,IAAI,SAAS,KAAK,QAAQ,qBAAqB,IAAI,EAAE,CAAC,WAAW,IAAI;AAAA,IAC1F,mBAAmB,CAAC,OAAO,KAAK,QAAQ,qBAAqB,IAAI,EAAE,CAAC,QAAQ;AAAA,IAC5E,oBAAoB,CAAC,OAAO,KAAK,QAAQ,qBAAqB,IAAI,EAAE,CAAC,SAAS;AAAA,IAC9E,mCAAmC,CAAC,IAAI,YACtC,KAAK,SAAS,qBAAqB,IAAI,EAAE,CAAC,qBAAqB,OAAO;AAAA,IAExE,WAAW,CAAC,WAAW,KAAK,QAAQ,aAAa,IAAI,MAAM,CAAC,QAAQ;AAAA,IAEpE,MAAM,YAAY,EAAE,SAAS,GAAG;AAC9B,UAAI,OAAO,aAAa,YAAY,CAAC,gBAAgB,KAAK,QAAQ,GAAG;AACnE,cAAM,IAAI,UAAU,mDAAmD;AAAA,MACzE;AACA,UAAI;AACF,eAAO,MAAM,KAAsB,OAAO,qBAAqB,SAAS,YAAY,CAAC,EAAE;AAAA,MACzF,SAAS,KAAK;AAEZ,YAAI,eAAe,qBAAqB,IAAI,eAAe,IAAK,QAAO;AACvE,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/request.ts","../src/session.ts","../src/storage.ts","../src/client.ts","../src/account.ts","../src/index.ts"],"sourcesContent":["export class ThrottleAuthError extends Error {\n readonly code: string;\n readonly statusCode: number;\n readonly retryAfter?: number;\n readonly details?: unknown;\n\n constructor(args: { code: string; message: string; statusCode: number; retryAfter?: number; details?: unknown }) {\n super(args.message);\n this.name = 'ThrottleAuthError';\n this.code = args.code;\n this.statusCode = args.statusCode;\n this.retryAfter = args.retryAfter;\n this.details = args.details;\n }\n}\n","import { ThrottleAuthError } from './errors';\n\nexport interface RequestInput {\n method: string;\n path: string;\n baseUrl: string;\n publishableKey: string;\n accessToken?: string;\n stepUpToken?: string;\n body?: unknown;\n}\n\n/** Returns the UNWRAPPED `data` from the `{ data: … }` envelope. Throws ThrottleAuthError otherwise. */\nexport async function request(input: RequestInput): Promise<any> {\n const headers: Record<string, string> = { 'X-API-Key': input.publishableKey };\n if (input.body !== undefined) headers['Content-Type'] = 'application/json';\n if (input.accessToken) headers.Authorization = `Bearer ${input.accessToken}`;\n if (input.stepUpToken) headers['X-Step-Up'] = input.stepUpToken;\n\n const res = await fetch(`${input.baseUrl}/v1/storefront${input.path}`, {\n method: input.method,\n headers,\n ...(input.body !== undefined ? { body: JSON.stringify(input.body) } : {}),\n });\n\n const text = await res.text();\n let parsed: any = {};\n try {\n parsed = text ? JSON.parse(text) : {};\n } catch {\n // Non-JSON body — an HTML gateway page, say. Leave parsed empty so the\n // branch below still throws a typed error rather than a raw SyntaxError.\n }\n\n if (!res.ok) {\n const e = parsed?.error ?? {};\n // `Retry-After` is server-controlled but not trusted: Number('soon') is\n // NaN, and a NaN reaches the UI as \"wait NaN seconds\".\n const ra = Number(res.headers.get('retry-after'));\n throw new ThrottleAuthError({\n code: e.code ?? 'request_failed',\n message: e.message ?? `Request failed with ${res.status}`,\n statusCode: res.status,\n retryAfter: Number.isFinite(ra) && ra >= 0 ? ra : undefined,\n details: e.details,\n });\n }\n\n // `'data' in parsed`, not `parsed?.data ?? parsed`: a legitimate\n // `{ \"data\": null }` is nullish, and `??` would fall through and hand the\n // caller the whole envelope instead of the null the API actually sent.\n return parsed && typeof parsed === 'object' && 'data' in parsed ? parsed.data : (parsed ?? {});\n}\n","import type { Customer, Session } from './types';\n\nexport type AuthStatus = 'loading' | 'authenticated' | 'unauthenticated';\n\nexport interface AuthSnapshot {\n status: AuthStatus;\n customer: Customer | null;\n /**\n * False here does NOT only mean \"we emailed them and they have not clicked\".\n * While it is false the API may also be withholding pre-existing account\n * data behind the claim cutoff — empty order lists and a 403 on `PATCH /me`\n * are expected, not broken. See the plan header.\n */\n emailVerified: boolean;\n}\n\ntype Listener = (snapshot: AuthSnapshot) => void;\n\nexport class SessionState {\n #snapshot: AuthSnapshot = { status: 'loading', customer: null, emailVerified: false };\n #accessToken: string | null = null;\n #expiresAt: number | null = null;\n #listeners = new Set<Listener>();\n\n get(): AuthSnapshot { return this.#snapshot; }\n accessToken(): string | null { return this.#accessToken; }\n expiresAt(): number | null { return this.#expiresAt; }\n\n setSession(session: Session): void {\n this.#accessToken = session.accessToken;\n this.#expiresAt = Date.parse(session.expiresAt);\n this.#publish({\n status: 'authenticated',\n customer: session.customer,\n emailVerified: Boolean(session.customer?.emailVerified),\n });\n }\n\n setStatus(status: AuthStatus): void {\n this.#publish({ ...this.#snapshot, status });\n }\n\n clear(): void {\n this.#accessToken = null;\n this.#expiresAt = null;\n this.#publish({ status: 'unauthenticated', customer: null, emailVerified: false });\n }\n\n subscribe(fn: Listener): () => void {\n this.#listeners.add(fn);\n return () => { this.#listeners.delete(fn); };\n }\n\n #publish(next: AuthSnapshot): void {\n // Identity matters: React's useSyncExternalStore re-renders on reference\n // change, and a token refresh every ten minutes must not re-render the\n // whole account area when nothing visible changed.\n const same =\n next.status === this.#snapshot.status &&\n next.emailVerified === this.#snapshot.emailVerified &&\n customerEquals(next.customer, this.#snapshot.customer);\n if (same) return;\n this.#snapshot = next;\n for (const fn of [...this.#listeners]) {\n // A merchant's subscriber throwing must not stop the rest from hearing.\n try { fn(next); } catch { /* merchant callback */ }\n }\n }\n}\n\nfunction customerEquals(a: Customer | null, b: Customer | null): boolean {\n if (a === b) return true;\n if (!a || !b) return false;\n const keys = new Set([...Object.keys(a), ...Object.keys(b)]) as Set<keyof Customer>;\n for (const k of keys) if (a[k] !== b[k]) return false;\n return true;\n}\n","import type { AuthStorage } from './types';\n\nexport type { AuthStorage };\n\nexport function memoryStorage(): AuthStorage {\n const map = new Map<string, string>();\n return {\n get: (k) => map.get(k) ?? null,\n set: (k, v) => void map.set(k, v),\n remove: (k) => void map.delete(k),\n };\n}\n\n/**\n * localStorage when it works, memory when it does not. Safari private mode,\n * hardened browser settings and server-side rendering all make localStorage\n * either absent or throwing; none of them may take the storefront down.\n */\nexport function localStorageAdapter(): AuthStorage {\n const fallback = memoryStorage();\n const ls = (): Storage | null => {\n try {\n return typeof localStorage !== 'undefined' ? localStorage : null;\n } catch {\n return null;\n }\n };\n return {\n get(k) {\n try {\n const v = ls()?.getItem(k);\n if (v != null) return v;\n } catch { /* fall through */ }\n return fallback.get(k);\n },\n set(k, v) {\n fallback.set(k, v);\n try { ls()?.setItem(k, v); } catch { /* memory-only this session */ }\n },\n remove(k) {\n fallback.remove(k);\n try { ls()?.removeItem(k); } catch { /* already gone */ }\n },\n };\n}\n","import { request } from './request';\nimport { ThrottleAuthError } from './errors';\nimport { SessionState, type AuthSnapshot } from './session';\nimport { localStorageAdapter, type AuthStorage } from './storage';\nimport type { Customer, Session, ThrottleAuthConfig } from './types';\n\nconst DEFAULT_BASE_URL = 'https://api.usethrottle.dev';\n/** Refresh this far before expiry so ordinary calls rarely see a 401 at all. */\nconst REFRESH_SKEW_MS = 30_000;\n\nexport interface DeviceSession {\n id: string;\n userAgent: string | null;\n ipPrefix: string | null;\n createdAt: string;\n lastUsedAt: string;\n current: boolean;\n}\n\nexport interface ThrottleAuth {\n register(email: string, password: string): Promise<{ status: 'active' | 'pending' }>;\n signIn(email: string, password: string): Promise<void>;\n signOut(): Promise<void>;\n signOutEverywhere(): Promise<void>;\n restore(): Promise<void>;\n getSnapshot(): AuthSnapshot;\n /**\n * The current access token, refreshed first when it is about to expire\n * (single-flight, shared with every other caller), or null when signed out.\n * Rejects when a refresh fails without ending the session (a 5xx, a 429 or\n * a network error); the buyer stays signed in. `@usethrottle/catalog`\n * treats a rejection as signed out for that request.\n * Pass it to `@usethrottle/catalog`'s `customerToken`.\n */\n getAccessToken(): Promise<string | null>;\n subscribe(fn: (s: AuthSnapshot) => void): () => void;\n stepUp(password: string): Promise<void>;\n call<T = any>(method: string, path: string, body?: unknown): Promise<T>;\n verifyEmail(token: string): Promise<void>;\n resendVerification(): Promise<void>;\n forgotPassword(email: string): Promise<void>;\n resetPassword(token: string, password: string): Promise<void>;\n changePassword(password: string): Promise<void>;\n listSessions(): Promise<DeviceSession[]>;\n revokeSession(id: string): Promise<void>;\n /**\n * Resolves once any sign-in or registration claim in flight has settled.\n * `createThrottleAuth` always supplies it (it resolves at once there);\n * `ThrottleProvider` supplies one that tracks its cart claim. Optional so a\n * hand-made `ThrottleAuth` written against 0.11 still compiles.\n */\n whenClaimSettled?(): Promise<void>;\n}\n\nexport function createThrottleAuth(\n config: ThrottleAuthConfig,\n): ThrottleAuth & Required<Pick<ThrottleAuth, 'whenClaimSettled'>> {\n const baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, '');\n const storage: AuthStorage = config.storage ?? localStorageAdapter();\n // Namespaced by key so two Throttle applications on one origin cannot read\n // each other's refresh token out of shared localStorage.\n const storageKey = `throttle_auth_rt:${config.publishableKey}`;\n const lockName = `throttle_auth_refresh:${config.publishableKey}`;\n\n const state = new SessionState();\n let refreshInFlight: Promise<void> | null = null;\n let stepUpToken: string | null = null;\n let stepUpExpiresAt = 0;\n\n const base = { baseUrl, publishableKey: config.publishableKey };\n\n async function persist(session: Session): Promise<void> {\n state.setSession(session);\n await storage.set(storageKey, session.refreshToken);\n }\n\n async function forget(): Promise<void> {\n stepUpToken = null;\n state.clear();\n await storage.remove(storageKey);\n }\n\n /**\n * Cross-tab single flight. Two tabs refreshing at once would each present the\n * same stored token; the second is a replay, and the server kills the family.\n * Web Locks serialises them; where it is unavailable the in-process guard\n * below still covers the common single-tab case.\n */\n function withLock<T>(fn: () => Promise<T>): Promise<T> {\n const locks = (globalThis as any).navigator?.locks;\n return locks?.request ? locks.request(lockName, fn) : fn();\n }\n\n async function doRefresh(): Promise<void> {\n await withLock(async () => {\n // Re-read INSIDE the lock: another tab may have rotated while we waited,\n // and presenting the token we read before the lock would be a replay.\n const refreshToken = await storage.get(storageKey);\n if (!refreshToken) {\n await forget();\n throw new ThrottleAuthError({ code: 'session_revoked', message: 'No session', statusCode: 401 });\n }\n try {\n const data = await request({ ...base, method: 'POST', path: '/auth/refresh', body: { refreshToken } });\n await persist(data as Session);\n } catch (err) {\n // Drop the stored token ONLY when the server actually refused the\n // session: 401 session_revoked, or 403 environment_mismatch. Those are\n // the two the refresh route returns, and there is nothing left to\n // retry with in either case.\n //\n // Everything else keeps the token. `request()` throws a\n // ThrottleAuthError for EVERY non-2xx, so testing the error class\n // alone also caught a 502 with an HTML gateway body — a buyer whose\n // tab refreshed during a rolling deploy was permanently signed out\n // client-side even though their session was never invalidated. A 429\n // is the same shape: \"try later\", not \"you are logged out\". And a\n // fetch() that rejects outright never produces a ThrottleAuthError,\n // so it was already handled.\n const refused =\n err instanceof ThrottleAuthError && (err.statusCode === 401 || err.statusCode === 403);\n if (refused) await forget();\n throw err;\n }\n });\n }\n\n function refresh(): Promise<void> {\n if (!refreshInFlight) {\n refreshInFlight = doRefresh().finally(() => { refreshInFlight = null; });\n }\n return refreshInFlight;\n }\n\n async function accessToken(): Promise<string | null> {\n const expires = state.expiresAt();\n if (state.accessToken() && expires && expires - Date.now() > REFRESH_SKEW_MS) {\n return state.accessToken();\n }\n if (await storage.get(storageKey)) {\n await refresh();\n return state.accessToken();\n }\n return state.accessToken();\n }\n\n async function ensureStepUp(): Promise<boolean> {\n if (stepUpToken && stepUpExpiresAt > Date.now()) return true;\n if (!config.onStepUpRequired) return false;\n const password = await config.onStepUpRequired();\n if (!password) return false;\n await stepUp(password);\n return true;\n }\n\n async function stepUp(password: string): Promise<void> {\n const data = await request({\n ...base, method: 'POST', path: '/auth/step-up',\n accessToken: await accessToken() ?? undefined, body: { password },\n });\n stepUpToken = data.stepUpToken;\n stepUpExpiresAt = Date.now() + (Number(data.expiresIn) || 300) * 1000 - 5_000;\n }\n\n async function call<T = any>(method: string, path: string, body?: unknown): Promise<T> {\n let retriedAuth = false;\n let retriedStepUp = false;\n // Only true on the retry that follows a `step_up_required` 403 — never\n // attached speculatively. Sending an authorization-grade header on every\n // request once minted meant it rode along on unrelated calls too, and\n // cross-origin each of those then failed CORS preflight. The cost is one\n // extra round trip per gated call, which is how the server signals\n // step-up in the first place.\n let sendStepUp = false;\n\n for (;;) {\n const token = await accessToken();\n try {\n return await request({\n ...base, method, path, body,\n accessToken: token ?? undefined,\n stepUpToken: sendStepUp ? (stepUpToken ?? undefined) : undefined,\n });\n } catch (err) {\n const e = err as ThrottleAuthError;\n // `session_revoked` belongs here too. The server returns it for a\n // stale session EPOCH as well as for a genuinely dead session, and a\n // changed password bumps the epoch while deliberately sparing the\n // current session — so one refresh recovers it. When the session\n // really is dead the refresh fails and forget() runs, which is the\n // same outcome, one request later.\n const expired = e.statusCode === 401 &&\n (e.code === 'unauthorized' || e.code === 'token_expired' || e.code === 'session_revoked');\n if (expired && !retriedAuth) {\n retriedAuth = true;\n await refresh(); // shared — ten callers here produce ONE request\n continue;\n }\n if (e.code === 'step_up_required' && !retriedStepUp) {\n retriedStepUp = true;\n // ensureStepUp() reuses the cached token when it's still within its\n // 300s validity (no re-prompt); it was never sent above, so this is\n // the first the server has seen of it for this call.\n if (await ensureStepUp()) { sendStepUp = true; continue; }\n }\n throw err;\n }\n }\n }\n\n return {\n async register(email, password) {\n const data = await request({ ...base, method: 'POST', path: '/auth/register', body: { email, password } });\n if (data?.status === 'pending') return { status: 'pending' };\n await persist(data as Session);\n return { status: 'active' };\n },\n\n async signIn(email, password) {\n const data = await request({ ...base, method: 'POST', path: '/auth/login', body: { email, password } });\n await persist(data as Session);\n },\n\n async signOut() {\n try { await call('POST', '/auth/logout'); } catch { /* local state still goes */ }\n await forget();\n },\n\n async signOutEverywhere() {\n try { await call('POST', '/auth/logout-all'); } catch { /* local state still goes */ }\n await forget();\n },\n\n async restore() {\n if (!(await storage.get(storageKey))) { state.setStatus('unauthenticated'); return; }\n try { await refresh(); } catch { /* forget() already ran */ }\n },\n\n getSnapshot: () => state.get(),\n\n async getAccessToken() {\n try {\n return await accessToken();\n } catch (err) {\n // A refused refresh already ran forget(): the buyer is signed out.\n // Anything else (a 502, a network error) keeps the session; rethrow.\n if (state.get().status === 'unauthenticated') return null;\n throw err;\n }\n },\n\n subscribe: (fn) => state.subscribe(fn),\n stepUp,\n call,\n\n async verifyEmail(token) {\n await request({ ...base, method: 'POST', path: '/auth/verify-email', body: { token } });\n // `ver` is a claim baked into the access token, and the claim cutoff is\n // read from the session row. Without a new token the buyer stays gated —\n // and their own order history stays hidden — for the rest of this\n // token's ten minutes.\n if (await storage.get(storageKey)) {\n try { await refresh(); } catch { /* verification still succeeded */ }\n }\n },\n\n async resendVerification() {\n await call('POST', '/auth/verify-email/resend');\n },\n\n async forgotPassword(email) {\n // Always 202, whether or not the address has an account. Do not infer\n // anything from it and do not tell the buyer whether it existed.\n await request({ ...base, method: 'POST', path: '/auth/forgot-password', body: { email } });\n },\n\n async resetPassword(token, password) {\n await request({ ...base, method: 'POST', path: '/auth/reset-password', body: { token, password } });\n // The server revokes every session on reset, this one included.\n await forget();\n },\n\n async changePassword(password) {\n await call('POST', '/me/change-password', { password });\n // The change bumps the session epoch. This session was deliberately\n // spared, but the access token in hand now carries a stale epoch and the\n // next write would 401. Rotate now rather than on the buyer's next click\n // — and do not let a failed rotation report a change that already\n // succeeded server-side as a failure.\n try { await refresh(); } catch { /* the password change already succeeded */ }\n },\n\n async listSessions() {\n return call<DeviceSession[]>('GET', '/me/sessions');\n },\n\n async revokeSession(id) {\n const mine = await call<DeviceSession[]>('GET', '/me/sessions');\n const current = mine.find((s) => s.current);\n await call('DELETE', `/me/sessions/${encodeURIComponent(id)}`);\n if (current?.id === id) await forget();\n },\n\n // The core never claims a cart; `ThrottleProvider` overrides this with one\n // that tracks its sign-in claim.\n whenClaimSettled: () => Promise.resolve(),\n };\n}\n\nexport type { AuthSnapshot, Customer, Session, ThrottleAuthConfig };\n","import type { ThrottleAuth } from './client';\nimport { ThrottleAuthError } from './errors';\nimport type {\n Address, AddressInput, Customer, Invoice, OpenCart, Order, OrderDetail,\n PaymentMethod, ProfilePatch, Subscription, SubscriptionShippingAddress,\n} from './types';\n\nexport interface Page { cursor?: string; limit?: number }\n\n/** What the payment widget needs to render a card form. Passed through from\n * the processor — `buyerExternalIdentifier` in particular must reach the\n * widget unchanged, because the session token pins it and the processor\n * refuses a mismatch by rendering nothing at all. */\nexport interface CardSetupSession {\n embedToken: string;\n checkoutSessionId: string;\n amount: number;\n currency: string;\n merchantAccountId?: string;\n environment?: string;\n buyerExternalIdentifier: string;\n country: string;\n /** A ready-made page that hosts the card form, if you would rather redirect\n * or iframe than embed the widget yourself. */\n hostedUrl: string;\n embedUrl: string;\n}\n\nexport interface ThrottleAccount {\n getProfile(): Promise<Customer>;\n updateProfile(patch: ProfilePatch): Promise<Customer>;\n listAddresses(): Promise<Address[]>;\n createAddress(input: AddressInput): Promise<Address>;\n updateAddress(id: string, patch: Partial<AddressInput>): Promise<Address>;\n deleteAddress(id: string): Promise<void>;\n listPaymentMethods(): Promise<PaymentMethod[]>;\n setDefaultPaymentMethod(id: string): Promise<PaymentMethod>;\n deletePaymentMethod(id: string): Promise<void>;\n /** Opens a processor-hosted session the buyer types their card into. The\n * returned values are handed straight to the payment widget. */\n startCardSetup(): Promise<CardSetupSession>;\n /** Records the card the widget just vaulted, identified by the transaction\n * the widget returns. Safe to call twice with the same id. */\n confirmCardSetup(transactionId: string): Promise<PaymentMethod>;\n listOrders(page?: Page): Promise<Order[]>;\n getOrder(id: string): Promise<OrderDetail>;\n listInvoices(page?: Page): Promise<Invoice[]>;\n getInvoice(id: string): Promise<Invoice>;\n /** A 600-second signed URL. Fetch it on click — it expires. */\n getInvoicePdfUrl(id: string): Promise<{ url: string }>;\n listSubscriptions(page?: Page): Promise<Subscription[]>;\n getSubscription(id: string): Promise<Subscription>;\n /**\n * Voids an unpaid order. Refused once money has been captured — that is a\n * return, not a cancellation, and only the merchant may move money back.\n */\n cancelOrder(id: string, opts?: { reason?: string }): Promise<Order>;\n /** Opens an RMA the merchant approves. Changes no order state by itself. */\n requestOrderReturn(\n id: string,\n input: { items: Array<{ lineItemId: string; quantity: number }>; reason?: string },\n ): Promise<{ id: string; status: string }>;\n cancelSubscription(id: string, opts?: { atPeriodEnd?: boolean }): Promise<Subscription>;\n pauseSubscription(id: string): Promise<Subscription>;\n resumeSubscription(id: string): Promise<Subscription>;\n /**\n * Where a physical subscription's box goes, from the next renewal. Needs a\n * fresh sign-in (step-up), like cancelling. A subscription that ships\n * nothing answers `subscription_not_physical`.\n */\n updateSubscriptionShippingAddress(id: string, address: SubscriptionShippingAddress): Promise<Subscription>;\n claimCart(cartId: string): Promise<{ cartId: string; customerId: string }>;\n /**\n * The buyer's newest open or idle-abandoned cart in `currency` (see `status`), or null. Answers null as well\n * when the API predates the route (404). Always present on the account that\n * `createAccount` and `ThrottleProvider` build; optional here so a hand-made\n * `ThrottleAccount` written against 0.11 still compiles.\n */\n getOpenCart?(input: { currency: string }): Promise<OpenCart | null>;\n}\n\nconst seg = (v: string) => encodeURIComponent(v);\n\nfunction query(page?: Page): string {\n const params = new URLSearchParams();\n if (page?.cursor) params.set('cursor', page.cursor);\n if (page?.limit != null) params.set('limit', String(page.limit));\n const s = params.toString();\n return s ? `?${s}` : '';\n}\n\nexport function createAccount(\n auth: ThrottleAuth,\n): ThrottleAccount & Required<Pick<ThrottleAccount, 'getOpenCart'>> {\n const { call } = auth;\n return {\n getProfile: () => call('GET', '/me'),\n updateProfile: (patch) => call('PATCH', '/me', patch),\n\n listAddresses: () => call('GET', '/me/addresses'),\n createAddress: (input) => call('POST', '/me/addresses', input),\n updateAddress: (id, patch) => call('PATCH', `/me/addresses/${seg(id)}`, patch),\n deleteAddress: (id) => call('DELETE', `/me/addresses/${seg(id)}`),\n\n listPaymentMethods: () => call('GET', '/me/payment-methods'),\n // The platform has no \"change this subscription's card\" capability, so\n // this is how a buyer changes what they are billed on: move the default.\n setDefaultPaymentMethod: (id) => call('PATCH', `/me/payment-methods/${seg(id)}`, { isDefault: true }),\n deletePaymentMethod: (id) => call('DELETE', `/me/payment-methods/${seg(id)}`),\n\n // Saving a card is two calls because the card number never reaches us: the\n // first mints a processor-hosted embed session, the buyer types their card\n // into that, and the second records what the processor vaulted. Everything\n // about the saved card is read back from the processor, so nothing here\n // trusts what the browser claims the card was.\n startCardSetup: () => call('POST', '/me/payment-methods/embed-token'),\n confirmCardSetup: (transactionId) =>\n call('POST', '/me/payment-methods/confirm', { transactionId }),\n\n listOrders: (page) => call('GET', `/me/orders${query(page)}`),\n getOrder: (id) => call('GET', `/me/orders/${seg(id)}`),\n listInvoices: (page) => call('GET', `/me/invoices${query(page)}`),\n getInvoice: (id) => call('GET', `/me/invoices/${seg(id)}`),\n getInvoicePdfUrl: (id) => call('GET', `/me/invoices/${seg(id)}/pdf`),\n listSubscriptions: (page) => call('GET', `/me/subscriptions${query(page)}`),\n getSubscription: (id) => call('GET', `/me/subscriptions/${seg(id)}`),\n\n cancelOrder: (id, opts) => call('POST', `/me/orders/${seg(id)}/cancel`, opts),\n requestOrderReturn: (id, input) => call('POST', `/me/orders/${seg(id)}/return-request`, input),\n cancelSubscription: (id, opts) => call('POST', `/me/subscriptions/${seg(id)}/cancel`, opts),\n pauseSubscription: (id) => call('POST', `/me/subscriptions/${seg(id)}/pause`),\n resumeSubscription: (id) => call('POST', `/me/subscriptions/${seg(id)}/resume`),\n updateSubscriptionShippingAddress: (id, address) =>\n call('PATCH', `/me/subscriptions/${seg(id)}/shipping-address`, address),\n\n claimCart: (cartId) => call('POST', `/me/carts/${seg(cartId)}/claim`),\n\n async getOpenCart({ currency }) {\n if (typeof currency !== 'string' || !/^[A-Za-z]{3}$/.test(currency)) {\n throw new TypeError('getOpenCart: currency must be a 3-letter ISO code');\n }\n try {\n return await call<OpenCart | null>('GET', `/me/cart?currency=${currency.toUpperCase()}`);\n } catch (err) {\n // An API that predates the route: no cart to follow, not a failure.\n if (err instanceof ThrottleAuthError && err.statusCode === 404) return null;\n throw err;\n }\n },\n };\n}\n","export { createThrottleAuth } from './client';\nexport type { ThrottleAuth, DeviceSession } from './client';\nexport { ThrottleAuthError } from './errors';\nexport { memoryStorage, localStorageAdapter } from './storage';\nexport type { AuthSnapshot, AuthStatus } from './session';\nexport type { AuthStorage, Customer, Session, ThrottleAuthConfig } from './types';\nexport { createAccount } from './account';\nexport type { ThrottleAccount, Page } from './account';\nexport type {\n Address, AddressInput, Invoice, OpenCart, Order, PaymentMethod, ProfilePatch, Subscription,\n SubscriptionShippingAddress,\n} from './types';\n// Money helpers (MC2-R34). This is money's two-argument `formatMoney`; the\n// `./components` entry keeps its own three-argument one (MC2-R48).\nexport * as money from '@usethrottle/money';\nexport {\n formatMoney,\n currencySymbol,\n minorUnitsOf,\n toDecimalString,\n toMinor,\n parseMoney,\n moneyValue,\n CURRENCIES,\n isKnownCurrency,\n UnknownCurrencyError,\n} from '@usethrottle/money';\nexport type { CurrencyCode, MoneyValue } from '@usethrottle/money';\n"],"mappings":"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","names":[]}
@@ -1,10 +1,11 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode } from 'react';
3
- import { R as Resource } from '../../../hooks-DkpLrEiC.js';
3
+ import { R as Resource } from '../../../hooks-q2sYQa7f.js';
4
4
  export { A as AccountModal, a as AccountModalProps, b as AddCardDialog, I as InvoiceDetail, c as InvoicesPanel, O as OrderDetail, P as PaymentMethodsPanel, d as ProfilePanel, S as SecurityPanel, e as SubscriptionsPanel, V as VerifyEmailBanner } from '../../../AccountModal-pIMgledL.js';
5
5
  export { A as ACCOUNT_TABS, a as AccountDashboard, b as AccountDashboardProps, c as AccountPanelVariant, d as AccountTab, e as AddressesPanel, f as OrdersPanel } from '../../../AccountDashboard-V63ghvjY.js';
6
- import { A as Address, a as AddressInput } from '../../../client-7LVKfuXO.js';
6
+ import { A as Address, a as AddressInput } from '../../../client-BripyQad.js';
7
7
  import '../../../localization-SnIAZXJn.js';
8
+ import '@usethrottle/money';
8
9
 
9
10
  interface PanelStateProps<T> {
10
11
  resource: Resource<T>;
@@ -17,7 +17,7 @@ import {
17
17
  SecurityPanel,
18
18
  SubscriptionsPanel,
19
19
  VerifyEmailBanner
20
- } from "../../../chunk-6WN3J5MM.js";
20
+ } from "../../../chunk-37RG635A.js";
21
21
  import "../../../chunk-UFGW76AZ.js";
22
22
  import "../../../chunk-QPVS6JXP.js";
23
23
  import "../../../chunk-CUNMJ2PH.js";
@@ -6,8 +6,8 @@ import {
6
6
  SignUpButton,
7
7
  SignUpPage,
8
8
  StepUpDialog
9
- } from "../../../chunk-VDK23T6L.js";
10
- import "../../../chunk-RCNUWITB.js";
9
+ } from "../../../chunk-X4IZ7RC6.js";
10
+ import "../../../chunk-YRJFGH6J.js";
11
11
  import {
12
12
  AuthFlow,
13
13
  AuthModal,
@@ -1,8 +1,10 @@
1
1
  "use client";
2
2
  "use strict";
3
+ var __create = Object.create;
3
4
  var __defProp = Object.defineProperty;
4
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
6
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
7
9
  var __esm = (fn, res) => function __init() {
8
10
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
@@ -19,6 +21,14 @@ var __copyProps = (to, from, except, desc) => {
19
21
  }
20
22
  return to;
21
23
  };
24
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
25
+ // If the importer is in node compatibility mode or this is not an ESM
26
+ // file that has been converted to a CommonJS file using a Babel-
27
+ // compatible transform (i.e. "__esModule" has not been set), then set
28
+ // "default" to the CommonJS "module.exports" for node compatibility.
29
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
30
+ mod
31
+ ));
22
32
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
23
33
 
24
34
  // src/errors.ts
@@ -3608,22 +3618,8 @@ var init_PaymentMethodsPanel = __esm({
3608
3618
 
3609
3619
  // src/react/components/format.ts
3610
3620
  function formatMoney(minorUnits, currency, locale) {
3611
- const code = (currency || "USD").toUpperCase();
3612
- let digits = 2;
3613
- try {
3614
- digits = new Intl.NumberFormat("en-US", { style: "currency", currency: code }).resolvedOptions().maximumFractionDigits ?? 2;
3615
- } catch {
3616
- }
3617
- const major = minorUnits / 10 ** digits;
3618
- try {
3619
- return new Intl.NumberFormat(locale, { style: "currency", currency: code }).format(major);
3620
- } catch {
3621
- try {
3622
- return new Intl.NumberFormat("en-US", { style: "currency", currency: code }).format(major);
3623
- } catch {
3624
- return `${code} ${major.toFixed(digits)}`;
3625
- }
3626
- }
3621
+ void locale;
3622
+ return (0, import_money.formatMoney)(minorUnits, currency);
3627
3623
  }
3628
3624
  function formatDate(value, locale) {
3629
3625
  const date = value instanceof Date ? value : new Date(value);
@@ -3649,9 +3645,11 @@ function scheduleDueLabel(row, locale) {
3649
3645
  return `${new Intl.DateTimeFormat("en-US", opts).format(date)} UTC`;
3650
3646
  }
3651
3647
  }
3648
+ var import_money;
3652
3649
  var init_format = __esm({
3653
3650
  "src/react/components/format.ts"() {
3654
3651
  "use strict";
3652
+ import_money = require("@usethrottle/money");
3655
3653
  }
3656
3654
  });
3657
3655
 
@@ -3667,10 +3665,10 @@ function OrderStatus(props) {
3667
3665
  const labels = props.t.orders.statusLabels;
3668
3666
  const payLabels = props.t.orders.paymentLabels;
3669
3667
  const lifecycle = labels[copyKey(props.status)] ?? props.status.replace(/_/g, " ");
3670
- const money = props.paymentStatus ? payLabels[copyKey(props.paymentStatus)] : void 0;
3668
+ const money2 = props.paymentStatus ? payLabels[copyKey(props.paymentStatus)] : void 0;
3671
3669
  return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_jsx_runtime36.Fragment, { children: [
3672
3670
  /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Badge, { tone: TERMINAL_STATUSES.has(props.status) ? "muted" : "neutral", children: lifecycle }),
3673
- money ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Badge, { tone: ATTENTION_PAYMENT_STATES.has(props.paymentStatus) ? "warning" : "neutral", children: money }) : null
3671
+ money2 ? /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(Badge, { tone: ATTENTION_PAYMENT_STATES.has(props.paymentStatus) ? "warning" : "neutral", children: money2 }) : null
3674
3672
  ] });
3675
3673
  }
3676
3674
  var import_jsx_runtime36, ATTENTION_PAYMENT_STATES, TERMINAL_STATUSES;
@@ -3811,7 +3809,7 @@ function OrderDetail(props) {
3811
3809
  subscriptionId: li.subscriptionId ?? null
3812
3810
  }))
3813
3811
  };
3814
- const money = (v) => formatMoney(v, order.currency, locale);
3812
+ const money2 = (v) => formatMoney(v, order.currency, locale);
3815
3813
  const paid = SETTLED_PAYMENT.has(order.paymentStatus);
3816
3814
  const showCancel = allowCancel && CAN_CANCEL.has(order.status) && !paid;
3817
3815
  const showReorder = !!props.onReorder && (CAN_REORDER.has(order.status) || !!props.reorderOnPaid && REORDER_PAID_PAYMENT.has(order.paymentStatus));
@@ -3837,10 +3835,10 @@ function OrderDetail(props) {
3837
3835
  " ",
3838
3836
  item.quantity,
3839
3837
  " \xD7 ",
3840
- money(item.unitPrice)
3838
+ money2(item.unitPrice)
3841
3839
  ] })
3842
3840
  ] }),
3843
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { children: money(item.total) })
3841
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { children: money2(item.total) })
3844
3842
  ] }, item.id)) })
3845
3843
  ] }),
3846
3844
  /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
@@ -3878,13 +3876,13 @@ function OrderDetail(props) {
3878
3876
  /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("aside", { ...a.el("orderDetail.rail", "throttle-detail__rail"), children: [
3879
3877
  /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { className: "throttle-detail__section", children: [
3880
3878
  /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "throttle-detail__label", children: t.orders.total }),
3881
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "throttle-detail__headline", children: money(order.total) })
3879
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)("span", { className: "throttle-detail__headline", children: money2(order.total) })
3882
3880
  ] }),
3883
3881
  /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { ...a.el("orderDetail.totals", "throttle-totals"), children: [
3884
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Line, { label: t.orders.subtotal, value: money(order.subtotal) }),
3885
- order.discountTotal ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Line, { label: t.orders.discount, value: money(-order.discountTotal) }) : null,
3886
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Line, { label: t.orders.shipping, value: money(order.shippingTotal) }),
3887
- /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Line, { label: t.orders.tax, value: money(order.taxTotal) })
3882
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Line, { label: t.orders.subtotal, value: money2(order.subtotal) }),
3883
+ order.discountTotal ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Line, { label: t.orders.discount, value: money2(-order.discountTotal) }) : null,
3884
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Line, { label: t.orders.shipping, value: money2(order.shippingTotal) }),
3885
+ /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Line, { label: t.orders.tax, value: money2(order.taxTotal) })
3888
3886
  ] }),
3889
3887
  /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)("div", { ...a.el("orderDetail.actions", "throttle-detail__actions"), children: [
3890
3888
  props.onPayNow && CAN_PAY.has(order.status) ? /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(Button, { elementKey: "orderDetail.payButton", onClick: () => props.onPayNow(target), children: t.orders.payNow }) : null,
@@ -4140,7 +4138,7 @@ function InvoiceDetail(props) {
4140
4138
  ) : null,
4141
4139
  error ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Alert, { tone: "error", children: error }) : null,
4142
4140
  /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(PanelState, { resource, isEmpty: (i) => i === null, emptyTitle: t.invoices.empty, skeletonRows: 4, children: (invoice) => {
4143
- const money = (v) => formatMoney(v, invoice.currency, locale);
4141
+ const money2 = (v) => formatMoney(v, invoice.currency, locale);
4144
4142
  const lines = invoice.lineItems ?? [];
4145
4143
  const partOfOrder = invoice.orderTotal != null;
4146
4144
  const isDepositReceipt = partOfOrder && invoice.balanceDue != null;
@@ -4169,23 +4167,23 @@ function InvoiceDetail(props) {
4169
4167
  " ",
4170
4168
  item.quantity,
4171
4169
  " \xD7 ",
4172
- money(item.unitPrice)
4170
+ money2(item.unitPrice)
4173
4171
  ] })
4174
4172
  ] }),
4175
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: money(item.total) })
4173
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { children: money2(item.total) })
4176
4174
  ] }, i)) })
4177
4175
  ] }) : null
4178
4176
  ] }),
4179
4177
  /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("aside", { ...a.el("invoiceDetail.rail", "throttle-detail__rail"), children: [
4180
4178
  /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { className: "throttle-detail__section", children: [
4181
4179
  /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "throttle-detail__label", children: headlineLabel }),
4182
- /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "throttle-detail__headline", children: money(invoice.total) })
4180
+ /* @__PURE__ */ (0, import_jsx_runtime41.jsx)("span", { className: "throttle-detail__headline", children: money2(invoice.total) })
4183
4181
  ] }),
4184
4182
  /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { ...a.el("invoiceDetail.totals", "throttle-totals"), children: [
4185
- partOfOrder ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Line2, { label: t.invoices.orderTotal, value: money(invoice.orderTotal) }) : null,
4186
- partOfOrder && invoice.amountPaid ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Line2, { label: t.invoices.amountPaid, value: `-${money(invoice.amountPaid)}` }) : null,
4187
- partOfOrder && invoice.compWaived ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Line2, { label: t.invoices.waived, value: `-${money(invoice.compWaived)}` }) : null,
4188
- isDepositReceipt && invoice.balanceDue ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Line2, { label: t.invoices.balanceDue, value: money(invoice.balanceDue) }) : null,
4183
+ partOfOrder ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Line2, { label: t.invoices.orderTotal, value: money2(invoice.orderTotal) }) : null,
4184
+ partOfOrder && invoice.amountPaid ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Line2, { label: t.invoices.amountPaid, value: `-${money2(invoice.amountPaid)}` }) : null,
4185
+ partOfOrder && invoice.compWaived ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Line2, { label: t.invoices.waived, value: `-${money2(invoice.compWaived)}` }) : null,
4186
+ isDepositReceipt && invoice.balanceDue ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Line2, { label: t.invoices.balanceDue, value: money2(invoice.balanceDue) }) : null,
4189
4187
  invoice.dueAt ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Line2, { label: t.invoices.due, value: formatDate(invoice.dueAt, locale) }) : null,
4190
4188
  invoice.periodStart && invoice.periodEnd ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
4191
4189
  Line2,
@@ -4194,7 +4192,7 @@ function InvoiceDetail(props) {
4194
4192
  value: `${formatDate(invoice.periodStart, locale)} \u2013 ${formatDate(invoice.periodEnd, locale)}`
4195
4193
  }
4196
4194
  ) : null,
4197
- invoice.amountRefunded ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Line2, { label: t.invoices.refunded, value: money(invoice.amountRefunded) }) : null
4195
+ invoice.amountRefunded ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(Line2, { label: t.invoices.refunded, value: money2(invoice.amountRefunded) }) : null
4198
4196
  ] }),
4199
4197
  /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)("div", { ...a.el("invoiceDetail.actions", "throttle-detail__actions"), children: [
4200
4198
  props.onPay && PAYABLE.has(invoice.status) ? /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(
@@ -5109,6 +5107,7 @@ __export(components_exports, {
5109
5107
  AddressesPanel: () => AddressesPanel,
5110
5108
  AuthFlow: () => AuthFlow,
5111
5109
  AuthModal: () => AuthModal,
5110
+ CURRENCIES: () => import_money2.CURRENCIES,
5112
5111
  ForgotPassword: () => ForgotPassword,
5113
5112
  InvoiceDetail: () => InvoiceDetail,
5114
5113
  InvoicesPanel: () => InvoicesPanel,
@@ -5135,16 +5134,25 @@ __export(components_exports, {
5135
5134
  ThrottleAuthError: () => ThrottleAuthError,
5136
5135
  ThrottleAuthProvider: () => ThrottleAuthProvider,
5137
5136
  ThrottleProvider: () => ThrottleProvider,
5137
+ UnknownCurrencyError: () => import_money2.UnknownCurrencyError,
5138
5138
  UserButton: () => UserButton,
5139
5139
  VerifyEmail: () => VerifyEmail,
5140
5140
  VerifyEmailBanner: () => VerifyEmailBanner,
5141
5141
  createAccount: () => createAccount,
5142
5142
  createThrottleAuth: () => createThrottleAuth,
5143
+ currencySymbol: () => import_money2.currencySymbol,
5143
5144
  enUS: () => enUS,
5144
5145
  formatDate: () => formatDate,
5145
5146
  formatMoney: () => formatMoney,
5147
+ isKnownCurrency: () => import_money2.isKnownCurrency,
5146
5148
  localStorageAdapter: () => localStorageAdapter,
5147
5149
  memoryStorage: () => memoryStorage,
5150
+ minorUnitsOf: () => import_money2.minorUnitsOf,
5151
+ money: () => money,
5152
+ moneyValue: () => import_money2.moneyValue,
5153
+ parseMoney: () => import_money2.parseMoney,
5154
+ toDecimalString: () => import_money2.toDecimalString,
5155
+ toMinor: () => import_money2.toMinor,
5148
5156
  useAddresses: () => useAddresses,
5149
5157
  useAuth: () => useAuth,
5150
5158
  useAuthContext: () => useAuthContext,
@@ -6215,6 +6223,8 @@ init_client();
6215
6223
  init_errors();
6216
6224
  init_storage();
6217
6225
  init_account();
6226
+ var money = __toESM(require("@usethrottle/money"), 1);
6227
+ var import_money2 = require("@usethrottle/money");
6218
6228
  // Annotate the CommonJS export names for ESM import in node:
6219
6229
  0 && (module.exports = {
6220
6230
  ACCOUNT_TABS,
@@ -6224,6 +6234,7 @@ init_account();
6224
6234
  AddressesPanel,
6225
6235
  AuthFlow,
6226
6236
  AuthModal,
6237
+ CURRENCIES,
6227
6238
  ForgotPassword,
6228
6239
  InvoiceDetail,
6229
6240
  InvoicesPanel,
@@ -6250,16 +6261,25 @@ init_account();
6250
6261
  ThrottleAuthError,
6251
6262
  ThrottleAuthProvider,
6252
6263
  ThrottleProvider,
6264
+ UnknownCurrencyError,
6253
6265
  UserButton,
6254
6266
  VerifyEmail,
6255
6267
  VerifyEmailBanner,
6256
6268
  createAccount,
6257
6269
  createThrottleAuth,
6270
+ currencySymbol,
6258
6271
  enUS,
6259
6272
  formatDate,
6260
6273
  formatMoney,
6274
+ isKnownCurrency,
6261
6275
  localStorageAdapter,
6262
6276
  memoryStorage,
6277
+ minorUnitsOf,
6278
+ money,
6279
+ moneyValue,
6280
+ parseMoney,
6281
+ toDecimalString,
6282
+ toMinor,
6263
6283
  useAddresses,
6264
6284
  useAuth,
6265
6285
  useAuthContext,