@usethrottle/auth 0.10.1 → 0.11.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.
- package/README.md +1 -1
- package/dist/{chunk-ZYYWXVX5.js → chunk-EFMKBOTL.js} +4 -3
- package/dist/chunk-EFMKBOTL.js.map +1 -0
- package/dist/{chunk-X4DGZ4JU.js → chunk-YY6YATXT.js} +2 -1
- package/dist/chunk-YY6YATXT.js.map +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +27 -1
- package/dist/index.d.ts +27 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/react/components/index.cjs +120 -55
- package/dist/react/components/index.cjs.map +1 -1
- package/dist/react/components/index.d.cts +7 -2
- package/dist/react/components/index.d.ts +7 -2
- package/dist/react/components/index.js +89 -26
- package/dist/react/components/index.js.map +1 -1
- package/dist/react/forms/index.js +1 -1
- package/dist/react/index.cjs +3 -1
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +29 -1
- package/dist/react/index.d.ts +29 -1
- package/dist/react/index.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-X4DGZ4JU.js.map +0 -1
- package/dist/chunk-ZYYWXVX5.js.map +0 -1
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 * 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\nexport function createThrottleAuth(config: ThrottleAuthConfig): ThrottleAuth {\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}\n\nexport type { AuthSnapshot, Customer, Session, ThrottleAuthConfig };\n","import type { ThrottleAuth } from './client';\nimport type {\n Address, AddressInput, Customer, Invoice, Order, OrderDetail,\n PaymentMethod, ProfilePatch, Subscription,\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 claimCart(cartId: string): Promise<{ cartId: string; customerId: string }>;\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(auth: ThrottleAuth): ThrottleAccount {\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\n claimCart: (cartId) => call('POST', `/me/carts/${seg(cartId)}/claim`),\n };\n}\n"],"mappings":"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","names":[]}
|
|
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\nexport function createThrottleAuth(config: ThrottleAuthConfig): ThrottleAuth {\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}\n\nexport type { AuthSnapshot, Customer, Session, ThrottleAuthConfig };\n","import type { ThrottleAuth } from './client';\nimport type {\n Address, AddressInput, Customer, Invoice, 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\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(auth: ThrottleAuth): ThrottleAccount {\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}\n"],"mappings":"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","names":[]}
|
|
@@ -79,7 +79,7 @@ __export(components_exports, {
|
|
|
79
79
|
module.exports = __toCommonJS(components_exports);
|
|
80
80
|
|
|
81
81
|
// src/react/components/provider.tsx
|
|
82
|
-
var
|
|
82
|
+
var import_react32 = require("react");
|
|
83
83
|
|
|
84
84
|
// src/errors.ts
|
|
85
85
|
var ThrottleAuthError = class extends Error {
|
|
@@ -472,6 +472,7 @@ function createAccount(auth) {
|
|
|
472
472
|
cancelSubscription: (id, opts) => call("POST", `/me/subscriptions/${seg(id)}/cancel`, opts),
|
|
473
473
|
pauseSubscription: (id) => call("POST", `/me/subscriptions/${seg(id)}/pause`),
|
|
474
474
|
resumeSubscription: (id) => call("POST", `/me/subscriptions/${seg(id)}/resume`),
|
|
475
|
+
updateSubscriptionShippingAddress: (id, address) => call("PATCH", `/me/subscriptions/${seg(id)}/shipping-address`, address),
|
|
475
476
|
claimCart: (cartId) => call("POST", `/me/carts/${seg(cartId)}/claim`)
|
|
476
477
|
};
|
|
477
478
|
}
|
|
@@ -835,6 +836,8 @@ var THROTTLE_ELEMENT_KEYS = [
|
|
|
835
836
|
"subscriptionsPanel.cancelNowButton",
|
|
836
837
|
"subscriptionsPanel.pauseButton",
|
|
837
838
|
"subscriptionsPanel.resumeButton",
|
|
839
|
+
"subscriptionsPanel.changeAddressButton",
|
|
840
|
+
"subscriptionsPanel.addressForm",
|
|
838
841
|
"subscriptionsPanel.table",
|
|
839
842
|
"subscriptionsPanel.row",
|
|
840
843
|
"securityPanel.root",
|
|
@@ -1252,6 +1255,11 @@ var enUS = {
|
|
|
1252
1255
|
cancelNow: "Cancel immediately",
|
|
1253
1256
|
pauseButton: "Pause",
|
|
1254
1257
|
resumeButton: "Resume",
|
|
1258
|
+
/** A physical subscription's ship-to, and the control that changes it. */
|
|
1259
|
+
shipsTo: "Ships to",
|
|
1260
|
+
changeAddress: "Change address",
|
|
1261
|
+
changeAddressTitle: "Change shipping address",
|
|
1262
|
+
changeAddressHint: "Your next box ships here. Orders already placed keep their address.",
|
|
1255
1263
|
cancelConfirm: "Cancel this subscription?",
|
|
1256
1264
|
cancelScheduled: "Cancels at the end of the period",
|
|
1257
1265
|
columnPlan: "Plan",
|
|
@@ -2911,10 +2919,10 @@ function AuthModal(props) {
|
|
|
2911
2919
|
}
|
|
2912
2920
|
|
|
2913
2921
|
// src/react/components/account/AccountModal.tsx
|
|
2914
|
-
var
|
|
2922
|
+
var import_react31 = require("react");
|
|
2915
2923
|
|
|
2916
2924
|
// src/react/components/account/AccountDashboard.tsx
|
|
2917
|
-
var
|
|
2925
|
+
var import_react30 = require("react");
|
|
2918
2926
|
|
|
2919
2927
|
// src/react/components/account/VerifyEmailBanner.tsx
|
|
2920
2928
|
var import_react19 = require("react");
|
|
@@ -3143,7 +3151,8 @@ function useSubscriptions(page) {
|
|
|
3143
3151
|
...res,
|
|
3144
3152
|
cancel: (id, opts) => after(account.cancelSubscription(id, opts)),
|
|
3145
3153
|
pause: (id) => after(account.pauseSubscription(id)),
|
|
3146
|
-
resume: (id) => after(account.resumeSubscription(id))
|
|
3154
|
+
resume: (id) => after(account.resumeSubscription(id)),
|
|
3155
|
+
updateShippingAddress: (id, address) => after(account.updateSubscriptionShippingAddress(id, address))
|
|
3147
3156
|
};
|
|
3148
3157
|
}
|
|
3149
3158
|
function useOrder(id) {
|
|
@@ -3329,7 +3338,7 @@ function AddressForm(props) {
|
|
|
3329
3338
|
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
|
|
3330
3339
|
"form",
|
|
3331
3340
|
{
|
|
3332
|
-
...a.el("addressesPanel.form", "throttle-stack"),
|
|
3341
|
+
...a.el(props.elementKey ?? "addressesPanel.form", "throttle-stack"),
|
|
3333
3342
|
onSubmit: (e) => {
|
|
3334
3343
|
e.preventDefault();
|
|
3335
3344
|
props.onSubmit({
|
|
@@ -3349,7 +3358,7 @@ function AddressForm(props) {
|
|
|
3349
3358
|
},
|
|
3350
3359
|
children: [
|
|
3351
3360
|
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(FieldRow, { children: [
|
|
3352
|
-
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Field, { label: t.addresses.label, value: form.label, onChange: set("label") }),
|
|
3361
|
+
props.hideLabel ? null : /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Field, { label: t.addresses.label, value: form.label, onChange: set("label") }),
|
|
3353
3362
|
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Field, { label: t.addresses.company, value: form.company, onChange: set("company"), autoComplete: "organization" })
|
|
3354
3363
|
] }),
|
|
3355
3364
|
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(FieldRow, { children: [
|
|
@@ -4441,6 +4450,9 @@ function InvoicesPanel(props) {
|
|
|
4441
4450
|
) }) }) });
|
|
4442
4451
|
}
|
|
4443
4452
|
|
|
4453
|
+
// src/react/components/account/SubscriptionsPanel.tsx
|
|
4454
|
+
var import_react28 = require("react");
|
|
4455
|
+
|
|
4444
4456
|
// ../core-cadence/src/cadence.ts
|
|
4445
4457
|
var INTERVAL_UNITS = ["hour", "day", "week", "month"];
|
|
4446
4458
|
var NAMED_INTERVALS = ["weekly", "biweekly", "monthly", "quarterly", "yearly"];
|
|
@@ -4493,6 +4505,12 @@ var CAN_PAUSE = /* @__PURE__ */ new Set(["active"]);
|
|
|
4493
4505
|
var CAN_RESUME = /* @__PURE__ */ new Set(["paused"]);
|
|
4494
4506
|
var CAN_CANCEL2 = /* @__PURE__ */ new Set(["active", "trialing", "paused", "past_due", "unpaid"]);
|
|
4495
4507
|
var isInstallment = (sub) => sub.totalPayments != null;
|
|
4508
|
+
var canChangeAddress = (sub) => sub.deliveryMethod === "shipment" && sub.status !== "cancelled" && sub.status !== "completed";
|
|
4509
|
+
function oneLine(address) {
|
|
4510
|
+
if (!address) return null;
|
|
4511
|
+
const parts = [address.addressLine1, address.addressLine2, address.city, address.stateProvince, address.postalCode, address.countryCode];
|
|
4512
|
+
return parts.filter(Boolean).join(", ") || null;
|
|
4513
|
+
}
|
|
4496
4514
|
function SubscriptionsPanel(props) {
|
|
4497
4515
|
const a = useAppearance(props.appearance);
|
|
4498
4516
|
const scoped = useAppearanceProviderValue(props.appearance);
|
|
@@ -4501,6 +4519,7 @@ function SubscriptionsPanel(props) {
|
|
|
4501
4519
|
const resource = useSubscriptions();
|
|
4502
4520
|
const { submitting, error, run } = useAction();
|
|
4503
4521
|
const confirm = useConfirm();
|
|
4522
|
+
const [editingAddress, setEditingAddress] = (0, import_react28.useState)(null);
|
|
4504
4523
|
const variant = props.variant ?? "rows";
|
|
4505
4524
|
const rowsVariant = variant === "rows";
|
|
4506
4525
|
const listBase = rowsVariant ? "throttle-rows" : "throttle-stack";
|
|
@@ -4529,6 +4548,21 @@ function SubscriptionsPanel(props) {
|
|
|
4529
4548
|
if (upcoming.length === 0) return null;
|
|
4530
4549
|
return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("ul", { className: "throttle-muted", "aria-label": t.subscriptions.upcomingPayments, children: upcoming.map((r) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("li", { children: t.subscriptions.upcomingPayment.replace("{amount}", formatMoney(r.net, sub.currency, locale)).replace("{date}", scheduleDueLabel(r, locale)) }, r.dueAt)) });
|
|
4531
4550
|
};
|
|
4551
|
+
const shipsTo = (sub) => sub.deliveryMethod === "shipment" && oneLine(sub.shippingAddress) ? /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("p", { className: "throttle-muted", children: [
|
|
4552
|
+
t.subscriptions.shipsTo,
|
|
4553
|
+
" ",
|
|
4554
|
+
oneLine(sub.shippingAddress)
|
|
4555
|
+
] }) : null;
|
|
4556
|
+
const addressAction = (sub, variantFor) => canChangeAddress(sub) ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
4557
|
+
Button,
|
|
4558
|
+
{
|
|
4559
|
+
variant: variantFor("secondary"),
|
|
4560
|
+
elementKey: "subscriptionsPanel.changeAddressButton",
|
|
4561
|
+
disabled: submitting,
|
|
4562
|
+
onClick: () => setEditingAddress(sub.id),
|
|
4563
|
+
children: t.subscriptions.changeAddress
|
|
4564
|
+
}
|
|
4565
|
+
) : null;
|
|
4532
4566
|
const renewsLabel = (sub) => formatDate(
|
|
4533
4567
|
sub.status === "completed" ? sub.completedAt ?? sub.currentPeriodEnd : sub.status === "cancelled" ? sub.cancelledAt ?? sub.currentPeriodEnd : sub.currentPeriodEnd,
|
|
4534
4568
|
locale
|
|
@@ -4590,7 +4624,32 @@ function SubscriptionsPanel(props) {
|
|
|
4590
4624
|
) : null
|
|
4591
4625
|
] });
|
|
4592
4626
|
return /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { ...a.rootProps, children: /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { ...a.el("subscriptionsPanel.root", "throttle-panel"), children: [
|
|
4593
|
-
error ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Alert, { tone: "error", children: error }) : null,
|
|
4627
|
+
error && !editingAddress ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Alert, { tone: "error", children: error }) : null,
|
|
4628
|
+
editingAddress ? (() => {
|
|
4629
|
+
const sub = resource.data.find((row) => row.id === editingAddress);
|
|
4630
|
+
const current = sub?.shippingAddress;
|
|
4631
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { className: "throttle-stack", children: [
|
|
4632
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("strong", { children: t.subscriptions.changeAddressTitle }),
|
|
4633
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "throttle-muted", children: t.subscriptions.changeAddressHint }),
|
|
4634
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
4635
|
+
AddressForm,
|
|
4636
|
+
{
|
|
4637
|
+
elementKey: "subscriptionsPanel.addressForm",
|
|
4638
|
+
hideLabel: true,
|
|
4639
|
+
initial: current ? { ...current, label: null } : void 0,
|
|
4640
|
+
submitting,
|
|
4641
|
+
error,
|
|
4642
|
+
onCancel: () => setEditingAddress(null),
|
|
4643
|
+
onSubmit: ({ label: _label, isDefault: _isDefault, ...address }) => {
|
|
4644
|
+
void run(async () => {
|
|
4645
|
+
await resource.updateShippingAddress(editingAddress, address);
|
|
4646
|
+
setEditingAddress(null);
|
|
4647
|
+
});
|
|
4648
|
+
}
|
|
4649
|
+
}
|
|
4650
|
+
)
|
|
4651
|
+
] });
|
|
4652
|
+
})() : null,
|
|
4594
4653
|
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
4595
4654
|
PanelState,
|
|
4596
4655
|
{
|
|
@@ -4612,7 +4671,8 @@ function SubscriptionsPanel(props) {
|
|
|
4612
4671
|
sub.planName ?? sub.planReference,
|
|
4613
4672
|
sub.totalPayments != null ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "throttle-muted", children: t.subscriptions.installmentProgress.replace("{paid}", String(Math.min(sub.paymentsMade ?? 0, sub.totalPayments))).replace("{total}", String(sub.totalPayments)) }) : null,
|
|
4614
4673
|
nextPaymentLabel(sub) ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "throttle-muted", children: nextPaymentLabel(sub) }) : null,
|
|
4615
|
-
upcomingList(sub)
|
|
4674
|
+
upcomingList(sub),
|
|
4675
|
+
shipsTo(sub)
|
|
4616
4676
|
] }) },
|
|
4617
4677
|
{ key: "price", label: t.subscriptions.columnPrice, render: (sub) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "throttle-table__money", children: priceLabel(sub) }) },
|
|
4618
4678
|
{ key: "renews", label: t.subscriptions.columnRenews, render: (sub) => renewsLabel(sub) },
|
|
@@ -4620,7 +4680,10 @@ function SubscriptionsPanel(props) {
|
|
|
4620
4680
|
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(StatusBadge, { status: sub.status, labels: t.subscriptions.statusLabels }),
|
|
4621
4681
|
sub.cancelAtPeriodEnd ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Badge, { tone: "warning", children: t.subscriptions.cancelScheduled }) : null
|
|
4622
4682
|
] }) },
|
|
4623
|
-
{ key: "actions", label: t.common.actions, render: (sub) =>
|
|
4683
|
+
{ key: "actions", label: t.common.actions, render: (sub) => /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_jsx_runtime43.Fragment, { children: [
|
|
4684
|
+
lifecycleActions(sub, (base) => base),
|
|
4685
|
+
addressAction(sub, (base) => base)
|
|
4686
|
+
] }) }
|
|
4624
4687
|
]
|
|
4625
4688
|
}
|
|
4626
4689
|
) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { ...a.el("subscriptionsPanel.list", listBase), children: rows.map((sub) => /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("div", { ...a.el("subscriptionsPanel.item", itemBase), children: [
|
|
@@ -4633,6 +4696,7 @@ function SubscriptionsPanel(props) {
|
|
|
4633
4696
|
nextPaymentLabel(sub) ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "throttle-muted", children: nextPaymentLabel(sub) }) : null,
|
|
4634
4697
|
upcomingList(sub),
|
|
4635
4698
|
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "throttle-muted", children: priceLabel(sub) }),
|
|
4699
|
+
shipsTo(sub),
|
|
4636
4700
|
sub.status === "completed" ? /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("p", { className: "throttle-muted", children: [
|
|
4637
4701
|
t.subscriptions.statusLabels.completed,
|
|
4638
4702
|
" ",
|
|
@@ -4653,7 +4717,8 @@ function SubscriptionsPanel(props) {
|
|
|
4653
4717
|
] }) : null,
|
|
4654
4718
|
sub.cancelAtPeriodEnd ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Badge, { tone: "warning", children: t.subscriptions.cancelScheduled }) : null
|
|
4655
4719
|
] }),
|
|
4656
|
-
lifecycleActions(sub, actionVariant)
|
|
4720
|
+
lifecycleActions(sub, actionVariant),
|
|
4721
|
+
addressAction(sub, actionVariant)
|
|
4657
4722
|
] }, sub.id)) })
|
|
4658
4723
|
}
|
|
4659
4724
|
)
|
|
@@ -4661,7 +4726,7 @@ function SubscriptionsPanel(props) {
|
|
|
4661
4726
|
}
|
|
4662
4727
|
|
|
4663
4728
|
// src/react/components/account/SecurityPanel.tsx
|
|
4664
|
-
var
|
|
4729
|
+
var import_react29 = require("react");
|
|
4665
4730
|
|
|
4666
4731
|
// src/react/components/account/device.ts
|
|
4667
4732
|
var BROWSERS = [
|
|
@@ -4704,16 +4769,16 @@ function SecurityPanel(props) {
|
|
|
4704
4769
|
const rowsVariant = variant === "rows";
|
|
4705
4770
|
const itemBase = rowsVariant ? "throttle-rowitem" : "throttle-listitem";
|
|
4706
4771
|
const revokeVariant = rowsVariant ? "linkDanger" : "danger";
|
|
4707
|
-
const [password, setPassword] = (0,
|
|
4772
|
+
const [password, setPassword] = (0, import_react29.useState)("");
|
|
4708
4773
|
const passwordAction = useAction();
|
|
4709
4774
|
const sessionAction = useAction();
|
|
4710
|
-
const [sessions, setSessions] = (0,
|
|
4711
|
-
const [listError, setListError] = (0,
|
|
4712
|
-
const errorMessageRef = (0,
|
|
4713
|
-
(0,
|
|
4775
|
+
const [sessions, setSessions] = (0, import_react29.useState)(null);
|
|
4776
|
+
const [listError, setListError] = (0, import_react29.useState)(null);
|
|
4777
|
+
const errorMessageRef = (0, import_react29.useRef)(errorMessage);
|
|
4778
|
+
(0, import_react29.useEffect)(() => {
|
|
4714
4779
|
errorMessageRef.current = errorMessage;
|
|
4715
4780
|
});
|
|
4716
|
-
const load = (0,
|
|
4781
|
+
const load = (0, import_react29.useCallback)(async () => {
|
|
4717
4782
|
try {
|
|
4718
4783
|
setSessions(await auth.listSessions());
|
|
4719
4784
|
setListError(null);
|
|
@@ -4721,7 +4786,7 @@ function SecurityPanel(props) {
|
|
|
4721
4786
|
setListError(errorMessageRef.current(err));
|
|
4722
4787
|
}
|
|
4723
4788
|
}, [auth]);
|
|
4724
|
-
(0,
|
|
4789
|
+
(0, import_react29.useEffect)(() => {
|
|
4725
4790
|
void load();
|
|
4726
4791
|
}, [load]);
|
|
4727
4792
|
const others = (sessions ?? []).filter((s) => !s.current);
|
|
@@ -4869,10 +4934,10 @@ function AccountDashboard(props) {
|
|
|
4869
4934
|
const { status } = useAuth();
|
|
4870
4935
|
const shown = props.tabs ?? [...ACCOUNT_TABS];
|
|
4871
4936
|
const controlled = props.tab !== void 0;
|
|
4872
|
-
const [internal, setInternal] = (0,
|
|
4873
|
-
const [openOrderId, setOpenOrderId] = (0,
|
|
4874
|
-
const idBase = (0,
|
|
4875
|
-
(0,
|
|
4937
|
+
const [internal, setInternal] = (0, import_react30.useState)(shown[0] ?? "profile");
|
|
4938
|
+
const [openOrderId, setOpenOrderId] = (0, import_react30.useState)(null);
|
|
4939
|
+
const idBase = (0, import_react30.useId)();
|
|
4940
|
+
(0, import_react30.useEffect)(() => {
|
|
4876
4941
|
if (props.routing !== "hash" || typeof window === "undefined") return;
|
|
4877
4942
|
const apply = () => {
|
|
4878
4943
|
const next = TAB_FOR_HASH[window.location.hash] ?? shown[0];
|
|
@@ -4968,7 +5033,7 @@ function AccountModal(props) {
|
|
|
4968
5033
|
const a = useAppearance(props.appearance);
|
|
4969
5034
|
const scoped = useAppearanceProviderValue(props.appearance);
|
|
4970
5035
|
const { t } = useCopy(props.localization);
|
|
4971
|
-
const titleId = (0,
|
|
5036
|
+
const titleId = (0, import_react31.useId)();
|
|
4972
5037
|
return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
|
|
4973
5038
|
Modal,
|
|
4974
5039
|
{
|
|
@@ -4995,9 +5060,9 @@ function warnOnce(key, message) {
|
|
|
4995
5060
|
warned.add(key);
|
|
4996
5061
|
console.warn(`[@usethrottle/auth] ${message}`);
|
|
4997
5062
|
}
|
|
4998
|
-
var ThrottleUIContext = (0,
|
|
5063
|
+
var ThrottleUIContext = (0, import_react32.createContext)(null);
|
|
4999
5064
|
function useThrottle() {
|
|
5000
|
-
const ctx = (0,
|
|
5065
|
+
const ctx = (0, import_react32.useContext)(ThrottleUIContext);
|
|
5001
5066
|
if (!ctx) {
|
|
5002
5067
|
warnOnce(
|
|
5003
5068
|
"use-throttle-no-provider",
|
|
@@ -5032,51 +5097,51 @@ function ThrottleProvider(props) {
|
|
|
5032
5097
|
__captureStepUp
|
|
5033
5098
|
} = props;
|
|
5034
5099
|
useInjectStyles(injectStyles);
|
|
5035
|
-
const [stepUpOpen, setStepUpOpen] = (0,
|
|
5036
|
-
const resolveStepUp = (0,
|
|
5037
|
-
const claimRef = (0,
|
|
5100
|
+
const [stepUpOpen, setStepUpOpen] = (0, import_react32.useState)(false);
|
|
5101
|
+
const resolveStepUp = (0, import_react32.useRef)(null);
|
|
5102
|
+
const claimRef = (0, import_react32.useRef)(claimCartOnSignIn);
|
|
5038
5103
|
claimRef.current = claimCartOnSignIn;
|
|
5039
|
-
const [overlay, setOverlay] = (0,
|
|
5040
|
-
const overlayRestoreFocus = (0,
|
|
5041
|
-
const [accountTabs, setAccountTabs] = (0,
|
|
5042
|
-
const onOverlaySuccess = (0,
|
|
5043
|
-
const openSignIn = (0,
|
|
5104
|
+
const [overlay, setOverlay] = (0, import_react32.useState)(null);
|
|
5105
|
+
const overlayRestoreFocus = (0, import_react32.useRef)(null);
|
|
5106
|
+
const [accountTabs, setAccountTabs] = (0, import_react32.useState)(void 0);
|
|
5107
|
+
const onOverlaySuccess = (0, import_react32.useRef)(null);
|
|
5108
|
+
const openSignIn = (0, import_react32.useCallback)((onSuccess) => {
|
|
5044
5109
|
onOverlaySuccess.current = onSuccess ?? null;
|
|
5045
5110
|
setOverlay("signIn");
|
|
5046
5111
|
}, []);
|
|
5047
|
-
const openSignUp = (0,
|
|
5112
|
+
const openSignUp = (0, import_react32.useCallback)((onSuccess) => {
|
|
5048
5113
|
onOverlaySuccess.current = onSuccess ?? null;
|
|
5049
5114
|
setOverlay("signUp");
|
|
5050
5115
|
}, []);
|
|
5051
|
-
const openAccount = (0,
|
|
5116
|
+
const openAccount = (0, import_react32.useCallback)((opts) => {
|
|
5052
5117
|
onOverlaySuccess.current = null;
|
|
5053
5118
|
overlayRestoreFocus.current = opts?.restoreFocusTo ?? null;
|
|
5054
5119
|
setAccountTabs(opts?.tabs);
|
|
5055
5120
|
setOverlay("account");
|
|
5056
5121
|
}, []);
|
|
5057
|
-
const closeOverlay = (0,
|
|
5122
|
+
const closeOverlay = (0, import_react32.useCallback)(() => {
|
|
5058
5123
|
onOverlaySuccess.current = null;
|
|
5059
5124
|
overlayRestoreFocus.current = null;
|
|
5060
5125
|
setOverlay(null);
|
|
5061
5126
|
}, []);
|
|
5062
|
-
const handleOverlaySuccess = (0,
|
|
5127
|
+
const handleOverlaySuccess = (0, import_react32.useCallback)(() => {
|
|
5063
5128
|
const fn = onOverlaySuccess.current;
|
|
5064
5129
|
onOverlaySuccess.current = null;
|
|
5065
5130
|
setOverlay(null);
|
|
5066
5131
|
fn?.();
|
|
5067
5132
|
}, []);
|
|
5068
|
-
const ui = (0,
|
|
5133
|
+
const ui = (0, import_react32.useMemo)(
|
|
5069
5134
|
() => ({ overlay, openSignIn, openSignUp, openAccount, close: closeOverlay }),
|
|
5070
5135
|
[overlay, openSignIn, openSignUp, openAccount, closeOverlay]
|
|
5071
5136
|
);
|
|
5072
|
-
const askForStepUp = (0,
|
|
5137
|
+
const askForStepUp = (0, import_react32.useCallback)(
|
|
5073
5138
|
() => new Promise((resolve) => {
|
|
5074
5139
|
resolveStepUp.current = resolve;
|
|
5075
5140
|
setStepUpOpen(true);
|
|
5076
5141
|
}),
|
|
5077
5142
|
[]
|
|
5078
5143
|
);
|
|
5079
|
-
const auth = (0,
|
|
5144
|
+
const auth = (0, import_react32.useMemo)(() => {
|
|
5080
5145
|
__captureStepUp?.(askForStepUp);
|
|
5081
5146
|
const client = injected ?? createThrottleAuth({ publishableKey, baseUrl, storage, onStepUpRequired: askForStepUp });
|
|
5082
5147
|
const account = createAccount(client);
|
|
@@ -5127,18 +5192,18 @@ function ThrottleProvider(props) {
|
|
|
5127
5192
|
}
|
|
5128
5193
|
|
|
5129
5194
|
// src/react/components/auth/StepUpDialog.tsx
|
|
5130
|
-
var
|
|
5195
|
+
var import_react33 = require("react");
|
|
5131
5196
|
var import_jsx_runtime48 = require("react/jsx-runtime");
|
|
5132
5197
|
|
|
5133
5198
|
// src/react/components/auth/SignInButton.tsx
|
|
5134
|
-
var
|
|
5199
|
+
var import_react34 = require("react");
|
|
5135
5200
|
var import_jsx_runtime49 = require("react/jsx-runtime");
|
|
5136
5201
|
function SignInButton(props) {
|
|
5137
5202
|
const a = useAppearance(props.appearance);
|
|
5138
5203
|
const scoped = useAppearanceProviderValue(props.appearance);
|
|
5139
5204
|
const { t } = useCopy(props.localization);
|
|
5140
|
-
const ui = (0,
|
|
5141
|
-
const [localOpen, setLocalOpen] = (0,
|
|
5205
|
+
const ui = (0, import_react34.useContext)(ThrottleUIContext);
|
|
5206
|
+
const [localOpen, setLocalOpen] = (0, import_react34.useState)(false);
|
|
5142
5207
|
const useShared = ui !== null && props.initialView === void 0;
|
|
5143
5208
|
const label = props.children ?? t.signIn.submitButton;
|
|
5144
5209
|
if (props.mode === "redirect") {
|
|
@@ -5152,7 +5217,7 @@ function SignInButton(props) {
|
|
|
5152
5217
|
if (useShared) ui.close();
|
|
5153
5218
|
else setLocalOpen(false);
|
|
5154
5219
|
};
|
|
5155
|
-
const trigger = props.asChild && (0,
|
|
5220
|
+
const trigger = props.asChild && (0, import_react34.isValidElement)(props.children) ? (0, import_react34.cloneElement)(props.children, { onClick: openModal }) : /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(Button, { elementKey: "signInButton.root", onClick: openModal, children: label });
|
|
5156
5221
|
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(AppearanceProvider, { value: scoped, children: [
|
|
5157
5222
|
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { ...a.rootProps, children: trigger }),
|
|
5158
5223
|
!useShared ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
@@ -5173,14 +5238,14 @@ function SignInButton(props) {
|
|
|
5173
5238
|
}
|
|
5174
5239
|
|
|
5175
5240
|
// src/react/components/auth/SignUpButton.tsx
|
|
5176
|
-
var
|
|
5241
|
+
var import_react35 = require("react");
|
|
5177
5242
|
var import_jsx_runtime50 = require("react/jsx-runtime");
|
|
5178
5243
|
function SignUpButton(props) {
|
|
5179
5244
|
const a = useAppearance(props.appearance);
|
|
5180
5245
|
const scoped = useAppearanceProviderValue(props.appearance);
|
|
5181
5246
|
const { t } = useCopy(props.localization);
|
|
5182
|
-
const ui = (0,
|
|
5183
|
-
const [localOpen, setLocalOpen] = (0,
|
|
5247
|
+
const ui = (0, import_react35.useContext)(ThrottleUIContext);
|
|
5248
|
+
const [localOpen, setLocalOpen] = (0, import_react35.useState)(false);
|
|
5184
5249
|
const useShared = ui !== null && props.initialView === void 0;
|
|
5185
5250
|
const label = props.children ?? t.signUp.submitButton;
|
|
5186
5251
|
if (props.mode === "redirect") {
|
|
@@ -5194,7 +5259,7 @@ function SignUpButton(props) {
|
|
|
5194
5259
|
if (useShared) ui.close();
|
|
5195
5260
|
else setLocalOpen(false);
|
|
5196
5261
|
};
|
|
5197
|
-
const trigger = props.asChild && (0,
|
|
5262
|
+
const trigger = props.asChild && (0, import_react35.isValidElement)(props.children) ? (0, import_react35.cloneElement)(props.children, { onClick: openModal }) : /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(Button, { elementKey: "signUpButton.root", onClick: openModal, children: label });
|
|
5198
5263
|
return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(AppearanceProvider, { value: scoped, children: [
|
|
5199
5264
|
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { ...a.rootProps, children: trigger }),
|
|
5200
5265
|
!useShared ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
@@ -5298,19 +5363,19 @@ function Protect(props) {
|
|
|
5298
5363
|
}
|
|
5299
5364
|
|
|
5300
5365
|
// src/react/components/UserButton.tsx
|
|
5301
|
-
var
|
|
5366
|
+
var import_react36 = require("react");
|
|
5302
5367
|
var import_jsx_runtime55 = require("react/jsx-runtime");
|
|
5303
5368
|
function UserButtonRoot(props) {
|
|
5304
5369
|
const a = useAppearance(props.appearance);
|
|
5305
5370
|
const scoped = useAppearanceProviderValue(props.appearance);
|
|
5306
5371
|
const { t } = useCopy(props.localization);
|
|
5307
5372
|
const { auth, status, customer, emailVerified } = useAuth();
|
|
5308
|
-
const ui = (0,
|
|
5309
|
-
const [localOpen, setLocalOpen] = (0,
|
|
5373
|
+
const ui = (0, import_react36.useContext)(ThrottleUIContext);
|
|
5374
|
+
const [localOpen, setLocalOpen] = (0, import_react36.useState)(false);
|
|
5310
5375
|
const accountOpen = ui ? false : localOpen;
|
|
5311
|
-
const titleId = (0,
|
|
5312
|
-
const rootRef = (0,
|
|
5313
|
-
const openerRef = (0,
|
|
5376
|
+
const titleId = (0, import_react36.useId)();
|
|
5377
|
+
const rootRef = (0, import_react36.useRef)(null);
|
|
5378
|
+
const openerRef = (0, import_react36.useRef)(null);
|
|
5314
5379
|
const openAccount = () => {
|
|
5315
5380
|
const opener = rootRef.current?.querySelector('button[aria-haspopup="menu"]') ?? null;
|
|
5316
5381
|
openerRef.current = opener;
|