@wocart/storefront 1.8.0 → 1.9.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/USAGE.md +6 -0
- package/dist/client/collections.d.ts +18 -0
- package/dist/client/collections.js +29 -0
- package/dist/client/index.d.ts +3 -1
- package/dist/client/index.js +4 -1
- package/dist/domain.d.ts +2 -0
- package/dist/domain.js +2 -0
- package/dist/routes.d.ts +1 -0
- package/dist/routes.js +2 -0
- package/dist/schemas.d.ts +6 -0
- package/dist/schemas.js +6 -0
- package/dist/types.d.ts +7 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,18 @@ 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.9.0 — 2026-10-17
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Page type `collection` at `/collections/:handle`: a collection's page,
|
|
13
|
+
which a merchant's menu can now link to. `storefrontPath("collection", {
|
|
14
|
+
handle })` builds it, `matchStorefrontPath` recognises it, and the WhatsApp
|
|
15
|
+
widget counts it as the catalog surface.
|
|
16
|
+
- `store.collections.get(handle)` → `StoreCollection` (handle, title,
|
|
17
|
+
description, in the client's language), `null` for an unknown handle, which
|
|
18
|
+
is not reported as a failure. `StoreCollectionSchema`.
|
|
19
|
+
|
|
8
20
|
## 1.8.0 — 2026-10-17
|
|
9
21
|
|
|
10
22
|
### Added
|
package/USAGE.md
CHANGED
|
@@ -105,6 +105,7 @@ break those links.
|
|
|
105
105
|
| `home` | `/` | the home page | required |
|
|
106
106
|
| `catalog` | `/products` | every product | required |
|
|
107
107
|
| `category` | `/category/:slug` | one category's products | required when the store has categories |
|
|
108
|
+
| `collection` | `/collections/:handle` | one collection's products, in the merchant's order | required — a menu can link to any collection |
|
|
108
109
|
| `product` | `/products/:handle` | one product (its public handle, never an id) | required |
|
|
109
110
|
| `page` | `/pages/:slug` | a legal or merchant page | required — checkout consent links to the store's legal pages |
|
|
110
111
|
| `landing` | `/lp/:slug` | a landing page | required when the store runs landing pages |
|
|
@@ -651,6 +652,11 @@ const onSale = await store.products.list({ onSale: true, limit: 8 });
|
|
|
651
652
|
- An empty or unknown collection lists nothing — show nothing, never the
|
|
652
653
|
whole catalog instead: "Best sellers" means the merchant's picks.
|
|
653
654
|
- `onSale` is computed: a product priced below its compare-at price.
|
|
655
|
+
- A collection has a page of its own (page type `collection`,
|
|
656
|
+
`/collections/:handle`) that a merchant's menu can link to. Name it with
|
|
657
|
+
`store.collections.get(handle)` — title and description in the client's
|
|
658
|
+
language, `null` for an unknown handle (answer a real 404) — and list it
|
|
659
|
+
with `products.list({ collection: handle })`.
|
|
654
660
|
- `featured: true` and `ProductList.storeFeatured` are deprecated: they mean
|
|
655
661
|
the `featured` collection.
|
|
656
662
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collections Namespace - the merchant's curated product lists
|
|
3
|
+
*
|
|
4
|
+
* A collection has a page of its own (`/collections/:handle`, page type
|
|
5
|
+
* `collection`): `get(handle)` names it — title and description in the
|
|
6
|
+
* client's language — and `products.list({ collection })` lists its products
|
|
7
|
+
* in the merchant's order.
|
|
8
|
+
*
|
|
9
|
+
* Failure contract: `get(handle)` → null means "no such collection" or a
|
|
10
|
+
* failed read — the page answers a real 404.
|
|
11
|
+
*/
|
|
12
|
+
import { type ClientCore } from "./core.js";
|
|
13
|
+
import type { StoreCollection } from "../types.js";
|
|
14
|
+
export interface CollectionsNamespace {
|
|
15
|
+
/** A collection by handle (`best-sellers`). Resolves to `null` for an unknown handle or a failed read. */
|
|
16
|
+
get(handle: string): Promise<StoreCollection | null>;
|
|
17
|
+
}
|
|
18
|
+
export declare function createCollectionsNamespace(core: ClientCore): CollectionsNamespace;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collections Namespace - the merchant's curated product lists
|
|
3
|
+
*
|
|
4
|
+
* A collection has a page of its own (`/collections/:handle`, page type
|
|
5
|
+
* `collection`): `get(handle)` names it — title and description in the
|
|
6
|
+
* client's language — and `products.list({ collection })` lists its products
|
|
7
|
+
* in the merchant's order.
|
|
8
|
+
*
|
|
9
|
+
* Failure contract: `get(handle)` → null means "no such collection" or a
|
|
10
|
+
* failed read — the page answers a real 404.
|
|
11
|
+
*/
|
|
12
|
+
import { StoreCollectionSchema } from "../schemas.js";
|
|
13
|
+
import { STOREFRONT_OPERATIONS } from "../domain.js";
|
|
14
|
+
import { localizedPath } from "./paths.js";
|
|
15
|
+
import { isNotFoundAnswer, reportDegradedRead } from "./core.js";
|
|
16
|
+
export function createCollectionsNamespace(core) {
|
|
17
|
+
return {
|
|
18
|
+
async get(handle) {
|
|
19
|
+
try {
|
|
20
|
+
return await core.get(localizedPath(core.config, `/store/collections/${encodeURIComponent(handle)}`), StoreCollectionSchema, { operation: STOREFRONT_OPERATIONS.collectionsGet });
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
if (!isNotFoundAnswer(error))
|
|
24
|
+
reportDegradedRead(core.config, error, "collections.get");
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
package/dist/client/index.d.ts
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* Store Client Factory — the SDK's front door.
|
|
3
3
|
*
|
|
4
4
|
* One server-side call builds the whole read/write surface a theme needs, over one
|
|
5
|
-
* shared core: config, products, categories, pages, menus,
|
|
5
|
+
* shared core: config, products, categories, collections, pages, menus,
|
|
6
|
+
* shipping, geo, cart,
|
|
6
7
|
* orders. The core is internal — consumers see only namespaces.
|
|
7
8
|
*
|
|
8
9
|
* One core means one connection story for every namespace: every read is
|
|
@@ -32,6 +33,7 @@ export declare function createStoreClient(config: StoreScope): {
|
|
|
32
33
|
categories: import("./categories.js").CategoriesNamespace;
|
|
33
34
|
pages: import("./pages.js").PagesNamespace;
|
|
34
35
|
menus: import("./menus.js").MenusNamespace;
|
|
36
|
+
collections: import("./collections.js").CollectionsNamespace;
|
|
35
37
|
pageData: import("./page-data.js").PageDataNamespace;
|
|
36
38
|
shipping: import("./shipping.js").ShippingNamespace;
|
|
37
39
|
geo: import("./geo.js").GeoNamespace;
|
package/dist/client/index.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* Store Client Factory — the SDK's front door.
|
|
3
3
|
*
|
|
4
4
|
* One server-side call builds the whole read/write surface a theme needs, over one
|
|
5
|
-
* shared core: config, products, categories, pages, menus,
|
|
5
|
+
* shared core: config, products, categories, collections, pages, menus,
|
|
6
|
+
* shipping, geo, cart,
|
|
6
7
|
* orders. The core is internal — consumers see only namespaces.
|
|
7
8
|
*
|
|
8
9
|
* One core means one connection story for every namespace: every read is
|
|
@@ -32,6 +33,7 @@ import { createProductsNamespace } from "./products.js";
|
|
|
32
33
|
import { createCategoriesNamespace } from "./categories.js";
|
|
33
34
|
import { createPagesNamespace } from "./pages.js";
|
|
34
35
|
import { createMenusNamespace } from "./menus.js";
|
|
36
|
+
import { createCollectionsNamespace } from "./collections.js";
|
|
35
37
|
import { createPageDataNamespace } from "./page-data.js";
|
|
36
38
|
import { createShippingNamespace } from "./shipping.js";
|
|
37
39
|
import { createGeoNamespace } from "./geo.js";
|
|
@@ -46,6 +48,7 @@ export function createStoreClient(config) {
|
|
|
46
48
|
categories: createCategoriesNamespace(core),
|
|
47
49
|
pages: createPagesNamespace(core),
|
|
48
50
|
menus: createMenusNamespace(core),
|
|
51
|
+
collections: createCollectionsNamespace(core),
|
|
49
52
|
pageData: createPageDataNamespace(core),
|
|
50
53
|
shipping: createShippingNamespace(core),
|
|
51
54
|
geo: createGeoNamespace(core),
|
package/dist/domain.d.ts
CHANGED
|
@@ -354,6 +354,7 @@ export declare const STOREFRONT_OPERATIONS: {
|
|
|
354
354
|
readonly pagesGet: "pages.get";
|
|
355
355
|
readonly pagesLanding: "pages.landing";
|
|
356
356
|
readonly menusGet: "menus.get";
|
|
357
|
+
readonly collectionsGet: "collections.get";
|
|
357
358
|
readonly shippingRates: "shipping.rates";
|
|
358
359
|
readonly shippingRate: "shipping.rate";
|
|
359
360
|
readonly geoCommunes: "geo.communes";
|
|
@@ -392,6 +393,7 @@ export declare const STOREFRONT_RETRY_POLICIES: {
|
|
|
392
393
|
readonly "pages.get": "safe-read";
|
|
393
394
|
readonly "pages.landing": "safe-read";
|
|
394
395
|
readonly "menus.get": "safe-read";
|
|
396
|
+
readonly "collections.get": "safe-read";
|
|
395
397
|
readonly "products.get": "safe-read";
|
|
396
398
|
readonly "products.list": "safe-read";
|
|
397
399
|
readonly "products.reviews.list": "safe-read";
|
package/dist/domain.js
CHANGED
|
@@ -207,6 +207,7 @@ export const STOREFRONT_OPERATIONS = {
|
|
|
207
207
|
pagesGet: "pages.get",
|
|
208
208
|
pagesLanding: "pages.landing",
|
|
209
209
|
menusGet: "menus.get",
|
|
210
|
+
collectionsGet: "collections.get",
|
|
210
211
|
shippingRates: "shipping.rates",
|
|
211
212
|
shippingRate: "shipping.rate",
|
|
212
213
|
geoCommunes: "geo.communes",
|
|
@@ -244,6 +245,7 @@ export const STOREFRONT_RETRY_POLICIES = {
|
|
|
244
245
|
[STOREFRONT_OPERATIONS.pagesGet]: "safe-read",
|
|
245
246
|
[STOREFRONT_OPERATIONS.pagesLanding]: "safe-read",
|
|
246
247
|
[STOREFRONT_OPERATIONS.menusGet]: "safe-read",
|
|
248
|
+
[STOREFRONT_OPERATIONS.collectionsGet]: "safe-read",
|
|
247
249
|
[STOREFRONT_OPERATIONS.productsGet]: "safe-read",
|
|
248
250
|
[STOREFRONT_OPERATIONS.productsList]: "safe-read",
|
|
249
251
|
[STOREFRONT_OPERATIONS.productsReviewsList]: "safe-read",
|
package/dist/routes.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ export declare const STOREFRONT_PAGE_PATHS: {
|
|
|
20
20
|
readonly home: "/";
|
|
21
21
|
readonly catalog: "/products";
|
|
22
22
|
readonly category: "/category/:slug";
|
|
23
|
+
readonly collection: "/collections/:handle";
|
|
23
24
|
readonly product: "/products/:handle";
|
|
24
25
|
readonly page: "/pages/:slug";
|
|
25
26
|
readonly landing: "/lp/:slug";
|
package/dist/routes.js
CHANGED
|
@@ -3,6 +3,7 @@ export const STOREFRONT_PAGE_PATHS = {
|
|
|
3
3
|
home: "/",
|
|
4
4
|
catalog: "/products",
|
|
5
5
|
category: "/category/:slug",
|
|
6
|
+
collection: "/collections/:handle",
|
|
6
7
|
product: "/products/:handle",
|
|
7
8
|
page: "/pages/:slug",
|
|
8
9
|
landing: "/lp/:slug",
|
|
@@ -58,6 +59,7 @@ const WIDGET_SURFACE = {
|
|
|
58
59
|
home: "home",
|
|
59
60
|
catalog: "catalog",
|
|
60
61
|
category: "catalog",
|
|
62
|
+
collection: "catalog",
|
|
61
63
|
product: "product",
|
|
62
64
|
page: "pages",
|
|
63
65
|
landing: "landing",
|
package/dist/schemas.d.ts
CHANGED
|
@@ -246,6 +246,12 @@ interface StoreMenuItemShape {
|
|
|
246
246
|
type: string;
|
|
247
247
|
children: StoreMenuItemShape[];
|
|
248
248
|
}
|
|
249
|
+
/** A collection's page — GET /store/collections/{handle}. Its products come from `products.list({ collection })`. */
|
|
250
|
+
export declare const StoreCollectionSchema: z.ZodObject<{
|
|
251
|
+
handle: z.ZodString;
|
|
252
|
+
title: z.ZodString;
|
|
253
|
+
description: z.ZodNullable<z.ZodString>;
|
|
254
|
+
}, z.core.$strip>;
|
|
249
255
|
export declare const StoreMenuSchema: z.ZodObject<{
|
|
250
256
|
handle: z.ZodString;
|
|
251
257
|
title: z.ZodString;
|
package/dist/schemas.js
CHANGED
|
@@ -145,6 +145,12 @@ export const StoreMenuItemSchema = z.lazy(() => z.object({
|
|
|
145
145
|
type: z.string(),
|
|
146
146
|
children: z.array(StoreMenuItemSchema),
|
|
147
147
|
}));
|
|
148
|
+
/** A collection's page — GET /store/collections/{handle}. Its products come from `products.list({ collection })`. */
|
|
149
|
+
export const StoreCollectionSchema = z.object({
|
|
150
|
+
handle: z.string(),
|
|
151
|
+
title: z.string(),
|
|
152
|
+
description: z.string().nullable(),
|
|
153
|
+
});
|
|
148
154
|
export const StoreMenuSchema = z.object({
|
|
149
155
|
handle: z.string(),
|
|
150
156
|
title: z.string(),
|
package/dist/types.d.ts
CHANGED
|
@@ -212,6 +212,13 @@ export interface StorePagePublic {
|
|
|
212
212
|
metaTitle: string | null;
|
|
213
213
|
metaDescription: string | null;
|
|
214
214
|
}
|
|
215
|
+
/** A collection as its page names it — GET /store/collections/{handle}. */
|
|
216
|
+
export interface StoreCollection {
|
|
217
|
+
handle: string;
|
|
218
|
+
/** In the client's language when the store translated it, else the primary. */
|
|
219
|
+
title: string;
|
|
220
|
+
description: string | null;
|
|
221
|
+
}
|
|
215
222
|
/** A navigation menu — GET /store/menus/{handle}. */
|
|
216
223
|
export interface StoreMenu {
|
|
217
224
|
handle: string;
|
package/package.json
CHANGED