@usethrottle/auth 0.11.0 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +52 -0
  2. package/dist/AccountDashboard-V63ghvjY.d.ts +90 -0
  3. package/dist/AccountModal-KA54WUFW.js +13 -0
  4. package/dist/AccountModal-KA54WUFW.js.map +1 -0
  5. package/dist/AccountModal-pIMgledL.d.ts +141 -0
  6. package/dist/AuthModal-T2GYI6ZF.js +13 -0
  7. package/dist/AuthModal-T2GYI6ZF.js.map +1 -0
  8. package/dist/SignUpPage-BJcMUb2V.d.ts +160 -0
  9. package/dist/chunk-3B4DNX5T.js +2 -0
  10. package/dist/chunk-3B4DNX5T.js.map +1 -0
  11. package/dist/chunk-5EUZYJJL.js +29 -0
  12. package/dist/chunk-5EUZYJJL.js.map +1 -0
  13. package/dist/chunk-6WN3J5MM.js +2075 -0
  14. package/dist/chunk-6WN3J5MM.js.map +1 -0
  15. package/dist/chunk-CUNMJ2PH.js +1320 -0
  16. package/dist/chunk-CUNMJ2PH.js.map +1 -0
  17. package/dist/chunk-ETYOOYYV.js +2 -0
  18. package/dist/chunk-ETYOOYYV.js.map +1 -0
  19. package/dist/chunk-JSDZMPCV.js +520 -0
  20. package/dist/chunk-JSDZMPCV.js.map +1 -0
  21. package/dist/chunk-QPVS6JXP.js +39 -0
  22. package/dist/chunk-QPVS6JXP.js.map +1 -0
  23. package/dist/chunk-RCNUWITB.js +747 -0
  24. package/dist/chunk-RCNUWITB.js.map +1 -0
  25. package/dist/{chunk-YY6YATXT.js → chunk-TDQC3LMQ.js} +17 -3
  26. package/dist/chunk-TDQC3LMQ.js.map +1 -0
  27. package/dist/{chunk-EFMKBOTL.js → chunk-UFGW76AZ.js} +2 -2
  28. package/dist/chunk-VDK23T6L.js +230 -0
  29. package/dist/chunk-VDK23T6L.js.map +1 -0
  30. package/dist/chunk-X6D35EAX.js +19 -0
  31. package/dist/chunk-X6D35EAX.js.map +1 -0
  32. package/dist/client-7LVKfuXO.d.ts +319 -0
  33. package/dist/hooks-DkpLrEiC.d.ts +148 -0
  34. package/dist/index.cjs +16 -2
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +34 -3
  37. package/dist/index.d.ts +34 -3
  38. package/dist/index.js +16 -2
  39. package/dist/index.js.map +1 -1
  40. package/dist/localization-SnIAZXJn.d.ts +389 -0
  41. package/dist/react/components/account/index.d.ts +37 -0
  42. package/dist/react/components/account/index.js +44 -0
  43. package/dist/react/components/account/index.js.map +1 -0
  44. package/dist/react/components/auth/index.d.ts +17 -0
  45. package/dist/react/components/auth/index.js +40 -0
  46. package/dist/react/components/auth/index.js.map +1 -0
  47. package/dist/react/components/guards.d.ts +21 -0
  48. package/dist/react/components/guards.js +13 -0
  49. package/dist/react/components/guards.js.map +1 -0
  50. package/dist/react/components/index.cjs +3561 -2805
  51. package/dist/react/components/index.cjs.map +1 -1
  52. package/dist/react/components/index.d.cts +14 -2
  53. package/dist/react/components/index.d.ts +14 -821
  54. package/dist/react/components/index.js +90 -4680
  55. package/dist/react/components/index.js.map +1 -1
  56. package/dist/react/components/provider.d.ts +79 -0
  57. package/dist/react/components/provider.js +18 -0
  58. package/dist/react/components/provider.js.map +1 -0
  59. package/dist/react/forms/index.js +1 -1
  60. package/dist/react/index.cjs +16 -2
  61. package/dist/react/index.cjs.map +1 -1
  62. package/dist/react/index.d.cts +34 -3
  63. package/dist/react/index.d.ts +5 -433
  64. package/dist/react/index.js +3 -2
  65. package/dist/styles.css +7 -4
  66. package/package.json +4 -1
  67. package/dist/chunk-YY6YATXT.js.map +0 -1
  68. /package/dist/{chunk-EFMKBOTL.js.map → chunk-UFGW76AZ.js.map} +0 -0
