@usethrottle/cart 0.1.0 → 2.0.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 +65 -0
- package/dist/index.cjs +61 -1
- package/dist/index.d.cts +159 -2
- package/dist/index.d.ts +159 -2
- package/dist/index.js +60 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -50,6 +50,71 @@ console.log(order.id, order.status);
|
|
|
50
50
|
|
|
51
51
|
All monetary values are integers in the smallest currency unit (cents for USD).
|
|
52
52
|
|
|
53
|
+
## Shipping and tax
|
|
54
|
+
|
|
55
|
+
Use the secret-key client on your backend to calculate and persist cart totals
|
|
56
|
+
with Throttle's native engine:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
const estimate = await client.shippingTax.calculateCart(cart.id, {
|
|
60
|
+
kind: 'cart_estimate',
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const locked = await client.shippingTax.calculateCart(cart.id, {
|
|
64
|
+
kind: 'checkout_final',
|
|
65
|
+
selectedShippingMethodId: estimate.shipping.selectedMethod?.id,
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
External stores can also request read-only storefront quotes with a publishable
|
|
70
|
+
`pk_` quote token. Create one from the dashboard Shipping & Tax page or with
|
|
71
|
+
`POST /api/v1/shipping-tax/quote-tokens`.
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
import { StorefrontQuoteClient } from '@usethrottle/cart';
|
|
75
|
+
|
|
76
|
+
const quotes = new StorefrontQuoteClient({
|
|
77
|
+
storeId: 'store_uuid',
|
|
78
|
+
quoteToken: 'pk_publishable_quote_token',
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const estimate = await quotes.quote({
|
|
82
|
+
currency: 'USD',
|
|
83
|
+
items: [
|
|
84
|
+
{
|
|
85
|
+
id: 'sku_123',
|
|
86
|
+
quantity: 1,
|
|
87
|
+
subtotalAmount: 12900,
|
|
88
|
+
requiresShipping: true,
|
|
89
|
+
taxCategory: 'standard',
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
addresses: {
|
|
93
|
+
shipping: { countryCode: 'US', stateProvince: 'CA', postalCode: '90001' },
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
For provider-owned totals, set the store to `byo` mode on the shipping or tax
|
|
99
|
+
axis (or both) and push the final snapshot through
|
|
100
|
+
`/api/v1/shipping-tax/external-snapshots`. Throttle accepts external pushes
|
|
101
|
+
when at least one axis is in `byo` mode:
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
await client.shippingTax.pushExternalSnapshot({
|
|
105
|
+
storeId: 'store_uuid',
|
|
106
|
+
cartId: cart.id,
|
|
107
|
+
currency: 'USD',
|
|
108
|
+
totals: {
|
|
109
|
+
subtotal: 12900,
|
|
110
|
+
discountTotal: 0,
|
|
111
|
+
shippingTotal: 600,
|
|
112
|
+
taxTotal: 1215,
|
|
113
|
+
total: 14715,
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
```
|
|
117
|
+
|
|
53
118
|
## Subscriptions
|
|
54
119
|
|
|
55
120
|
Pass `type: 'subscription'` and a `recurring` block on the line item:
|
package/dist/index.cjs
CHANGED
|
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
CartClient: () => CartClient,
|
|
24
|
+
StorefrontQuoteClient: () => StorefrontQuoteClient,
|
|
24
25
|
ThrottleApiError: () => ThrottleApiError
|
|
25
26
|
});
|
|
26
27
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -48,7 +49,7 @@ var CartClient = class {
|
|
|
48
49
|
constructor(opts) {
|
|
49
50
|
if (!opts.apiKey) throw new Error("CartClient: apiKey is required");
|
|
50
51
|
this.apiKey = opts.apiKey;
|
|
51
|
-
this.baseUrl = (opts.baseUrl ?? "https://
|
|
52
|
+
this.baseUrl = (opts.baseUrl ?? "https://api.usethrottle.dev").replace(/\/+$/, "");
|
|
52
53
|
this.fetchImpl = opts.fetch ?? globalThis.fetch;
|
|
53
54
|
this.timeoutMs = opts.timeoutMs ?? 3e4;
|
|
54
55
|
}
|
|
@@ -111,6 +112,12 @@ var CartClient = class {
|
|
|
111
112
|
clear: (cartId) => this.request("DELETE", `/api/v1/carts/${cartId}/tax-lines`)
|
|
112
113
|
};
|
|
113
114
|
}
|
|
115
|
+
get shippingTax() {
|
|
116
|
+
return {
|
|
117
|
+
calculateCart: (cartId, input = {}) => this.request("POST", `/api/v1/shipping-tax/carts/${cartId}/calculate`, input),
|
|
118
|
+
pushExternalSnapshot: (input) => this.request("POST", "/api/v1/shipping-tax/external-snapshots", input)
|
|
119
|
+
};
|
|
120
|
+
}
|
|
114
121
|
get events() {
|
|
115
122
|
return {
|
|
116
123
|
list: (cartId, opts) => {
|
|
@@ -123,8 +130,61 @@ var CartClient = class {
|
|
|
123
130
|
};
|
|
124
131
|
}
|
|
125
132
|
};
|
|
133
|
+
|
|
134
|
+
// src/storefront.ts
|
|
135
|
+
var StorefrontQuoteClient = class {
|
|
136
|
+
storeId;
|
|
137
|
+
quoteToken;
|
|
138
|
+
baseUrl;
|
|
139
|
+
fetchImpl;
|
|
140
|
+
timeoutMs;
|
|
141
|
+
origin;
|
|
142
|
+
constructor(opts) {
|
|
143
|
+
if (!opts.storeId) throw new Error("StorefrontQuoteClient: storeId is required");
|
|
144
|
+
if (!opts.quoteToken?.startsWith("pk_")) {
|
|
145
|
+
throw new Error("StorefrontQuoteClient: quoteToken must be a publishable pk_ token");
|
|
146
|
+
}
|
|
147
|
+
this.storeId = opts.storeId;
|
|
148
|
+
this.quoteToken = opts.quoteToken;
|
|
149
|
+
this.baseUrl = (opts.baseUrl ?? "https://api.usethrottle.dev").replace(/\/+$/, "");
|
|
150
|
+
this.fetchImpl = opts.fetch ?? globalThis.fetch;
|
|
151
|
+
this.timeoutMs = opts.timeoutMs ?? 15e3;
|
|
152
|
+
this.origin = opts.origin;
|
|
153
|
+
}
|
|
154
|
+
async quote(input) {
|
|
155
|
+
const ctrl = new AbortController();
|
|
156
|
+
const timer = setTimeout(() => ctrl.abort(), this.timeoutMs);
|
|
157
|
+
try {
|
|
158
|
+
const headers = { "content-type": "application/json" };
|
|
159
|
+
if (this.origin) headers.origin = this.origin;
|
|
160
|
+
const res = await this.fetchImpl(`${this.baseUrl}/api/v1/shipping-tax/quotes`, {
|
|
161
|
+
method: "POST",
|
|
162
|
+
headers,
|
|
163
|
+
body: JSON.stringify({
|
|
164
|
+
storeId: this.storeId,
|
|
165
|
+
quoteToken: this.quoteToken,
|
|
166
|
+
...input
|
|
167
|
+
}),
|
|
168
|
+
signal: ctrl.signal
|
|
169
|
+
});
|
|
170
|
+
const json = await res.json().catch(() => ({}));
|
|
171
|
+
if (!res.ok) {
|
|
172
|
+
throw new ThrottleApiError({
|
|
173
|
+
code: json?.error?.code ?? "unknown_error",
|
|
174
|
+
message: json?.error?.message ?? `HTTP ${res.status}`,
|
|
175
|
+
statusCode: res.status,
|
|
176
|
+
details: json?.error?.details
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
return json.data;
|
|
180
|
+
} finally {
|
|
181
|
+
clearTimeout(timer);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
};
|
|
126
185
|
// Annotate the CommonJS export names for ESM import in node:
|
|
127
186
|
0 && (module.exports = {
|
|
128
187
|
CartClient,
|
|
188
|
+
StorefrontQuoteClient,
|
|
129
189
|
ThrottleApiError
|
|
130
190
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -57,8 +57,9 @@ interface SelectedShipping {
|
|
|
57
57
|
estimatedDeliveryDays: number | null;
|
|
58
58
|
}
|
|
59
59
|
interface AppliedDiscount {
|
|
60
|
+
discountId?: string | null;
|
|
60
61
|
code: string;
|
|
61
|
-
type: 'percentage' | 'fixed_amount'
|
|
62
|
+
type: 'percentage' | 'fixed_amount';
|
|
62
63
|
amount: number;
|
|
63
64
|
currency: string;
|
|
64
65
|
freeShipping: boolean;
|
|
@@ -153,6 +154,139 @@ interface Order {
|
|
|
153
154
|
total: number;
|
|
154
155
|
currency: string;
|
|
155
156
|
}
|
|
157
|
+
interface ShippingTaxAddress {
|
|
158
|
+
countryCode?: string;
|
|
159
|
+
stateProvince?: string;
|
|
160
|
+
postalCode?: string;
|
|
161
|
+
city?: string;
|
|
162
|
+
addressLine1?: string;
|
|
163
|
+
addressLine2?: string;
|
|
164
|
+
[key: string]: unknown;
|
|
165
|
+
}
|
|
166
|
+
interface ShippingTaxQuoteItem {
|
|
167
|
+
id: string;
|
|
168
|
+
quantity?: number;
|
|
169
|
+
unitPrice?: number;
|
|
170
|
+
subtotalAmount: number;
|
|
171
|
+
discountAmount?: number;
|
|
172
|
+
productType?: string;
|
|
173
|
+
requiresShipping?: boolean;
|
|
174
|
+
shippingProfileIds?: string[];
|
|
175
|
+
taxCategory?: string;
|
|
176
|
+
weight?: number;
|
|
177
|
+
weightUnit?: 'lb' | 'kg';
|
|
178
|
+
metadata?: Record<string, unknown>;
|
|
179
|
+
[key: string]: unknown;
|
|
180
|
+
}
|
|
181
|
+
interface ShippingTaxQuoteInput {
|
|
182
|
+
currency?: string;
|
|
183
|
+
items: ShippingTaxQuoteItem[];
|
|
184
|
+
discountsTotal?: number;
|
|
185
|
+
selectedShippingMethodId?: string | null;
|
|
186
|
+
addresses?: {
|
|
187
|
+
shipping?: ShippingTaxAddress | null;
|
|
188
|
+
billing?: ShippingTaxAddress | null;
|
|
189
|
+
customer?: ShippingTaxAddress | null;
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
interface ShippingTaxCartCalculateInput {
|
|
193
|
+
kind?: 'cart_estimate' | 'checkout_final';
|
|
194
|
+
selectedShippingMethodId?: string | null;
|
|
195
|
+
persist?: boolean;
|
|
196
|
+
}
|
|
197
|
+
interface ShippingTaxMethod {
|
|
198
|
+
id: string;
|
|
199
|
+
type?: 'ship' | 'pickup';
|
|
200
|
+
label: string;
|
|
201
|
+
amount: number;
|
|
202
|
+
currency: string;
|
|
203
|
+
deliveryWindowLabel?: string | null;
|
|
204
|
+
deliveryMinDays?: number | null;
|
|
205
|
+
deliveryMaxDays?: number | null;
|
|
206
|
+
warnings?: Array<{
|
|
207
|
+
code: string;
|
|
208
|
+
message: string;
|
|
209
|
+
field?: string;
|
|
210
|
+
}>;
|
|
211
|
+
}
|
|
212
|
+
interface ShippingTaxCalculationResponse {
|
|
213
|
+
snapshotId?: string;
|
|
214
|
+
kind: 'quote' | 'cart_estimate' | 'checkout_final' | 'external_snapshot';
|
|
215
|
+
status: 'estimated' | 'final' | 'failed';
|
|
216
|
+
source: 'off' | 'byo' | 'calculated' | 'app_based' | 'external_push';
|
|
217
|
+
storeId: string;
|
|
218
|
+
merchantId?: string;
|
|
219
|
+
currency: string;
|
|
220
|
+
configId?: string;
|
|
221
|
+
configVersion?: number;
|
|
222
|
+
shippingRequired: boolean;
|
|
223
|
+
shipping: {
|
|
224
|
+
shippingRequired: boolean;
|
|
225
|
+
methods: ShippingTaxMethod[];
|
|
226
|
+
selectedMethod: ShippingTaxMethod | null;
|
|
227
|
+
warnings: Array<{
|
|
228
|
+
code: string;
|
|
229
|
+
message: string;
|
|
230
|
+
field?: string;
|
|
231
|
+
}>;
|
|
232
|
+
errors: Array<{
|
|
233
|
+
code: string;
|
|
234
|
+
message: string;
|
|
235
|
+
field?: string;
|
|
236
|
+
}>;
|
|
237
|
+
matchedZoneIds: string[];
|
|
238
|
+
};
|
|
239
|
+
tax: {
|
|
240
|
+
taxTotal: number;
|
|
241
|
+
lines: TaxLine[];
|
|
242
|
+
warnings: Array<{
|
|
243
|
+
code: string;
|
|
244
|
+
message: string;
|
|
245
|
+
field?: string;
|
|
246
|
+
}>;
|
|
247
|
+
errors: Array<{
|
|
248
|
+
code: string;
|
|
249
|
+
message: string;
|
|
250
|
+
field?: string;
|
|
251
|
+
}>;
|
|
252
|
+
matchedRegionIds: string[];
|
|
253
|
+
};
|
|
254
|
+
selectedShippingMethodId?: string | null;
|
|
255
|
+
taxLines: TaxLine[];
|
|
256
|
+
totals: {
|
|
257
|
+
subtotal: number;
|
|
258
|
+
discountTotal: number;
|
|
259
|
+
shippingTotal: number;
|
|
260
|
+
taxTotal: number;
|
|
261
|
+
total: number;
|
|
262
|
+
};
|
|
263
|
+
prompts: Array<{
|
|
264
|
+
code: 'missing_info';
|
|
265
|
+
field: string;
|
|
266
|
+
message: string;
|
|
267
|
+
}>;
|
|
268
|
+
warnings: Array<{
|
|
269
|
+
code: string;
|
|
270
|
+
message: string;
|
|
271
|
+
field?: string;
|
|
272
|
+
}>;
|
|
273
|
+
errors: Array<{
|
|
274
|
+
code: string;
|
|
275
|
+
message: string;
|
|
276
|
+
field?: string;
|
|
277
|
+
}>;
|
|
278
|
+
}
|
|
279
|
+
interface ExternalShippingTaxSnapshotInput {
|
|
280
|
+
storeId: string;
|
|
281
|
+
cartId?: string | null;
|
|
282
|
+
checkoutSessionId?: string | null;
|
|
283
|
+
orderId?: string | null;
|
|
284
|
+
currency?: string;
|
|
285
|
+
totals: ShippingTaxCalculationResponse['totals'];
|
|
286
|
+
selectedShipping?: Record<string, unknown> | null;
|
|
287
|
+
taxLines?: TaxLine[];
|
|
288
|
+
source?: string;
|
|
289
|
+
}
|
|
156
290
|
|
|
157
291
|
interface CartClientOptions {
|
|
158
292
|
apiKey: string;
|
|
@@ -191,6 +325,10 @@ declare class CartClient {
|
|
|
191
325
|
set: (cartId: string, lines: TaxLineInput[]) => Promise<Cart>;
|
|
192
326
|
clear: (cartId: string) => Promise<Cart>;
|
|
193
327
|
};
|
|
328
|
+
get shippingTax(): {
|
|
329
|
+
calculateCart: (cartId: string, input?: ShippingTaxCartCalculateInput) => Promise<ShippingTaxCalculationResponse>;
|
|
330
|
+
pushExternalSnapshot: (input: ExternalShippingTaxSnapshotInput) => Promise<ShippingTaxCalculationResponse>;
|
|
331
|
+
};
|
|
194
332
|
get events(): {
|
|
195
333
|
list: (cartId: string, opts?: {
|
|
196
334
|
sinceSequence?: number;
|
|
@@ -199,6 +337,25 @@ declare class CartClient {
|
|
|
199
337
|
};
|
|
200
338
|
}
|
|
201
339
|
|
|
340
|
+
interface StorefrontQuoteClientOptions {
|
|
341
|
+
storeId: string;
|
|
342
|
+
quoteToken: string;
|
|
343
|
+
baseUrl?: string;
|
|
344
|
+
fetch?: typeof globalThis.fetch;
|
|
345
|
+
timeoutMs?: number;
|
|
346
|
+
origin?: string;
|
|
347
|
+
}
|
|
348
|
+
declare class StorefrontQuoteClient {
|
|
349
|
+
private readonly storeId;
|
|
350
|
+
private readonly quoteToken;
|
|
351
|
+
private readonly baseUrl;
|
|
352
|
+
private readonly fetchImpl;
|
|
353
|
+
private readonly timeoutMs;
|
|
354
|
+
private readonly origin?;
|
|
355
|
+
constructor(opts: StorefrontQuoteClientOptions);
|
|
356
|
+
quote(input: ShippingTaxQuoteInput): Promise<ShippingTaxCalculationResponse>;
|
|
357
|
+
}
|
|
358
|
+
|
|
202
359
|
declare class ThrottleApiError extends Error {
|
|
203
360
|
readonly code: string;
|
|
204
361
|
readonly statusCode: number;
|
|
@@ -211,4 +368,4 @@ declare class ThrottleApiError extends Error {
|
|
|
211
368
|
});
|
|
212
369
|
}
|
|
213
370
|
|
|
214
|
-
export { type AddLineItemInput, type AppliedDiscount, type Cart, CartClient, type CartEvent, type CheckoutInput, type CreateCartInput, type LineItem, type Order, type SelectShippingInput, type SelectedShipping, type TaxLine, type TaxLineInput, ThrottleApiError, type UpdateCartInput, type UpdateLineItemInput };
|
|
371
|
+
export { type AddLineItemInput, type AppliedDiscount, type Cart, CartClient, type CartEvent, type CheckoutInput, type CreateCartInput, type ExternalShippingTaxSnapshotInput, type LineItem, type Order, type SelectShippingInput, type SelectedShipping, type ShippingTaxAddress, type ShippingTaxCalculationResponse, type ShippingTaxCartCalculateInput, type ShippingTaxMethod, type ShippingTaxQuoteInput, type ShippingTaxQuoteItem, StorefrontQuoteClient, type TaxLine, type TaxLineInput, ThrottleApiError, type UpdateCartInput, type UpdateLineItemInput };
|
package/dist/index.d.ts
CHANGED
|
@@ -57,8 +57,9 @@ interface SelectedShipping {
|
|
|
57
57
|
estimatedDeliveryDays: number | null;
|
|
58
58
|
}
|
|
59
59
|
interface AppliedDiscount {
|
|
60
|
+
discountId?: string | null;
|
|
60
61
|
code: string;
|
|
61
|
-
type: 'percentage' | 'fixed_amount'
|
|
62
|
+
type: 'percentage' | 'fixed_amount';
|
|
62
63
|
amount: number;
|
|
63
64
|
currency: string;
|
|
64
65
|
freeShipping: boolean;
|
|
@@ -153,6 +154,139 @@ interface Order {
|
|
|
153
154
|
total: number;
|
|
154
155
|
currency: string;
|
|
155
156
|
}
|
|
157
|
+
interface ShippingTaxAddress {
|
|
158
|
+
countryCode?: string;
|
|
159
|
+
stateProvince?: string;
|
|
160
|
+
postalCode?: string;
|
|
161
|
+
city?: string;
|
|
162
|
+
addressLine1?: string;
|
|
163
|
+
addressLine2?: string;
|
|
164
|
+
[key: string]: unknown;
|
|
165
|
+
}
|
|
166
|
+
interface ShippingTaxQuoteItem {
|
|
167
|
+
id: string;
|
|
168
|
+
quantity?: number;
|
|
169
|
+
unitPrice?: number;
|
|
170
|
+
subtotalAmount: number;
|
|
171
|
+
discountAmount?: number;
|
|
172
|
+
productType?: string;
|
|
173
|
+
requiresShipping?: boolean;
|
|
174
|
+
shippingProfileIds?: string[];
|
|
175
|
+
taxCategory?: string;
|
|
176
|
+
weight?: number;
|
|
177
|
+
weightUnit?: 'lb' | 'kg';
|
|
178
|
+
metadata?: Record<string, unknown>;
|
|
179
|
+
[key: string]: unknown;
|
|
180
|
+
}
|
|
181
|
+
interface ShippingTaxQuoteInput {
|
|
182
|
+
currency?: string;
|
|
183
|
+
items: ShippingTaxQuoteItem[];
|
|
184
|
+
discountsTotal?: number;
|
|
185
|
+
selectedShippingMethodId?: string | null;
|
|
186
|
+
addresses?: {
|
|
187
|
+
shipping?: ShippingTaxAddress | null;
|
|
188
|
+
billing?: ShippingTaxAddress | null;
|
|
189
|
+
customer?: ShippingTaxAddress | null;
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
interface ShippingTaxCartCalculateInput {
|
|
193
|
+
kind?: 'cart_estimate' | 'checkout_final';
|
|
194
|
+
selectedShippingMethodId?: string | null;
|
|
195
|
+
persist?: boolean;
|
|
196
|
+
}
|
|
197
|
+
interface ShippingTaxMethod {
|
|
198
|
+
id: string;
|
|
199
|
+
type?: 'ship' | 'pickup';
|
|
200
|
+
label: string;
|
|
201
|
+
amount: number;
|
|
202
|
+
currency: string;
|
|
203
|
+
deliveryWindowLabel?: string | null;
|
|
204
|
+
deliveryMinDays?: number | null;
|
|
205
|
+
deliveryMaxDays?: number | null;
|
|
206
|
+
warnings?: Array<{
|
|
207
|
+
code: string;
|
|
208
|
+
message: string;
|
|
209
|
+
field?: string;
|
|
210
|
+
}>;
|
|
211
|
+
}
|
|
212
|
+
interface ShippingTaxCalculationResponse {
|
|
213
|
+
snapshotId?: string;
|
|
214
|
+
kind: 'quote' | 'cart_estimate' | 'checkout_final' | 'external_snapshot';
|
|
215
|
+
status: 'estimated' | 'final' | 'failed';
|
|
216
|
+
source: 'off' | 'byo' | 'calculated' | 'app_based' | 'external_push';
|
|
217
|
+
storeId: string;
|
|
218
|
+
merchantId?: string;
|
|
219
|
+
currency: string;
|
|
220
|
+
configId?: string;
|
|
221
|
+
configVersion?: number;
|
|
222
|
+
shippingRequired: boolean;
|
|
223
|
+
shipping: {
|
|
224
|
+
shippingRequired: boolean;
|
|
225
|
+
methods: ShippingTaxMethod[];
|
|
226
|
+
selectedMethod: ShippingTaxMethod | null;
|
|
227
|
+
warnings: Array<{
|
|
228
|
+
code: string;
|
|
229
|
+
message: string;
|
|
230
|
+
field?: string;
|
|
231
|
+
}>;
|
|
232
|
+
errors: Array<{
|
|
233
|
+
code: string;
|
|
234
|
+
message: string;
|
|
235
|
+
field?: string;
|
|
236
|
+
}>;
|
|
237
|
+
matchedZoneIds: string[];
|
|
238
|
+
};
|
|
239
|
+
tax: {
|
|
240
|
+
taxTotal: number;
|
|
241
|
+
lines: TaxLine[];
|
|
242
|
+
warnings: Array<{
|
|
243
|
+
code: string;
|
|
244
|
+
message: string;
|
|
245
|
+
field?: string;
|
|
246
|
+
}>;
|
|
247
|
+
errors: Array<{
|
|
248
|
+
code: string;
|
|
249
|
+
message: string;
|
|
250
|
+
field?: string;
|
|
251
|
+
}>;
|
|
252
|
+
matchedRegionIds: string[];
|
|
253
|
+
};
|
|
254
|
+
selectedShippingMethodId?: string | null;
|
|
255
|
+
taxLines: TaxLine[];
|
|
256
|
+
totals: {
|
|
257
|
+
subtotal: number;
|
|
258
|
+
discountTotal: number;
|
|
259
|
+
shippingTotal: number;
|
|
260
|
+
taxTotal: number;
|
|
261
|
+
total: number;
|
|
262
|
+
};
|
|
263
|
+
prompts: Array<{
|
|
264
|
+
code: 'missing_info';
|
|
265
|
+
field: string;
|
|
266
|
+
message: string;
|
|
267
|
+
}>;
|
|
268
|
+
warnings: Array<{
|
|
269
|
+
code: string;
|
|
270
|
+
message: string;
|
|
271
|
+
field?: string;
|
|
272
|
+
}>;
|
|
273
|
+
errors: Array<{
|
|
274
|
+
code: string;
|
|
275
|
+
message: string;
|
|
276
|
+
field?: string;
|
|
277
|
+
}>;
|
|
278
|
+
}
|
|
279
|
+
interface ExternalShippingTaxSnapshotInput {
|
|
280
|
+
storeId: string;
|
|
281
|
+
cartId?: string | null;
|
|
282
|
+
checkoutSessionId?: string | null;
|
|
283
|
+
orderId?: string | null;
|
|
284
|
+
currency?: string;
|
|
285
|
+
totals: ShippingTaxCalculationResponse['totals'];
|
|
286
|
+
selectedShipping?: Record<string, unknown> | null;
|
|
287
|
+
taxLines?: TaxLine[];
|
|
288
|
+
source?: string;
|
|
289
|
+
}
|
|
156
290
|
|
|
157
291
|
interface CartClientOptions {
|
|
158
292
|
apiKey: string;
|
|
@@ -191,6 +325,10 @@ declare class CartClient {
|
|
|
191
325
|
set: (cartId: string, lines: TaxLineInput[]) => Promise<Cart>;
|
|
192
326
|
clear: (cartId: string) => Promise<Cart>;
|
|
193
327
|
};
|
|
328
|
+
get shippingTax(): {
|
|
329
|
+
calculateCart: (cartId: string, input?: ShippingTaxCartCalculateInput) => Promise<ShippingTaxCalculationResponse>;
|
|
330
|
+
pushExternalSnapshot: (input: ExternalShippingTaxSnapshotInput) => Promise<ShippingTaxCalculationResponse>;
|
|
331
|
+
};
|
|
194
332
|
get events(): {
|
|
195
333
|
list: (cartId: string, opts?: {
|
|
196
334
|
sinceSequence?: number;
|
|
@@ -199,6 +337,25 @@ declare class CartClient {
|
|
|
199
337
|
};
|
|
200
338
|
}
|
|
201
339
|
|
|
340
|
+
interface StorefrontQuoteClientOptions {
|
|
341
|
+
storeId: string;
|
|
342
|
+
quoteToken: string;
|
|
343
|
+
baseUrl?: string;
|
|
344
|
+
fetch?: typeof globalThis.fetch;
|
|
345
|
+
timeoutMs?: number;
|
|
346
|
+
origin?: string;
|
|
347
|
+
}
|
|
348
|
+
declare class StorefrontQuoteClient {
|
|
349
|
+
private readonly storeId;
|
|
350
|
+
private readonly quoteToken;
|
|
351
|
+
private readonly baseUrl;
|
|
352
|
+
private readonly fetchImpl;
|
|
353
|
+
private readonly timeoutMs;
|
|
354
|
+
private readonly origin?;
|
|
355
|
+
constructor(opts: StorefrontQuoteClientOptions);
|
|
356
|
+
quote(input: ShippingTaxQuoteInput): Promise<ShippingTaxCalculationResponse>;
|
|
357
|
+
}
|
|
358
|
+
|
|
202
359
|
declare class ThrottleApiError extends Error {
|
|
203
360
|
readonly code: string;
|
|
204
361
|
readonly statusCode: number;
|
|
@@ -211,4 +368,4 @@ declare class ThrottleApiError extends Error {
|
|
|
211
368
|
});
|
|
212
369
|
}
|
|
213
370
|
|
|
214
|
-
export { type AddLineItemInput, type AppliedDiscount, type Cart, CartClient, type CartEvent, type CheckoutInput, type CreateCartInput, type LineItem, type Order, type SelectShippingInput, type SelectedShipping, type TaxLine, type TaxLineInput, ThrottleApiError, type UpdateCartInput, type UpdateLineItemInput };
|
|
371
|
+
export { type AddLineItemInput, type AppliedDiscount, type Cart, CartClient, type CartEvent, type CheckoutInput, type CreateCartInput, type ExternalShippingTaxSnapshotInput, type LineItem, type Order, type SelectShippingInput, type SelectedShipping, type ShippingTaxAddress, type ShippingTaxCalculationResponse, type ShippingTaxCartCalculateInput, type ShippingTaxMethod, type ShippingTaxQuoteInput, type ShippingTaxQuoteItem, StorefrontQuoteClient, type TaxLine, type TaxLineInput, ThrottleApiError, type UpdateCartInput, type UpdateLineItemInput };
|
package/dist/index.js
CHANGED
|
@@ -21,7 +21,7 @@ var CartClient = class {
|
|
|
21
21
|
constructor(opts) {
|
|
22
22
|
if (!opts.apiKey) throw new Error("CartClient: apiKey is required");
|
|
23
23
|
this.apiKey = opts.apiKey;
|
|
24
|
-
this.baseUrl = (opts.baseUrl ?? "https://
|
|
24
|
+
this.baseUrl = (opts.baseUrl ?? "https://api.usethrottle.dev").replace(/\/+$/, "");
|
|
25
25
|
this.fetchImpl = opts.fetch ?? globalThis.fetch;
|
|
26
26
|
this.timeoutMs = opts.timeoutMs ?? 3e4;
|
|
27
27
|
}
|
|
@@ -84,6 +84,12 @@ var CartClient = class {
|
|
|
84
84
|
clear: (cartId) => this.request("DELETE", `/api/v1/carts/${cartId}/tax-lines`)
|
|
85
85
|
};
|
|
86
86
|
}
|
|
87
|
+
get shippingTax() {
|
|
88
|
+
return {
|
|
89
|
+
calculateCart: (cartId, input = {}) => this.request("POST", `/api/v1/shipping-tax/carts/${cartId}/calculate`, input),
|
|
90
|
+
pushExternalSnapshot: (input) => this.request("POST", "/api/v1/shipping-tax/external-snapshots", input)
|
|
91
|
+
};
|
|
92
|
+
}
|
|
87
93
|
get events() {
|
|
88
94
|
return {
|
|
89
95
|
list: (cartId, opts) => {
|
|
@@ -96,7 +102,60 @@ var CartClient = class {
|
|
|
96
102
|
};
|
|
97
103
|
}
|
|
98
104
|
};
|
|
105
|
+
|
|
106
|
+
// src/storefront.ts
|
|
107
|
+
var StorefrontQuoteClient = class {
|
|
108
|
+
storeId;
|
|
109
|
+
quoteToken;
|
|
110
|
+
baseUrl;
|
|
111
|
+
fetchImpl;
|
|
112
|
+
timeoutMs;
|
|
113
|
+
origin;
|
|
114
|
+
constructor(opts) {
|
|
115
|
+
if (!opts.storeId) throw new Error("StorefrontQuoteClient: storeId is required");
|
|
116
|
+
if (!opts.quoteToken?.startsWith("pk_")) {
|
|
117
|
+
throw new Error("StorefrontQuoteClient: quoteToken must be a publishable pk_ token");
|
|
118
|
+
}
|
|
119
|
+
this.storeId = opts.storeId;
|
|
120
|
+
this.quoteToken = opts.quoteToken;
|
|
121
|
+
this.baseUrl = (opts.baseUrl ?? "https://api.usethrottle.dev").replace(/\/+$/, "");
|
|
122
|
+
this.fetchImpl = opts.fetch ?? globalThis.fetch;
|
|
123
|
+
this.timeoutMs = opts.timeoutMs ?? 15e3;
|
|
124
|
+
this.origin = opts.origin;
|
|
125
|
+
}
|
|
126
|
+
async quote(input) {
|
|
127
|
+
const ctrl = new AbortController();
|
|
128
|
+
const timer = setTimeout(() => ctrl.abort(), this.timeoutMs);
|
|
129
|
+
try {
|
|
130
|
+
const headers = { "content-type": "application/json" };
|
|
131
|
+
if (this.origin) headers.origin = this.origin;
|
|
132
|
+
const res = await this.fetchImpl(`${this.baseUrl}/api/v1/shipping-tax/quotes`, {
|
|
133
|
+
method: "POST",
|
|
134
|
+
headers,
|
|
135
|
+
body: JSON.stringify({
|
|
136
|
+
storeId: this.storeId,
|
|
137
|
+
quoteToken: this.quoteToken,
|
|
138
|
+
...input
|
|
139
|
+
}),
|
|
140
|
+
signal: ctrl.signal
|
|
141
|
+
});
|
|
142
|
+
const json = await res.json().catch(() => ({}));
|
|
143
|
+
if (!res.ok) {
|
|
144
|
+
throw new ThrottleApiError({
|
|
145
|
+
code: json?.error?.code ?? "unknown_error",
|
|
146
|
+
message: json?.error?.message ?? `HTTP ${res.status}`,
|
|
147
|
+
statusCode: res.status,
|
|
148
|
+
details: json?.error?.details
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
return json.data;
|
|
152
|
+
} finally {
|
|
153
|
+
clearTimeout(timer);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
};
|
|
99
157
|
export {
|
|
100
158
|
CartClient,
|
|
159
|
+
StorefrontQuoteClient,
|
|
101
160
|
ThrottleApiError
|
|
102
161
|
};
|