@usethrottle/auth 0.10.0 → 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 -0
- package/dist/{chunk-TKSBAC7W.js → chunk-EFMKBOTL.js} +4 -3
- package/dist/chunk-EFMKBOTL.js.map +1 -0
- package/dist/{chunk-HQP5QTHQ.js → chunk-YY6YATXT.js} +10 -1
- package/dist/chunk-YY6YATXT.js.map +1 -0
- package/dist/index.cjs +9 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +33 -1
- package/dist/index.d.ts +33 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/react/components/index.cjs +128 -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 +11 -1
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +35 -1
- package/dist/react/index.d.ts +35 -1
- package/dist/react/index.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-HQP5QTHQ.js.map +0 -1
- package/dist/chunk-TKSBAC7W.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 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 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 {
|
|
@@ -381,6 +381,14 @@ function createThrottleAuth(config) {
|
|
|
381
381
|
}
|
|
382
382
|
},
|
|
383
383
|
getSnapshot: () => state.get(),
|
|
384
|
+
async getAccessToken() {
|
|
385
|
+
try {
|
|
386
|
+
return await accessToken();
|
|
387
|
+
} catch (err) {
|
|
388
|
+
if (state.get().status === "unauthenticated") return null;
|
|
389
|
+
throw err;
|
|
390
|
+
}
|
|
391
|
+
},
|
|
384
392
|
subscribe: (fn) => state.subscribe(fn),
|
|
385
393
|
stepUp,
|
|
386
394
|
call,
|
|
@@ -464,6 +472,7 @@ function createAccount(auth) {
|
|
|
464
472
|
cancelSubscription: (id, opts) => call("POST", `/me/subscriptions/${seg(id)}/cancel`, opts),
|
|
465
473
|
pauseSubscription: (id) => call("POST", `/me/subscriptions/${seg(id)}/pause`),
|
|
466
474
|
resumeSubscription: (id) => call("POST", `/me/subscriptions/${seg(id)}/resume`),
|
|
475
|
+
updateSubscriptionShippingAddress: (id, address) => call("PATCH", `/me/subscriptions/${seg(id)}/shipping-address`, address),
|
|
467
476
|
claimCart: (cartId) => call("POST", `/me/carts/${seg(cartId)}/claim`)
|
|
468
477
|
};
|
|
469
478
|
}
|
|
@@ -827,6 +836,8 @@ var THROTTLE_ELEMENT_KEYS = [
|
|
|
827
836
|
"subscriptionsPanel.cancelNowButton",
|
|
828
837
|
"subscriptionsPanel.pauseButton",
|
|
829
838
|
"subscriptionsPanel.resumeButton",
|
|
839
|
+
"subscriptionsPanel.changeAddressButton",
|
|
840
|
+
"subscriptionsPanel.addressForm",
|
|
830
841
|
"subscriptionsPanel.table",
|
|
831
842
|
"subscriptionsPanel.row",
|
|
832
843
|
"securityPanel.root",
|
|
@@ -1244,6 +1255,11 @@ var enUS = {
|
|
|
1244
1255
|
cancelNow: "Cancel immediately",
|
|
1245
1256
|
pauseButton: "Pause",
|
|
1246
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.",
|
|
1247
1263
|
cancelConfirm: "Cancel this subscription?",
|
|
1248
1264
|
cancelScheduled: "Cancels at the end of the period",
|
|
1249
1265
|
columnPlan: "Plan",
|
|
@@ -2903,10 +2919,10 @@ function AuthModal(props) {
|
|
|
2903
2919
|
}
|
|
2904
2920
|
|
|
2905
2921
|
// src/react/components/account/AccountModal.tsx
|
|
2906
|
-
var
|
|
2922
|
+
var import_react31 = require("react");
|
|
2907
2923
|
|
|
2908
2924
|
// src/react/components/account/AccountDashboard.tsx
|
|
2909
|
-
var
|
|
2925
|
+
var import_react30 = require("react");
|
|
2910
2926
|
|
|
2911
2927
|
// src/react/components/account/VerifyEmailBanner.tsx
|
|
2912
2928
|
var import_react19 = require("react");
|
|
@@ -3135,7 +3151,8 @@ function useSubscriptions(page) {
|
|
|
3135
3151
|
...res,
|
|
3136
3152
|
cancel: (id, opts) => after(account.cancelSubscription(id, opts)),
|
|
3137
3153
|
pause: (id) => after(account.pauseSubscription(id)),
|
|
3138
|
-
resume: (id) => after(account.resumeSubscription(id))
|
|
3154
|
+
resume: (id) => after(account.resumeSubscription(id)),
|
|
3155
|
+
updateShippingAddress: (id, address) => after(account.updateSubscriptionShippingAddress(id, address))
|
|
3139
3156
|
};
|
|
3140
3157
|
}
|
|
3141
3158
|
function useOrder(id) {
|
|
@@ -3321,7 +3338,7 @@ function AddressForm(props) {
|
|
|
3321
3338
|
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
|
|
3322
3339
|
"form",
|
|
3323
3340
|
{
|
|
3324
|
-
...a.el("addressesPanel.form", "throttle-stack"),
|
|
3341
|
+
...a.el(props.elementKey ?? "addressesPanel.form", "throttle-stack"),
|
|
3325
3342
|
onSubmit: (e) => {
|
|
3326
3343
|
e.preventDefault();
|
|
3327
3344
|
props.onSubmit({
|
|
@@ -3341,7 +3358,7 @@ function AddressForm(props) {
|
|
|
3341
3358
|
},
|
|
3342
3359
|
children: [
|
|
3343
3360
|
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(FieldRow, { children: [
|
|
3344
|
-
/* @__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") }),
|
|
3345
3362
|
/* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Field, { label: t.addresses.company, value: form.company, onChange: set("company"), autoComplete: "organization" })
|
|
3346
3363
|
] }),
|
|
3347
3364
|
/* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(FieldRow, { children: [
|
|
@@ -4433,6 +4450,9 @@ function InvoicesPanel(props) {
|
|
|
4433
4450
|
) }) }) });
|
|
4434
4451
|
}
|
|
4435
4452
|
|
|
4453
|
+
// src/react/components/account/SubscriptionsPanel.tsx
|
|
4454
|
+
var import_react28 = require("react");
|
|
4455
|
+
|
|
4436
4456
|
// ../core-cadence/src/cadence.ts
|
|
4437
4457
|
var INTERVAL_UNITS = ["hour", "day", "week", "month"];
|
|
4438
4458
|
var NAMED_INTERVALS = ["weekly", "biweekly", "monthly", "quarterly", "yearly"];
|
|
@@ -4485,6 +4505,12 @@ var CAN_PAUSE = /* @__PURE__ */ new Set(["active"]);
|
|
|
4485
4505
|
var CAN_RESUME = /* @__PURE__ */ new Set(["paused"]);
|
|
4486
4506
|
var CAN_CANCEL2 = /* @__PURE__ */ new Set(["active", "trialing", "paused", "past_due", "unpaid"]);
|
|
4487
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
|
+
}
|
|
4488
4514
|
function SubscriptionsPanel(props) {
|
|
4489
4515
|
const a = useAppearance(props.appearance);
|
|
4490
4516
|
const scoped = useAppearanceProviderValue(props.appearance);
|
|
@@ -4493,6 +4519,7 @@ function SubscriptionsPanel(props) {
|
|
|
4493
4519
|
const resource = useSubscriptions();
|
|
4494
4520
|
const { submitting, error, run } = useAction();
|
|
4495
4521
|
const confirm = useConfirm();
|
|
4522
|
+
const [editingAddress, setEditingAddress] = (0, import_react28.useState)(null);
|
|
4496
4523
|
const variant = props.variant ?? "rows";
|
|
4497
4524
|
const rowsVariant = variant === "rows";
|
|
4498
4525
|
const listBase = rowsVariant ? "throttle-rows" : "throttle-stack";
|
|
@@ -4521,6 +4548,21 @@ function SubscriptionsPanel(props) {
|
|
|
4521
4548
|
if (upcoming.length === 0) return null;
|
|
4522
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)) });
|
|
4523
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;
|
|
4524
4566
|
const renewsLabel = (sub) => formatDate(
|
|
4525
4567
|
sub.status === "completed" ? sub.completedAt ?? sub.currentPeriodEnd : sub.status === "cancelled" ? sub.cancelledAt ?? sub.currentPeriodEnd : sub.currentPeriodEnd,
|
|
4526
4568
|
locale
|
|
@@ -4582,7 +4624,32 @@ function SubscriptionsPanel(props) {
|
|
|
4582
4624
|
) : null
|
|
4583
4625
|
] });
|
|
4584
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: [
|
|
4585
|
-
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,
|
|
4586
4653
|
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
4587
4654
|
PanelState,
|
|
4588
4655
|
{
|
|
@@ -4604,7 +4671,8 @@ function SubscriptionsPanel(props) {
|
|
|
4604
4671
|
sub.planName ?? sub.planReference,
|
|
4605
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,
|
|
4606
4673
|
nextPaymentLabel(sub) ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "throttle-muted", children: nextPaymentLabel(sub) }) : null,
|
|
4607
|
-
upcomingList(sub)
|
|
4674
|
+
upcomingList(sub),
|
|
4675
|
+
shipsTo(sub)
|
|
4608
4676
|
] }) },
|
|
4609
4677
|
{ key: "price", label: t.subscriptions.columnPrice, render: (sub) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("span", { className: "throttle-table__money", children: priceLabel(sub) }) },
|
|
4610
4678
|
{ key: "renews", label: t.subscriptions.columnRenews, render: (sub) => renewsLabel(sub) },
|
|
@@ -4612,7 +4680,10 @@ function SubscriptionsPanel(props) {
|
|
|
4612
4680
|
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(StatusBadge, { status: sub.status, labels: t.subscriptions.statusLabels }),
|
|
4613
4681
|
sub.cancelAtPeriodEnd ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Badge, { tone: "warning", children: t.subscriptions.cancelScheduled }) : null
|
|
4614
4682
|
] }) },
|
|
4615
|
-
{ 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
|
+
] }) }
|
|
4616
4687
|
]
|
|
4617
4688
|
}
|
|
4618
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: [
|
|
@@ -4625,6 +4696,7 @@ function SubscriptionsPanel(props) {
|
|
|
4625
4696
|
nextPaymentLabel(sub) ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)("div", { className: "throttle-muted", children: nextPaymentLabel(sub) }) : null,
|
|
4626
4697
|
upcomingList(sub),
|
|
4627
4698
|
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)("p", { className: "throttle-muted", children: priceLabel(sub) }),
|
|
4699
|
+
shipsTo(sub),
|
|
4628
4700
|
sub.status === "completed" ? /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)("p", { className: "throttle-muted", children: [
|
|
4629
4701
|
t.subscriptions.statusLabels.completed,
|
|
4630
4702
|
" ",
|
|
@@ -4645,7 +4717,8 @@ function SubscriptionsPanel(props) {
|
|
|
4645
4717
|
] }) : null,
|
|
4646
4718
|
sub.cancelAtPeriodEnd ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(Badge, { tone: "warning", children: t.subscriptions.cancelScheduled }) : null
|
|
4647
4719
|
] }),
|
|
4648
|
-
lifecycleActions(sub, actionVariant)
|
|
4720
|
+
lifecycleActions(sub, actionVariant),
|
|
4721
|
+
addressAction(sub, actionVariant)
|
|
4649
4722
|
] }, sub.id)) })
|
|
4650
4723
|
}
|
|
4651
4724
|
)
|
|
@@ -4653,7 +4726,7 @@ function SubscriptionsPanel(props) {
|
|
|
4653
4726
|
}
|
|
4654
4727
|
|
|
4655
4728
|
// src/react/components/account/SecurityPanel.tsx
|
|
4656
|
-
var
|
|
4729
|
+
var import_react29 = require("react");
|
|
4657
4730
|
|
|
4658
4731
|
// src/react/components/account/device.ts
|
|
4659
4732
|
var BROWSERS = [
|
|
@@ -4696,16 +4769,16 @@ function SecurityPanel(props) {
|
|
|
4696
4769
|
const rowsVariant = variant === "rows";
|
|
4697
4770
|
const itemBase = rowsVariant ? "throttle-rowitem" : "throttle-listitem";
|
|
4698
4771
|
const revokeVariant = rowsVariant ? "linkDanger" : "danger";
|
|
4699
|
-
const [password, setPassword] = (0,
|
|
4772
|
+
const [password, setPassword] = (0, import_react29.useState)("");
|
|
4700
4773
|
const passwordAction = useAction();
|
|
4701
4774
|
const sessionAction = useAction();
|
|
4702
|
-
const [sessions, setSessions] = (0,
|
|
4703
|
-
const [listError, setListError] = (0,
|
|
4704
|
-
const errorMessageRef = (0,
|
|
4705
|
-
(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)(() => {
|
|
4706
4779
|
errorMessageRef.current = errorMessage;
|
|
4707
4780
|
});
|
|
4708
|
-
const load = (0,
|
|
4781
|
+
const load = (0, import_react29.useCallback)(async () => {
|
|
4709
4782
|
try {
|
|
4710
4783
|
setSessions(await auth.listSessions());
|
|
4711
4784
|
setListError(null);
|
|
@@ -4713,7 +4786,7 @@ function SecurityPanel(props) {
|
|
|
4713
4786
|
setListError(errorMessageRef.current(err));
|
|
4714
4787
|
}
|
|
4715
4788
|
}, [auth]);
|
|
4716
|
-
(0,
|
|
4789
|
+
(0, import_react29.useEffect)(() => {
|
|
4717
4790
|
void load();
|
|
4718
4791
|
}, [load]);
|
|
4719
4792
|
const others = (sessions ?? []).filter((s) => !s.current);
|
|
@@ -4861,10 +4934,10 @@ function AccountDashboard(props) {
|
|
|
4861
4934
|
const { status } = useAuth();
|
|
4862
4935
|
const shown = props.tabs ?? [...ACCOUNT_TABS];
|
|
4863
4936
|
const controlled = props.tab !== void 0;
|
|
4864
|
-
const [internal, setInternal] = (0,
|
|
4865
|
-
const [openOrderId, setOpenOrderId] = (0,
|
|
4866
|
-
const idBase = (0,
|
|
4867
|
-
(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)(() => {
|
|
4868
4941
|
if (props.routing !== "hash" || typeof window === "undefined") return;
|
|
4869
4942
|
const apply = () => {
|
|
4870
4943
|
const next = TAB_FOR_HASH[window.location.hash] ?? shown[0];
|
|
@@ -4960,7 +5033,7 @@ function AccountModal(props) {
|
|
|
4960
5033
|
const a = useAppearance(props.appearance);
|
|
4961
5034
|
const scoped = useAppearanceProviderValue(props.appearance);
|
|
4962
5035
|
const { t } = useCopy(props.localization);
|
|
4963
|
-
const titleId = (0,
|
|
5036
|
+
const titleId = (0, import_react31.useId)();
|
|
4964
5037
|
return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AppearanceProvider, { value: scoped, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
|
|
4965
5038
|
Modal,
|
|
4966
5039
|
{
|
|
@@ -4987,9 +5060,9 @@ function warnOnce(key, message) {
|
|
|
4987
5060
|
warned.add(key);
|
|
4988
5061
|
console.warn(`[@usethrottle/auth] ${message}`);
|
|
4989
5062
|
}
|
|
4990
|
-
var ThrottleUIContext = (0,
|
|
5063
|
+
var ThrottleUIContext = (0, import_react32.createContext)(null);
|
|
4991
5064
|
function useThrottle() {
|
|
4992
|
-
const ctx = (0,
|
|
5065
|
+
const ctx = (0, import_react32.useContext)(ThrottleUIContext);
|
|
4993
5066
|
if (!ctx) {
|
|
4994
5067
|
warnOnce(
|
|
4995
5068
|
"use-throttle-no-provider",
|
|
@@ -5024,51 +5097,51 @@ function ThrottleProvider(props) {
|
|
|
5024
5097
|
__captureStepUp
|
|
5025
5098
|
} = props;
|
|
5026
5099
|
useInjectStyles(injectStyles);
|
|
5027
|
-
const [stepUpOpen, setStepUpOpen] = (0,
|
|
5028
|
-
const resolveStepUp = (0,
|
|
5029
|
-
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);
|
|
5030
5103
|
claimRef.current = claimCartOnSignIn;
|
|
5031
|
-
const [overlay, setOverlay] = (0,
|
|
5032
|
-
const overlayRestoreFocus = (0,
|
|
5033
|
-
const [accountTabs, setAccountTabs] = (0,
|
|
5034
|
-
const onOverlaySuccess = (0,
|
|
5035
|
-
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) => {
|
|
5036
5109
|
onOverlaySuccess.current = onSuccess ?? null;
|
|
5037
5110
|
setOverlay("signIn");
|
|
5038
5111
|
}, []);
|
|
5039
|
-
const openSignUp = (0,
|
|
5112
|
+
const openSignUp = (0, import_react32.useCallback)((onSuccess) => {
|
|
5040
5113
|
onOverlaySuccess.current = onSuccess ?? null;
|
|
5041
5114
|
setOverlay("signUp");
|
|
5042
5115
|
}, []);
|
|
5043
|
-
const openAccount = (0,
|
|
5116
|
+
const openAccount = (0, import_react32.useCallback)((opts) => {
|
|
5044
5117
|
onOverlaySuccess.current = null;
|
|
5045
5118
|
overlayRestoreFocus.current = opts?.restoreFocusTo ?? null;
|
|
5046
5119
|
setAccountTabs(opts?.tabs);
|
|
5047
5120
|
setOverlay("account");
|
|
5048
5121
|
}, []);
|
|
5049
|
-
const closeOverlay = (0,
|
|
5122
|
+
const closeOverlay = (0, import_react32.useCallback)(() => {
|
|
5050
5123
|
onOverlaySuccess.current = null;
|
|
5051
5124
|
overlayRestoreFocus.current = null;
|
|
5052
5125
|
setOverlay(null);
|
|
5053
5126
|
}, []);
|
|
5054
|
-
const handleOverlaySuccess = (0,
|
|
5127
|
+
const handleOverlaySuccess = (0, import_react32.useCallback)(() => {
|
|
5055
5128
|
const fn = onOverlaySuccess.current;
|
|
5056
5129
|
onOverlaySuccess.current = null;
|
|
5057
5130
|
setOverlay(null);
|
|
5058
5131
|
fn?.();
|
|
5059
5132
|
}, []);
|
|
5060
|
-
const ui = (0,
|
|
5133
|
+
const ui = (0, import_react32.useMemo)(
|
|
5061
5134
|
() => ({ overlay, openSignIn, openSignUp, openAccount, close: closeOverlay }),
|
|
5062
5135
|
[overlay, openSignIn, openSignUp, openAccount, closeOverlay]
|
|
5063
5136
|
);
|
|
5064
|
-
const askForStepUp = (0,
|
|
5137
|
+
const askForStepUp = (0, import_react32.useCallback)(
|
|
5065
5138
|
() => new Promise((resolve) => {
|
|
5066
5139
|
resolveStepUp.current = resolve;
|
|
5067
5140
|
setStepUpOpen(true);
|
|
5068
5141
|
}),
|
|
5069
5142
|
[]
|
|
5070
5143
|
);
|
|
5071
|
-
const auth = (0,
|
|
5144
|
+
const auth = (0, import_react32.useMemo)(() => {
|
|
5072
5145
|
__captureStepUp?.(askForStepUp);
|
|
5073
5146
|
const client = injected ?? createThrottleAuth({ publishableKey, baseUrl, storage, onStepUpRequired: askForStepUp });
|
|
5074
5147
|
const account = createAccount(client);
|
|
@@ -5119,18 +5192,18 @@ function ThrottleProvider(props) {
|
|
|
5119
5192
|
}
|
|
5120
5193
|
|
|
5121
5194
|
// src/react/components/auth/StepUpDialog.tsx
|
|
5122
|
-
var
|
|
5195
|
+
var import_react33 = require("react");
|
|
5123
5196
|
var import_jsx_runtime48 = require("react/jsx-runtime");
|
|
5124
5197
|
|
|
5125
5198
|
// src/react/components/auth/SignInButton.tsx
|
|
5126
|
-
var
|
|
5199
|
+
var import_react34 = require("react");
|
|
5127
5200
|
var import_jsx_runtime49 = require("react/jsx-runtime");
|
|
5128
5201
|
function SignInButton(props) {
|
|
5129
5202
|
const a = useAppearance(props.appearance);
|
|
5130
5203
|
const scoped = useAppearanceProviderValue(props.appearance);
|
|
5131
5204
|
const { t } = useCopy(props.localization);
|
|
5132
|
-
const ui = (0,
|
|
5133
|
-
const [localOpen, setLocalOpen] = (0,
|
|
5205
|
+
const ui = (0, import_react34.useContext)(ThrottleUIContext);
|
|
5206
|
+
const [localOpen, setLocalOpen] = (0, import_react34.useState)(false);
|
|
5134
5207
|
const useShared = ui !== null && props.initialView === void 0;
|
|
5135
5208
|
const label = props.children ?? t.signIn.submitButton;
|
|
5136
5209
|
if (props.mode === "redirect") {
|
|
@@ -5144,7 +5217,7 @@ function SignInButton(props) {
|
|
|
5144
5217
|
if (useShared) ui.close();
|
|
5145
5218
|
else setLocalOpen(false);
|
|
5146
5219
|
};
|
|
5147
|
-
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 });
|
|
5148
5221
|
return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(AppearanceProvider, { value: scoped, children: [
|
|
5149
5222
|
/* @__PURE__ */ (0, import_jsx_runtime49.jsx)("span", { ...a.rootProps, children: trigger }),
|
|
5150
5223
|
!useShared ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
|
|
@@ -5165,14 +5238,14 @@ function SignInButton(props) {
|
|
|
5165
5238
|
}
|
|
5166
5239
|
|
|
5167
5240
|
// src/react/components/auth/SignUpButton.tsx
|
|
5168
|
-
var
|
|
5241
|
+
var import_react35 = require("react");
|
|
5169
5242
|
var import_jsx_runtime50 = require("react/jsx-runtime");
|
|
5170
5243
|
function SignUpButton(props) {
|
|
5171
5244
|
const a = useAppearance(props.appearance);
|
|
5172
5245
|
const scoped = useAppearanceProviderValue(props.appearance);
|
|
5173
5246
|
const { t } = useCopy(props.localization);
|
|
5174
|
-
const ui = (0,
|
|
5175
|
-
const [localOpen, setLocalOpen] = (0,
|
|
5247
|
+
const ui = (0, import_react35.useContext)(ThrottleUIContext);
|
|
5248
|
+
const [localOpen, setLocalOpen] = (0, import_react35.useState)(false);
|
|
5176
5249
|
const useShared = ui !== null && props.initialView === void 0;
|
|
5177
5250
|
const label = props.children ?? t.signUp.submitButton;
|
|
5178
5251
|
if (props.mode === "redirect") {
|
|
@@ -5186,7 +5259,7 @@ function SignUpButton(props) {
|
|
|
5186
5259
|
if (useShared) ui.close();
|
|
5187
5260
|
else setLocalOpen(false);
|
|
5188
5261
|
};
|
|
5189
|
-
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 });
|
|
5190
5263
|
return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(AppearanceProvider, { value: scoped, children: [
|
|
5191
5264
|
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { ...a.rootProps, children: trigger }),
|
|
5192
5265
|
!useShared ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
@@ -5290,19 +5363,19 @@ function Protect(props) {
|
|
|
5290
5363
|
}
|
|
5291
5364
|
|
|
5292
5365
|
// src/react/components/UserButton.tsx
|
|
5293
|
-
var
|
|
5366
|
+
var import_react36 = require("react");
|
|
5294
5367
|
var import_jsx_runtime55 = require("react/jsx-runtime");
|
|
5295
5368
|
function UserButtonRoot(props) {
|
|
5296
5369
|
const a = useAppearance(props.appearance);
|
|
5297
5370
|
const scoped = useAppearanceProviderValue(props.appearance);
|
|
5298
5371
|
const { t } = useCopy(props.localization);
|
|
5299
5372
|
const { auth, status, customer, emailVerified } = useAuth();
|
|
5300
|
-
const ui = (0,
|
|
5301
|
-
const [localOpen, setLocalOpen] = (0,
|
|
5373
|
+
const ui = (0, import_react36.useContext)(ThrottleUIContext);
|
|
5374
|
+
const [localOpen, setLocalOpen] = (0, import_react36.useState)(false);
|
|
5302
5375
|
const accountOpen = ui ? false : localOpen;
|
|
5303
|
-
const titleId = (0,
|
|
5304
|
-
const rootRef = (0,
|
|
5305
|
-
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);
|
|
5306
5379
|
const openAccount = () => {
|
|
5307
5380
|
const opener = rootRef.current?.querySelector('button[aria-haspopup="menu"]') ?? null;
|
|
5308
5381
|
openerRef.current = opener;
|