@@ -0,0 +1,319 @@
1
+ interface Customer {
2
+ id: string;
3
+ email: string;
4
+ emailVerified: boolean;
5
+ firstName?: string | null;
6
+ lastName?: string | null;
7
+ phone?: string | null;
8
+ company?: string | null;
9
+ acceptsMarketing?: boolean;
10
+ }
11
+ interface Session {
12
+ accessToken: string;
13
+ expiresAt: string;
14
+ refreshToken: string;
15
+ customer: Customer;
16
+ }
17
+ /**
18
+ * Defined here rather than in `storage.ts` so `ThrottleAuthConfig` can name it
19
+ * without importing a module that does not exist until Task 2. `storage.ts`
20
+ * imports and re-exports it.
21
+ */
22
+ interface AuthStorage {
23
+ get(key: string): string | null | Promise<string | null>;
24
+ set(key: string, value: string): void | Promise<void>;
25
+ remove(key: string): void | Promise<void>;
26
+ }
27
+ interface ThrottleAuthConfig {
28
+ publishableKey: string;
29
+ baseUrl?: string;
30
+ storage?: AuthStorage;
31
+ /** Called when a route needs a step-up proof. Return the buyer's password, or null to cancel. */
32
+ onStepUpRequired?: () => Promise<string | null>;
33
+ }
34
+ interface ProfilePatch {
35
+ firstName?: string;
36
+ lastName?: string;
37
+ phone?: string;
38
+ company?: string | null;
39
+ acceptsMarketing?: boolean;
40
+ }
41
+ interface AddressInput {
42
+ label?: string;
43
+ firstName?: string;
44
+ lastName?: string;
45
+ company?: string;
46
+ addressLine1: string;
47
+ addressLine2?: string;
48
+ city: string;
49
+ stateProvince?: string;
50
+ postalCode?: string;
51
+ countryCode: string;
52
+ phone?: string;
53
+ isDefault?: boolean;
54
+ }
55
+ interface Address {
56
+ id: string;
57
+ label: string | null;
58
+ firstName: string | null;
59
+ lastName: string | null;
60
+ company: string | null;
61
+ addressLine1: string;
62
+ addressLine2: string | null;
63
+ city: string;
64
+ stateProvince: string | null;
65
+ postalCode: string | null;
66
+ countryCode: string;
67
+ phone: string | null;
68
+ isDefault: boolean;
69
+ createdAt: string;
70
+ updatedAt: string;
71
+ }
72
+ interface PaymentMethod {
73
+ id: string;
74
+ methodType: string;
75
+ cardBrand: string | null;
76
+ cardLastFour: string | null;
77
+ cardExpMonth: number | null;
78
+ cardExpYear: number | null;
79
+ isDefault: boolean;
80
+ createdAt: string;
81
+ }
82
+ interface Order {
83
+ id: string;
84
+ orderNumber: string;
85
+ status: string;
86
+ type: string;
87
+ paymentStatus: string;
88
+ currency: string;
89
+ subtotal: number;
90
+ taxTotal: number;
91
+ discountTotal: number;
92
+ shippingTotal: number;
93
+ total: number;
94
+ buyerVatNumber: string | null;
95
+ taxReverseCharge: boolean;
96
+ billingAddress: unknown | null;
97
+ shippingAddress: unknown | null;
98
+ discountCode: string | null;
99
+ /** Set only when the order is linked to exactly one subscription. Read `subscriptionIds`. */
100
+ subscriptionId: string | null;
101
+ /** Every subscription this order created, in line order. One cart can hold several. */
102
+ subscriptionIds: string[];
103
+ /**
104
+ * The invoice raised for this order, when one exists. Resolved on the
105
+ * detail read only — the list would need a lookup per row.
106
+ */
107
+ invoiceId?: string | null;
108
+ cancelledAt: string | null;
109
+ completedAt: string | null;
110
+ closedAt: string | null;
111
+ createdAt: string;
112
+ updatedAt: string;
113
+ }
114
+ interface OrderLineItem {
115
+ id: string;
116
+ name: string;
117
+ description: string | null;
118
+ quantity: number;
119
+ /** Integer minor units, like every other amount on the wire. */
120
+ unitPrice: number;
121
+ subtotal: number;
122
+ taxAmount: number;
123
+ discountAmount: number;
124
+ total: number;
125
+ imageUrl: string | null;
126
+ /** The subscription this line created, or null for a one-time line. */
127
+ subscriptionId: string | null;
128
+ /**
129
+ * The catalog SKU the line was bought as, or null. Carried so "order
130
+ * again" can re-add the line; never display it. Sent by APIs with the
131
+ * Storefront Part 8 change (absent from older ones, read as null); optional
132
+ * in the type so 0.11-shaped implementations still compile.
133
+ */
134
+ referenceId?: string | null;
135
+ }
136
+ /** The buyer's newest open (or idle-abandoned) cart in one currency. */
137
+ interface OpenCart {
138
+ cartId: string;
139
+ sessionId: string;
140
+ sessionExpiresAt: string;
141
+ currency: string;
142
+ status: 'open' | 'abandoned';
143
+ }
144
+ /**
145
+ * What `getOrder` returns. Deliberately NOT folded into `Order`: the list route
146
+ * does not load line items, so a required `lineItems` on `Order` would be a
147
+ * promise the list response cannot keep.
148
+ */
149
+ interface OrderDetail extends Order {
150
+ lineItems: OrderLineItem[];
151
+ }
152
+ interface InvoiceLineItem {
153
+ name: string;
154
+ description: string | null;
155
+ quantity: number;
156
+ unitPrice: number;
157
+ taxAmount: number;
158
+ discountAmount: number;
159
+ total: number;
160
+ }
161
+ interface Invoice {
162
+ id: string;
163
+ number: string;
164
+ status: string;
165
+ currency: string;
166
+ subtotal: number;
167
+ taxTotal: number;
168
+ shippingTotal: number;
169
+ discountTotal: number;
170
+ total: number;
171
+ amountRefunded: number;
172
+ issuedAt: string;
173
+ dueAt: string | null;
174
+ periodStart: string | null;
175
+ periodEnd: string | null;
176
+ createdAt: string;
177
+ updatedAt: string;
178
+ /** What this invoice billed: 'order' | 'net30' | 'subscription'. */
179
+ sourceType: string | null;
180
+ /** Frozen at issue — the lines actually billed, not the order's lines today. */
181
+ lineItems: InvoiceLineItem[];
182
+ /**
183
+ * Set when the invoice bills less than the order: the order total its lines
184
+ * add up to. `total` is then the amount due (Net-N invoice) or the amount
185
+ * paid (a deposit receipt). Null when the invoice bills the whole order.
186
+ */
187
+ orderTotal: number | null;
188
+ /** Net-N invoices: paid on the order before this invoice (e.g. a deposit). */
189
+ amountPaid: number | null;
190
+ /** Net-N invoices: waived by a comp. */
191
+ compWaived: number | null;
192
+ /** Deposit receipts: the balance still due, billed on the Net-N invoice. */
193
+ balanceDue: number | null;
194
+ /** Resolved on the detail read only; null on list rows and when the hop fails. */
195
+ orderId: string | null;
196
+ orderNumber: string | null;
197
+ subscriptionId: string | null;
198
+ }
199
+ interface Subscription {
200
+ id: string;
201
+ status: string;
202
+ planReference: string;
203
+ planName: string | null;
204
+ interval: string;
205
+ intervalUnit: string | null;
206
+ intervalCount: number | null;
207
+ totalPayments: number | null;
208
+ paymentsMade: number;
209
+ completedAt: string | null;
210
+ /** Installment plans only: every payment in order; dueAt is an estimate. */
211
+ paymentSchedule?: Array<{
212
+ index: number;
213
+ amount: number;
214
+ discount: number;
215
+ net: number;
216
+ intervalUnit: string | null;
217
+ intervalCount: number | null;
218
+ status: 'paid' | 'due' | 'upcoming';
219
+ dueAt: string | null;
220
+ }> | null;
221
+ /** Installment plans only: the sum of every payment's net amount. */
222
+ scheduleTotal?: number | null;
223
+ /** Installment plans only: what the next payment will charge; null once complete. */
224
+ nextPaymentAmount?: number | null;
225
+ amount: number;
226
+ quantity: number;
227
+ currency: string;
228
+ currentPeriodStart: string;
229
+ currentPeriodEnd: string;
230
+ trialEnd: string | null;
231
+ cancelledAt: string | null;
232
+ cancelAtPeriodEnd: boolean;
233
+ pendingPlanReference: string | null;
234
+ pendingPlanName: string | null;
235
+ pendingInterval: string | null;
236
+ pendingQuantity: number | null;
237
+ pausedAt: string | null;
238
+ lastPaymentAt: string | null;
239
+ /** `shipment` = a physical subscription: every renewal ships a box to `shippingAddress`. */
240
+ deliveryMethod?: 'access_grant' | 'shipment';
241
+ /** Where a physical subscription ships; null when nothing ships. */
242
+ shippingAddress?: SubscriptionShippingAddress | null;
243
+ createdAt: string;
244
+ updatedAt: string;
245
+ }
246
+ /** Where a physical subscription's box goes. */
247
+ interface SubscriptionShippingAddress {
248
+ firstName?: string;
249
+ lastName?: string;
250
+ company?: string;
251
+ addressLine1: string;
252
+ addressLine2?: string;
253
+ city: string;
254
+ stateProvince?: string;
255
+ postalCode?: string;
256
+ countryCode: string;
257
+ phone?: string;
258
+ }
259
+
260
+ type AuthStatus = 'loading' | 'authenticated' | 'unauthenticated';
261
+ interface AuthSnapshot {
262
+ status: AuthStatus;
263
+ customer: Customer | null;
264
+ /**
265
+ * False here does NOT only mean "we emailed them and they have not clicked".
266
+ * While it is false the API may also be withholding pre-existing account
267
+ * data behind the claim cutoff — empty order lists and a 403 on `PATCH /me`
268
+ * are expected, not broken. See the plan header.
269
+ */
270
+ emailVerified: boolean;
271
+ }
272
+
273
+ interface DeviceSession {
274
+ id: string;
275
+ userAgent: string | null;
276
+ ipPrefix: string | null;
277
+ createdAt: string;
278
+ lastUsedAt: string;
279
+ current: boolean;
280
+ }
281
+ interface ThrottleAuth {
282
+ register(email: string, password: string): Promise<{
283
+ status: 'active' | 'pending';
284
+ }>;
285
+ signIn(email: string, password: string): Promise<void>;
286
+ signOut(): Promise<void>;
287
+ signOutEverywhere(): Promise<void>;
288
+ restore(): Promise<void>;
289
+ getSnapshot(): AuthSnapshot;
290
+ /**
291
+ * The current access token, refreshed first when it is about to expire
292
+ * (single-flight, shared with every other caller), or null when signed out.
293
+ * Rejects when a refresh fails without ending the session (a 5xx, a 429 or
294
+ * a network error); the buyer stays signed in. `@usethrottle/catalog`
295
+ * treats a rejection as signed out for that request.
296
+ * Pass it to `@usethrottle/catalog`'s `customerToken`.
297
+ */
298
+ getAccessToken(): Promise<string | null>;
299
+ subscribe(fn: (s: AuthSnapshot) => void): () => void;
300
+ stepUp(password: string): Promise<void>;
301
+ call<T = any>(method: string, path: string, body?: unknown): Promise<T>;
302
+ verifyEmail(token: string): Promise<void>;
303
+ resendVerification(): Promise<void>;
304
+ forgotPassword(email: string): Promise<void>;
305
+ resetPassword(token: string, password: string): Promise<void>;
306
+ changePassword(password: string): Promise<void>;
307
+ listSessions(): Promise<DeviceSession[]>;
308
+ revokeSession(id: string): Promise<void>;
309
+ /**
310
+ * Resolves once any sign-in or registration claim in flight has settled.
311
+ * `createThrottleAuth` always supplies it (it resolves at once there);
312
+ * `ThrottleProvider` supplies one that tracks its cart claim. Optional so a
313
+ * hand-made `ThrottleAuth` written against 0.11 still compiles.
314
+ */
315
+ whenClaimSettled?(): Promise<void>;
316
+ }
317
+ declare function createThrottleAuth(config: ThrottleAuthConfig): ThrottleAuth & Required<Pick<ThrottleAuth, 'whenClaimSettled'>>;
318
+
319
+ export { type Address as A, type Customer as C, type DeviceSession as D, type Invoice as I, type OpenCart as O, type PaymentMethod as P, type Session as S, type ThrottleAuth as T, type AddressInput as a, type AuthSnapshot as b, type AuthStatus as c, type AuthStorage as d, type Order as e, type OrderDetail as f, type ProfilePatch as g, type Subscription as h, type SubscriptionShippingAddress as i, type ThrottleAuthConfig as j, createThrottleAuth as k };
@@ -0,0 +1,148 @@
1
+ import { C as Customer, g as ProfilePatch, A as Address, a as AddressInput, P as PaymentMethod, e as Order, f as OrderDetail, I as Invoice, h as Subscription, i as SubscriptionShippingAddress, O as OpenCart, T as ThrottleAuth } from './client-7LVKfuXO.js';
2
+
3
+ interface Page {
4
+ cursor?: string;
5
+ limit?: number;
6
+ }
7
+ /** What the payment widget needs to render a card form. Passed through from
8
+ * the processor — `buyerExternalIdentifier` in particular must reach the
9
+ * widget unchanged, because the session token pins it and the processor
10
+ * refuses a mismatch by rendering nothing at all. */
11
+ interface CardSetupSession {
12
+ embedToken: string;
13
+ checkoutSessionId: string;
14
+ amount: number;
15
+ currency: string;
16
+ merchantAccountId?: string;
17
+ environment?: string;
18
+ buyerExternalIdentifier: string;
19
+ country: string;
20
+ /** A ready-made page that hosts the card form, if you would rather redirect
21
+ * or iframe than embed the widget yourself. */
22
+ hostedUrl: string;
23
+ embedUrl: string;
24
+ }
25
+ interface ThrottleAccount {
26
+ getProfile(): Promise<Customer>;
27
+ updateProfile(patch: ProfilePatch): Promise<Customer>;
28
+ listAddresses(): Promise<Address[]>;
29
+ createAddress(input: AddressInput): Promise<Address>;
30
+ updateAddress(id: string, patch: Partial<AddressInput>): Promise<Address>;
31
+ deleteAddress(id: string): Promise<void>;
32
+ listPaymentMethods(): Promise<PaymentMethod[]>;
33
+ setDefaultPaymentMethod(id: string): Promise<PaymentMethod>;
34
+ deletePaymentMethod(id: string): Promise<void>;
35
+ /** Opens a processor-hosted session the buyer types their card into. The
36
+ * returned values are handed straight to the payment widget. */
37
+ startCardSetup(): Promise<CardSetupSession>;
38
+ /** Records the card the widget just vaulted, identified by the transaction
39
+ * the widget returns. Safe to call twice with the same id. */
40
+ confirmCardSetup(transactionId: string): Promise<PaymentMethod>;
41
+ listOrders(page?: Page): Promise<Order[]>;
42
+ getOrder(id: string): Promise<OrderDetail>;
43
+ listInvoices(page?: Page): Promise<Invoice[]>;
44
+ getInvoice(id: string): Promise<Invoice>;
45
+ /** A 600-second signed URL. Fetch it on click — it expires. */
46
+ getInvoicePdfUrl(id: string): Promise<{
47
+ url: string;
48
+ }>;
49
+ listSubscriptions(page?: Page): Promise<Subscription[]>;
50
+ getSubscription(id: string): Promise<Subscription>;
51
+ /**
52
+ * Voids an unpaid order. Refused once money has been captured — that is a
53
+ * return, not a cancellation, and only the merchant may move money back.
54
+ */
55
+ cancelOrder(id: string, opts?: {
56
+ reason?: string;
57
+ }): Promise<Order>;
58
+ /** Opens an RMA the merchant approves. Changes no order state by itself. */
59
+ requestOrderReturn(id: string, input: {
60
+ items: Array<{
61
+ lineItemId: string;
62
+ quantity: number;
63
+ }>;
64
+ reason?: string;
65
+ }): Promise<{
66
+ id: string;
67
+ status: string;
68
+ }>;
69
+ cancelSubscription(id: string, opts?: {
70
+ atPeriodEnd?: boolean;
71
+ }): Promise<Subscription>;
72
+ pauseSubscription(id: string): Promise<Subscription>;
73
+ resumeSubscription(id: string): Promise<Subscription>;
74
+ /**
75
+ * Where a physical subscription's box goes, from the next renewal. Needs a
76
+ * fresh sign-in (step-up), like cancelling. A subscription that ships
77
+ * nothing answers `subscription_not_physical`.
78
+ */
79
+ updateSubscriptionShippingAddress(id: string, address: SubscriptionShippingAddress): Promise<Subscription>;
80
+ claimCart(cartId: string): Promise<{
81
+ cartId: string;
82
+ customerId: string;
83
+ }>;
84
+ /**
85
+ * The buyer's newest open or idle-abandoned cart in `currency` (see `status`), or null. Answers null as well
86
+ * when the API predates the route (404). Always present on the account that
87
+ * `createAccount` and `ThrottleProvider` build; optional here so a hand-made
88
+ * `ThrottleAccount` written against 0.11 still compiles.
89
+ */
90
+ getOpenCart?(input: {
91
+ currency: string;
92
+ }): Promise<OpenCart | null>;
93
+ }
94
+ declare function createAccount(auth: ThrottleAuth): ThrottleAccount & Required<Pick<ThrottleAccount, 'getOpenCart'>>;
95
+
96
+ declare class ThrottleAuthError extends Error {
97
+ readonly code: string;
98
+ readonly statusCode: number;
99
+ readonly retryAfter?: number;
100
+ readonly details?: unknown;
101
+ constructor(args: {
102
+ code: string;
103
+ message: string;
104
+ statusCode: number;
105
+ retryAfter?: number;
106
+ details?: unknown;
107
+ });
108
+ }
109
+
110
+ interface Resource<T> {
111
+ data: T;
112
+ isLoading: boolean;
113
+ error: ThrottleAuthError | null;
114
+ refetch(): Promise<void>;
115
+ }
116
+ declare function useCustomer(): Resource<Customer | null> & {
117
+ update(patch: ProfilePatch): Promise<void>;
118
+ };
119
+ declare function useAddresses(): Resource<Address[]> & {
120
+ create(input: AddressInput): Promise<void>;
121
+ update(id: string, patch: Partial<AddressInput>): Promise<void>;
122
+ remove(id: string): Promise<void>;
123
+ };
124
+ declare function useSavedCards(): Resource<PaymentMethod[]> & {
125
+ setDefault(id: string): Promise<void>;
126
+ remove(id: string): Promise<void>;
127
+ };
128
+ declare function useOrders(page?: Page): Resource<Order[]>;
129
+ declare function useInvoices(page?: Page): Resource<Invoice[]>;
130
+ declare function useSubscriptions(page?: Page): Resource<Subscription[]> & {
131
+ cancel(id: string, opts?: {
132
+ atPeriodEnd?: boolean;
133
+ }): Promise<void>;
134
+ pause(id: string): Promise<void>;
135
+ resume(id: string): Promise<void>;
136
+ /** Where a physical subscription ships, from the next renewal (step-up). */
137
+ updateShippingAddress(id: string, address: SubscriptionShippingAddress): Promise<void>;
138
+ };
139
+ /**
140
+ * Single-resource reads for the detail views. A `null` id means "nothing
141
+ * selected" and must not call the API — `useResource` still runs, so the
142
+ * loader resolves to null rather than being skipped, which keeps the
143
+ * loading/error shape identical whether or not an id is present.
144
+ */
145
+ declare function useOrder(id: string | null): Resource<OrderDetail | null>;
146
+ declare function useInvoice(id: string | null): Resource<Invoice | null>;
147
+
148
+ export { type Page as P, type Resource as R, type ThrottleAccount as T, ThrottleAuthError as a, useCustomer as b, createAccount as c, useInvoice as d, useInvoices as e, useOrder as f, useOrders as g, useSavedCards as h, useSubscriptions as i, useAddresses as u };
package/dist/index.cjs CHANGED
@@ -373,7 +373,10 @@ function createThrottleAuth(config) {
373
373
  const current = mine.find((s) => s.current);
374
374
  await call("DELETE", `/me/sessions/${encodeURIComponent(id)}`);
375
375
  if (current?.id === id) await forget();
376
- }
376
+ },
377
+ // The core never claims a cart; `ThrottleProvider` overrides this with one
378
+ // that tracks its sign-in claim.
379
+ whenClaimSettled: () => Promise.resolve()
377
380
  };
