@wocart/storefront 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 +14 -0
- package/USAGE.md +25 -2
- package/dist/client/cart.d.ts +8 -2
- package/dist/client/cart.js +3 -2
- package/dist/domain.d.ts +14 -0
- package/dist/domain.js +10 -0
- package/dist/endpoints/storefront-routes.d.ts +4 -1
- package/dist/endpoints/storefront-routes.js +3 -2
- package/dist/schemas.d.ts +9 -0
- package/dist/schemas.js +6 -0
- package/dist/types.d.ts +17 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,20 @@ 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.3.0 — 2026-10-15
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Delivery quotes.** `cart.validate(items, { destination })` answers
|
|
13
|
+
`delivery`: the fee and total the order will charge at that wilaya, commune
|
|
14
|
+
and delivery type — product shipping profiles, commune overrides, the
|
|
15
|
+
free-delivery threshold and free-shipping offers included — or
|
|
16
|
+
`available: false` where the store does not deliver. The server computes the
|
|
17
|
+
quote with the same function it charges orders with. A platform server that
|
|
18
|
+
predates the quote answers without `delivery`.
|
|
19
|
+
- `DeliveryDestinationSchema`, `DeliveryDestination` and `CartDeliveryQuote`.
|
|
20
|
+
- The `cartValidate` route passes a `destination` through.
|
|
21
|
+
|
|
8
22
|
## 1.2.0 — 2026-10-15
|
|
9
23
|
|
|
10
24
|
### Added
|
package/USAGE.md
CHANGED
|
@@ -745,6 +745,28 @@ type ShippingRate = {
|
|
|
745
745
|
If the map is empty or one rate is null, show a useful unavailable state. Do
|
|
746
746
|
not silently display zero shipping.
|
|
747
747
|
|
|
748
|
+
These are the store default profile's wilaya rates — a guide for "delivery
|
|
749
|
+
from X DZD", never the fee an order is charged. The fee also depends on each
|
|
750
|
+
product's own shipping profile, the commune, the free-delivery threshold and
|
|
751
|
+
free-shipping offers. To show what the shopper will pay, quote it:
|
|
752
|
+
|
|
753
|
+
~~~ts
|
|
754
|
+
const result = await store.cart.validate(items, {
|
|
755
|
+
destination: { wilayaId: 16, communeId: "c-16-001", deliveryType: "home" },
|
|
756
|
+
});
|
|
757
|
+
|
|
758
|
+
if (result.success && result.data.delivery) {
|
|
759
|
+
const quote = result.data.delivery;
|
|
760
|
+
// quote.available → quote.fee and quote.total are what the order charges.
|
|
761
|
+
// !quote.available → the store does not deliver there; an order is refused.
|
|
762
|
+
}
|
|
763
|
+
~~~
|
|
764
|
+
|
|
765
|
+
The quote comes from the same function the order uses, so the fee and total
|
|
766
|
+
it names are the ones charged. A single-product order form quotes the same
|
|
767
|
+
way, with its one product as the only line. From the browser, post
|
|
768
|
+
`{ items, destination }` to the `cartValidate` route.
|
|
769
|
+
|
|
748
770
|
### Wilayas and communes
|
|
749
771
|
|
|
750
772
|
~~~ts
|
|
@@ -1430,8 +1452,9 @@ render null as not found.
|
|
|
1430
1452
|
### The cart total is different after checkout
|
|
1431
1453
|
|
|
1432
1454
|
This is expected when a browser price, offer, stock state, or delivery value
|
|
1433
|
-
was stale
|
|
1434
|
-
|
|
1455
|
+
was stale, or when the theme computed a fee or total itself. Show the totals
|
|
1456
|
+
cart.validate answers — with a destination for the delivery fee — and treat
|
|
1457
|
+
order creation as the final server decision.
|
|
1435
1458
|
|
|
1436
1459
|
### OTP says unavailable
|
|
1437
1460
|
|
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 } from "../domain.js";
|
|
16
|
+
import type { BasketLineInput, DeliveryDestination } from "../domain.js";
|
|
17
17
|
export interface CartNamespace {
|
|
18
18
|
/**
|
|
19
19
|
* Re-price and re-check a basket against the live catalog.
|
|
@@ -21,8 +21,14 @@ export interface CartNamespace {
|
|
|
21
21
|
* optional variant fields); pricing from their side is never trusted, and
|
|
22
22
|
* each line's product name and variant label come back from the catalog in
|
|
23
23
|
* the client's language.
|
|
24
|
+
*
|
|
25
|
+
* With a `destination`, the answer also carries `delivery`: the fee and
|
|
26
|
+
* total the order would charge there. A theme shows that, never a fee or
|
|
27
|
+
* total of its own making.
|
|
24
28
|
*/
|
|
25
|
-
validate(items: readonly BasketLineInput[]
|
|
29
|
+
validate(items: readonly BasketLineInput[], options?: {
|
|
30
|
+
destination?: DeliveryDestination;
|
|
31
|
+
}): Promise<ClientResult<CartValidation>>;
|
|
26
32
|
}
|
|
27
33
|
/**
|
|
28
34
|
* Create cart namespace
|
package/dist/client/cart.js
CHANGED
|
@@ -19,8 +19,9 @@ import { localizedPath } from "./paths.js";
|
|
|
19
19
|
*/
|
|
20
20
|
export function createCartNamespace(core) {
|
|
21
21
|
return {
|
|
22
|
-
async validate(items) {
|
|
23
|
-
|
|
22
|
+
async validate(items, options) {
|
|
23
|
+
const destination = options?.destination;
|
|
24
|
+
return core.post(localizedPath(core.config, "/store/cart/validate"), destination ? { items, destination } : { items }, { schema: CartValidationSchema, operation: STOREFRONT_OPERATIONS.cartValidate });
|
|
24
25
|
},
|
|
25
26
|
};
|
|
26
27
|
}
|
package/dist/domain.d.ts
CHANGED
|
@@ -175,6 +175,20 @@ 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
|
+
* Where a basket would be delivered, for a delivery quote. The commune is
|
|
180
|
+
* optional — without it the wilaya's rate applies; with it, the commune's own
|
|
181
|
+
* override when the merchant set one.
|
|
182
|
+
*/
|
|
183
|
+
export declare const DeliveryDestinationSchema: z.ZodObject<{
|
|
184
|
+
wilayaId: z.ZodNumber;
|
|
185
|
+
communeId: z.ZodOptional<z.ZodString>;
|
|
186
|
+
deliveryType: z.ZodEnum<{
|
|
187
|
+
home: "home";
|
|
188
|
+
stop_desk: "stop_desk";
|
|
189
|
+
}>;
|
|
190
|
+
}, z.core.$strip>;
|
|
191
|
+
export type DeliveryDestination = z.infer<typeof DeliveryDestinationSchema>;
|
|
178
192
|
/** Shopper's selected delivery mode and destination. Policy decides whether address is required. */
|
|
179
193
|
export declare const DeliverySelectionSchema: z.ZodObject<{
|
|
180
194
|
wilayaId: z.ZodNumber;
|
package/dist/domain.js
CHANGED
|
@@ -126,6 +126,16 @@ 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
|
+
* Where a basket would be delivered, for a delivery quote. The commune is
|
|
131
|
+
* optional — without it the wilaya's rate applies; with it, the commune's own
|
|
132
|
+
* override when the merchant set one.
|
|
133
|
+
*/
|
|
134
|
+
export const DeliveryDestinationSchema = z.object({
|
|
135
|
+
wilayaId: WilayaIdSchema,
|
|
136
|
+
communeId: z.string().min(1).max(200).optional(),
|
|
137
|
+
deliveryType: z.enum(["home", "stop_desk"]),
|
|
138
|
+
});
|
|
129
139
|
/** Shopper's selected delivery mode and destination. Policy decides whether address is required. */
|
|
130
140
|
export const DeliverySelectionSchema = z.object({
|
|
131
141
|
wilayaId: z.number().int().min(1).max(58),
|
|
@@ -32,7 +32,10 @@ export interface StorefrontRoutes<C extends AstroAPIContext> {
|
|
|
32
32
|
readonly otpSend: StorefrontApiRoute<C>;
|
|
33
33
|
/** POST `{ phone, requestId, code }` → `{ data: OtpVerifyResult }`. */
|
|
34
34
|
readonly otpVerify: StorefrontApiRoute<C>;
|
|
35
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* POST `{ items, destination? }` → `{ success: true, data: CartValidation }`.
|
|
37
|
+
* With a destination, `data.delivery` is the fee and total the order will charge.
|
|
38
|
+
*/
|
|
36
39
|
readonly cartValidate: StorefrontApiRoute<C>;
|
|
37
40
|
/** POST an `AbandonedCheckoutInput` → 204. */
|
|
38
41
|
readonly abandonedUpsert: 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, MAX_BASKET_LINES, WilayaIdSchema, } from "../domain.js";
|
|
24
|
+
import { AbandonedCheckoutInputSchema, BasketLineInputSchema, DeliveryDestinationSchema, 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;
|
|
@@ -33,6 +33,7 @@ const otpVerifyInput = z.object({
|
|
|
33
33
|
});
|
|
34
34
|
const cartValidateInput = z.object({
|
|
35
35
|
items: z.array(BasketLineInputSchema).min(1).max(MAX_BASKET_LINES),
|
|
36
|
+
destination: DeliveryDestinationSchema.optional(),
|
|
36
37
|
});
|
|
37
38
|
const abandonedConvertInput = z.object({
|
|
38
39
|
sessionId: z.string().uuid(),
|
|
@@ -87,7 +88,7 @@ export function createStorefrontRoutes(options) {
|
|
|
87
88
|
method: "POST",
|
|
88
89
|
inputSchema: cartValidateInput,
|
|
89
90
|
successBody: (data) => ({ success: true, data }),
|
|
90
|
-
call: (client, { items }) => client.cart.validate(items),
|
|
91
|
+
call: (client, { items, destination }) => destination ? client.cart.validate(items, { destination }) : client.cart.validate(items),
|
|
91
92
|
}),
|
|
92
93
|
abandonedUpsert: route({
|
|
93
94
|
method: "POST",
|
package/dist/schemas.d.ts
CHANGED
|
@@ -692,6 +692,15 @@ export declare const CartValidationSchema: z.ZodObject<{
|
|
|
692
692
|
qualified: z.ZodBoolean;
|
|
693
693
|
remaining: z.ZodNumber;
|
|
694
694
|
}, z.core.$strip>;
|
|
695
|
+
delivery: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
696
|
+
available: z.ZodLiteral<true>;
|
|
697
|
+
fee: z.ZodNumber;
|
|
698
|
+
total: z.ZodNumber;
|
|
699
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
700
|
+
available: z.ZodLiteral<false>;
|
|
701
|
+
fee: z.ZodNull;
|
|
702
|
+
total: z.ZodNull;
|
|
703
|
+
}, z.core.$strip>], "available">>;
|
|
695
704
|
}, z.core.$strip>;
|
|
696
705
|
export declare const CreatedOrderSchema: z.ZodObject<{
|
|
697
706
|
orderId: z.ZodString;
|
package/dist/schemas.js
CHANGED
|
@@ -314,6 +314,12 @@ export const CartValidationSchema = z.object({
|
|
|
314
314
|
qualified: z.boolean(),
|
|
315
315
|
remaining: z.number(),
|
|
316
316
|
}),
|
|
317
|
+
delivery: z
|
|
318
|
+
.discriminatedUnion("available", [
|
|
319
|
+
z.object({ available: z.literal(true), fee: z.number(), total: z.number() }),
|
|
320
|
+
z.object({ available: z.literal(false), fee: z.null(), total: z.null() }),
|
|
321
|
+
])
|
|
322
|
+
.optional(),
|
|
317
323
|
});
|
|
318
324
|
export const CreatedOrderSchema = z.object({
|
|
319
325
|
orderId: z.string(),
|
package/dist/types.d.ts
CHANGED
|
@@ -275,7 +275,24 @@ export interface CartValidation {
|
|
|
275
275
|
qualified: boolean;
|
|
276
276
|
remaining: number;
|
|
277
277
|
};
|
|
278
|
+
/**
|
|
279
|
+
* Present when `validate` was given a destination: what the order would
|
|
280
|
+
* charge there, from the same quote the order itself uses (shipping
|
|
281
|
+
* profiles, commune overrides, the free-delivery threshold and offers).
|
|
282
|
+
* `available: false` — fee and total null — means the store does not
|
|
283
|
+
* deliver there, and an order to it is refused.
|
|
284
|
+
*/
|
|
285
|
+
delivery?: CartDeliveryQuote | undefined;
|
|
278
286
|
}
|
|
287
|
+
export type CartDeliveryQuote = {
|
|
288
|
+
available: true;
|
|
289
|
+
fee: number;
|
|
290
|
+
total: number;
|
|
291
|
+
} | {
|
|
292
|
+
available: false;
|
|
293
|
+
fee: null;
|
|
294
|
+
total: null;
|
|
295
|
+
};
|
|
279
296
|
/** What POST /store/orders returns on 201. */
|
|
280
297
|
export interface CreatedOrder {
|
|
281
298
|
orderId: string;
|
package/package.json
CHANGED