@usethrottle/cart 3.12.0 → 3.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +121 -0
- package/dist/index.cjs +207 -0
- package/dist/index.d.cts +283 -1
- package/dist/index.d.ts +283 -1
- package/dist/index.js +194 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -144,6 +144,127 @@ button — checkout still works. Omitting `returnUrl` or `cancelUrl` falls back
|
|
|
144
144
|
to Throttle's own `/complete` page and this same hosted cart page,
|
|
145
145
|
respectively.
|
|
146
146
|
|
|
147
|
+
### Resolved carts
|
|
148
|
+
|
|
149
|
+
A resolved cart's lines are priced by an installed app (a line resolver, such
|
|
150
|
+
as Product Catalog), never by the browser. Create the session with
|
|
151
|
+
`lineResolver` and the environment's `currency`, then add lines by
|
|
152
|
+
`referenceId`. Throttle asks the app for the price, stock and limits on every
|
|
153
|
+
add, quantity change, sign-in merge and checkout.
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
import {
|
|
157
|
+
QuantityUnavailableError,
|
|
158
|
+
LineNotPurchasableError,
|
|
159
|
+
LineResolverUnavailableError,
|
|
160
|
+
CartPricesChangedError,
|
|
161
|
+
} from '@usethrottle/cart';
|
|
162
|
+
|
|
163
|
+
await cart.create({
|
|
164
|
+
currency: 'USD', // required with lineResolver; must be the environment's currency
|
|
165
|
+
lineResolver: { extensionId: '0b6a3c1e-8d2f-4a5b-9c7d-1e2f3a4b5c6d' },
|
|
166
|
+
locale: 'en-US', // optional, passed to the app
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
try {
|
|
170
|
+
await cart.addResolvedItem({ referenceId: 'TSHIRT-BLUE-M', quantity: 2 });
|
|
171
|
+
} catch (e) {
|
|
172
|
+
if (e instanceof QuantityUnavailableError) showMessage(`Only ${e.maxQuantity ?? 0} available`);
|
|
173
|
+
else if (e instanceof LineNotPurchasableError) showMessage('No longer available');
|
|
174
|
+
else if (e instanceof LineResolverUnavailableError) showMessage('Try again in a moment');
|
|
175
|
+
else throw e;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Re-check every owned line (for example when the buyer comes back to the cart).
|
|
179
|
+
const { changed, ...current } = await cart.refresh();
|
|
180
|
+
|
|
181
|
+
try {
|
|
182
|
+
const { checkoutUrl } = await cart.checkout({ returnUrl, cancelUrl });
|
|
183
|
+
location.href = checkoutUrl;
|
|
184
|
+
} catch (e) {
|
|
185
|
+
if (e instanceof CartPricesChangedError) {
|
|
186
|
+
// The new prices are already applied; show them, then check out again.
|
|
187
|
+
if (e.cart) render(e.cart);
|
|
188
|
+
} else throw e;
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
`addResolvedItem()` sends only `referenceId`, `quantity` (default 1) and
|
|
193
|
+
`metadata`. The app sets the name, price and image: sending `unitPrice`,
|
|
194
|
+
`name`, `imageUrl`, `taxAmount`, `discountAmount`, a reserved metadata key
|
|
195
|
+
(`lineResolver`, `requiresShipping`) or a metadata key that changes a shipping
|
|
196
|
+
or tax quote answers `400 price_locked` (`PriceLockedError.fields` names them).
|
|
197
|
+
`updateItem()` keeps working for quantity and other metadata; a quantity change
|
|
198
|
+
is re-checked by the app.
|
|
199
|
+
|
|
200
|
+
A resolved cart carries `lineResolver: { extensionId }` (`extensionId` is
|
|
201
|
+
`null` if the app's installation is gone), and each line carries `resolution`:
|
|
202
|
+
`null` on a line the app does not own, otherwise `{ status, code, maxQuantity,
|
|
203
|
+
minQuantity }`. `status` is `resolved`, `refused` (the app refused the line;
|
|
204
|
+
`code` says why, for example `OUT_OF_STOCK`) or `stale` (the last re-check
|
|
205
|
+
failed; checkout re-checks it). Carts created without `lineResolver` have
|
|
206
|
+
neither key.
|
|
207
|
+
|
|
208
|
+
Shipping on a resolved cart is priced by Throttle, not the browser: pick a
|
|
209
|
+
method Throttle quotes for the cart with
|
|
210
|
+
`cart.selectShippingMethod({ methodId })`, which sends only the method id (the
|
|
211
|
+
cart needs a shipping address first). A method Throttle does not quote answers
|
|
212
|
+
`422 shipping_method_unavailable`. If you use `selectShipping()` instead, a
|
|
213
|
+
`rateAmount` or `currency` different from the quote answers `400
|
|
214
|
+
price_locked`. There is no flat-rate fallback (no selection means shipping
|
|
215
|
+
is not calculated yet). The checkout hand-off re-checks every line and
|
|
216
|
+
re-quotes shipping; any change answers `409 cart_prices_changed` with the
|
|
217
|
+
updated `cart` and, when shipping moved, `shipping: { methodId,
|
|
218
|
+
previousAmount, amount, reason? }` (`amount` is `null` with `reason`
|
|
219
|
+
`method_unavailable` or `quote_unavailable`).
|
|
220
|
+
|
|
221
|
+
#### From your server (`CartClient`)
|
|
222
|
+
|
|
223
|
+
Other apps can integrate the same way with a secret key. Create the cart with
|
|
224
|
+
`lineResolver` (and the environment's `currency`), optionally pricing up to 50
|
|
225
|
+
lines in one call with `lineItems` (all or nothing), then add lines by
|
|
226
|
+
`referenceId`:
|
|
227
|
+
|
|
228
|
+
```ts
|
|
229
|
+
const cart = await client.carts.create({
|
|
230
|
+
applicationId,
|
|
231
|
+
currency: 'USD',
|
|
232
|
+
lineResolver: { extensionId: '0b6a3c1e-8d2f-4a5b-9c7d-1e2f3a4b5c6d' },
|
|
233
|
+
locale: 'en-GB',
|
|
234
|
+
lineItems: [{ referenceId: 'TSHIRT-BLUE-M', quantity: 2 }],
|
|
235
|
+
});
|
|
236
|
+
const line = await client.items.addResolvedItem(cart.id, { referenceId: 'MUG-WHITE', quantity: 1 });
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
A server cart has no refresh: `refresh()` exists only on a browser cart
|
|
240
|
+
session (`CartSessionClient`). From the server, a line is re-checked with the
|
|
241
|
+
app when you change its quantity with `items.update(cartId, itemId,
|
|
242
|
+
{ quantity })`. To re-check the whole cart, mint a hosted-cart session for it
|
|
243
|
+
(`POST /api/v1/carts/{id}/sessions`, which answers `{ sessionId, cartUrl,
|
|
244
|
+
expiresAt }`) and call `CartSessionClient.forSession(sessionId).refresh()`. An
|
|
245
|
+
owned line's `unitPrice`, `taxAmount`, `discountAmount` and reserved metadata
|
|
246
|
+
keys answer `400 price_locked` for every caller. Both clients throw the same
|
|
247
|
+
typed errors:
|
|
248
|
+
|
|
249
|
+
| Error class | Status / code | Typed fields (`details`) |
|
|
250
|
+
| --- | --- | --- |
|
|
251
|
+
| `PriceLockedError` | `400 price_locked` | `fields` |
|
|
252
|
+
| `QuantityUnavailableError` | `409 quantity_unavailable` | `reason`, `maxQuantity` (or `null`) |
|
|
253
|
+
| `LineNotPurchasableError` | `422 line_not_purchasable` | `reason` on an add; `lines` at checkout |
|
|
254
|
+
| `LineResolverUnavailableError` | `503 line_resolver_unavailable` | `reason` (or `null`); nothing changed, retry |
|
|
255
|
+
| `LineResolverNotAvailableError` | `422 line_resolver_not_available` | `reason`; the app is not installed |
|
|
256
|
+
| `CurrencyNotEnabledError` | `422 currency_not_enabled` | `details.currency`, `details.enabledCurrencies` |
|
|
257
|
+
| `ResolvedLinesRequiredError` | `422 resolved_lines_required` | the store only accepts resolved lines |
|
|
258
|
+
| `LineLimitReachedError` | `422 line_limit_reached` | `details.maxLines` (50 per app) |
|
|
259
|
+
| `CartPricesChangedError` | `409 cart_prices_changed` | `cart`, `shipping` (or `null`) |
|
|
260
|
+
| `ShippingMethodUnavailableError` | `422 shipping_method_unavailable` | |
|
|
261
|
+
| `ShippingQuoteUnavailableError` | `503 shipping_quote_unavailable` | nothing changed, retry |
|
|
262
|
+
| `AmountTooLargeError` | `422 amount_too_large` | lower the quantity |
|
|
263
|
+
| `CartChangedError` | `409 cart_changed` | the cart changed during the add; retry |
|
|
264
|
+
|
|
265
|
+
Every class extends `ThrottleApiError` (and so `ThrottleError`), so existing
|
|
266
|
+
`instanceof ThrottleApiError` and `e.code` checks keep working.
|
|
267
|
+
|
|
147
268
|
## Net-N invoice terms
|
|
148
269
|
|
|
149
270
|
Cart-level invoice terms are optional. Pass `netN` on cart create or update to
|
package/dist/index.cjs
CHANGED
|
@@ -20,11 +20,24 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
AmountTooLargeError: () => AmountTooLargeError,
|
|
24
|
+
CartChangedError: () => CartChangedError,
|
|
23
25
|
CartClient: () => CartClient,
|
|
24
26
|
CartNotFoundError: () => CartNotFoundError,
|
|
25
27
|
CartNotOpenError: () => CartNotOpenError,
|
|
28
|
+
CartPricesChangedError: () => CartPricesChangedError,
|
|
26
29
|
CartSessionClient: () => CartSessionClient,
|
|
27
30
|
CartTimeoutError: () => CartTimeoutError,
|
|
31
|
+
CurrencyNotEnabledError: () => CurrencyNotEnabledError,
|
|
32
|
+
LineLimitReachedError: () => LineLimitReachedError,
|
|
33
|
+
LineNotPurchasableError: () => LineNotPurchasableError,
|
|
34
|
+
LineResolverNotAvailableError: () => LineResolverNotAvailableError,
|
|
35
|
+
LineResolverUnavailableError: () => LineResolverUnavailableError,
|
|
36
|
+
PriceLockedError: () => PriceLockedError,
|
|
37
|
+
QuantityUnavailableError: () => QuantityUnavailableError,
|
|
38
|
+
ResolvedLinesRequiredError: () => ResolvedLinesRequiredError,
|
|
39
|
+
ShippingMethodUnavailableError: () => ShippingMethodUnavailableError,
|
|
40
|
+
ShippingQuoteUnavailableError: () => ShippingQuoteUnavailableError,
|
|
28
41
|
StorefrontQuoteClient: () => StorefrontQuoteClient,
|
|
29
42
|
ThrottleApiError: () => ThrottleApiError,
|
|
30
43
|
ThrottleError: () => import_errors2.ThrottleError,
|
|
@@ -77,6 +90,130 @@ var CartTimeoutError = class extends import_errors.ThrottleError {
|
|
|
77
90
|
this.name = "CartTimeoutError";
|
|
78
91
|
}
|
|
79
92
|
};
|
|
93
|
+
function coded(code, statusCode, args) {
|
|
94
|
+
return {
|
|
95
|
+
code,
|
|
96
|
+
statusCode: args.statusCode ?? statusCode,
|
|
97
|
+
message: args.message,
|
|
98
|
+
details: args.details,
|
|
99
|
+
responseHeaders: args.responseHeaders
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
var str = (v) => typeof v === "string" ? v : null;
|
|
103
|
+
var num = (v) => typeof v === "number" ? v : null;
|
|
104
|
+
var PriceLockedError = class extends ThrottleApiError {
|
|
105
|
+
/** The refused fields, e.g. `['unitPrice', 'metadata.lineResolver']`. */
|
|
106
|
+
fields;
|
|
107
|
+
constructor(args) {
|
|
108
|
+
super(coded("price_locked", 400, args));
|
|
109
|
+
this.name = "PriceLockedError";
|
|
110
|
+
this.fields = Array.isArray(args.details?.fields) ? args.details.fields : [];
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
var QuantityUnavailableError = class extends ThrottleApiError {
|
|
114
|
+
reason;
|
|
115
|
+
maxQuantity;
|
|
116
|
+
constructor(args) {
|
|
117
|
+
super(coded("quantity_unavailable", 409, args));
|
|
118
|
+
this.name = "QuantityUnavailableError";
|
|
119
|
+
this.reason = str(args.details?.reason);
|
|
120
|
+
this.maxQuantity = num(args.details?.maxQuantity);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
var LineNotPurchasableError = class extends ThrottleApiError {
|
|
124
|
+
reason;
|
|
125
|
+
lines;
|
|
126
|
+
constructor(args) {
|
|
127
|
+
super(coded("line_not_purchasable", 422, args));
|
|
128
|
+
this.name = "LineNotPurchasableError";
|
|
129
|
+
this.reason = str(args.details?.reason);
|
|
130
|
+
this.lines = Array.isArray(args.details?.lines) ? args.details.lines : null;
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
var LineResolverUnavailableError = class extends ThrottleApiError {
|
|
134
|
+
reason;
|
|
135
|
+
constructor(args) {
|
|
136
|
+
super(coded("line_resolver_unavailable", 503, args));
|
|
137
|
+
this.name = "LineResolverUnavailableError";
|
|
138
|
+
this.reason = str(args.details?.reason);
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
var LineResolverNotAvailableError = class extends ThrottleApiError {
|
|
142
|
+
reason;
|
|
143
|
+
constructor(args) {
|
|
144
|
+
super(coded("line_resolver_not_available", 422, args));
|
|
145
|
+
this.name = "LineResolverNotAvailableError";
|
|
146
|
+
this.reason = str(args.details?.reason);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
var CurrencyNotEnabledError = class extends ThrottleApiError {
|
|
150
|
+
constructor(args) {
|
|
151
|
+
super(coded("currency_not_enabled", 422, args));
|
|
152
|
+
this.name = "CurrencyNotEnabledError";
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
var ResolvedLinesRequiredError = class extends ThrottleApiError {
|
|
156
|
+
constructor(args) {
|
|
157
|
+
super(coded("resolved_lines_required", 422, args));
|
|
158
|
+
this.name = "ResolvedLinesRequiredError";
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
var LineLimitReachedError = class extends ThrottleApiError {
|
|
162
|
+
constructor(args) {
|
|
163
|
+
super(coded("line_limit_reached", 422, args));
|
|
164
|
+
this.name = "LineLimitReachedError";
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
var CartPricesChangedError = class extends ThrottleApiError {
|
|
168
|
+
cart;
|
|
169
|
+
shipping;
|
|
170
|
+
constructor(args) {
|
|
171
|
+
super(coded("cart_prices_changed", 409, args));
|
|
172
|
+
this.name = "CartPricesChangedError";
|
|
173
|
+
const d = args.details;
|
|
174
|
+
this.cart = d?.cart && typeof d.cart === "object" ? d.cart : null;
|
|
175
|
+
this.shipping = d?.shipping && typeof d.shipping === "object" ? d.shipping : null;
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
var ShippingMethodUnavailableError = class extends ThrottleApiError {
|
|
179
|
+
constructor(args) {
|
|
180
|
+
super(coded("shipping_method_unavailable", 422, args));
|
|
181
|
+
this.name = "ShippingMethodUnavailableError";
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
var ShippingQuoteUnavailableError = class extends ThrottleApiError {
|
|
185
|
+
constructor(args) {
|
|
186
|
+
super(coded("shipping_quote_unavailable", 503, args));
|
|
187
|
+
this.name = "ShippingQuoteUnavailableError";
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
var AmountTooLargeError = class extends ThrottleApiError {
|
|
191
|
+
constructor(args) {
|
|
192
|
+
super(coded("amount_too_large", 422, args));
|
|
193
|
+
this.name = "AmountTooLargeError";
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
var CartChangedError = class extends ThrottleApiError {
|
|
197
|
+
constructor(args) {
|
|
198
|
+
super(coded("cart_changed", 409, args));
|
|
199
|
+
this.name = "CartChangedError";
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
var RESOLVED_CART_ERRORS = {
|
|
203
|
+
price_locked: PriceLockedError,
|
|
204
|
+
quantity_unavailable: QuantityUnavailableError,
|
|
205
|
+
line_not_purchasable: LineNotPurchasableError,
|
|
206
|
+
line_resolver_unavailable: LineResolverUnavailableError,
|
|
207
|
+
line_resolver_not_available: LineResolverNotAvailableError,
|
|
208
|
+
currency_not_enabled: CurrencyNotEnabledError,
|
|
209
|
+
resolved_lines_required: ResolvedLinesRequiredError,
|
|
210
|
+
line_limit_reached: LineLimitReachedError,
|
|
211
|
+
cart_prices_changed: CartPricesChangedError,
|
|
212
|
+
shipping_method_unavailable: ShippingMethodUnavailableError,
|
|
213
|
+
shipping_quote_unavailable: ShippingQuoteUnavailableError,
|
|
214
|
+
amount_too_large: AmountTooLargeError,
|
|
215
|
+
cart_changed: CartChangedError
|
|
216
|
+
};
|
|
80
217
|
function cartErrorFromResponse(args) {
|
|
81
218
|
if (args.statusCode === 409 && args.code === "cart_not_open") {
|
|
82
219
|
return new CartNotOpenError({
|
|
@@ -94,6 +231,15 @@ function cartErrorFromResponse(args) {
|
|
|
94
231
|
responseHeaders: args.responseHeaders
|
|
95
232
|
});
|
|
96
233
|
}
|
|
234
|
+
const ResolvedCartError = Object.prototype.hasOwnProperty.call(RESOLVED_CART_ERRORS, args.code) ? RESOLVED_CART_ERRORS[args.code] : void 0;
|
|
235
|
+
if (ResolvedCartError) {
|
|
236
|
+
return new ResolvedCartError({
|
|
237
|
+
message: args.message,
|
|
238
|
+
statusCode: args.statusCode,
|
|
239
|
+
details: args.details,
|
|
240
|
+
responseHeaders: args.responseHeaders
|
|
241
|
+
});
|
|
242
|
+
}
|
|
97
243
|
return new ThrottleApiError(args);
|
|
98
244
|
}
|
|
99
245
|
|
|
@@ -151,6 +297,17 @@ var CartClient = class {
|
|
|
151
297
|
get items() {
|
|
152
298
|
return {
|
|
153
299
|
add: (cartId, input) => this.request("POST", `/api/v1/carts/${segment(cartId)}/items`, input),
|
|
300
|
+
/**
|
|
301
|
+
* Add a line to a resolved cart (one created with `lineResolver`). Only
|
|
302
|
+
* the item, quantity and metadata are sent; the app sets the name, price
|
|
303
|
+
* and image. Refusals throw the typed resolver errors.
|
|
304
|
+
*/
|
|
305
|
+
addResolvedItem: (cartId, input) => {
|
|
306
|
+
const body = { referenceId: input.referenceId };
|
|
307
|
+
if (input.quantity !== void 0) body.quantity = input.quantity;
|
|
308
|
+
if (input.metadata !== void 0) body.metadata = input.metadata;
|
|
309
|
+
return this.request("POST", `/api/v1/carts/${segment(cartId)}/items`, body);
|
|
310
|
+
},
|
|
154
311
|
update: (cartId, itemId, input) => this.request("PATCH", `/api/v1/carts/${segment(cartId)}/items/${segment(itemId)}`, input),
|
|
155
312
|
remove: (cartId, itemId) => this.request("DELETE", `/api/v1/carts/${segment(cartId)}/items/${segment(itemId)}`)
|
|
156
313
|
};
|
|
@@ -323,6 +480,32 @@ var CartSessionClient = class _CartSessionClient {
|
|
|
323
480
|
async addItem(input) {
|
|
324
481
|
return (await this.request("POST", `${this.basePath()}/items`, input)).cart;
|
|
325
482
|
}
|
|
483
|
+
/**
|
|
484
|
+
* Add a line to a resolved cart (one created with `lineResolver`). Only the
|
|
485
|
+
* item, quantity and metadata are sent; the app sets the name, price and
|
|
486
|
+
* image. A refusal throws `QuantityUnavailableError`,
|
|
487
|
+
* `LineNotPurchasableError` or `LineResolverUnavailableError`.
|
|
488
|
+
*/
|
|
489
|
+
async addResolvedItem(input) {
|
|
490
|
+
const body = { referenceId: input.referenceId };
|
|
491
|
+
if (input.quantity !== void 0) body.quantity = input.quantity;
|
|
492
|
+
if (input.metadata !== void 0) body.metadata = input.metadata;
|
|
493
|
+
return (await this.request("POST", `${this.basePath()}/items`, body)).cart;
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Ask the app that prices a resolved cart to re-check every line it owns.
|
|
497
|
+
* `changed` is true when a price, name or refusal changed. An unresolved
|
|
498
|
+
* cart comes back unchanged. Throws `LineResolverUnavailableError` (nothing
|
|
499
|
+
* changed) when the app does not answer.
|
|
500
|
+
*/
|
|
501
|
+
async refresh() {
|
|
502
|
+
const data = await this.request(
|
|
503
|
+
"POST",
|
|
504
|
+
`${this.basePath()}/refresh`,
|
|
505
|
+
{}
|
|
506
|
+
);
|
|
507
|
+
return { ...data.cart, changed: data.changed };
|
|
508
|
+
}
|
|
326
509
|
async updateItem(itemId, input) {
|
|
327
510
|
return (await this.request(
|
|
328
511
|
"PATCH",
|
|
@@ -336,6 +519,17 @@ var CartSessionClient = class _CartSessionClient {
|
|
|
336
519
|
async selectShipping(input) {
|
|
337
520
|
return (await this.request("POST", `${this.basePath()}/shipping`, input)).cart;
|
|
338
521
|
}
|
|
522
|
+
/**
|
|
523
|
+
* Pick a shipping method on a resolved cart. Throttle quotes the amount, so
|
|
524
|
+
* only `methodId` is sent. A method Throttle does not quote for the cart
|
|
525
|
+
* (it needs a shipping address first) throws `ShippingMethodUnavailableError`;
|
|
526
|
+
* a failed quote throws `ShippingQuoteUnavailableError`.
|
|
527
|
+
*/
|
|
528
|
+
async selectShippingMethod(input) {
|
|
529
|
+
return (await this.request("POST", `${this.basePath()}/shipping`, {
|
|
530
|
+
methodId: input.methodId
|
|
531
|
+
})).cart;
|
|
532
|
+
}
|
|
339
533
|
async clearShipping() {
|
|
340
534
|
return (await this.request("DELETE", `${this.basePath()}/shipping`)).cart;
|
|
341
535
|
}
|
|
@@ -424,11 +618,24 @@ var CartSessionClient = class _CartSessionClient {
|
|
|
424
618
|
};
|
|
425
619
|
// Annotate the CommonJS export names for ESM import in node:
|
|
426
620
|
0 && (module.exports = {
|
|
621
|
+
AmountTooLargeError,
|
|
622
|
+
CartChangedError,
|
|
427
623
|
CartClient,
|
|
428
624
|
CartNotFoundError,
|
|
429
625
|
CartNotOpenError,
|
|
626
|
+
CartPricesChangedError,
|
|
430
627
|
CartSessionClient,
|
|
431
628
|
CartTimeoutError,
|
|
629
|
+
CurrencyNotEnabledError,
|
|
630
|
+
LineLimitReachedError,
|
|
631
|
+
LineNotPurchasableError,
|
|
632
|
+
LineResolverNotAvailableError,
|
|
633
|
+
LineResolverUnavailableError,
|
|
634
|
+
PriceLockedError,
|
|
635
|
+
QuantityUnavailableError,
|
|
636
|
+
ResolvedLinesRequiredError,
|
|
637
|
+
ShippingMethodUnavailableError,
|
|
638
|
+
ShippingQuoteUnavailableError,
|
|
432
639
|
StorefrontQuoteClient,
|
|
433
640
|
ThrottleApiError,
|
|
434
641
|
ThrottleError,
|
package/dist/index.d.cts
CHANGED
|
@@ -60,6 +60,14 @@ interface Cart {
|
|
|
60
60
|
lineItems?: LineItem[];
|
|
61
61
|
createdAt: string;
|
|
62
62
|
updatedAt: string;
|
|
63
|
+
/**
|
|
64
|
+
* Resolved carts only: the installed app that prices the cart's owned
|
|
65
|
+
* lines. `extensionId` is null when the installation can no longer be
|
|
66
|
+
* found. Absent on a cart created without `lineResolver`.
|
|
67
|
+
*/
|
|
68
|
+
lineResolver?: {
|
|
69
|
+
extensionId: string | null;
|
|
70
|
+
};
|
|
63
71
|
}
|
|
64
72
|
/**
|
|
65
73
|
* The cart as the session (browser, opaque-token) surface returns it —
|
|
@@ -165,6 +173,55 @@ interface LineItem {
|
|
|
165
173
|
imageUrl: string | null;
|
|
166
174
|
position: number;
|
|
167
175
|
metadata: Record<string, unknown>;
|
|
176
|
+
/**
|
|
177
|
+
* Resolved carts only: the app's last answer for this line, or null on a
|
|
178
|
+
* line the app does not own. Absent on an unresolved cart.
|
|
179
|
+
*/
|
|
180
|
+
resolution?: LineResolution | null;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* An owned line's state on a resolved cart.
|
|
184
|
+
*
|
|
185
|
+
* - `resolved`: the app priced the line on its last answer.
|
|
186
|
+
* - `refused`: the app refused the line on its last answer; `code` says why
|
|
187
|
+
* (`OUT_OF_STOCK`, `QUANTITY_UNAVAILABLE`, `BELOW_MIN`, `ABOVE_MAX`,
|
|
188
|
+
* `NOT_FOUND`, `NOT_PURCHASABLE`, `NO_PRICE_IN_CURRENCY`,
|
|
189
|
+
* `PRICE_SOURCE_MISMATCH`).
|
|
190
|
+
* - `stale`: the last re-resolve failed; the line keeps its earlier price and
|
|
191
|
+
* `code` keeps any earlier refusal. Checkout re-resolves it.
|
|
192
|
+
*
|
|
193
|
+
* `maxQuantity` / `minQuantity` are the limits from the app's last answer
|
|
194
|
+
* (a refusal's own `maxQuantity` wins), or null.
|
|
195
|
+
*/
|
|
196
|
+
interface LineResolution {
|
|
197
|
+
status: 'resolved' | 'refused' | 'stale';
|
|
198
|
+
code: string | null;
|
|
199
|
+
maxQuantity: number | null;
|
|
200
|
+
minQuantity: number | null;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* A line of a resolved cart: the app sets its name, price and image, so the
|
|
204
|
+
* browser sends only which item and how many.
|
|
205
|
+
*/
|
|
206
|
+
interface AddResolvedLineItemInput {
|
|
207
|
+
/** The app's id for the item (for Product Catalog, the variant SKU). */
|
|
208
|
+
referenceId: string;
|
|
209
|
+
/** 1 to 10,000. Defaults to 1. */
|
|
210
|
+
quantity?: number;
|
|
211
|
+
/**
|
|
212
|
+
* Buyer metadata. The reserved keys (`lineResolver`, `requiresShipping`)
|
|
213
|
+
* and the keys that change a shipping or tax quote are set by the app and
|
|
214
|
+
* answer `400 price_locked`.
|
|
215
|
+
*/
|
|
216
|
+
metadata?: Record<string, unknown>;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Pick a shipping method on a resolved cart (or in an environment where
|
|
220
|
+
* browser carts may only hold resolved lines): Throttle quotes the amount,
|
|
221
|
+
* so only the method id is sent.
|
|
222
|
+
*/
|
|
223
|
+
interface SelectShippingMethodInput {
|
|
224
|
+
methodId: string;
|
|
168
225
|
}
|
|
169
226
|
interface SelectedShipping {
|
|
170
227
|
methodId: string;
|
|
@@ -219,6 +276,24 @@ interface CreateCartInput {
|
|
|
219
276
|
currency?: string;
|
|
220
277
|
netN?: number | null;
|
|
221
278
|
metadata?: Record<string, unknown>;
|
|
279
|
+
/**
|
|
280
|
+
* Make this a resolved cart: the installed app with this extension id
|
|
281
|
+
* prices its lines (add them with `items.addResolvedItem()`). Requires
|
|
282
|
+
* `currency`, which must be the environment's currency.
|
|
283
|
+
*/
|
|
284
|
+
lineResolver?: {
|
|
285
|
+
extensionId: string;
|
|
286
|
+
};
|
|
287
|
+
/** Buyer locale passed to the app that prices the lines (BCP 47, e.g. `en-GB`). */
|
|
288
|
+
locale?: string;
|
|
289
|
+
/**
|
|
290
|
+
* Resolved lines to add at create (requires `lineResolver`): 1 to 50, each
|
|
291
|
+
* `referenceId` at most once, priced in one call to the app, all or nothing.
|
|
292
|
+
*/
|
|
293
|
+
lineItems?: Array<{
|
|
294
|
+
referenceId: string;
|
|
295
|
+
quantity?: number;
|
|
296
|
+
}>;
|
|
222
297
|
}
|
|
223
298
|
interface UpdateCartInput {
|
|
224
299
|
customerId?: string;
|
|
@@ -478,6 +553,12 @@ declare class CartClient {
|
|
|
478
553
|
};
|
|
479
554
|
get items(): {
|
|
480
555
|
add: (cartId: string, input: AddLineItemInput) => Promise<LineItem>;
|
|
556
|
+
/**
|
|
557
|
+
* Add a line to a resolved cart (one created with `lineResolver`). Only
|
|
558
|
+
* the item, quantity and metadata are sent; the app sets the name, price
|
|
559
|
+
* and image. Refusals throw the typed resolver errors.
|
|
560
|
+
*/
|
|
561
|
+
addResolvedItem: (cartId: string, input: AddResolvedLineItemInput) => Promise<LineItem>;
|
|
481
562
|
update: (cartId: string, itemId: string, input: UpdateLineItemInput) => Promise<LineItem>;
|
|
482
563
|
remove: (cartId: string, itemId: string) => Promise<void>;
|
|
483
564
|
};
|
|
@@ -567,6 +648,16 @@ interface CreateCartSessionInput {
|
|
|
567
648
|
currency?: string;
|
|
568
649
|
netN?: number;
|
|
569
650
|
metadata?: Record<string, unknown>;
|
|
651
|
+
/**
|
|
652
|
+
* Make this a resolved cart: the installed app with this extension id
|
|
653
|
+
* prices its lines (add them with `addResolvedItem()`). Requires
|
|
654
|
+
* `currency`, which must be the environment's currency.
|
|
655
|
+
*/
|
|
656
|
+
lineResolver?: {
|
|
657
|
+
extensionId: string;
|
|
658
|
+
};
|
|
659
|
+
/** Buyer locale passed to the app that prices the lines (BCP 47, e.g. `en-US`). */
|
|
660
|
+
locale?: string;
|
|
570
661
|
}
|
|
571
662
|
interface CartBranding {
|
|
572
663
|
logoUrl: string | null;
|
|
@@ -660,9 +751,32 @@ declare class CartSessionClient {
|
|
|
660
751
|
*/
|
|
661
752
|
summary(): Promise<CartSessionSummary>;
|
|
662
753
|
addItem(input: AddLineItemInput): Promise<CartSessionCart>;
|
|
754
|
+
/**
|
|
755
|
+
* Add a line to a resolved cart (one created with `lineResolver`). Only the
|
|
756
|
+
* item, quantity and metadata are sent; the app sets the name, price and
|
|
757
|
+
* image. A refusal throws `QuantityUnavailableError`,
|
|
758
|
+
* `LineNotPurchasableError` or `LineResolverUnavailableError`.
|
|
759
|
+
*/
|
|
760
|
+
addResolvedItem(input: AddResolvedLineItemInput): Promise<CartSessionCart>;
|
|
761
|
+
/**
|
|
762
|
+
* Ask the app that prices a resolved cart to re-check every line it owns.
|
|
763
|
+
* `changed` is true when a price, name or refusal changed. An unresolved
|
|
764
|
+
* cart comes back unchanged. Throws `LineResolverUnavailableError` (nothing
|
|
765
|
+
* changed) when the app does not answer.
|
|
766
|
+
*/
|
|
767
|
+
refresh(): Promise<CartSessionCart & {
|
|
768
|
+
changed: boolean;
|
|
769
|
+
}>;
|
|
663
770
|
updateItem(itemId: string, input: UpdateLineItemInput): Promise<CartSessionCart>;
|
|
664
771
|
removeItem(itemId: string): Promise<CartSessionCart>;
|
|
665
772
|
selectShipping(input: SelectShippingInput): Promise<CartSessionCart>;
|
|
773
|
+
/**
|
|
774
|
+
* Pick a shipping method on a resolved cart. Throttle quotes the amount, so
|
|
775
|
+
* only `methodId` is sent. A method Throttle does not quote for the cart
|
|
776
|
+
* (it needs a shipping address first) throws `ShippingMethodUnavailableError`;
|
|
777
|
+
* a failed quote throws `ShippingQuoteUnavailableError`.
|
|
778
|
+
*/
|
|
779
|
+
selectShippingMethod(input: SelectShippingMethodInput): Promise<CartSessionCart>;
|
|
666
780
|
clearShipping(): Promise<CartSessionCart>;
|
|
667
781
|
applyDiscount(code: string): Promise<CartSessionCart>;
|
|
668
782
|
removeDiscount(): Promise<CartSessionCart>;
|
|
@@ -759,6 +873,174 @@ declare class CartTimeoutError extends ThrottleError {
|
|
|
759
873
|
path?: string;
|
|
760
874
|
});
|
|
761
875
|
}
|
|
876
|
+
/** Constructor arguments shared by the resolved-cart error classes. */
|
|
877
|
+
interface CartErrorArgs {
|
|
878
|
+
message: string;
|
|
879
|
+
statusCode?: number;
|
|
880
|
+
details?: Record<string, unknown>;
|
|
881
|
+
responseHeaders?: ThrottleErrorArgs['responseHeaders'];
|
|
882
|
+
}
|
|
883
|
+
/** `details` of `400 price_locked`: the request fields the app sets. */
|
|
884
|
+
type PriceLockedDetails = {
|
|
885
|
+
fields: string[];
|
|
886
|
+
};
|
|
887
|
+
/**
|
|
888
|
+
* `400 price_locked`: the request sent a field the pricing app owns (a
|
|
889
|
+
* price, name, image, or a reserved or quote-affecting metadata key). On a
|
|
890
|
+
* resolved cart, add lines with `addResolvedItem()`.
|
|
891
|
+
*/
|
|
892
|
+
declare class PriceLockedError extends ThrottleApiError {
|
|
893
|
+
readonly details?: PriceLockedDetails;
|
|
894
|
+
/** The refused fields, e.g. `['unitPrice', 'metadata.lineResolver']`. */
|
|
895
|
+
readonly fields: string[];
|
|
896
|
+
constructor(args: CartErrorArgs);
|
|
897
|
+
}
|
|
898
|
+
/** `details` of `409 quantity_unavailable`. */
|
|
899
|
+
type QuantityUnavailableDetails = {
|
|
900
|
+
/** `OUT_OF_STOCK`, `QUANTITY_UNAVAILABLE`, `BELOW_MIN`, `ABOVE_MAX` or `MAX_LINE_ITEM_QUANTITY`. */
|
|
901
|
+
reason: string;
|
|
902
|
+
maxQuantity?: number;
|
|
903
|
+
referenceId?: string;
|
|
904
|
+
itemId?: string;
|
|
905
|
+
};
|
|
906
|
+
/**
|
|
907
|
+
* `409 quantity_unavailable`: the app refused the quantity. Nothing in the
|
|
908
|
+
* cart changed. `maxQuantity` is how many can be ordered, when known.
|
|
909
|
+
*/
|
|
910
|
+
declare class QuantityUnavailableError extends ThrottleApiError {
|
|
911
|
+
readonly details?: QuantityUnavailableDetails;
|
|
912
|
+
readonly reason: string | null;
|
|
913
|
+
readonly maxQuantity: number | null;
|
|
914
|
+
constructor(args: CartErrorArgs);
|
|
915
|
+
}
|
|
916
|
+
/** A line refused at checkout hand-off (`line_not_purchasable` `details.lines`). */
|
|
917
|
+
type RefusedCartLine = {
|
|
918
|
+
itemId: string;
|
|
919
|
+
referenceId: string;
|
|
920
|
+
code: string;
|
|
921
|
+
maxQuantity?: number;
|
|
922
|
+
};
|
|
923
|
+
/**
|
|
924
|
+
* `details` of `422 line_not_purchasable`: `{ reason, referenceId, itemId? }`
|
|
925
|
+
* on an add or quantity change, `{ lines }` at the checkout hand-off.
|
|
926
|
+
*/
|
|
927
|
+
type LineNotPurchasableDetails = {
|
|
928
|
+
/** `NOT_FOUND`, `NOT_PURCHASABLE`, `NO_PRICE_IN_CURRENCY` or `PRICE_SOURCE_MISMATCH`. */
|
|
929
|
+
reason?: string;
|
|
930
|
+
referenceId?: string;
|
|
931
|
+
itemId?: string;
|
|
932
|
+
lines?: RefusedCartLine[];
|
|
933
|
+
};
|
|
934
|
+
/**
|
|
935
|
+
* `422 line_not_purchasable`: the app refused the item (`reason`), or, at
|
|
936
|
+
* checkout, some lines cannot be bought (`lines`; remove them or change their
|
|
937
|
+
* quantity, then check out again).
|
|
938
|
+
*/
|
|
939
|
+
declare class LineNotPurchasableError extends ThrottleApiError {
|
|
940
|
+
readonly details?: LineNotPurchasableDetails;
|
|
941
|
+
readonly reason: string | null;
|
|
942
|
+
readonly lines: RefusedCartLine[] | null;
|
|
943
|
+
constructor(args: CartErrorArgs);
|
|
944
|
+
}
|
|
945
|
+
/** `details` of `503 line_resolver_unavailable`. */
|
|
946
|
+
type LineResolverUnavailableDetails = {
|
|
947
|
+
reason?: string;
|
|
948
|
+
};
|
|
949
|
+
/**
|
|
950
|
+
* `503 line_resolver_unavailable`: the app that prices the cart did not
|
|
951
|
+
* answer (or answered badly). Nothing in the cart changed; retry later.
|
|
952
|
+
*/
|
|
953
|
+
declare class LineResolverUnavailableError extends ThrottleApiError {
|
|
954
|
+
readonly details?: LineResolverUnavailableDetails;
|
|
955
|
+
readonly reason: string | null;
|
|
956
|
+
constructor(args: CartErrorArgs);
|
|
957
|
+
}
|
|
958
|
+
/** `details` of `422 line_resolver_not_available`. */
|
|
959
|
+
type LineResolverNotAvailableDetails = {
|
|
960
|
+
reason?: string;
|
|
961
|
+
};
|
|
962
|
+
/**
|
|
963
|
+
* `422 line_resolver_not_available`: the app named in `lineResolver` is not
|
|
964
|
+
* installed (or cannot price carts) in this environment, so no cart was created.
|
|
965
|
+
*/
|
|
966
|
+
declare class LineResolverNotAvailableError extends ThrottleApiError {
|
|
967
|
+
readonly details?: LineResolverNotAvailableDetails;
|
|
968
|
+
readonly reason: string | null;
|
|
969
|
+
constructor(args: CartErrorArgs);
|
|
970
|
+
}
|
|
971
|
+
/** `details` of `422 currency_not_enabled`. */
|
|
972
|
+
type CurrencyNotEnabledDetails = {
|
|
973
|
+
currency: string;
|
|
974
|
+
enabledCurrencies: string[];
|
|
975
|
+
};
|
|
976
|
+
/** `422 currency_not_enabled`: a resolved cart must use the environment's currency. */
|
|
977
|
+
declare class CurrencyNotEnabledError extends ThrottleApiError {
|
|
978
|
+
readonly details?: CurrencyNotEnabledDetails;
|
|
979
|
+
constructor(args: CartErrorArgs);
|
|
980
|
+
}
|
|
981
|
+
/**
|
|
982
|
+
* `422 resolved_lines_required`: the store only accepts cart lines priced by
|
|
983
|
+
* an installed app; create the cart session with `lineResolver`.
|
|
984
|
+
*/
|
|
985
|
+
declare class ResolvedLinesRequiredError extends ThrottleApiError {
|
|
986
|
+
constructor(args: CartErrorArgs);
|
|
987
|
+
}
|
|
988
|
+
/** `details` of `422 line_limit_reached`. */
|
|
989
|
+
type LineLimitReachedDetails = {
|
|
990
|
+
maxLines: number;
|
|
991
|
+
};
|
|
992
|
+
/** `422 line_limit_reached`: a cart holds at most `maxLines` lines priced by one app. */
|
|
993
|
+
declare class LineLimitReachedError extends ThrottleApiError {
|
|
994
|
+
readonly details?: LineLimitReachedDetails;
|
|
995
|
+
constructor(args: CartErrorArgs);
|
|
996
|
+
}
|
|
997
|
+
/**
|
|
998
|
+
* The stored shipping selection after the checkout hand-off re-quoted it.
|
|
999
|
+
* `amount` is the new quote, or null with a `reason`: `method_unavailable`
|
|
1000
|
+
* (no longer offered, so cleared) or `quote_unavailable` (could not be
|
|
1001
|
+
* quoted now; kept for the next hand-off).
|
|
1002
|
+
*/
|
|
1003
|
+
type CartShippingChange = {
|
|
1004
|
+
methodId: string;
|
|
1005
|
+
previousAmount: number;
|
|
1006
|
+
amount: number | null;
|
|
1007
|
+
reason?: 'method_unavailable' | 'quote_unavailable';
|
|
1008
|
+
};
|
|
1009
|
+
/** `details` of `409 cart_prices_changed`. */
|
|
1010
|
+
type CartPricesChangedDetails = {
|
|
1011
|
+
cart: CartSessionCart;
|
|
1012
|
+
shipping?: CartShippingChange;
|
|
1013
|
+
};
|
|
1014
|
+
/**
|
|
1015
|
+
* `409 cart_prices_changed` at checkout: prices (or shipping) changed since
|
|
1016
|
+
* the buyer last saw the cart. The new prices are already applied; show
|
|
1017
|
+
* `cart`, then check out again. `cart` is null when the response carried none.
|
|
1018
|
+
*/
|
|
1019
|
+
declare class CartPricesChangedError extends ThrottleApiError {
|
|
1020
|
+
readonly details?: CartPricesChangedDetails;
|
|
1021
|
+
readonly cart: CartSessionCart | null;
|
|
1022
|
+
readonly shipping: CartShippingChange | null;
|
|
1023
|
+
constructor(args: CartErrorArgs);
|
|
1024
|
+
}
|
|
1025
|
+
/**
|
|
1026
|
+
* `422 shipping_method_unavailable`: on a resolved cart shipping is priced by
|
|
1027
|
+
* Throttle; the method is not one Throttle quotes for this cart.
|
|
1028
|
+
*/
|
|
1029
|
+
declare class ShippingMethodUnavailableError extends ThrottleApiError {
|
|
1030
|
+
constructor(args: CartErrorArgs);
|
|
1031
|
+
}
|
|
1032
|
+
/** `503 shipping_quote_unavailable`: shipping cannot be priced right now. Nothing changed. */
|
|
1033
|
+
declare class ShippingQuoteUnavailableError extends ThrottleApiError {
|
|
1034
|
+
constructor(args: CartErrorArgs);
|
|
1035
|
+
}
|
|
1036
|
+
/** `422 amount_too_large`: the line or cart amount is larger than a cart can hold. */
|
|
1037
|
+
declare class AmountTooLargeError extends ThrottleApiError {
|
|
1038
|
+
constructor(args: CartErrorArgs);
|
|
1039
|
+
}
|
|
1040
|
+
/** `409 cart_changed`: the cart changed while the item was being added; nothing was added. Retry. */
|
|
1041
|
+
declare class CartChangedError extends ThrottleApiError {
|
|
1042
|
+
constructor(args: CartErrorArgs);
|
|
1043
|
+
}
|
|
762
1044
|
/**
|
|
763
1045
|
* Map a raw API error envelope to the most specific Cart SDK error class.
|
|
764
1046
|
* Falls back to {@link ThrottleApiError} for everything unrecognised.
|
|
@@ -771,4 +1053,4 @@ declare function cartErrorFromResponse(args: {
|
|
|
771
1053
|
responseHeaders?: ThrottleErrorArgs['responseHeaders'];
|
|
772
1054
|
}): ThrottleApiError;
|
|
773
1055
|
|
|
774
|
-
export { type AddLineItemInput, type AppliedDiscount, type Cart, type CartAddress, type CartBranding, CartClient, type CartEvent, CartNotFoundError, CartNotOpenError, type CartSession, type CartSessionCart, CartSessionClient, type CartSessionClientOptions, type CartSessionSummary, CartTimeoutError, type CheckoutHandoff, type CheckoutHandoffInput, type CheckoutInput, type CreateCartInput, type CreateCartSessionInput, type ExternalShippingTaxSnapshotInput, type LegacyLineRecurring, type LineItem, type LineRecurringInput, type Order, type SelectShippingInput, type SelectedShipping, type ShippingTaxAddress, type ShippingTaxCalculationResponse, type ShippingTaxCartCalculateInput, type ShippingTaxMethod, type ShippingTaxQuoteInput, type ShippingTaxQuoteItem, type StoredLineRecurring, StorefrontQuoteClient, type SubscriptionInterval, type SubscriptionIntervalUnit, type TaxLine, type TaxLineInput, ThrottleApiError, type UpdateCartInput, type UpdateCartSessionInput, type UpdateLineItemInput, cartErrorFromResponse };
|
|
1056
|
+
export { type AddLineItemInput, type AddResolvedLineItemInput, AmountTooLargeError, type AppliedDiscount, type Cart, type CartAddress, type CartBranding, CartChangedError, CartClient, type CartErrorArgs, type CartEvent, CartNotFoundError, CartNotOpenError, type CartPricesChangedDetails, CartPricesChangedError, type CartSession, type CartSessionCart, CartSessionClient, type CartSessionClientOptions, type CartSessionSummary, type CartShippingChange, CartTimeoutError, type CheckoutHandoff, type CheckoutHandoffInput, type CheckoutInput, type CreateCartInput, type CreateCartSessionInput, type CurrencyNotEnabledDetails, CurrencyNotEnabledError, type ExternalShippingTaxSnapshotInput, type LegacyLineRecurring, type LineItem, type LineLimitReachedDetails, LineLimitReachedError, type LineNotPurchasableDetails, LineNotPurchasableError, type LineRecurringInput, type LineResolution, type LineResolverNotAvailableDetails, LineResolverNotAvailableError, type LineResolverUnavailableDetails, LineResolverUnavailableError, type Order, type PriceLockedDetails, PriceLockedError, type QuantityUnavailableDetails, QuantityUnavailableError, type RefusedCartLine, ResolvedLinesRequiredError, type SelectShippingInput, type SelectShippingMethodInput, type SelectedShipping, ShippingMethodUnavailableError, ShippingQuoteUnavailableError, type ShippingTaxAddress, type ShippingTaxCalculationResponse, type ShippingTaxCartCalculateInput, type ShippingTaxMethod, type ShippingTaxQuoteInput, type ShippingTaxQuoteItem, type StoredLineRecurring, StorefrontQuoteClient, type SubscriptionInterval, type SubscriptionIntervalUnit, type TaxLine, type TaxLineInput, ThrottleApiError, type UpdateCartInput, type UpdateCartSessionInput, type UpdateLineItemInput, cartErrorFromResponse };
|
package/dist/index.d.ts
CHANGED
|
@@ -60,6 +60,14 @@ interface Cart {
|
|
|
60
60
|
lineItems?: LineItem[];
|
|
61
61
|
createdAt: string;
|
|
62
62
|
updatedAt: string;
|
|
63
|
+
/**
|
|
64
|
+
* Resolved carts only: the installed app that prices the cart's owned
|
|
65
|
+
* lines. `extensionId` is null when the installation can no longer be
|
|
66
|
+
* found. Absent on a cart created without `lineResolver`.
|
|
67
|
+
*/
|
|
68
|
+
lineResolver?: {
|
|
69
|
+
extensionId: string | null;
|
|
70
|
+
};
|
|
63
71
|
}
|
|
64
72
|
/**
|
|
65
73
|
* The cart as the session (browser, opaque-token) surface returns it —
|
|
@@ -165,6 +173,55 @@ interface LineItem {
|
|
|
165
173
|
imageUrl: string | null;
|
|
166
174
|
position: number;
|
|
167
175
|
metadata: Record<string, unknown>;
|
|
176
|
+
/**
|
|
177
|
+
* Resolved carts only: the app's last answer for this line, or null on a
|
|
178
|
+
* line the app does not own. Absent on an unresolved cart.
|
|
179
|
+
*/
|
|
180
|
+
resolution?: LineResolution | null;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* An owned line's state on a resolved cart.
|
|
184
|
+
*
|
|
185
|
+
* - `resolved`: the app priced the line on its last answer.
|
|
186
|
+
* - `refused`: the app refused the line on its last answer; `code` says why
|
|
187
|
+
* (`OUT_OF_STOCK`, `QUANTITY_UNAVAILABLE`, `BELOW_MIN`, `ABOVE_MAX`,
|
|
188
|
+
* `NOT_FOUND`, `NOT_PURCHASABLE`, `NO_PRICE_IN_CURRENCY`,
|
|
189
|
+
* `PRICE_SOURCE_MISMATCH`).
|
|
190
|
+
* - `stale`: the last re-resolve failed; the line keeps its earlier price and
|
|
191
|
+
* `code` keeps any earlier refusal. Checkout re-resolves it.
|
|
192
|
+
*
|
|
193
|
+
* `maxQuantity` / `minQuantity` are the limits from the app's last answer
|
|
194
|
+
* (a refusal's own `maxQuantity` wins), or null.
|
|
195
|
+
*/
|
|
196
|
+
interface LineResolution {
|
|
197
|
+
status: 'resolved' | 'refused' | 'stale';
|
|
198
|
+
code: string | null;
|
|
199
|
+
maxQuantity: number | null;
|
|
200
|
+
minQuantity: number | null;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* A line of a resolved cart: the app sets its name, price and image, so the
|
|
204
|
+
* browser sends only which item and how many.
|
|
205
|
+
*/
|
|
206
|
+
interface AddResolvedLineItemInput {
|
|
207
|
+
/** The app's id for the item (for Product Catalog, the variant SKU). */
|
|
208
|
+
referenceId: string;
|
|
209
|
+
/** 1 to 10,000. Defaults to 1. */
|
|
210
|
+
quantity?: number;
|
|
211
|
+
/**
|
|
212
|
+
* Buyer metadata. The reserved keys (`lineResolver`, `requiresShipping`)
|
|
213
|
+
* and the keys that change a shipping or tax quote are set by the app and
|
|
214
|
+
* answer `400 price_locked`.
|
|
215
|
+
*/
|
|
216
|
+
metadata?: Record<string, unknown>;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Pick a shipping method on a resolved cart (or in an environment where
|
|
220
|
+
* browser carts may only hold resolved lines): Throttle quotes the amount,
|
|
221
|
+
* so only the method id is sent.
|
|
222
|
+
*/
|
|
223
|
+
interface SelectShippingMethodInput {
|
|
224
|
+
methodId: string;
|
|
168
225
|
}
|
|
169
226
|
interface SelectedShipping {
|
|
170
227
|
methodId: string;
|
|
@@ -219,6 +276,24 @@ interface CreateCartInput {
|
|
|
219
276
|
currency?: string;
|
|
220
277
|
netN?: number | null;
|
|
221
278
|
metadata?: Record<string, unknown>;
|
|
279
|
+
/**
|
|
280
|
+
* Make this a resolved cart: the installed app with this extension id
|
|
281
|
+
* prices its lines (add them with `items.addResolvedItem()`). Requires
|
|
282
|
+
* `currency`, which must be the environment's currency.
|
|
283
|
+
*/
|
|
284
|
+
lineResolver?: {
|
|
285
|
+
extensionId: string;
|
|
286
|
+
};
|
|
287
|
+
/** Buyer locale passed to the app that prices the lines (BCP 47, e.g. `en-GB`). */
|
|
288
|
+
locale?: string;
|
|
289
|
+
/**
|
|
290
|
+
* Resolved lines to add at create (requires `lineResolver`): 1 to 50, each
|
|
291
|
+
* `referenceId` at most once, priced in one call to the app, all or nothing.
|
|
292
|
+
*/
|
|
293
|
+
lineItems?: Array<{
|
|
294
|
+
referenceId: string;
|
|
295
|
+
quantity?: number;
|
|
296
|
+
}>;
|
|
222
297
|
}
|
|
223
298
|
interface UpdateCartInput {
|
|
224
299
|
customerId?: string;
|
|
@@ -478,6 +553,12 @@ declare class CartClient {
|
|
|
478
553
|
};
|
|
479
554
|
get items(): {
|
|
480
555
|
add: (cartId: string, input: AddLineItemInput) => Promise<LineItem>;
|
|
556
|
+
/**
|
|
557
|
+
* Add a line to a resolved cart (one created with `lineResolver`). Only
|
|
558
|
+
* the item, quantity and metadata are sent; the app sets the name, price
|
|
559
|
+
* and image. Refusals throw the typed resolver errors.
|
|
560
|
+
*/
|
|
561
|
+
addResolvedItem: (cartId: string, input: AddResolvedLineItemInput) => Promise<LineItem>;
|
|
481
562
|
update: (cartId: string, itemId: string, input: UpdateLineItemInput) => Promise<LineItem>;
|
|
482
563
|
remove: (cartId: string, itemId: string) => Promise<void>;
|
|
483
564
|
};
|
|
@@ -567,6 +648,16 @@ interface CreateCartSessionInput {
|
|
|
567
648
|
currency?: string;
|
|
568
649
|
netN?: number;
|
|
569
650
|
metadata?: Record<string, unknown>;
|
|
651
|
+
/**
|
|
652
|
+
* Make this a resolved cart: the installed app with this extension id
|
|
653
|
+
* prices its lines (add them with `addResolvedItem()`). Requires
|
|
654
|
+
* `currency`, which must be the environment's currency.
|
|
655
|
+
*/
|
|
656
|
+
lineResolver?: {
|
|
657
|
+
extensionId: string;
|
|
658
|
+
};
|
|
659
|
+
/** Buyer locale passed to the app that prices the lines (BCP 47, e.g. `en-US`). */
|
|
660
|
+
locale?: string;
|
|
570
661
|
}
|
|
571
662
|
interface CartBranding {
|
|
572
663
|
logoUrl: string | null;
|
|
@@ -660,9 +751,32 @@ declare class CartSessionClient {
|
|
|
660
751
|
*/
|
|
661
752
|
summary(): Promise<CartSessionSummary>;
|
|
662
753
|
addItem(input: AddLineItemInput): Promise<CartSessionCart>;
|
|
754
|
+
/**
|
|
755
|
+
* Add a line to a resolved cart (one created with `lineResolver`). Only the
|
|
756
|
+
* item, quantity and metadata are sent; the app sets the name, price and
|
|
757
|
+
* image. A refusal throws `QuantityUnavailableError`,
|
|
758
|
+
* `LineNotPurchasableError` or `LineResolverUnavailableError`.
|
|
759
|
+
*/
|
|
760
|
+
addResolvedItem(input: AddResolvedLineItemInput): Promise<CartSessionCart>;
|
|
761
|
+
/**
|
|
762
|
+
* Ask the app that prices a resolved cart to re-check every line it owns.
|
|
763
|
+
* `changed` is true when a price, name or refusal changed. An unresolved
|
|
764
|
+
* cart comes back unchanged. Throws `LineResolverUnavailableError` (nothing
|
|
765
|
+
* changed) when the app does not answer.
|
|
766
|
+
*/
|
|
767
|
+
refresh(): Promise<CartSessionCart & {
|
|
768
|
+
changed: boolean;
|
|
769
|
+
}>;
|
|
663
770
|
updateItem(itemId: string, input: UpdateLineItemInput): Promise<CartSessionCart>;
|
|
664
771
|
removeItem(itemId: string): Promise<CartSessionCart>;
|
|
665
772
|
selectShipping(input: SelectShippingInput): Promise<CartSessionCart>;
|
|
773
|
+
/**
|
|
774
|
+
* Pick a shipping method on a resolved cart. Throttle quotes the amount, so
|
|
775
|
+
* only `methodId` is sent. A method Throttle does not quote for the cart
|
|
776
|
+
* (it needs a shipping address first) throws `ShippingMethodUnavailableError`;
|
|
777
|
+
* a failed quote throws `ShippingQuoteUnavailableError`.
|
|
778
|
+
*/
|
|
779
|
+
selectShippingMethod(input: SelectShippingMethodInput): Promise<CartSessionCart>;
|
|
666
780
|
clearShipping(): Promise<CartSessionCart>;
|
|
667
781
|
applyDiscount(code: string): Promise<CartSessionCart>;
|
|
668
782
|
removeDiscount(): Promise<CartSessionCart>;
|
|
@@ -759,6 +873,174 @@ declare class CartTimeoutError extends ThrottleError {
|
|
|
759
873
|
path?: string;
|
|
760
874
|
});
|
|
761
875
|
}
|
|
876
|
+
/** Constructor arguments shared by the resolved-cart error classes. */
|
|
877
|
+
interface CartErrorArgs {
|
|
878
|
+
message: string;
|
|
879
|
+
statusCode?: number;
|
|
880
|
+
details?: Record<string, unknown>;
|
|
881
|
+
responseHeaders?: ThrottleErrorArgs['responseHeaders'];
|
|
882
|
+
}
|
|
883
|
+
/** `details` of `400 price_locked`: the request fields the app sets. */
|
|
884
|
+
type PriceLockedDetails = {
|
|
885
|
+
fields: string[];
|
|
886
|
+
};
|
|
887
|
+
/**
|
|
888
|
+
* `400 price_locked`: the request sent a field the pricing app owns (a
|
|
889
|
+
* price, name, image, or a reserved or quote-affecting metadata key). On a
|
|
890
|
+
* resolved cart, add lines with `addResolvedItem()`.
|
|
891
|
+
*/
|
|
892
|
+
declare class PriceLockedError extends ThrottleApiError {
|
|
893
|
+
readonly details?: PriceLockedDetails;
|
|
894
|
+
/** The refused fields, e.g. `['unitPrice', 'metadata.lineResolver']`. */
|
|
895
|
+
readonly fields: string[];
|
|
896
|
+
constructor(args: CartErrorArgs);
|
|
897
|
+
}
|
|
898
|
+
/** `details` of `409 quantity_unavailable`. */
|
|
899
|
+
type QuantityUnavailableDetails = {
|
|
900
|
+
/** `OUT_OF_STOCK`, `QUANTITY_UNAVAILABLE`, `BELOW_MIN`, `ABOVE_MAX` or `MAX_LINE_ITEM_QUANTITY`. */
|
|
901
|
+
reason: string;
|
|
902
|
+
maxQuantity?: number;
|
|
903
|
+
referenceId?: string;
|
|
904
|
+
itemId?: string;
|
|
905
|
+
};
|
|
906
|
+
/**
|
|
907
|
+
* `409 quantity_unavailable`: the app refused the quantity. Nothing in the
|
|
908
|
+
* cart changed. `maxQuantity` is how many can be ordered, when known.
|
|
909
|
+
*/
|
|
910
|
+
declare class QuantityUnavailableError extends ThrottleApiError {
|
|
911
|
+
readonly details?: QuantityUnavailableDetails;
|
|
912
|
+
readonly reason: string | null;
|
|
913
|
+
readonly maxQuantity: number | null;
|
|
914
|
+
constructor(args: CartErrorArgs);
|
|
915
|
+
}
|
|
916
|
+
/** A line refused at checkout hand-off (`line_not_purchasable` `details.lines`). */
|
|
917
|
+
type RefusedCartLine = {
|
|
918
|
+
itemId: string;
|
|
919
|
+
referenceId: string;
|
|
920
|
+
code: string;
|
|
921
|
+
maxQuantity?: number;
|
|
922
|
+
};
|
|
923
|
+
/**
|
|
924
|
+
* `details` of `422 line_not_purchasable`: `{ reason, referenceId, itemId? }`
|
|
925
|
+
* on an add or quantity change, `{ lines }` at the checkout hand-off.
|
|
926
|
+
*/
|
|
927
|
+
type LineNotPurchasableDetails = {
|
|
928
|
+
/** `NOT_FOUND`, `NOT_PURCHASABLE`, `NO_PRICE_IN_CURRENCY` or `PRICE_SOURCE_MISMATCH`. */
|
|
929
|
+
reason?: string;
|
|
930
|
+
referenceId?: string;
|
|
931
|
+
itemId?: string;
|
|
932
|
+
lines?: RefusedCartLine[];
|
|
933
|
+
};
|
|
934
|
+
/**
|
|
935
|
+
* `422 line_not_purchasable`: the app refused the item (`reason`), or, at
|
|
936
|
+
* checkout, some lines cannot be bought (`lines`; remove them or change their
|
|
937
|
+
* quantity, then check out again).
|
|
938
|
+
*/
|
|
939
|
+
declare class LineNotPurchasableError extends ThrottleApiError {
|
|
940
|
+
readonly details?: LineNotPurchasableDetails;
|
|
941
|
+
readonly reason: string | null;
|
|
942
|
+
readonly lines: RefusedCartLine[] | null;
|
|
943
|
+
constructor(args: CartErrorArgs);
|
|
944
|
+
}
|
|
945
|
+
/** `details` of `503 line_resolver_unavailable`. */
|
|
946
|
+
type LineResolverUnavailableDetails = {
|
|
947
|
+
reason?: string;
|
|
948
|
+
};
|
|
949
|
+
/**
|
|
950
|
+
* `503 line_resolver_unavailable`: the app that prices the cart did not
|
|
951
|
+
* answer (or answered badly). Nothing in the cart changed; retry later.
|
|
952
|
+
*/
|
|
953
|
+
declare class LineResolverUnavailableError extends ThrottleApiError {
|
|
954
|
+
readonly details?: LineResolverUnavailableDetails;
|
|
955
|
+
readonly reason: string | null;
|
|
956
|
+
constructor(args: CartErrorArgs);
|
|
957
|
+
}
|
|
958
|
+
/** `details` of `422 line_resolver_not_available`. */
|
|
959
|
+
type LineResolverNotAvailableDetails = {
|
|
960
|
+
reason?: string;
|
|
961
|
+
};
|
|
962
|
+
/**
|
|
963
|
+
* `422 line_resolver_not_available`: the app named in `lineResolver` is not
|
|
964
|
+
* installed (or cannot price carts) in this environment, so no cart was created.
|
|
965
|
+
*/
|
|
966
|
+
declare class LineResolverNotAvailableError extends ThrottleApiError {
|
|
967
|
+
readonly details?: LineResolverNotAvailableDetails;
|
|
968
|
+
readonly reason: string | null;
|
|
969
|
+
constructor(args: CartErrorArgs);
|
|
970
|
+
}
|
|
971
|
+
/** `details` of `422 currency_not_enabled`. */
|
|
972
|
+
type CurrencyNotEnabledDetails = {
|
|
973
|
+
currency: string;
|
|
974
|
+
enabledCurrencies: string[];
|
|
975
|
+
};
|
|
976
|
+
/** `422 currency_not_enabled`: a resolved cart must use the environment's currency. */
|
|
977
|
+
declare class CurrencyNotEnabledError extends ThrottleApiError {
|
|
978
|
+
readonly details?: CurrencyNotEnabledDetails;
|
|
979
|
+
constructor(args: CartErrorArgs);
|
|
980
|
+
}
|
|
981
|
+
/**
|
|
982
|
+
* `422 resolved_lines_required`: the store only accepts cart lines priced by
|
|
983
|
+
* an installed app; create the cart session with `lineResolver`.
|
|
984
|
+
*/
|
|
985
|
+
declare class ResolvedLinesRequiredError extends ThrottleApiError {
|
|
986
|
+
constructor(args: CartErrorArgs);
|
|
987
|
+
}
|
|
988
|
+
/** `details` of `422 line_limit_reached`. */
|
|
989
|
+
type LineLimitReachedDetails = {
|
|
990
|
+
maxLines: number;
|
|
991
|
+
};
|
|
992
|
+
/** `422 line_limit_reached`: a cart holds at most `maxLines` lines priced by one app. */
|
|
993
|
+
declare class LineLimitReachedError extends ThrottleApiError {
|
|
994
|
+
readonly details?: LineLimitReachedDetails;
|
|
995
|
+
constructor(args: CartErrorArgs);
|
|
996
|
+
}
|
|
997
|
+
/**
|
|
998
|
+
* The stored shipping selection after the checkout hand-off re-quoted it.
|
|
999
|
+
* `amount` is the new quote, or null with a `reason`: `method_unavailable`
|
|
1000
|
+
* (no longer offered, so cleared) or `quote_unavailable` (could not be
|
|
1001
|
+
* quoted now; kept for the next hand-off).
|
|
1002
|
+
*/
|
|
1003
|
+
type CartShippingChange = {
|
|
1004
|
+
methodId: string;
|
|
1005
|
+
previousAmount: number;
|
|
1006
|
+
amount: number | null;
|
|
1007
|
+
reason?: 'method_unavailable' | 'quote_unavailable';
|
|
1008
|
+
};
|
|
1009
|
+
/** `details` of `409 cart_prices_changed`. */
|
|
1010
|
+
type CartPricesChangedDetails = {
|
|
1011
|
+
cart: CartSessionCart;
|
|
1012
|
+
shipping?: CartShippingChange;
|
|
1013
|
+
};
|
|
1014
|
+
/**
|
|
1015
|
+
* `409 cart_prices_changed` at checkout: prices (or shipping) changed since
|
|
1016
|
+
* the buyer last saw the cart. The new prices are already applied; show
|
|
1017
|
+
* `cart`, then check out again. `cart` is null when the response carried none.
|
|
1018
|
+
*/
|
|
1019
|
+
declare class CartPricesChangedError extends ThrottleApiError {
|
|
1020
|
+
readonly details?: CartPricesChangedDetails;
|
|
1021
|
+
readonly cart: CartSessionCart | null;
|
|
1022
|
+
readonly shipping: CartShippingChange | null;
|
|
1023
|
+
constructor(args: CartErrorArgs);
|
|
1024
|
+
}
|
|
1025
|
+
/**
|
|
1026
|
+
* `422 shipping_method_unavailable`: on a resolved cart shipping is priced by
|
|
1027
|
+
* Throttle; the method is not one Throttle quotes for this cart.
|
|
1028
|
+
*/
|
|
1029
|
+
declare class ShippingMethodUnavailableError extends ThrottleApiError {
|
|
1030
|
+
constructor(args: CartErrorArgs);
|
|
1031
|
+
}
|
|
1032
|
+
/** `503 shipping_quote_unavailable`: shipping cannot be priced right now. Nothing changed. */
|
|
1033
|
+
declare class ShippingQuoteUnavailableError extends ThrottleApiError {
|
|
1034
|
+
constructor(args: CartErrorArgs);
|
|
1035
|
+
}
|
|
1036
|
+
/** `422 amount_too_large`: the line or cart amount is larger than a cart can hold. */
|
|
1037
|
+
declare class AmountTooLargeError extends ThrottleApiError {
|
|
1038
|
+
constructor(args: CartErrorArgs);
|
|
1039
|
+
}
|
|
1040
|
+
/** `409 cart_changed`: the cart changed while the item was being added; nothing was added. Retry. */
|
|
1041
|
+
declare class CartChangedError extends ThrottleApiError {
|
|
1042
|
+
constructor(args: CartErrorArgs);
|
|
1043
|
+
}
|
|
762
1044
|
/**
|
|
763
1045
|
* Map a raw API error envelope to the most specific Cart SDK error class.
|
|
764
1046
|
* Falls back to {@link ThrottleApiError} for everything unrecognised.
|
|
@@ -771,4 +1053,4 @@ declare function cartErrorFromResponse(args: {
|
|
|
771
1053
|
responseHeaders?: ThrottleErrorArgs['responseHeaders'];
|
|
772
1054
|
}): ThrottleApiError;
|
|
773
1055
|
|
|
774
|
-
export { type AddLineItemInput, type AppliedDiscount, type Cart, type CartAddress, type CartBranding, CartClient, type CartEvent, CartNotFoundError, CartNotOpenError, type CartSession, type CartSessionCart, CartSessionClient, type CartSessionClientOptions, type CartSessionSummary, CartTimeoutError, type CheckoutHandoff, type CheckoutHandoffInput, type CheckoutInput, type CreateCartInput, type CreateCartSessionInput, type ExternalShippingTaxSnapshotInput, type LegacyLineRecurring, type LineItem, type LineRecurringInput, type Order, type SelectShippingInput, type SelectedShipping, type ShippingTaxAddress, type ShippingTaxCalculationResponse, type ShippingTaxCartCalculateInput, type ShippingTaxMethod, type ShippingTaxQuoteInput, type ShippingTaxQuoteItem, type StoredLineRecurring, StorefrontQuoteClient, type SubscriptionInterval, type SubscriptionIntervalUnit, type TaxLine, type TaxLineInput, ThrottleApiError, type UpdateCartInput, type UpdateCartSessionInput, type UpdateLineItemInput, cartErrorFromResponse };
|
|
1056
|
+
export { type AddLineItemInput, type AddResolvedLineItemInput, AmountTooLargeError, type AppliedDiscount, type Cart, type CartAddress, type CartBranding, CartChangedError, CartClient, type CartErrorArgs, type CartEvent, CartNotFoundError, CartNotOpenError, type CartPricesChangedDetails, CartPricesChangedError, type CartSession, type CartSessionCart, CartSessionClient, type CartSessionClientOptions, type CartSessionSummary, type CartShippingChange, CartTimeoutError, type CheckoutHandoff, type CheckoutHandoffInput, type CheckoutInput, type CreateCartInput, type CreateCartSessionInput, type CurrencyNotEnabledDetails, CurrencyNotEnabledError, type ExternalShippingTaxSnapshotInput, type LegacyLineRecurring, type LineItem, type LineLimitReachedDetails, LineLimitReachedError, type LineNotPurchasableDetails, LineNotPurchasableError, type LineRecurringInput, type LineResolution, type LineResolverNotAvailableDetails, LineResolverNotAvailableError, type LineResolverUnavailableDetails, LineResolverUnavailableError, type Order, type PriceLockedDetails, PriceLockedError, type QuantityUnavailableDetails, QuantityUnavailableError, type RefusedCartLine, ResolvedLinesRequiredError, type SelectShippingInput, type SelectShippingMethodInput, type SelectedShipping, ShippingMethodUnavailableError, ShippingQuoteUnavailableError, type ShippingTaxAddress, type ShippingTaxCalculationResponse, type ShippingTaxCartCalculateInput, type ShippingTaxMethod, type ShippingTaxQuoteInput, type ShippingTaxQuoteItem, type StoredLineRecurring, StorefrontQuoteClient, type SubscriptionInterval, type SubscriptionIntervalUnit, type TaxLine, type TaxLineInput, ThrottleApiError, type UpdateCartInput, type UpdateCartSessionInput, type UpdateLineItemInput, cartErrorFromResponse };
|
package/dist/index.js
CHANGED
|
@@ -42,6 +42,130 @@ var CartTimeoutError = class extends ThrottleError {
|
|
|
42
42
|
this.name = "CartTimeoutError";
|
|
43
43
|
}
|
|
44
44
|
};
|
|
45
|
+
function coded(code, statusCode, args) {
|
|
46
|
+
return {
|
|
47
|
+
code,
|
|
48
|
+
statusCode: args.statusCode ?? statusCode,
|
|
49
|
+
message: args.message,
|
|
50
|
+
details: args.details,
|
|
51
|
+
responseHeaders: args.responseHeaders
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
var str = (v) => typeof v === "string" ? v : null;
|
|
55
|
+
var num = (v) => typeof v === "number" ? v : null;
|
|
56
|
+
var PriceLockedError = class extends ThrottleApiError {
|
|
57
|
+
/** The refused fields, e.g. `['unitPrice', 'metadata.lineResolver']`. */
|
|
58
|
+
fields;
|
|
59
|
+
constructor(args) {
|
|
60
|
+
super(coded("price_locked", 400, args));
|
|
61
|
+
this.name = "PriceLockedError";
|
|
62
|
+
this.fields = Array.isArray(args.details?.fields) ? args.details.fields : [];
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
var QuantityUnavailableError = class extends ThrottleApiError {
|
|
66
|
+
reason;
|
|
67
|
+
maxQuantity;
|
|
68
|
+
constructor(args) {
|
|
69
|
+
super(coded("quantity_unavailable", 409, args));
|
|
70
|
+
this.name = "QuantityUnavailableError";
|
|
71
|
+
this.reason = str(args.details?.reason);
|
|
72
|
+
this.maxQuantity = num(args.details?.maxQuantity);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
var LineNotPurchasableError = class extends ThrottleApiError {
|
|
76
|
+
reason;
|
|
77
|
+
lines;
|
|
78
|
+
constructor(args) {
|
|
79
|
+
super(coded("line_not_purchasable", 422, args));
|
|
80
|
+
this.name = "LineNotPurchasableError";
|
|
81
|
+
this.reason = str(args.details?.reason);
|
|
82
|
+
this.lines = Array.isArray(args.details?.lines) ? args.details.lines : null;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
var LineResolverUnavailableError = class extends ThrottleApiError {
|
|
86
|
+
reason;
|
|
87
|
+
constructor(args) {
|
|
88
|
+
super(coded("line_resolver_unavailable", 503, args));
|
|
89
|
+
this.name = "LineResolverUnavailableError";
|
|
90
|
+
this.reason = str(args.details?.reason);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
var LineResolverNotAvailableError = class extends ThrottleApiError {
|
|
94
|
+
reason;
|
|
95
|
+
constructor(args) {
|
|
96
|
+
super(coded("line_resolver_not_available", 422, args));
|
|
97
|
+
this.name = "LineResolverNotAvailableError";
|
|
98
|
+
this.reason = str(args.details?.reason);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
var CurrencyNotEnabledError = class extends ThrottleApiError {
|
|
102
|
+
constructor(args) {
|
|
103
|
+
super(coded("currency_not_enabled", 422, args));
|
|
104
|
+
this.name = "CurrencyNotEnabledError";
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
var ResolvedLinesRequiredError = class extends ThrottleApiError {
|
|
108
|
+
constructor(args) {
|
|
109
|
+
super(coded("resolved_lines_required", 422, args));
|
|
110
|
+
this.name = "ResolvedLinesRequiredError";
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
var LineLimitReachedError = class extends ThrottleApiError {
|
|
114
|
+
constructor(args) {
|
|
115
|
+
super(coded("line_limit_reached", 422, args));
|
|
116
|
+
this.name = "LineLimitReachedError";
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
var CartPricesChangedError = class extends ThrottleApiError {
|
|
120
|
+
cart;
|
|
121
|
+
shipping;
|
|
122
|
+
constructor(args) {
|
|
123
|
+
super(coded("cart_prices_changed", 409, args));
|
|
124
|
+
this.name = "CartPricesChangedError";
|
|
125
|
+
const d = args.details;
|
|
126
|
+
this.cart = d?.cart && typeof d.cart === "object" ? d.cart : null;
|
|
127
|
+
this.shipping = d?.shipping && typeof d.shipping === "object" ? d.shipping : null;
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
var ShippingMethodUnavailableError = class extends ThrottleApiError {
|
|
131
|
+
constructor(args) {
|
|
132
|
+
super(coded("shipping_method_unavailable", 422, args));
|
|
133
|
+
this.name = "ShippingMethodUnavailableError";
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
var ShippingQuoteUnavailableError = class extends ThrottleApiError {
|
|
137
|
+
constructor(args) {
|
|
138
|
+
super(coded("shipping_quote_unavailable", 503, args));
|
|
139
|
+
this.name = "ShippingQuoteUnavailableError";
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
var AmountTooLargeError = class extends ThrottleApiError {
|
|
143
|
+
constructor(args) {
|
|
144
|
+
super(coded("amount_too_large", 422, args));
|
|
145
|
+
this.name = "AmountTooLargeError";
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
var CartChangedError = class extends ThrottleApiError {
|
|
149
|
+
constructor(args) {
|
|
150
|
+
super(coded("cart_changed", 409, args));
|
|
151
|
+
this.name = "CartChangedError";
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
var RESOLVED_CART_ERRORS = {
|
|
155
|
+
price_locked: PriceLockedError,
|
|
156
|
+
quantity_unavailable: QuantityUnavailableError,
|
|
157
|
+
line_not_purchasable: LineNotPurchasableError,
|
|
158
|
+
line_resolver_unavailable: LineResolverUnavailableError,
|
|
159
|
+
line_resolver_not_available: LineResolverNotAvailableError,
|
|
160
|
+
currency_not_enabled: CurrencyNotEnabledError,
|
|
161
|
+
resolved_lines_required: ResolvedLinesRequiredError,
|
|
162
|
+
line_limit_reached: LineLimitReachedError,
|
|
163
|
+
cart_prices_changed: CartPricesChangedError,
|
|
164
|
+
shipping_method_unavailable: ShippingMethodUnavailableError,
|
|
165
|
+
shipping_quote_unavailable: ShippingQuoteUnavailableError,
|
|
166
|
+
amount_too_large: AmountTooLargeError,
|
|
167
|
+
cart_changed: CartChangedError
|
|
168
|
+
};
|
|
45
169
|
function cartErrorFromResponse(args) {
|
|
46
170
|
if (args.statusCode === 409 && args.code === "cart_not_open") {
|
|
47
171
|
return new CartNotOpenError({
|
|
@@ -59,6 +183,15 @@ function cartErrorFromResponse(args) {
|
|
|
59
183
|
responseHeaders: args.responseHeaders
|
|
60
184
|
});
|
|
61
185
|
}
|
|
186
|
+
const ResolvedCartError = Object.prototype.hasOwnProperty.call(RESOLVED_CART_ERRORS, args.code) ? RESOLVED_CART_ERRORS[args.code] : void 0;
|
|
187
|
+
if (ResolvedCartError) {
|
|
188
|
+
return new ResolvedCartError({
|
|
189
|
+
message: args.message,
|
|
190
|
+
statusCode: args.statusCode,
|
|
191
|
+
details: args.details,
|
|
192
|
+
responseHeaders: args.responseHeaders
|
|
193
|
+
});
|
|
194
|
+
}
|
|
62
195
|
return new ThrottleApiError(args);
|
|
63
196
|
}
|
|
64
197
|
|
|
@@ -116,6 +249,17 @@ var CartClient = class {
|
|
|
116
249
|
get items() {
|
|
117
250
|
return {
|
|
118
251
|
add: (cartId, input) => this.request("POST", `/api/v1/carts/${segment(cartId)}/items`, input),
|
|
252
|
+
/**
|
|
253
|
+
* Add a line to a resolved cart (one created with `lineResolver`). Only
|
|
254
|
+
* the item, quantity and metadata are sent; the app sets the name, price
|
|
255
|
+
* and image. Refusals throw the typed resolver errors.
|
|
256
|
+
*/
|
|
257
|
+
addResolvedItem: (cartId, input) => {
|
|
258
|
+
const body = { referenceId: input.referenceId };
|
|
259
|
+
if (input.quantity !== void 0) body.quantity = input.quantity;
|
|
260
|
+
if (input.metadata !== void 0) body.metadata = input.metadata;
|
|
261
|
+
return this.request("POST", `/api/v1/carts/${segment(cartId)}/items`, body);
|
|
262
|
+
},
|
|
119
263
|
update: (cartId, itemId, input) => this.request("PATCH", `/api/v1/carts/${segment(cartId)}/items/${segment(itemId)}`, input),
|
|
120
264
|
remove: (cartId, itemId) => this.request("DELETE", `/api/v1/carts/${segment(cartId)}/items/${segment(itemId)}`)
|
|
121
265
|
};
|
|
@@ -288,6 +432,32 @@ var CartSessionClient = class _CartSessionClient {
|
|
|
288
432
|
async addItem(input) {
|
|
289
433
|
return (await this.request("POST", `${this.basePath()}/items`, input)).cart;
|
|
290
434
|
}
|
|
435
|
+
/**
|
|
436
|
+
* Add a line to a resolved cart (one created with `lineResolver`). Only the
|
|
437
|
+
* item, quantity and metadata are sent; the app sets the name, price and
|
|
438
|
+
* image. A refusal throws `QuantityUnavailableError`,
|
|
439
|
+
* `LineNotPurchasableError` or `LineResolverUnavailableError`.
|
|
440
|
+
*/
|
|
441
|
+
async addResolvedItem(input) {
|
|
442
|
+
const body = { referenceId: input.referenceId };
|
|
443
|
+
if (input.quantity !== void 0) body.quantity = input.quantity;
|
|
444
|
+
if (input.metadata !== void 0) body.metadata = input.metadata;
|
|
445
|
+
return (await this.request("POST", `${this.basePath()}/items`, body)).cart;
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Ask the app that prices a resolved cart to re-check every line it owns.
|
|
449
|
+
* `changed` is true when a price, name or refusal changed. An unresolved
|
|
450
|
+
* cart comes back unchanged. Throws `LineResolverUnavailableError` (nothing
|
|
451
|
+
* changed) when the app does not answer.
|
|
452
|
+
*/
|
|
453
|
+
async refresh() {
|
|
454
|
+
const data = await this.request(
|
|
455
|
+
"POST",
|
|
456
|
+
`${this.basePath()}/refresh`,
|
|
457
|
+
{}
|
|
458
|
+
);
|
|
459
|
+
return { ...data.cart, changed: data.changed };
|
|
460
|
+
}
|
|
291
461
|
async updateItem(itemId, input) {
|
|
292
462
|
return (await this.request(
|
|
293
463
|
"PATCH",
|
|
@@ -301,6 +471,17 @@ var CartSessionClient = class _CartSessionClient {
|
|
|
301
471
|
async selectShipping(input) {
|
|
302
472
|
return (await this.request("POST", `${this.basePath()}/shipping`, input)).cart;
|
|
303
473
|
}
|
|
474
|
+
/**
|
|
475
|
+
* Pick a shipping method on a resolved cart. Throttle quotes the amount, so
|
|
476
|
+
* only `methodId` is sent. A method Throttle does not quote for the cart
|
|
477
|
+
* (it needs a shipping address first) throws `ShippingMethodUnavailableError`;
|
|
478
|
+
* a failed quote throws `ShippingQuoteUnavailableError`.
|
|
479
|
+
*/
|
|
480
|
+
async selectShippingMethod(input) {
|
|
481
|
+
return (await this.request("POST", `${this.basePath()}/shipping`, {
|
|
482
|
+
methodId: input.methodId
|
|
483
|
+
})).cart;
|
|
484
|
+
}
|
|
304
485
|
async clearShipping() {
|
|
305
486
|
return (await this.request("DELETE", `${this.basePath()}/shipping`)).cart;
|
|
306
487
|
}
|
|
@@ -388,11 +569,24 @@ var CartSessionClient = class _CartSessionClient {
|
|
|
388
569
|
}
|
|
389
570
|
};
|
|
390
571
|
export {
|
|
572
|
+
AmountTooLargeError,
|
|
573
|
+
CartChangedError,
|
|
391
574
|
CartClient,
|
|
392
575
|
CartNotFoundError,
|
|
393
576
|
CartNotOpenError,
|
|
577
|
+
CartPricesChangedError,
|
|
394
578
|
CartSessionClient,
|
|
395
579
|
CartTimeoutError,
|
|
580
|
+
CurrencyNotEnabledError,
|
|
581
|
+
LineLimitReachedError,
|
|
582
|
+
LineNotPurchasableError,
|
|
583
|
+
LineResolverNotAvailableError,
|
|
584
|
+
LineResolverUnavailableError,
|
|
585
|
+
PriceLockedError,
|
|
586
|
+
QuantityUnavailableError,
|
|
587
|
+
ResolvedLinesRequiredError,
|
|
588
|
+
ShippingMethodUnavailableError,
|
|
589
|
+
ShippingQuoteUnavailableError,
|
|
396
590
|
StorefrontQuoteClient,
|
|
397
591
|
ThrottleApiError,
|
|
398
592
|
ThrottleError2 as ThrottleError,
|