378
381
  }
379
382
 
@@ -420,7 +423,18 @@ function createAccount(auth) {
420
423
  pauseSubscription: (id) => call("POST", `/me/subscriptions/${seg(id)}/pause`),
421
424
  resumeSubscription: (id) => call("POST", `/me/subscriptions/${seg(id)}/resume`),
422
425
  updateSubscriptionShippingAddress: (id, address) => call("PATCH", `/me/subscriptions/${seg(id)}/shipping-address`, address),
423
- claimCart: (cartId) => call("POST", `/me/carts/${seg(cartId)}/claim`)
426
+ claimCart: (cartId) => call("POST", `/me/carts/${seg(cartId)}/claim`),
427
+ async getOpenCart({ currency }) {
428
+ if (typeof currency !== "string" || !/^[A-Za-z]{3}$/.test(currency)) {
429
+ throw new TypeError("getOpenCart: currency must be a 3-letter ISO code");
430
+ }
431
+ try {
432
+ return await call("GET", `/me/cart?currency=${currency.toUpperCase()}`);
433
+ } catch (err) {
434
+ if (err instanceof ThrottleAuthError && err.statusCode === 404) return null;
435
+ throw err;
436
+ }
437
+ }
424
438
  };
425
439
  }
426
440
  // Annotate the CommonJS export names for ESM import in node: