@usethrottle/cart 3.12.0 → 3.14.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/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,25 @@ 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`: the environment's currency or one of its extra cart
283
+ * currencies (`cartCurrencies`).
284
+ */
285
+ lineResolver?: {
286
+ extensionId: string;
287
+ };
288
+ /** Buyer locale passed to the app that prices the lines (BCP 47, e.g. `en-GB`). */
289
+ locale?: string;
290
+ /**
291
+ * Resolved lines to add at create (requires `lineResolver`): 1 to 50, each
292
+ * `referenceId` at most once, priced in one call to the app, all or nothing.
293
+ */
294
+ lineItems?: Array<{
295
+ referenceId: string;
296
+ quantity?: number;
297
+ }>;
222
298
  }
223
299
  interface UpdateCartInput {
224
300
  customerId?: string;
@@ -478,6 +554,12 @@ declare class CartClient {
478
554
  };
479
555
  get items(): {
480
556
  add: (cartId: string, input: AddLineItemInput) => Promise<LineItem>;
557
+ /**
558
+ * Add a line to a resolved cart (one created with `lineResolver`). Only
559
+ * the item, quantity and metadata are sent; the app sets the name, price
560
+ * and image. Refusals throw the typed resolver errors.
561
+ */
562
+ addResolvedItem: (cartId: string, input: AddResolvedLineItemInput) => Promise<LineItem>;
481
563
  update: (cartId: string, itemId: string, input: UpdateLineItemInput) => Promise<LineItem>;
482
564
  remove: (cartId: string, itemId: string) => Promise<void>;
483
565
  };
@@ -567,6 +649,17 @@ interface CreateCartSessionInput {
567
649
  currency?: string;
568
650
  netN?: number;
569
651
  metadata?: Record<string, unknown>;
652
+ /**
653
+ * Make this a resolved cart: the installed app with this extension id
654
+ * prices its lines (add them with `addResolvedItem()`). Requires
655
+ * `currency`: the environment's currency or one of its extra cart
656
+ * currencies (`cartCurrencies`).
657
+ */
658
+ lineResolver?: {
659
+ extensionId: string;
660
+ };
661
+ /** Buyer locale passed to the app that prices the lines (BCP 47, e.g. `en-US`). */
662
+ locale?: string;
570
663
  }
571
664
  interface CartBranding {
572
665
  logoUrl: string | null;
@@ -660,9 +753,32 @@ declare class CartSessionClient {
660
753
  */
661
754
  summary(): Promise<CartSessionSummary>;
662
755
  addItem(input: AddLineItemInput): Promise<CartSessionCart>;
756
+ /**
757
+ * Add a line to a resolved cart (one created with `lineResolver`). Only the
758
+ * item, quantity and metadata are sent; the app sets the name, price and
759
+ * image. A refusal throws `QuantityUnavailableError`,
760
+ * `LineNotPurchasableError` or `LineResolverUnavailableError`.
761
+ */
762
+ addResolvedItem(input: AddResolvedLineItemInput): Promise<CartSessionCart>;
763
+ /**
764
+ * Ask the app that prices a resolved cart to re-check every line it owns.
765
+ * `changed` is true when a price, name or refusal changed. An unresolved
766
+ * cart comes back unchanged. Throws `LineResolverUnavailableError` (nothing
767
+ * changed) when the app does not answer.
768
+ */
769
+ refresh(): Promise<CartSessionCart & {
770
+ changed: boolean;
771
+ }>;
663
772
  updateItem(itemId: string, input: UpdateLineItemInput): Promise<CartSessionCart>;
664
773
  removeItem(itemId: string): Promise<CartSessionCart>;
665
774
  selectShipping(input: SelectShippingInput): Promise<CartSessionCart>;
775
+ /**
776
+ * Pick a shipping method on a resolved cart. Throttle quotes the amount, so
777
+ * only `methodId` is sent. A method Throttle does not quote for the cart
778
+ * (it needs a shipping address first) throws `ShippingMethodUnavailableError`;
779
+ * a failed quote throws `ShippingQuoteUnavailableError`.
780
+ */
781
+ selectShippingMethod(input: SelectShippingMethodInput): Promise<CartSessionCart>;
666
782
  clearShipping(): Promise<CartSessionCart>;
667
783
  applyDiscount(code: string): Promise<CartSessionCart>;
668
784
  removeDiscount(): Promise<CartSessionCart>;
@@ -759,6 +875,200 @@ declare class CartTimeoutError extends ThrottleError {
759
875
  path?: string;
760
876
  });
761
877
  }
878
+ /** Constructor arguments shared by the resolved-cart error classes. */
879
+ interface CartErrorArgs {
880
+ message: string;
881
+ statusCode?: number;
882
+ details?: Record<string, unknown>;
883
+ responseHeaders?: ThrottleErrorArgs['responseHeaders'];
884
+ }
885
+ /** `details` of `400 price_locked`: the request fields the app sets. */
886
+ type PriceLockedDetails = {
887
+ fields: string[];
888
+ };
889
+ /**
890
+ * `400 price_locked`: the request sent a field the pricing app owns (a
891
+ * price, name, image, or a reserved or quote-affecting metadata key). On a
892
+ * resolved cart, add lines with `addResolvedItem()`.
893
+ */
894
+ declare class PriceLockedError extends ThrottleApiError {
895
+ readonly details?: PriceLockedDetails;
896
+ /** The refused fields, e.g. `['unitPrice', 'metadata.lineResolver']`. */
897
+ readonly fields: string[];
898
+ constructor(args: CartErrorArgs);
899
+ }
900
+ /** `details` of `409 quantity_unavailable`. */
901
+ type QuantityUnavailableDetails = {
902
+ /** `OUT_OF_STOCK`, `QUANTITY_UNAVAILABLE`, `BELOW_MIN`, `ABOVE_MAX` or `MAX_LINE_ITEM_QUANTITY`. */
903
+ reason: string;
904
+ maxQuantity?: number;
905
+ referenceId?: string;
906
+ itemId?: string;
907
+ };
908
+ /**
909
+ * `409 quantity_unavailable`: the app refused the quantity. Nothing in the
910
+ * cart changed. `maxQuantity` is how many can be ordered, when known.
911
+ */
912
+ declare class QuantityUnavailableError extends ThrottleApiError {
913
+ readonly details?: QuantityUnavailableDetails;
914
+ readonly reason: string | null;
915
+ readonly maxQuantity: number | null;
916
+ constructor(args: CartErrorArgs);
917
+ }
918
+ /** A line refused at checkout hand-off (`line_not_purchasable` `details.lines`). */
919
+ type RefusedCartLine = {
920
+ itemId: string;
921
+ referenceId: string;
922
+ code: string;
923
+ maxQuantity?: number;
924
+ };
925
+ /**
926
+ * `details` of `422 line_not_purchasable`: `{ reason, referenceId, itemId? }`
927
+ * on an add or quantity change, `{ lines }` at the checkout hand-off.
928
+ */
929
+ type LineNotPurchasableDetails = {
930
+ /** `NOT_FOUND`, `NOT_PURCHASABLE`, `NO_PRICE_IN_CURRENCY` or `PRICE_SOURCE_MISMATCH`. */
931
+ reason?: string;
932
+ referenceId?: string;
933
+ itemId?: string;
934
+ lines?: RefusedCartLine[];
935
+ };
936
+ /**
937
+ * `422 line_not_purchasable`: the app refused the item (`reason`), or, at
938
+ * checkout, some lines cannot be bought (`lines`; remove them or change their
939
+ * quantity, then check out again).
940
+ */
941
+ declare class LineNotPurchasableError extends ThrottleApiError {
942
+ readonly details?: LineNotPurchasableDetails;
943
+ readonly reason: string | null;
944
+ readonly lines: RefusedCartLine[] | null;
945
+ constructor(args: CartErrorArgs);
946
+ }
947
+ /** `details` of `503 line_resolver_unavailable`. */
948
+ type LineResolverUnavailableDetails = {
949
+ reason?: string;
950
+ };
951
+ /**
952
+ * `503 line_resolver_unavailable`: the app that prices the cart did not
953
+ * answer (or answered badly). Nothing in the cart changed; retry later.
954
+ */
955
+ declare class LineResolverUnavailableError extends ThrottleApiError {
956
+ readonly details?: LineResolverUnavailableDetails;
957
+ readonly reason: string | null;
958
+ constructor(args: CartErrorArgs);
959
+ }
960
+ /** `details` of `422 line_resolver_not_available`. */
961
+ type LineResolverNotAvailableDetails = {
962
+ reason?: string;
963
+ };
964
+ /**
965
+ * `422 line_resolver_not_available`: the app named in `lineResolver` is not
966
+ * installed (or cannot price carts) in this environment, so no cart was created.
967
+ */
968
+ declare class LineResolverNotAvailableError extends ThrottleApiError {
969
+ readonly details?: LineResolverNotAvailableDetails;
970
+ readonly reason: string | null;
971
+ constructor(args: CartErrorArgs);
972
+ }
973
+ /** `details` of `422 currency_not_enabled`. */
974
+ type CurrencyNotEnabledDetails = {
975
+ currency: string;
976
+ enabledCurrencies: string[];
977
+ };
978
+ /**
979
+ * `422 currency_not_enabled`: a resolved cart must use the environment's
980
+ * currency or one of its extra cart currencies (`enabledCurrencies` lists them).
981
+ */
982
+ declare class CurrencyNotEnabledError extends ThrottleApiError {
983
+ readonly details?: CurrencyNotEnabledDetails;
984
+ constructor(args: CartErrorArgs);
985
+ }
986
+ /**
987
+ * `422 resolved_lines_required`: the store only accepts cart lines priced by
988
+ * an installed app; create the cart session with `lineResolver`.
989
+ */
990
+ declare class ResolvedLinesRequiredError extends ThrottleApiError {
991
+ constructor(args: CartErrorArgs);
992
+ }
993
+ /** `details` of `422 line_limit_reached`. */
994
+ type LineLimitReachedDetails = {
995
+ maxLines: number;
996
+ };
997
+ /** `422 line_limit_reached`: a cart holds at most `maxLines` lines priced by one app. */
998
+ declare class LineLimitReachedError extends ThrottleApiError {
999
+ readonly details?: LineLimitReachedDetails;
1000
+ constructor(args: CartErrorArgs);
1001
+ }
1002
+ /**
1003
+ * The stored shipping selection after the checkout hand-off re-quoted it.
1004
+ * `amount` is the new quote, or null with a `reason`: `method_unavailable`
1005
+ * (no longer offered, so cleared), `quote_unavailable` (could not be
1006
+ * quoted now; kept for the next hand-off) or `shipping_currency_unsupported`
1007
+ * (on a cart in an extra currency, its rate is a non-zero amount in another
1008
+ * currency; kept, and the buyer must choose another method).
1009
+ */
1010
+ type CartShippingChange = {
1011
+ methodId: string;
1012
+ previousAmount: number;
1013
+ amount: number | null;
1014
+ reason?: 'method_unavailable' | 'quote_unavailable' | 'shipping_currency_unsupported';
1015
+ };
1016
+ /** `details` of `409 cart_prices_changed`. */
1017
+ type CartPricesChangedDetails = {
1018
+ cart: CartSessionCart;
1019
+ shipping?: CartShippingChange;
1020
+ };
1021
+ /**
1022
+ * `409 cart_prices_changed` at checkout: prices (or shipping) changed since
1023
+ * the buyer last saw the cart. The new prices are already applied; show
1024
+ * `cart`, then check out again. `cart` is null when the response carried none.
1025
+ */
1026
+ declare class CartPricesChangedError extends ThrottleApiError {
1027
+ readonly details?: CartPricesChangedDetails;
1028
+ readonly cart: CartSessionCart | null;
1029
+ readonly shipping: CartShippingChange | null;
1030
+ constructor(args: CartErrorArgs);
1031
+ }
1032
+ /**
1033
+ * `422 shipping_method_unavailable`: on a resolved cart shipping is priced by
1034
+ * Throttle; the method is not one Throttle quotes for this cart.
1035
+ */
1036
+ declare class ShippingMethodUnavailableError extends ThrottleApiError {
1037
+ constructor(args: CartErrorArgs);
1038
+ }
1039
+ /** `503 shipping_quote_unavailable`: shipping cannot be priced right now. Nothing changed. */
1040
+ declare class ShippingQuoteUnavailableError extends ThrottleApiError {
1041
+ constructor(args: CartErrorArgs);
1042
+ }
1043
+ /** `422 amount_too_large`: the line or cart amount is larger than a cart can hold. */
1044
+ declare class AmountTooLargeError extends ThrottleApiError {
1045
+ constructor(args: CartErrorArgs);
1046
+ }
1047
+ /** `409 cart_changed`: the cart changed while the item was being added; nothing was added. Retry. */
1048
+ declare class CartChangedError extends ThrottleApiError {
1049
+ constructor(args: CartErrorArgs);
1050
+ }
1051
+ /**
1052
+ * `422 discount_currency_unsupported`: a fixed-amount discount can't be used
1053
+ * on a resolved cart in an extra currency. Nothing is applied; a percentage
1054
+ * discount works.
1055
+ */
1056
+ declare class DiscountCurrencyUnsupportedError extends ThrottleApiError {
1057
+ constructor(args: CartErrorArgs);
1058
+ }
1059
+ /**
1060
+ * `422 shipping_currency_unsupported`: on a resolved cart in an extra
1061
+ * currency, a non-zero shipping rate in another currency. Nothing new is
1062
+ * selected; choose a zero-rate method. At the checkout hand-off, `shipping`
1063
+ * is the kept selection.
1064
+ */
1065
+ declare class ShippingCurrencyUnsupportedError extends ThrottleApiError {
1066
+ readonly details?: {
1067
+ shipping?: CartShippingChange;
1068
+ };
1069
+ readonly shipping: CartShippingChange | null;
1070
+ constructor(args: CartErrorArgs);
1071
+ }
762
1072
  /**
763
1073
  * Map a raw API error envelope to the most specific Cart SDK error class.
764
1074
  * Falls back to {@link ThrottleApiError} for everything unrecognised.
@@ -771,4 +1081,4 @@ declare function cartErrorFromResponse(args: {
771
1081
  responseHeaders?: ThrottleErrorArgs['responseHeaders'];
772
1082
  }): ThrottleApiError;
773
1083
 
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 };
1084
+ 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, DiscountCurrencyUnsupportedError, 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, ShippingCurrencyUnsupportedError, 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,147 @@ 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 DiscountCurrencyUnsupportedError = class extends ThrottleApiError {
155
+ constructor(args) {
156
+ super(coded("discount_currency_unsupported", 422, args));
157
+ this.name = "DiscountCurrencyUnsupportedError";
158
+ }
159
+ };
160
+ var ShippingCurrencyUnsupportedError = class extends ThrottleApiError {
161
+ shipping;
162
+ constructor(args) {
163
+ super(coded("shipping_currency_unsupported", 422, args));
164
+ this.name = "ShippingCurrencyUnsupportedError";
165
+ const d = args.details;
166
+ this.shipping = d?.shipping && typeof d.shipping === "object" ? d.shipping : null;
167
+ }
168
+ };
169
+ var RESOLVED_CART_ERRORS = {
170
+ price_locked: PriceLockedError,
171
+ quantity_unavailable: QuantityUnavailableError,
172
+ line_not_purchasable: LineNotPurchasableError,
173
+ line_resolver_unavailable: LineResolverUnavailableError,
174
+ line_resolver_not_available: LineResolverNotAvailableError,
175
+ currency_not_enabled: CurrencyNotEnabledError,
176
+ resolved_lines_required: ResolvedLinesRequiredError,
177
+ line_limit_reached: LineLimitReachedError,
178
+ cart_prices_changed: CartPricesChangedError,
179
+ shipping_method_unavailable: ShippingMethodUnavailableError,
180
+ shipping_quote_unavailable: ShippingQuoteUnavailableError,
181
+ amount_too_large: AmountTooLargeError,
182
+ cart_changed: CartChangedError,
183
+ discount_currency_unsupported: DiscountCurrencyUnsupportedError,
184
+ shipping_currency_unsupported: ShippingCurrencyUnsupportedError
185
+ };
45
186
  function cartErrorFromResponse(args) {
46
187
  if (args.statusCode === 409 && args.code === "cart_not_open") {
47
188
  return new CartNotOpenError({
@@ -59,6 +200,15 @@ function cartErrorFromResponse(args) {
59
200
  responseHeaders: args.responseHeaders
60
201
  });
61
202
  }
203
+ const ResolvedCartError = Object.prototype.hasOwnProperty.call(RESOLVED_CART_ERRORS, args.code) ? RESOLVED_CART_ERRORS[args.code] : void 0;
204
+ if (ResolvedCartError) {
205
+ return new ResolvedCartError({
206
+ message: args.message,
207
+ statusCode: args.statusCode,
208
+ details: args.details,
209
+ responseHeaders: args.responseHeaders
210
+ });
211
+ }
62
212
  return new ThrottleApiError(args);
63
213
  }
64
214
 
@@ -116,6 +266,17 @@ var CartClient = class {
116
266
  get items() {
117
267
  return {
118
268
  add: (cartId, input) => this.request("POST", `/api/v1/carts/${segment(cartId)}/items`, input),
269
+ /**
270
+ * Add a line to a resolved cart (one created with `lineResolver`). Only
271
+ * the item, quantity and metadata are sent; the app sets the name, price
272
+ * and image. Refusals throw the typed resolver errors.
273
+ */
274
+ addResolvedItem: (cartId, input) => {
275
+ const body = { referenceId: input.referenceId };
276
+ if (input.quantity !== void 0) body.quantity = input.quantity;
277
+ if (input.metadata !== void 0) body.metadata = input.metadata;
278
+ return this.request("POST", `/api/v1/carts/${segment(cartId)}/items`, body);
279
+ },
119
280
  update: (cartId, itemId, input) => this.request("PATCH", `/api/v1/carts/${segment(cartId)}/items/${segment(itemId)}`, input),
120
281
  remove: (cartId, itemId) => this.request("DELETE", `/api/v1/carts/${segment(cartId)}/items/${segment(itemId)}`)
121
282
  };
@@ -288,6 +449,32 @@ var CartSessionClient = class _CartSessionClient {
288
449
  async addItem(input) {
289
450
  return (await this.request("POST", `${this.basePath()}/items`, input)).cart;
290
451
  }
452
+ /**
453
+ * Add a line to a resolved cart (one created with `lineResolver`). Only the
454
+ * item, quantity and metadata are sent; the app sets the name, price and
455
+ * image. A refusal throws `QuantityUnavailableError`,
456
+ * `LineNotPurchasableError` or `LineResolverUnavailableError`.
457
+ */
458
+ async addResolvedItem(input) {
459
+ const body = { referenceId: input.referenceId };
460
+ if (input.quantity !== void 0) body.quantity = input.quantity;
461
+ if (input.metadata !== void 0) body.metadata = input.metadata;
462
+ return (await this.request("POST", `${this.basePath()}/items`, body)).cart;
463
+ }
464
+ /**
465
+ * Ask the app that prices a resolved cart to re-check every line it owns.
466
+ * `changed` is true when a price, name or refusal changed. An unresolved
467
+ * cart comes back unchanged. Throws `LineResolverUnavailableError` (nothing
468
+ * changed) when the app does not answer.
469
+ */
470
+ async refresh() {
471
+ const data = await this.request(
472
+ "POST",
473
+ `${this.basePath()}/refresh`,
474
+ {}
475
+ );
476
+ return { ...data.cart, changed: data.changed };
477
+ }
291
478
  async updateItem(itemId, input) {
292
479
  return (await this.request(
293
480
  "PATCH",
@@ -301,6 +488,17 @@ var CartSessionClient = class _CartSessionClient {
301
488
  async selectShipping(input) {
302
489
  return (await this.request("POST", `${this.basePath()}/shipping`, input)).cart;
303
490
  }
491
+ /**
492
+ * Pick a shipping method on a resolved cart. Throttle quotes the amount, so
493
+ * only `methodId` is sent. A method Throttle does not quote for the cart
494
+ * (it needs a shipping address first) throws `ShippingMethodUnavailableError`;
495
+ * a failed quote throws `ShippingQuoteUnavailableError`.
496
+ */
497
+ async selectShippingMethod(input) {
498
+ return (await this.request("POST", `${this.basePath()}/shipping`, {
499
+ methodId: input.methodId
500
+ })).cart;
501
+ }
304
502
  async clearShipping() {
305
503
  return (await this.request("DELETE", `${this.basePath()}/shipping`)).cart;
306
504
  }
@@ -388,11 +586,26 @@ var CartSessionClient = class _CartSessionClient {
388
586
  }
389
587
  };
390
588
  export {
589
+ AmountTooLargeError,
590
+ CartChangedError,
391
591
  CartClient,
392
592
  CartNotFoundError,
393
593
  CartNotOpenError,
594
+ CartPricesChangedError,
394
595
  CartSessionClient,
395
596
  CartTimeoutError,
597
+ CurrencyNotEnabledError,
598
+ DiscountCurrencyUnsupportedError,
599
+ LineLimitReachedError,
600
+ LineNotPurchasableError,
601
+ LineResolverNotAvailableError,
602
+ LineResolverUnavailableError,
603
+ PriceLockedError,
604
+ QuantityUnavailableError,
605
+ ResolvedLinesRequiredError,
606
+ ShippingCurrencyUnsupportedError,
607
+ ShippingMethodUnavailableError,
608
+ ShippingQuoteUnavailableError,
396
609
  StorefrontQuoteClient,
397
610
  ThrottleApiError,
398
611
  ThrottleError2 as ThrottleError,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usethrottle/cart",
3
- "version": "3.12.0",
3
+ "version": "3.14.0",
4
4
  "description": "Typed REST client for the Throttle Cart API.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",