@usethrottle/catalog 1.2.0 → 1.3.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/CHANGELOG.md +12 -0
- package/README.md +7 -7
- package/dist/admin.cjs +16 -16
- package/dist/admin.d.cts +3 -2
- package/dist/admin.d.ts +3 -2
- package/dist/admin.js +1 -1
- package/dist/{catalog-error-yTBMAdCv.d.cts → catalog-error-BOaSKgY3.d.cts} +11 -1
- package/dist/{catalog-error-7DCsTyB2.d.ts → catalog-error-CSoPS0-d.d.ts} +11 -1
- package/dist/{chunk-B2DYAHNR.cjs → chunk-2YQNMBDI.cjs} +78 -23
- package/dist/{chunk-55G4ZTD5.js → chunk-3DLH56OX.js} +58 -3
- package/dist/{chunk-JNBKKAMP.js → chunk-CADIHOIR.js} +9 -1
- package/dist/{chunk-TDMDOHD3.cjs → chunk-GU63WFXI.cjs} +16 -8
- package/dist/{client-BrHJCyBP.d.cts → client-6j1Iz-iJ.d.cts} +1 -1
- package/dist/{client-Dm6I4nAZ.d.ts → client-B3mL2-xJ.d.ts} +1 -1
- package/dist/{contract-types-BPSzY_Co.d.ts → contract-types-BRyonOYH.d.cts} +11 -9
- package/dist/{contract-types-BPSzY_Co.d.cts → contract-types-BRyonOYH.d.ts} +11 -9
- package/dist/index.cjs +24 -2
- package/dist/index.d.cts +8 -5
- package/dist/index.d.ts +8 -5
- package/dist/index.js +25 -3
- package/dist/react-extras.cjs +8 -8
- package/dist/react-extras.d.cts +4 -3
- package/dist/react-extras.d.ts +4 -3
- package/dist/react-extras.js +2 -2
- package/dist/react.cjs +126 -54
- package/dist/react.d.cts +34 -10
- package/dist/react.d.ts +34 -10
- package/dist/react.js +108 -36
- package/dist/server.cjs +13 -13
- package/dist/server.d.cts +2 -1
- package/dist/server.d.ts +2 -1
- package/dist/server.js +1 -1
- package/dist/{types-BTrqSprj.d.cts → types-BfveENg1.d.ts} +43 -7
- package/dist/{types-BlYCKzB8.d.ts → types-D0PywKnN.d.cts} +43 -7
- package/dist/url.d.cts +2 -1
- package/dist/url.d.ts +2 -1
- package/dist/{use-query-QOEBuYlp.d.ts → use-query-CR7r5tam.d.ts} +1 -1
- package/dist/{use-query-BZgjxGPO.d.cts → use-query-UWf6Pi5g.d.cts} +1 -1
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @usethrottle/catalog
|
|
2
2
|
|
|
3
|
+
## 1.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- e159fc9: Multi-currency slice 2. Everything is additive: without the new calls the SDK behaves as 1.2.0.
|
|
8
|
+
|
|
9
|
+
- Money helpers from `@usethrottle/money` (a new dependency, `^1.0.0`): the `money` namespace and, by name, `formatMoney`, `currencySymbol`, `toDecimalString`, `toMinor`, `parseMoney`, `minorUnitsOf`, `isKnownCurrency`, `moneyValue`, `CURRENCIES`, `UnknownCurrencyError` and the `CurrencyCode` and `MoneyValue` types. Prices are integers in the minor units of their currency; format them with `formatMoney`.
|
|
10
|
+
- `CurrencyCode` typing on every price object's `currency` (product, variant, price list and cart line), `CartView.currency` and `OpenCartRef.currency`. `CartOptions.currency` stays `string`.
|
|
11
|
+
- `useCart().format(minor)` formats an amount in the cart's currency.
|
|
12
|
+
- `useCart().switchCurrency(next)` finds or creates the shopper's cart in `next` and moves the current cart's lines into it through Throttle's absorb route. Signed in, it finds the customer's open cart in that currency; as a guest, it reads the optional `CartStorage` per-currency slots (`getFor`, `setFor`, `removeFor`, implemented by `createMemoryCartStorage`). With no target it creates an empty cart in `next`. Removed lines and a dropped discount are reported through the hook's `warnings`. Any failure keeps the old cart, its stored id and its currency.
|
|
13
|
+
- The catalog Worker now accepts an empty cart create (`items: []`), which the switch needs. Older clients are unaffected.
|
|
14
|
+
|
|
3
15
|
## 1.2.0
|
|
4
16
|
|
|
5
17
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -32,13 +32,13 @@ for (const product of products) {
|
|
|
32
32
|
}
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
Prices are integers in minor units (
|
|
35
|
+
Prices are integers in the minor units of their currency; format them with `formatMoney` (`formatMoney(product.priceRange.minMinor, product.priceRange.currency)` gives `$19.99` for USD and `¥1,999` for JPY, the same on the server and in the browser). The root re-exports `@usethrottle/money` as `money` and by name (`formatMoney`, `currencySymbol`, `minorUnitsOf`, `toDecimalString`, `toMinor`, `parseMoney`, `moneyValue`, `CURRENCIES`, `isKnownCurrency`, `UnknownCurrencyError`, and the types `CurrencyCode` and `MoneyValue`); every `currency` the SDK answers is a `CurrencyCode`, which is still assignable to `string`. The client talks to `https://catalog.usethrottle.dev` by default (`baseUrl` changes it). Every call takes `{ signal, timeoutMs }`; the default timeout is 10 seconds.
|
|
36
36
|
|
|
37
37
|
## Entries
|
|
38
38
|
|
|
39
39
|
| Import | What it holds |
|
|
40
40
|
| ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
41
|
-
| `@usethrottle/catalog` | `createCatalogClient`, the error classes and `isCatalogError`, and the
|
|
41
|
+
| `@usethrottle/catalog` | `createCatalogClient`, the error classes and `isCatalogError`, the answer types, and the `@usethrottle/money` helpers (`money`, `formatMoney`, …). No DOM and no Node-only API. |
|
|
42
42
|
| `@usethrottle/catalog/react` | `CatalogProvider`, the read hooks, `useCart`, `useSubmitReview` and `useCustomerKey` (marked `"use client"`). |
|
|
43
43
|
| `@usethrottle/catalog/react/extras` | `useTags`, `useCollections` and `useReviewEligibility` (marked `"use client"`). They share `CatalogProvider` and the cache with `/react`: import the provider from `/react` and these three from here. |
|
|
44
44
|
| `@usethrottle/catalog/server` | `createServerCatalogClient`, `catalogTags`, `syncCatalogGeneration` and the paging helpers (`listAllProductHandles`, `staticProductParams`, `listAllCollectionHandles`, `listAllCategoryHandles`: it asks for `CATEGORY_TREE_MAX_DEPTH` levels, 10, so a sitemap lists the whole tree). |
|
|
@@ -105,7 +105,7 @@ try {
|
|
|
105
105
|
|
|
106
106
|
## Carts and checkout
|
|
107
107
|
|
|
108
|
-
Carts are resolved by the catalog: the browser sends SKUs and quantities, never prices. `carts.create` answers Throttle's hosted cart URL (`cartUrl`) and a session id. It takes three optional URLs, each an absolute `https` URL on the store's Checkout settings › Allowed return websites (otherwise `422 RETURN_URL_NOT_ALLOWED`, one issue per refused field):
|
|
108
|
+
Carts are resolved by the catalog: the browser sends SKUs and quantities, never prices. `carts.create` answers Throttle's hosted cart URL (`cartUrl`) and a session id; `items` may be empty, for an empty cart in a currency. It takes three optional URLs, each an absolute `https` URL on the store's Checkout settings › Allowed return websites (otherwise `422 RETURN_URL_NOT_ALLOWED`, one issue per refused field):
|
|
109
109
|
|
|
110
110
|
```ts
|
|
111
111
|
const cart = await catalog.carts.create({
|
|
@@ -117,7 +117,7 @@ const cart = await catalog.carts.create({
|
|
|
117
117
|
// cart.returnUrlApplied is false when Throttle did not store them.
|
|
118
118
|
```
|
|
119
119
|
|
|
120
|
-
Without them the shopper ends on Throttle's own completion page. To build your own cart page instead, use `catalog.carts.session(cart.sessionId)` (`get`, `add`, `update`, `remove`, `refresh`, `checkout({ returnUrl, cancelUrl })`). `checkout()` answers the checkout URL; it never navigates. Both are checked before any request: `carts.create` refuses a URL that is not absolute `https` (`INVALID_REQUEST`, naming the field), and `checkout()` one that is not absolute `http` or `https`.
|
|
120
|
+
Without them the shopper ends on Throttle's own completion page. To build your own cart page instead, use `catalog.carts.session(cart.sessionId)` (`get`, `add`, `update`, `remove`, `refresh`, `checkout({ returnUrl, cancelUrl })`, and `absorb(fromSessionId)`, which moves another session's cart into this one in this cart's currency, answering `{ cart, warnings }`; `useCart().switchCurrency` is built on it). `checkout()` answers the checkout URL; it never navigates. Both are checked before any request: `carts.create` refuses a URL that is not absolute `https` (`INVALID_REQUEST`, naming the field), and `checkout()` one that is not absolute `http` or `https`.
|
|
121
121
|
|
|
122
122
|
## React
|
|
123
123
|
|
|
@@ -191,7 +191,7 @@ function ProductGrid() {
|
|
|
191
191
|
- **Hooks:** `useProducts`, `useProduct`, `useRelated`, `useFilterValues`, `useCategories`, `useCollection`, `useSuggest` (debounced 200 ms, 2 characters at least), `useReviews` and `useConfig` from `/react`; `useTags`, `useCollections` and `useReviewEligibility` from `/react/extras` (below). Each answers `{ data, dataFor, error, isLoading, isPreviousData, isStale, isValidating, refetch }` and takes `enabled`, `initialData` (for an SSR hand-off), `staleTimeMs` and `keepPreviousData`. With a signed-in customer (`customerKey` set), `initialData` is shown and revalidated at once, since a server render with the server key is anonymous; to avoid the brief list-price paint, render the server side with the customer's token.
|
|
192
192
|
- **The cache** is per provider: answers are shown at once and refetched when older than 60 seconds, and calls for one key share one request. Two providers never share it.
|
|
193
193
|
- **`customerKey`** partitions the cache by customer. Change it in the same update as the token: a change starts an empty cache and every mounted hook refetches, so one customer never sees another's prices. It is required whenever `customerToken` can return a token: `useCart` drops the cart on a sign-out or a customer change only by watching it, so without it one customer's cart stays for the next shopper. Keep one `client` per currency and language (see [One client per currency and language](#one-client-per-currency-and-language)) and pass `customerToken` as a function.
|
|
194
|
-
- **`useCart`** keeps one cart per provider and runs its changes one at a time. It creates the cart on the first `add
|
|
194
|
+
- **`useCart`** keeps one cart per provider and runs its changes one at a time. It creates the cart on the first `add` and recreates it once if Throttle ended the session. `format(minor)` formats an amount in the cart's currency (`useCart().format(4763)` on a EUR cart is `€47.63`). **`switchCurrency(currency)`** keeps one cart per currency: it moves the cart into the shopper's open cart in that currency (a signed-in customer's from `customerCart`; a guest's from `cartStorage.getFor`, used only while that cart is still open), or into a new empty cart when there is none, and Throttle closes the old cart as merged. Lines with no price in the new currency stay behind and a discount code the new currency refuses is dropped; both are reported in `warnings` (`lines_removed`, `discount_dropped`). If anything fails before the move lands (the lookup, the new cart, the move itself, for example `422 currency_not_available_in_production`), `switchCurrency` rejects and the old cart, its stored id and the old currency stay. A signed-in switch needs `customerToken` on the client: the new cart is created as the customer's, and Throttle moves a customer's cart only into that customer's cart (`403 cart_owner_mismatch` otherwise). A `cartStorage` adapter may implement the optional `getFor(currency)`, `setFor(currency, id)` and `removeFor(currency)` (`createMemoryCartStorage` does); without them a guest switch always makes a new cart. These are guest slots: a signed-in switch never writes them, and the provider forgets them on a sign-in, a sign-out or a customer change (through `removeFor`, or `setFor(currency, '')` when the adapter has no `removeFor`), so the next guest never reaches a customer's cart. The cart is dropped when the signed-in customer signs out or changes, and kept on sign-in. `checkout()` uses the provider's `cartUrls` unless given URLs, and answers the checkout URL. `cartUrls` go on every cart create, so they must be absolute `https` URLs on the store's Allowed return websites, or every `add` fails; otherwise (on `http://localhost`, say) leave them out and pass the URLs to `checkout(input)`. The default `cartStorage` is memory only; key a persistent one by customer, as above: a new adapter object per customer, never one stable object that reads the current customer when called (a drop removes the outgoing customer's entry through the outgoing object, so such an adapter would delete the incoming customer's cart instead).
|
|
195
195
|
- **Rate limits:** a catalog `429` pauses every read of the provider until its retry time; each mounted key then refetches once.
|
|
196
196
|
- **`useSubmitReview(handle)`** submits a review with one idempotency key per submission.
|
|
197
197
|
|
|
@@ -229,7 +229,7 @@ function Shell({ customerId, children }) {
|
|
|
229
229
|
}
|
|
230
230
|
```
|
|
231
231
|
|
|
232
|
-
`useCart` looks the cart up once per visit when the slot is empty (or ended), and before it would create a new cart. **It resumes only when a currency is known:** set `currency` on the client (`createCatalogClient({ currency: 'USD' })`) or pass it to the hook, `useCart({ currency: 'USD' })`. With neither, `useCart` makes no lookup and the first `add` creates a cart as before. A found cart in another currency is not adopted. Without `customerCart` nothing changes from 1.1.0.
|
|
232
|
+
`useCart` looks the cart up once per visit when the slot is empty (or ended), and before it would create a new cart. **It resumes only when a currency is known:** set `currency` on the client (`createCatalogClient({ currency: 'USD' })`) or pass it to the hook, `useCart({ currency: 'USD' })`. With neither, `useCart` makes no lookup and the first `add` creates a cart as before. A found cart in another currency is not adopted. Without `customerCart` nothing changes from 1.1.0. Throttle refuses a write to a cart another device merged (`409 cart_not_open`), so it is never reopened; `useCart` then looks the customer's cart up. `switchCurrency` while signed in looks up the customer's open cart in the new currency and moves the cart into it, so a customer keeps one cart per currency across devices. The lookup runs once per visit, so a currency that becomes known only after mount does not trigger it; the first `add` finds the cart instead. With two `useCart` call sites that pass different currencies, the lookup and the create can use different currencies; pass one currency (or set it on the client).
|
|
233
233
|
|
|
234
234
|
### Key transport
|
|
235
235
|
|
|
@@ -444,7 +444,7 @@ The OpenAPI 3.1 document of the storefront API is at https://catalog.usethrottle
|
|
|
444
444
|
|
|
445
445
|
### One client per currency and language
|
|
446
446
|
|
|
447
|
-
Hooks take no per-call currency or language: both come from the client. A store with a currency or language switcher keeps one client per `(currency, locale)`, memoised on both, so the client changes only when one of them does. On a currency switch, run `useCart().switchCurrency()` first and swap the client only once it resolves.
|
|
447
|
+
Hooks take no per-call currency or language: both come from the client. A store with a currency or language switcher keeps one client per `(currency, locale)`, memoised on both, so the client changes only when one of them does. On a currency switch, run `useCart().switchCurrency()` first and swap the client only once it resolves. When it rejects, the cart is still in the old currency, so keep the old client; when it resolves, show `cart.warnings` (lines left behind, a dropped discount code).
|
|
448
448
|
|
|
449
449
|
```tsx
|
|
450
450
|
'use client';
|
package/dist/admin.cjs
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
var
|
|
13
|
+
var _chunk2YQNMBDIcjs = require('./chunk-2YQNMBDI.cjs');
|
|
14
14
|
require('./chunk-ETV4XYOV.cjs');
|
|
15
15
|
|
|
16
16
|
// src/generated/push-types.ts
|
|
@@ -45,7 +45,7 @@ var MAX_IDEMPOTENCY_KEY = 200;
|
|
|
45
45
|
var HEADER_SAFE = /^[\x21-\x7e]+$/u;
|
|
46
46
|
var MAX_RETRY_AFTER_S = 86400;
|
|
47
47
|
function invalidRequest(message) {
|
|
48
|
-
return new (0,
|
|
48
|
+
return new (0, _chunk2YQNMBDIcjs.CatalogError)({
|
|
49
49
|
code: "INVALID_REQUEST",
|
|
50
50
|
message,
|
|
51
51
|
statusCode: 0,
|
|
@@ -54,7 +54,7 @@ function invalidRequest(message) {
|
|
|
54
54
|
});
|
|
55
55
|
}
|
|
56
56
|
function clientError(code, message) {
|
|
57
|
-
return new (0,
|
|
57
|
+
return new (0, _chunk2YQNMBDIcjs.CatalogError)({
|
|
58
58
|
code,
|
|
59
59
|
message,
|
|
60
60
|
statusCode: 0,
|
|
@@ -126,13 +126,13 @@ function toError(status, headers, text) {
|
|
|
126
126
|
requestId
|
|
127
127
|
};
|
|
128
128
|
if (status === 429) {
|
|
129
|
-
return new (0,
|
|
129
|
+
return new (0, _chunk2YQNMBDIcjs.RateLimitedError)({
|
|
130
130
|
...init,
|
|
131
131
|
retryable: true,
|
|
132
|
-
retryAfterSeconds: retryAfter !== null && retryAfter >= 1 ? retryAfter :
|
|
132
|
+
retryAfterSeconds: retryAfter !== null && retryAfter >= 1 ? retryAfter : _chunk2YQNMBDIcjs.RATE_LIMIT_DEFAULT_RETRY_S
|
|
133
133
|
});
|
|
134
134
|
}
|
|
135
|
-
return new (0,
|
|
135
|
+
return new (0, _chunk2YQNMBDIcjs.CatalogError)(init);
|
|
136
136
|
}
|
|
137
137
|
function guarded(work, callerSignal, timeoutMs) {
|
|
138
138
|
if (_optionalChain([callerSignal, 'optionalAccess', _8 => _8.aborted])) return Promise.reject(callerSignal.reason);
|
|
@@ -151,7 +151,7 @@ function guarded(work, callerSignal, timeoutMs) {
|
|
|
151
151
|
const timer = setTimeout(() => {
|
|
152
152
|
finish();
|
|
153
153
|
controller.abort();
|
|
154
|
-
reject(new (0,
|
|
154
|
+
reject(new (0, _chunk2YQNMBDIcjs.TimeoutError)({ timeoutMs }));
|
|
155
155
|
}, timeoutMs);
|
|
156
156
|
_optionalChain([callerSignal, 'optionalAccess', _12 => _12.addEventListener, 'call', _13 => _13("abort", onAbort, { once: true })]);
|
|
157
157
|
work(controller.signal).then(
|
|
@@ -194,7 +194,7 @@ function createHttp(key, baseUrl, fetchFn, timeoutMs) {
|
|
|
194
194
|
signal
|
|
195
195
|
});
|
|
196
196
|
} catch (cause) {
|
|
197
|
-
throw new (0,
|
|
197
|
+
throw new (0, _chunk2YQNMBDIcjs.NetworkError)({ cause });
|
|
198
198
|
}
|
|
199
199
|
try {
|
|
200
200
|
return {
|
|
@@ -203,14 +203,14 @@ function createHttp(key, baseUrl, fetchFn, timeoutMs) {
|
|
|
203
203
|
text: await response.text()
|
|
204
204
|
};
|
|
205
205
|
} catch (cause) {
|
|
206
|
-
throw new (0,
|
|
206
|
+
throw new (0, _chunk2YQNMBDIcjs.NetworkError)({ cause });
|
|
207
207
|
}
|
|
208
208
|
},
|
|
209
209
|
spec.signal,
|
|
210
210
|
timeoutMs
|
|
211
211
|
);
|
|
212
212
|
} catch (error) {
|
|
213
|
-
if (error instanceof
|
|
213
|
+
if (error instanceof _chunk2YQNMBDIcjs.NetworkError && attempt < attempts) continue;
|
|
214
214
|
throw error;
|
|
215
215
|
}
|
|
216
216
|
}
|
|
@@ -223,7 +223,7 @@ function createHttp(key, baseUrl, fetchFn, timeoutMs) {
|
|
|
223
223
|
throw toError(answer.status, answer.headers, answer.text);
|
|
224
224
|
const parsed = parseJson(answer.text);
|
|
225
225
|
if (parsed === void 0)
|
|
226
|
-
throw new (0,
|
|
226
|
+
throw new (0, _chunk2YQNMBDIcjs.CatalogError)({
|
|
227
227
|
code: "INVALID_RESPONSE",
|
|
228
228
|
message: "The server answered with a body that is not JSON.",
|
|
229
229
|
statusCode: answer.status,
|
|
@@ -278,7 +278,7 @@ function refQuery(ref) {
|
|
|
278
278
|
return [[field, value]];
|
|
279
279
|
}
|
|
280
280
|
function unreadable() {
|
|
281
|
-
return new (0,
|
|
281
|
+
return new (0, _chunk2YQNMBDIcjs.CatalogError)({
|
|
282
282
|
code: "INVALID_RESPONSE",
|
|
283
283
|
message: "The server answered with an unexpected shape.",
|
|
284
284
|
statusCode: 200,
|
|
@@ -367,7 +367,7 @@ async function pollUntil(read, done, options = {}) {
|
|
|
367
367
|
const value = await read(options.signal);
|
|
368
368
|
if (done(value)) return value;
|
|
369
369
|
const remaining = deadline - Date.now();
|
|
370
|
-
if (remaining <= 0) throw new (0,
|
|
370
|
+
if (remaining <= 0) throw new (0, _chunk2YQNMBDIcjs.TimeoutError)({ timeoutMs });
|
|
371
371
|
await sleep(Math.min(intervalMs, remaining), options.signal);
|
|
372
372
|
}
|
|
373
373
|
}
|
|
@@ -452,7 +452,7 @@ function createJobs(http) {
|
|
|
452
452
|
await handle.send(rows, { idempotencyKey });
|
|
453
453
|
return;
|
|
454
454
|
} catch (error) {
|
|
455
|
-
if (!(error instanceof
|
|
455
|
+
if (!(error instanceof _chunk2YQNMBDIcjs.RateLimitedError) || retry >= QUEUE_RETRIES)
|
|
456
456
|
throw error;
|
|
457
457
|
await sleep(error.retryAfterSeconds * 1e3, signal);
|
|
458
458
|
}
|
|
@@ -589,7 +589,7 @@ function assertServer() {
|
|
|
589
589
|
function createCatalogAdmin(options) {
|
|
590
590
|
assertServer();
|
|
591
591
|
const key = checkKey(options.key);
|
|
592
|
-
const baseUrl = (_nullishCoalesce(options.baseUrl, () => (
|
|
592
|
+
const baseUrl = (_nullishCoalesce(options.baseUrl, () => ( _chunk2YQNMBDIcjs.DEFAULT_BASE_URL))).replace(/\/+$/u, "");
|
|
593
593
|
if (!/^https?:\/\/[^\s/]+/iu.test(baseUrl))
|
|
594
594
|
throw invalidRequest("baseUrl must be an absolute http or https URL.");
|
|
595
595
|
const http = createHttp(
|
|
@@ -678,4 +678,4 @@ async function verifyCatalogWebhook(input) {
|
|
|
678
678
|
|
|
679
679
|
|
|
680
680
|
|
|
681
|
-
exports.CartLineError =
|
|
681
|
+
exports.CartLineError = _chunk2YQNMBDIcjs.CartLineError; exports.CatalogError = _chunk2YQNMBDIcjs.CatalogError; exports.CustomerTokenInvalidError = _chunk2YQNMBDIcjs.CustomerTokenInvalidError; exports.FeatureUnavailableError = _chunk2YQNMBDIcjs.FeatureUnavailableError; exports.NetworkError = _chunk2YQNMBDIcjs.NetworkError; exports.OriginNotAllowedError = _chunk2YQNMBDIcjs.OriginNotAllowedError; exports.RateLimitedError = _chunk2YQNMBDIcjs.RateLimitedError; exports.TimeoutError = _chunk2YQNMBDIcjs.TimeoutError; exports.createCatalogAdmin = createCatalogAdmin; exports.isCatalogError = _chunk2YQNMBDIcjs.isCatalogError; exports.verifyCatalogWebhook = verifyCatalogWebhook;
|
package/dist/admin.d.cts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export { C as CartLineError, a as CartLineProblem, b as CatalogError, c as CatalogErrorCode, d as CatalogErrorInit, e as CatalogErrorIssue, f as CatalogErrorSource, g as ClientErrorCode, h as CustomerTokenInvalidError, F as FeatureUnavailableError, N as NetworkError, O as OriginNotAllowedError, R as RateLimitedError, T as TimeoutError, i as isCatalogError } from './catalog-error-
|
|
2
|
-
import './contract-types-
|
|
1
|
+
export { C as CartLineError, a as CartLineProblem, b as CatalogError, c as CatalogErrorCode, d as CatalogErrorInit, e as CatalogErrorIssue, f as CatalogErrorSource, g as ClientErrorCode, h as CustomerTokenInvalidError, F as FeatureUnavailableError, N as NetworkError, O as OriginNotAllowedError, R as RateLimitedError, T as TimeoutError, i as isCatalogError } from './catalog-error-BOaSKgY3.cjs';
|
|
2
|
+
import './contract-types-BRyonOYH.cjs';
|
|
3
|
+
import '@usethrottle/money';
|
|
3
4
|
|
|
4
5
|
type JobBatchAnswer = {
|
|
5
6
|
batchId: string;
|
package/dist/admin.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export { C as CartLineError, a as CartLineProblem, b as CatalogError, c as CatalogErrorCode, d as CatalogErrorInit, e as CatalogErrorIssue, f as CatalogErrorSource, g as ClientErrorCode, h as CustomerTokenInvalidError, F as FeatureUnavailableError, N as NetworkError, O as OriginNotAllowedError, R as RateLimitedError, T as TimeoutError, i as isCatalogError } from './catalog-error-
|
|
2
|
-
import './contract-types-
|
|
1
|
+
export { C as CartLineError, a as CartLineProblem, b as CatalogError, c as CatalogErrorCode, d as CatalogErrorInit, e as CatalogErrorIssue, f as CatalogErrorSource, g as ClientErrorCode, h as CustomerTokenInvalidError, F as FeatureUnavailableError, N as NetworkError, O as OriginNotAllowedError, R as RateLimitedError, T as TimeoutError, i as isCatalogError } from './catalog-error-CSoPS0-d.js';
|
|
2
|
+
import './contract-types-BRyonOYH.js';
|
|
3
|
+
import '@usethrottle/money';
|
|
3
4
|
|
|
4
5
|
type JobBatchAnswer = {
|
|
5
6
|
batchId: string;
|
package/dist/admin.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as CatalogContractErrorCode } from './contract-types-
|
|
1
|
+
import { i as CatalogContractErrorCode } from './contract-types-BRyonOYH.cjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Shared error type for every Throttle SDK.
|
|
@@ -153,6 +153,16 @@ declare const THROTTLE_CART_CODES: {
|
|
|
153
153
|
readonly statuses: readonly [501];
|
|
154
154
|
readonly retryable: false;
|
|
155
155
|
};
|
|
156
|
+
/** The absorb (MC2-R39): a customer's cart never moves into a guest's or another customer's. */
|
|
157
|
+
readonly cart_owner_mismatch: {
|
|
158
|
+
readonly statuses: readonly [403];
|
|
159
|
+
readonly retryable: false;
|
|
160
|
+
};
|
|
161
|
+
/** The absorb: the two carts are priced by different apps. */
|
|
162
|
+
readonly cart_resolver_mismatch: {
|
|
163
|
+
readonly statuses: readonly [422];
|
|
164
|
+
readonly retryable: false;
|
|
165
|
+
};
|
|
156
166
|
};
|
|
157
167
|
type ThrottleCartCode = keyof typeof THROTTLE_CART_CODES;
|
|
158
168
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as CatalogContractErrorCode } from './contract-types-
|
|
1
|
+
import { i as CatalogContractErrorCode } from './contract-types-BRyonOYH.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Shared error type for every Throttle SDK.
|
|
@@ -153,6 +153,16 @@ declare const THROTTLE_CART_CODES: {
|
|
|
153
153
|
readonly statuses: readonly [501];
|
|
154
154
|
readonly retryable: false;
|
|
155
155
|
};
|
|
156
|
+
/** The absorb (MC2-R39): a customer's cart never moves into a guest's or another customer's. */
|
|
157
|
+
readonly cart_owner_mismatch: {
|
|
158
|
+
readonly statuses: readonly [403];
|
|
159
|
+
readonly retryable: false;
|
|
160
|
+
};
|
|
161
|
+
/** The absorb: the two carts are priced by different apps. */
|
|
162
|
+
readonly cart_resolver_mismatch: {
|
|
163
|
+
readonly statuses: readonly [422];
|
|
164
|
+
readonly retryable: false;
|
|
165
|
+
};
|
|
156
166
|
};
|
|
157
167
|
type ThrottleCartCode = keyof typeof THROTTLE_CART_CODES;
|
|
158
168
|
|
|
@@ -1,9 +1,24 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
|
|
2
2
|
|
|
3
3
|
var _chunkETV4XYOVcjs = require('./chunk-ETV4XYOV.cjs');
|
|
4
4
|
|
|
5
5
|
// src/version.ts
|
|
6
|
-
var SDK_VERSION = true ? "1.
|
|
6
|
+
var SDK_VERSION = true ? "1.3.0" : "0.0.0-dev";
|
|
7
|
+
|
|
8
|
+
// src/index.ts
|
|
9
|
+
var _money = require('@usethrottle/money'); var money = _interopRequireWildcard(_money);
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
7
22
|
|
|
8
23
|
// src/errors/catalog-error.ts
|
|
9
24
|
var _errors = require('@usethrottle/errors');
|
|
@@ -190,6 +205,8 @@ var ERROR_KINDS = Object.freeze({
|
|
|
190
205
|
cart_session_not_found: "base",
|
|
191
206
|
origin_not_allowed: "origin",
|
|
192
207
|
checkout_unavailable: "base",
|
|
208
|
+
cart_owner_mismatch: "base",
|
|
209
|
+
cart_resolver_mismatch: "base",
|
|
193
210
|
// Client codes.
|
|
194
211
|
TIMEOUT: "timeout",
|
|
195
212
|
NETWORK_ERROR: "network",
|
|
@@ -731,6 +748,9 @@ function createTransport(o) {
|
|
|
731
748
|
function createCartSession(options, sessionId, throttleBaseUrl) {
|
|
732
749
|
const base = (_nullishCoalesce(throttleBaseUrl, () => ( THROTTLE_API_URL))).replace(/\/+$/u, "");
|
|
733
750
|
async function call(method, tail, body, opts, accept) {
|
|
751
|
+
return (await exchange(method, tail, body, opts, accept)).data;
|
|
752
|
+
}
|
|
753
|
+
async function exchange(method, tail, body, opts, accept) {
|
|
734
754
|
const signal = _optionalChain([opts, 'optionalAccess', _30 => _30.signal]);
|
|
735
755
|
if (_optionalChain([signal, 'optionalAccess', _31 => _31.aborted])) throw signal.reason;
|
|
736
756
|
const timeoutMs = _optionalChain([opts, 'optionalAccess', _32 => _32.timeoutMs]) === void 0 ? options.timeoutMs : checkTimeout(opts.timeoutMs);
|
|
@@ -768,7 +788,10 @@ function createCartSession(options, sessionId, throttleBaseUrl) {
|
|
|
768
788
|
retryable: false
|
|
769
789
|
});
|
|
770
790
|
}
|
|
771
|
-
return
|
|
791
|
+
return {
|
|
792
|
+
data,
|
|
793
|
+
meta: parsed.meta
|
|
794
|
+
};
|
|
772
795
|
}
|
|
773
796
|
throw toCatalogError(mapInput);
|
|
774
797
|
}
|
|
@@ -811,6 +834,27 @@ function createCartSession(options, sessionId, throttleBaseUrl) {
|
|
|
811
834
|
opts,
|
|
812
835
|
(data) => isHttpUrl(data.checkoutUrl)
|
|
813
836
|
);
|
|
837
|
+
},
|
|
838
|
+
absorb: async (fromSessionId, opts) => {
|
|
839
|
+
const { data, meta } = await exchange(
|
|
840
|
+
"POST",
|
|
841
|
+
() => "/absorb",
|
|
842
|
+
{ fromSessionId },
|
|
843
|
+
opts
|
|
844
|
+
);
|
|
845
|
+
if (typeof data.cart !== "object" || data.cart === null)
|
|
846
|
+
throw new CatalogError({
|
|
847
|
+
code: "INVALID_RESPONSE",
|
|
848
|
+
message: "Throttle answered an absorb without a cart.",
|
|
849
|
+
statusCode: 200,
|
|
850
|
+
source: "throttle",
|
|
851
|
+
retryable: false
|
|
852
|
+
});
|
|
853
|
+
const warnings = _optionalChain([meta, 'optionalAccess', _36 => _36.warnings]);
|
|
854
|
+
return {
|
|
855
|
+
cart: data.cart,
|
|
856
|
+
warnings: Array.isArray(warnings) ? warnings : []
|
|
857
|
+
};
|
|
814
858
|
}
|
|
815
859
|
};
|
|
816
860
|
}
|
|
@@ -839,7 +883,7 @@ function createCarts(transport, options) {
|
|
|
839
883
|
// The input's own currency and locale win over the call's and the
|
|
840
884
|
// client's; the return URLs are sent unchanged (P6-R2).
|
|
841
885
|
create: async (input, opts) => {
|
|
842
|
-
if (_optionalChain([opts, 'optionalAccess',
|
|
886
|
+
if (_optionalChain([opts, 'optionalAccess', _37 => _37.signal, 'optionalAccess', _38 => _38.aborted])) throw opts.signal.reason;
|
|
843
887
|
for (const field of [
|
|
844
888
|
"returnUrl",
|
|
845
889
|
"cancelUrl",
|
|
@@ -862,12 +906,12 @@ function createCarts(transport, options) {
|
|
|
862
906
|
customerToken: "optional",
|
|
863
907
|
tokenFallback: "throw",
|
|
864
908
|
featureRoute: true,
|
|
865
|
-
..._optionalChain([opts, 'optionalAccess',
|
|
909
|
+
..._optionalChain([opts, 'optionalAccess', _39 => _39.idempotencyKey]) === void 0 ? {} : { idempotencyKey: opts.idempotencyKey }
|
|
866
910
|
},
|
|
867
911
|
opts
|
|
868
912
|
);
|
|
869
913
|
},
|
|
870
|
-
session: (sessionId, opts) => createCartSession(options, sessionId, _optionalChain([opts, 'optionalAccess',
|
|
914
|
+
session: (sessionId, opts) => createCartSession(options, sessionId, _optionalChain([opts, 'optionalAccess', _40 => _40.throttleBaseUrl]))
|
|
871
915
|
};
|
|
872
916
|
}
|
|
873
917
|
|
|
@@ -908,11 +952,11 @@ function productsQuery(query = {}) {
|
|
|
908
952
|
featured: query.featured,
|
|
909
953
|
handles: query.handles,
|
|
910
954
|
skus: query.skus,
|
|
911
|
-
year: _optionalChain([vehicle, 'optionalAccess',
|
|
912
|
-
make: _optionalChain([vehicle, 'optionalAccess',
|
|
913
|
-
model: _optionalChain([vehicle, 'optionalAccess',
|
|
914
|
-
submodel: _optionalChain([vehicle, 'optionalAccess',
|
|
915
|
-
engine: _optionalChain([vehicle, 'optionalAccess',
|
|
955
|
+
year: _optionalChain([vehicle, 'optionalAccess', _41 => _41.year]),
|
|
956
|
+
make: _optionalChain([vehicle, 'optionalAccess', _42 => _42.make]),
|
|
957
|
+
model: _optionalChain([vehicle, 'optionalAccess', _43 => _43.model]),
|
|
958
|
+
submodel: _optionalChain([vehicle, 'optionalAccess', _44 => _44.submodel]),
|
|
959
|
+
engine: _optionalChain([vehicle, 'optionalAccess', _45 => _45.engine]),
|
|
916
960
|
sort: query.sort,
|
|
917
961
|
limit: query.limit,
|
|
918
962
|
page: query.page,
|
|
@@ -950,7 +994,7 @@ function createProducts(transport) {
|
|
|
950
994
|
path: `${SF}/products/${pathSegment(handle)}`,
|
|
951
995
|
// Always the full product (P6-R18).
|
|
952
996
|
query: buildQuery(
|
|
953
|
-
{ fields: "full", include: commaList(_optionalChain([opts, 'optionalAccess',
|
|
997
|
+
{ fields: "full", include: commaList(_optionalChain([opts, 'optionalAccess', _46 => _46.include])) },
|
|
954
998
|
["fields", "include"]
|
|
955
999
|
),
|
|
956
1000
|
customerToken: "optional",
|
|
@@ -966,7 +1010,7 @@ function createProducts(transport) {
|
|
|
966
1010
|
method: "GET",
|
|
967
1011
|
path: `${SF}/products/${pathSegment(handle)}/related`,
|
|
968
1012
|
query: buildQuery(
|
|
969
|
-
{ limit: _optionalChain([opts, 'optionalAccess',
|
|
1013
|
+
{ limit: _optionalChain([opts, 'optionalAccess', _47 => _47.limit]), fields: commaList(_optionalChain([opts, 'optionalAccess', _48 => _48.fields])) },
|
|
970
1014
|
["limit", "fields"]
|
|
971
1015
|
),
|
|
972
1016
|
customerToken: "optional",
|
|
@@ -1002,7 +1046,7 @@ function createSuggest(transport) {
|
|
|
1002
1046
|
{
|
|
1003
1047
|
method: "GET",
|
|
1004
1048
|
path: `${SF}/suggest`,
|
|
1005
|
-
query: buildQuery({ q, limit: _optionalChain([opts, 'optionalAccess',
|
|
1049
|
+
query: buildQuery({ q, limit: _optionalChain([opts, 'optionalAccess', _49 => _49.limit]) }, ["q", "limit"]),
|
|
1006
1050
|
// Never a customer token (P8-R22): list prices for everyone.
|
|
1007
1051
|
customerToken: "none",
|
|
1008
1052
|
tokenFree: true,
|
|
@@ -1027,10 +1071,10 @@ function createReviews(transport) {
|
|
|
1027
1071
|
path: reviewsPath(handle),
|
|
1028
1072
|
query: buildQuery(
|
|
1029
1073
|
{
|
|
1030
|
-
sort: _optionalChain([opts, 'optionalAccess',
|
|
1031
|
-
rating: _optionalChain([opts, 'optionalAccess',
|
|
1032
|
-
limit: _optionalChain([opts, 'optionalAccess',
|
|
1033
|
-
cursor: _optionalChain([opts, 'optionalAccess',
|
|
1074
|
+
sort: _optionalChain([opts, 'optionalAccess', _50 => _50.sort]),
|
|
1075
|
+
rating: _optionalChain([opts, 'optionalAccess', _51 => _51.rating]),
|
|
1076
|
+
limit: _optionalChain([opts, 'optionalAccess', _52 => _52.limit]),
|
|
1077
|
+
cursor: _optionalChain([opts, 'optionalAccess', _53 => _53.cursor])
|
|
1034
1078
|
},
|
|
1035
1079
|
["sort", "rating", "limit", "cursor"]
|
|
1036
1080
|
),
|
|
@@ -1062,7 +1106,7 @@ function createReviews(transport) {
|
|
|
1062
1106
|
customerToken: "required",
|
|
1063
1107
|
tokenFallback: "throw",
|
|
1064
1108
|
featureRoute: false,
|
|
1065
|
-
..._optionalChain([opts, 'optionalAccess',
|
|
1109
|
+
..._optionalChain([opts, 'optionalAccess', _54 => _54.idempotencyKey]) === void 0 ? {} : { idempotencyKey: opts.idempotencyKey }
|
|
1066
1110
|
},
|
|
1067
1111
|
opts
|
|
1068
1112
|
)
|
|
@@ -1078,7 +1122,7 @@ function createCategories(transport) {
|
|
|
1078
1122
|
{
|
|
1079
1123
|
method: "GET",
|
|
1080
1124
|
path: `${SF2}/categories`,
|
|
1081
|
-
query: buildQuery({ depth: _optionalChain([opts, 'optionalAccess',
|
|
1125
|
+
query: buildQuery({ depth: _optionalChain([opts, 'optionalAccess', _55 => _55.depth]) }, ["depth"]),
|
|
1082
1126
|
customerToken: "none",
|
|
1083
1127
|
tokenFallback: "anonymous",
|
|
1084
1128
|
featureRoute: true,
|
|
@@ -1107,7 +1151,7 @@ function createTags(transport) {
|
|
|
1107
1151
|
{
|
|
1108
1152
|
method: "GET",
|
|
1109
1153
|
path: `${SF2}/tags`,
|
|
1110
|
-
query: buildQuery({ q: _optionalChain([opts, 'optionalAccess',
|
|
1154
|
+
query: buildQuery({ q: _optionalChain([opts, 'optionalAccess', _56 => _56.q]), limit: _optionalChain([opts, 'optionalAccess', _57 => _57.limit]) }, ["q", "limit"]),
|
|
1111
1155
|
customerToken: "none",
|
|
1112
1156
|
tokenFallback: "anonymous",
|
|
1113
1157
|
featureRoute: true
|
|
@@ -1123,7 +1167,7 @@ function createCollections(transport) {
|
|
|
1123
1167
|
{
|
|
1124
1168
|
method: "GET",
|
|
1125
1169
|
path: `${SF2}/collections`,
|
|
1126
|
-
query: buildQuery({ limit: _optionalChain([opts, 'optionalAccess',
|
|
1170
|
+
query: buildQuery({ limit: _optionalChain([opts, 'optionalAccess', _58 => _58.limit]), cursor: _optionalChain([opts, 'optionalAccess', _59 => _59.cursor]) }, [
|
|
1127
1171
|
"limit",
|
|
1128
1172
|
"cursor"
|
|
1129
1173
|
]),
|
|
@@ -1209,4 +1253,15 @@ function createCatalogClient(options) {
|
|
|
1209
1253
|
|
|
1210
1254
|
|
|
1211
1255
|
|
|
1212
|
-
|
|
1256
|
+
|
|
1257
|
+
|
|
1258
|
+
|
|
1259
|
+
|
|
1260
|
+
|
|
1261
|
+
|
|
1262
|
+
|
|
1263
|
+
|
|
1264
|
+
|
|
1265
|
+
|
|
1266
|
+
|
|
1267
|
+
exports.SDK_VERSION = SDK_VERSION; exports.CatalogError = CatalogError; exports.RateLimitedError = RateLimitedError; exports.OriginNotAllowedError = OriginNotAllowedError; exports.CustomerTokenInvalidError = CustomerTokenInvalidError; exports.CartLineError = CartLineError; exports.TimeoutError = TimeoutError; exports.NetworkError = NetworkError; exports.FeatureUnavailableError = FeatureUnavailableError; exports.isCatalogError = isCatalogError; exports.DEFAULT_BASE_URL = DEFAULT_BASE_URL; exports.THROTTLE_CHECKOUT_URL = THROTTLE_CHECKOUT_URL; exports.RATE_LIMIT_DEFAULT_RETRY_S = RATE_LIMIT_DEFAULT_RETRY_S; exports.STALE_MS = STALE_MS; exports.CACHE_MAX_ENTRIES = CACHE_MAX_ENTRIES; exports.SUGGEST_DEBOUNCE_MS = SUGGEST_DEBOUNCE_MS; exports.SUGGEST_MIN_CHARS = SUGGEST_MIN_CHARS; exports.INDEXING_REVALIDATE_MS = INDEXING_REVALIDATE_MS; exports.CACHE_TAG = CACHE_TAG; exports.TAG_MAX_CHARS = TAG_MAX_CHARS; exports.DEFAULT_REVALIDATE_S = DEFAULT_REVALIDATE_S; exports.LIST_PAGE_SIZE = LIST_PAGE_SIZE; exports.LIST_MAX_HANDLES = LIST_MAX_HANDLES; exports.CATEGORY_TREE_MAX_DEPTH = CATEGORY_TREE_MAX_DEPTH; exports.createCatalogClient = createCatalogClient; exports.money = money; exports.CURRENCIES = _money.CURRENCIES; exports.UnknownCurrencyError = _money.UnknownCurrencyError; exports.currencySymbol = _money.currencySymbol; exports.formatMoney = _money.formatMoney; exports.isKnownCurrency = _money.isKnownCurrency; exports.minorUnitsOf = _money.minorUnitsOf; exports.moneyValue = _money.moneyValue; exports.parseMoney = _money.parseMoney; exports.toDecimalString = _money.toDecimalString; exports.toMinor = _money.toMinor;
|
|
@@ -3,7 +3,22 @@ import {
|
|
|
3
3
|
} from "./chunk-PKBMQBKP.js";
|
|
4
4
|
|
|
5
5
|
// src/version.ts
|
|
6
|
-
var SDK_VERSION = true ? "1.
|
|
6
|
+
var SDK_VERSION = true ? "1.3.0" : "0.0.0-dev";
|
|
7
|
+
|
|
8
|
+
// src/index.ts
|
|
9
|
+
import * as money from "@usethrottle/money";
|
|
10
|
+
import {
|
|
11
|
+
CURRENCIES,
|
|
12
|
+
UnknownCurrencyError,
|
|
13
|
+
currencySymbol,
|
|
14
|
+
formatMoney,
|
|
15
|
+
isKnownCurrency,
|
|
16
|
+
minorUnitsOf,
|
|
17
|
+
moneyValue,
|
|
18
|
+
parseMoney,
|
|
19
|
+
toDecimalString,
|
|
20
|
+
toMinor
|
|
21
|
+
} from "@usethrottle/money";
|
|
7
22
|
|
|
8
23
|
// src/errors/catalog-error.ts
|
|
9
24
|
import { ThrottleError } from "@usethrottle/errors";
|
|
@@ -190,6 +205,8 @@ var ERROR_KINDS = Object.freeze({
|
|
|
190
205
|
cart_session_not_found: "base",
|
|
191
206
|
origin_not_allowed: "origin",
|
|
192
207
|
checkout_unavailable: "base",
|
|
208
|
+
cart_owner_mismatch: "base",
|
|
209
|
+
cart_resolver_mismatch: "base",
|
|
193
210
|
// Client codes.
|
|
194
211
|
TIMEOUT: "timeout",
|
|
195
212
|
NETWORK_ERROR: "network",
|
|
@@ -731,6 +748,9 @@ function createTransport(o) {
|
|
|
731
748
|
function createCartSession(options, sessionId, throttleBaseUrl) {
|
|
732
749
|
const base = (throttleBaseUrl ?? THROTTLE_API_URL).replace(/\/+$/u, "");
|
|
733
750
|
async function call(method, tail, body, opts, accept) {
|
|
751
|
+
return (await exchange(method, tail, body, opts, accept)).data;
|
|
752
|
+
}
|
|
753
|
+
async function exchange(method, tail, body, opts, accept) {
|
|
734
754
|
const signal = opts?.signal;
|
|
735
755
|
if (signal?.aborted) throw signal.reason;
|
|
736
756
|
const timeoutMs = opts?.timeoutMs === void 0 ? options.timeoutMs : checkTimeout(opts.timeoutMs);
|
|
@@ -768,7 +788,10 @@ function createCartSession(options, sessionId, throttleBaseUrl) {
|
|
|
768
788
|
retryable: false
|
|
769
789
|
});
|
|
770
790
|
}
|
|
771
|
-
return
|
|
791
|
+
return {
|
|
792
|
+
data,
|
|
793
|
+
meta: parsed.meta
|
|
794
|
+
};
|
|
772
795
|
}
|
|
773
796
|
throw toCatalogError(mapInput);
|
|
774
797
|
}
|
|
@@ -811,6 +834,27 @@ function createCartSession(options, sessionId, throttleBaseUrl) {
|
|
|
811
834
|
opts,
|
|
812
835
|
(data) => isHttpUrl(data.checkoutUrl)
|
|
813
836
|
);
|
|
837
|
+
},
|
|
838
|
+
absorb: async (fromSessionId, opts) => {
|
|
839
|
+
const { data, meta } = await exchange(
|
|
840
|
+
"POST",
|
|
841
|
+
() => "/absorb",
|
|
842
|
+
{ fromSessionId },
|
|
843
|
+
opts
|
|
844
|
+
);
|
|
845
|
+
if (typeof data.cart !== "object" || data.cart === null)
|
|
846
|
+
throw new CatalogError({
|
|
847
|
+
code: "INVALID_RESPONSE",
|
|
848
|
+
message: "Throttle answered an absorb without a cart.",
|
|
849
|
+
statusCode: 200,
|
|
850
|
+
source: "throttle",
|
|
851
|
+
retryable: false
|
|
852
|
+
});
|
|
853
|
+
const warnings = meta?.warnings;
|
|
854
|
+
return {
|
|
855
|
+
cart: data.cart,
|
|
856
|
+
warnings: Array.isArray(warnings) ? warnings : []
|
|
857
|
+
};
|
|
814
858
|
}
|
|
815
859
|
};
|
|
816
860
|
}
|
|
@@ -1208,5 +1252,16 @@ export {
|
|
|
1208
1252
|
LIST_PAGE_SIZE,
|
|
1209
1253
|
LIST_MAX_HANDLES,
|
|
1210
1254
|
CATEGORY_TREE_MAX_DEPTH,
|
|
1211
|
-
createCatalogClient
|
|
1255
|
+
createCatalogClient,
|
|
1256
|
+
money,
|
|
1257
|
+
CURRENCIES,
|
|
1258
|
+
UnknownCurrencyError,
|
|
1259
|
+
currencySymbol,
|
|
1260
|
+
formatMoney,
|
|
1261
|
+
isKnownCurrency,
|
|
1262
|
+
minorUnitsOf,
|
|
1263
|
+
moneyValue,
|
|
1264
|
+
parseMoney,
|
|
1265
|
+
toDecimalString,
|
|
1266
|
+
toMinor
|
|
1212
1267
|
};
|