@wocart/storefront 1.3.0 → 1.4.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 +15 -0
- package/dist/client/cart.d.ts +9 -1
- package/dist/client/cart.js +7 -4
- package/dist/domain.d.ts +42 -0
- package/dist/domain.js +25 -0
- package/dist/endpoints/storefront-routes.d.ts +3 -1
- package/dist/endpoints/storefront-routes.js +13 -6
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,21 @@ follows [semantic versioning](https://semver.org/): breaking changes ship only
|
|
|
5
5
|
in a new major version, and an export is marked `@deprecated` for at least one
|
|
6
6
|
minor release before a major removes it.
|
|
7
7
|
|
|
8
|
+
## 1.4.0 — 2026-10-15
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **`cart.quote(lines, { destination })`** quotes what an order would cost for
|
|
13
|
+
a basket, or for one product exactly as its order form posts it: a quantity,
|
|
14
|
+
a variant per unit (`variantSelections`), an offer tier (`offerId`). The
|
|
15
|
+
server builds the lines the way the order does, so a product page's delivery
|
|
16
|
+
and total are the order's own. `validate(items, options)` is now its basket
|
|
17
|
+
form.
|
|
18
|
+
- `ProductQuoteInputSchema`, `CartQuoteLinesSchema` and the `ProductQuoteInput`
|
|
19
|
+
and `CartQuoteLines` types.
|
|
20
|
+
- The `cartValidate` route accepts a product form as well as a basket, each
|
|
21
|
+
with an optional `destination`.
|
|
22
|
+
|
|
8
23
|
## 1.3.0 — 2026-10-15
|
|
9
24
|
|
|
10
25
|
### Added
|
package/dist/client/cart.d.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import type { ClientCore, ClientResult } from "./core.js";
|
|
15
15
|
import type { CartValidation } from "../types.js";
|
|
16
|
-
import type { BasketLineInput, DeliveryDestination } from "../domain.js";
|
|
16
|
+
import type { BasketLineInput, CartQuoteLines, DeliveryDestination } from "../domain.js";
|
|
17
17
|
export interface CartNamespace {
|
|
18
18
|
/**
|
|
19
19
|
* Re-price and re-check a basket against the live catalog.
|
|
@@ -29,6 +29,14 @@ export interface CartNamespace {
|
|
|
29
29
|
validate(items: readonly BasketLineInput[], options?: {
|
|
30
30
|
destination?: DeliveryDestination;
|
|
31
31
|
}): Promise<ClientResult<CartValidation>>;
|
|
32
|
+
/**
|
|
33
|
+
* Quote what an order would cost, for a basket or for one product exactly as
|
|
34
|
+
* its order form posts it (quantity, variants per unit, offer tier). The lines
|
|
35
|
+
* are built the way the order builds them, so the quote and the order agree.
|
|
36
|
+
*/
|
|
37
|
+
quote(lines: CartQuoteLines, options?: {
|
|
38
|
+
destination?: DeliveryDestination;
|
|
39
|
+
}): Promise<ClientResult<CartValidation>>;
|
|
32
40
|
}
|
|
33
41
|
/**
|
|
34
42
|
* Create cart namespace
|
package/dist/client/cart.js
CHANGED
|
@@ -18,10 +18,13 @@ import { localizedPath } from "./paths.js";
|
|
|
18
18
|
* Create cart namespace
|
|
19
19
|
*/
|
|
20
20
|
export function createCartNamespace(core) {
|
|
21
|
+
// A closure rather than `this`: a theme may destructure `store.cart`.
|
|
22
|
+
const quote = async (lines, options) => {
|
|
23
|
+
const destination = options?.destination;
|
|
24
|
+
return core.post(localizedPath(core.config, "/store/cart/validate"), destination ? { ...lines, destination } : lines, { schema: CartValidationSchema, operation: STOREFRONT_OPERATIONS.cartValidate });
|
|
25
|
+
};
|
|
21
26
|
return {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return core.post(localizedPath(core.config, "/store/cart/validate"), destination ? { items, destination } : { items }, { schema: CartValidationSchema, operation: STOREFRONT_OPERATIONS.cartValidate });
|
|
25
|
-
},
|
|
27
|
+
validate: (items, options) => quote({ items: [...items] }, options),
|
|
28
|
+
quote,
|
|
26
29
|
};
|
|
27
30
|
}
|
package/dist/domain.d.ts
CHANGED
|
@@ -175,6 +175,48 @@ export declare const AbandonedCheckoutInputSchema: z.ZodObject<{
|
|
|
175
175
|
* `items[]` line: absent — not null — is the common wire shape.
|
|
176
176
|
*/
|
|
177
177
|
export type AbandonedCheckoutInput = z.infer<typeof AbandonedCheckoutInputSchema>;
|
|
178
|
+
/**
|
|
179
|
+
* One product as a product page's order form posts it: a quantity, or a
|
|
180
|
+
* variant chosen per unit, and an offer tier. The quote reads these the way the
|
|
181
|
+
* order does, so the page asks with exactly what its form will submit.
|
|
182
|
+
*/
|
|
183
|
+
export declare const ProductQuoteInputSchema: z.ZodObject<{
|
|
184
|
+
productId: z.ZodString;
|
|
185
|
+
productName: z.ZodString;
|
|
186
|
+
quantity: z.ZodOptional<z.ZodNumber>;
|
|
187
|
+
variantId: z.ZodOptional<z.ZodString>;
|
|
188
|
+
variantLabel: z.ZodOptional<z.ZodString>;
|
|
189
|
+
offerId: z.ZodOptional<z.ZodString>;
|
|
190
|
+
variantSelections: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
191
|
+
variantId: z.ZodString;
|
|
192
|
+
variantLabel: z.ZodOptional<z.ZodString>;
|
|
193
|
+
}, z.core.$strip>>>;
|
|
194
|
+
}, z.core.$strip>;
|
|
195
|
+
export type ProductQuoteInput = z.infer<typeof ProductQuoteInputSchema>;
|
|
196
|
+
/** What a quote is asked about: a basket, or one product as its form posts it. */
|
|
197
|
+
export declare const CartQuoteLinesSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
198
|
+
items: z.ZodArray<z.ZodObject<{
|
|
199
|
+
productId: z.ZodString;
|
|
200
|
+
productName: z.ZodString;
|
|
201
|
+
variantId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
202
|
+
variantLabel: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
203
|
+
quantity: z.ZodNumber;
|
|
204
|
+
pricePerUnit: z.ZodOptional<z.ZodNumber>;
|
|
205
|
+
offerId: z.ZodOptional<z.ZodString>;
|
|
206
|
+
}, z.core.$strip>>;
|
|
207
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
208
|
+
productId: z.ZodString;
|
|
209
|
+
productName: z.ZodString;
|
|
210
|
+
quantity: z.ZodOptional<z.ZodNumber>;
|
|
211
|
+
variantId: z.ZodOptional<z.ZodString>;
|
|
212
|
+
variantLabel: z.ZodOptional<z.ZodString>;
|
|
213
|
+
offerId: z.ZodOptional<z.ZodString>;
|
|
214
|
+
variantSelections: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
215
|
+
variantId: z.ZodString;
|
|
216
|
+
variantLabel: z.ZodOptional<z.ZodString>;
|
|
217
|
+
}, z.core.$strip>>>;
|
|
218
|
+
}, z.core.$strip>]>;
|
|
219
|
+
export type CartQuoteLines = z.infer<typeof CartQuoteLinesSchema>;
|
|
178
220
|
/**
|
|
179
221
|
* Where a basket would be delivered, for a delivery quote. The commune is
|
|
180
222
|
* optional — without it the wilaya's rate applies; with it, the commune's own
|
package/dist/domain.js
CHANGED
|
@@ -126,6 +126,31 @@ export const AbandonedCheckoutInputSchema = z.object({
|
|
|
126
126
|
fbc: z.string().max(500).optional(),
|
|
127
127
|
fbp: z.string().max(500).optional(),
|
|
128
128
|
});
|
|
129
|
+
/**
|
|
130
|
+
* One product as a product page's order form posts it: a quantity, or a
|
|
131
|
+
* variant chosen per unit, and an offer tier. The quote reads these the way the
|
|
132
|
+
* order does, so the page asks with exactly what its form will submit.
|
|
133
|
+
*/
|
|
134
|
+
export const ProductQuoteInputSchema = z.object({
|
|
135
|
+
productId: z.string().min(1).max(200),
|
|
136
|
+
productName: z.string().min(1).max(200),
|
|
137
|
+
quantity: z.number().int().min(1).max(MAX_BASKET_LINE_QUANTITY).optional(),
|
|
138
|
+
variantId: z.string().min(1).max(200).optional(),
|
|
139
|
+
variantLabel: z.string().max(200).optional(),
|
|
140
|
+
offerId: z.string().min(1).max(200).optional(),
|
|
141
|
+
variantSelections: z
|
|
142
|
+
.array(z.object({
|
|
143
|
+
variantId: z.string().min(1).max(200),
|
|
144
|
+
variantLabel: z.string().max(200).optional(),
|
|
145
|
+
}))
|
|
146
|
+
.max(MAX_BASKET_LINE_QUANTITY)
|
|
147
|
+
.optional(),
|
|
148
|
+
});
|
|
149
|
+
/** What a quote is asked about: a basket, or one product as its form posts it. */
|
|
150
|
+
export const CartQuoteLinesSchema = z.union([
|
|
151
|
+
z.object({ items: z.array(BasketLineInputSchema).min(1).max(MAX_BASKET_LINES) }),
|
|
152
|
+
ProductQuoteInputSchema,
|
|
153
|
+
]);
|
|
129
154
|
/**
|
|
130
155
|
* Where a basket would be delivered, for a delivery quote. The commune is
|
|
131
156
|
* optional — without it the wilaya's rate applies; with it, the commune's own
|
|
@@ -33,7 +33,9 @@ export interface StorefrontRoutes<C extends AstroAPIContext> {
|
|
|
33
33
|
/** POST `{ phone, requestId, code }` → `{ data: OtpVerifyResult }`. */
|
|
34
34
|
readonly otpVerify: StorefrontApiRoute<C>;
|
|
35
35
|
/**
|
|
36
|
-
* POST `{ items
|
|
36
|
+
* POST a basket `{ items }` or one product `{ productId, productName, quantity,
|
|
37
|
+
* variantSelections, offerId, … }`, each with an optional `destination` →
|
|
38
|
+
* `{ success: true, data: CartValidation }`.
|
|
37
39
|
* With a destination, `data.delivery` is the fee and total the order will charge.
|
|
38
40
|
*/
|
|
39
41
|
readonly cartValidate: StorefrontApiRoute<C>;
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* (see `createProxyEndpoint`), and the server's diagnostic fields ride along.
|
|
22
22
|
*/
|
|
23
23
|
import { z } from "zod";
|
|
24
|
-
import { AbandonedCheckoutInputSchema, BasketLineInputSchema, DeliveryDestinationSchema, MAX_BASKET_LINES, WilayaIdSchema, } from "../domain.js";
|
|
24
|
+
import { AbandonedCheckoutInputSchema, BasketLineInputSchema, DeliveryDestinationSchema, ProductQuoteInputSchema, MAX_BASKET_LINES, WilayaIdSchema, } from "../domain.js";
|
|
25
25
|
import { createProxyEndpoint, } from "./proxy.js";
|
|
26
26
|
export const REVIEWS_PAGE_DEFAULT = 20;
|
|
27
27
|
export const REVIEWS_PAGE_MAX = 50;
|
|
@@ -31,10 +31,17 @@ const otpVerifyInput = z.object({
|
|
|
31
31
|
requestId: z.string().min(1).max(200),
|
|
32
32
|
code: z.string().min(1).max(16),
|
|
33
33
|
});
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
/**
|
|
35
|
+
* A basket, or one product as its order form posts it — the same two shapes the
|
|
36
|
+
* server's quote takes — each with an optional destination to quote to.
|
|
37
|
+
*/
|
|
38
|
+
const cartValidateInput = z.union([
|
|
39
|
+
z.object({
|
|
40
|
+
items: z.array(BasketLineInputSchema).min(1).max(MAX_BASKET_LINES),
|
|
41
|
+
destination: DeliveryDestinationSchema.optional(),
|
|
42
|
+
}),
|
|
43
|
+
ProductQuoteInputSchema.extend({ destination: DeliveryDestinationSchema.optional() }),
|
|
44
|
+
]);
|
|
38
45
|
const abandonedConvertInput = z.object({
|
|
39
46
|
sessionId: z.string().uuid(),
|
|
40
47
|
orderId: z.string().min(1).max(200),
|
|
@@ -88,7 +95,7 @@ export function createStorefrontRoutes(options) {
|
|
|
88
95
|
method: "POST",
|
|
89
96
|
inputSchema: cartValidateInput,
|
|
90
97
|
successBody: (data) => ({ success: true, data }),
|
|
91
|
-
call: (client, {
|
|
98
|
+
call: (client, { destination, ...lines }) => client.cart.quote(lines, destination ? { destination } : undefined),
|
|
92
99
|
}),
|
|
93
100
|
abandonedUpsert: route({
|
|
94
101
|
method: "POST",
|
package/package.json
CHANGED