@wocart/storefront 2.2.0 → 3.1.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.
Files changed (43) hide show
  1. package/CHANGELOG.md +138 -0
  2. package/USAGE.md +189 -95
  3. package/dist/answer-readers.js +16 -43
  4. package/dist/astro.d.ts +6 -2
  5. package/dist/astro.js +3 -1
  6. package/dist/client/index.d.ts +1 -1
  7. package/dist/client/index.js +1 -1
  8. package/dist/client/products.d.ts +2 -3
  9. package/dist/client/products.js +2 -3
  10. package/dist/endpoints/revalidate-endpoint.d.ts +37 -0
  11. package/dist/endpoints/revalidate-endpoint.js +32 -0
  12. package/dist/endpoints/storefront-routes.js +1 -1
  13. package/dist/index.d.ts +8 -4
  14. package/dist/index.js +4 -2
  15. package/dist/locale-routing.d.ts +11 -20
  16. package/dist/locale-routing.js +28 -8
  17. package/dist/middleware.d.ts +6 -26
  18. package/dist/middleware.js +0 -9
  19. package/dist/product-view.d.ts +0 -8
  20. package/dist/product-view.js +0 -17
  21. package/dist/revalidate.d.ts +6 -0
  22. package/dist/revalidate.js +6 -0
  23. package/dist/routes.d.ts +44 -27
  24. package/dist/routes.js +54 -13
  25. package/dist/schemas.d.ts +144 -222
  26. package/dist/schemas.js +77 -137
  27. package/dist/seo.js +2 -2
  28. package/dist/server.d.ts +1 -1
  29. package/dist/server.js +1 -1
  30. package/dist/store-request.d.ts +5 -4
  31. package/dist/store-request.js +1 -1
  32. package/dist/storefront-middleware.d.ts +88 -0
  33. package/dist/storefront-middleware.js +37 -0
  34. package/dist/thank-you.d.ts +32 -0
  35. package/dist/thank-you.js +33 -0
  36. package/dist/types.d.ts +76 -111
  37. package/dist/unavailable-store.d.ts +23 -0
  38. package/dist/unavailable-store.js +58 -0
  39. package/dist/variant-picker.d.ts +6 -2
  40. package/dist/variant-picker.js +6 -9
  41. package/dist/whatsapp.d.ts +59 -6
  42. package/dist/whatsapp.js +28 -10
  43. package/package.json +1 -1
package/dist/routes.d.ts CHANGED
@@ -1,19 +1,3 @@
1
- /**
2
- * The storefront's page types and their public paths.
3
- *
4
- * A page type is what a URL *means* — a product, a category, a store page, a
5
- * landing page — and the path is where it lives. The paths are a platform
6
- * contract, not a theme decision: the platform builds them without running
7
- * the theme (the dashboard shows a page's public link, the server names the
8
- * landing page in a conversion's source URL), so a theme renders each page
9
- * type it supports at its path and builds every link to one with
10
- * `storefrontPath` — never a hand-written string. Any other route is the
11
- * theme's own (`/about`, `/offers/summer` …): Astro's file routing owns those,
12
- * and nothing here constrains them.
13
- *
14
- * Language prefixes are applied on top: `localizeHref(storefrontPath(…),
15
- * locale, routing)`.
16
- */
17
1
  import type { WidgetSurfaces } from "./types.js";
18
2
  /** Each page type's public path; `:handle` / `:slug` mark its one parameter. */
19
3
  export declare const STOREFRONT_PAGE_PATHS: {
@@ -28,6 +12,10 @@ export declare const STOREFRONT_PAGE_PATHS: {
28
12
  readonly thankYou: "/thank-you";
29
13
  /** Where a shopper follows an order by its number and phone; `?order=<number>` fills the number in. */
30
14
  readonly trackOrder: "/track-order";
15
+ /** The store's products matching a query; `?q=<words>` is the query. */
16
+ readonly search: "/search";
17
+ /** How to reach the store: its WhatsApp, phone, email and address. */
18
+ readonly contact: "/contact";
31
19
  };
32
20
  /** What a storefront URL means. */
33
21
  export type StorefrontPageType = keyof typeof STOREFRONT_PAGE_PATHS;
@@ -48,6 +36,39 @@ export interface StorefrontPageMatch {
48
36
  * not a path to render.
49
37
  */
50
38
  export declare function storefrontPath<T extends StorefrontPageType>(type: T, params?: StorefrontPathParams<T>): string;
39
+ /**
40
+ * Where a theme mounts each of `createStorefrontRoutes`' routes
41
+ * (`src/pages/api/…`), and where its browser scripts call them: one table,
42
+ * keyed like `StorefrontRoutes`, so the route files and the scripts never
43
+ * drift. Defaults, not requirements: every browser helper still takes its
44
+ * `endpoint`. `:wilayaId` and `:productId` mark a route's one parameter.
45
+ * `orderStatus` has no path here: a theme follows an order through its
46
+ * `orderStatus` action, not a route.
47
+ */
48
+ export declare const STOREFRONT_API_PATHS: {
49
+ readonly otpSend: "/api/otp/send";
50
+ readonly otpVerify: "/api/otp/verify";
51
+ readonly cartValidate: "/api/cart/validate";
52
+ readonly abandonedUpsert: "/api/abandoned/upsert";
53
+ readonly abandonedConvert: "/api/abandoned/convert";
54
+ readonly communes: "/api/communes/:wilayaId";
55
+ readonly reviewsList: "/api/reviews/:productId";
56
+ readonly reviewEligibility: "/api/reviews/eligibility";
57
+ readonly reviewUpload: "/api/reviews/upload";
58
+ readonly reviewSubmit: "/api/reviews/submit";
59
+ };
60
+ /** A storefront route of `createStorefrontRoutes`. */
61
+ export type StorefrontApiName = keyof typeof STOREFRONT_API_PATHS;
62
+ /** The parameter a route's path needs: `{ wilayaId }` for the communes, `{ productId }` for a product's reviews, nothing otherwise. */
63
+ export type StorefrontApiParams<N extends StorefrontApiName> = ParamOf<(typeof STOREFRONT_API_PATHS)[N]> extends never ? Record<string, never> : {
64
+ [K in ParamOf<(typeof STOREFRONT_API_PATHS)[N]>]: string | number;
65
+ };
66
+ /**
67
+ * A storefront route's same-origin path, its parameter encoded:
68
+ * `storefrontApiPath("communes", { wilayaId: 16 })` → `/api/communes/16`.
69
+ * Throws when the parameter is missing.
70
+ */
71
+ export declare function storefrontApiPath<N extends StorefrontApiName>(name: N, params?: StorefrontApiParams<N>): string;
51
72
  /**
52
73
  * Which page type a pathname is, and its parameter (decoded) — or null for
53
74
  * any other path. Exact matches only: `/products/` is the catalog,
@@ -56,19 +77,15 @@ export declare function storefrontPath<T extends StorefrontPageType>(type: T, pa
56
77
  * language prefix (`resolveLocalePath` gives it).
57
78
  */
58
79
  export declare function matchStorefrontPath(rawPathname: string): StorefrontPageMatch | null;
59
- /** One route with a parameter or a fixed path of its own, and the widget surface that renders it. */
60
- export interface StorefrontRoute {
61
- /** Path pattern; `:handle` and `:slug` mark the single path parameter. */
62
- readonly path: string;
63
- /** The `surfaces` key this route belongs to. */
64
- readonly surface: keyof WidgetSurfaces;
65
- }
66
80
  /**
67
- * @deprecated Use `STOREFRONT_PAGE_PATHS` (every page type, the home and the
68
- * catalog index included) with `storefrontPath` and `matchStorefrontPath`.
69
- * Kept equal to what it always listed.
81
+ * The page types that exist in the store's primary language only. A landing
82
+ * page is one campaign — a stack of images and one order form, written once
83
+ * for the ads that point at it — so it has no `/fr/lp/…` address, no language
84
+ * menu and no alternate links.
70
85
  */
71
- export declare const STOREFRONT_ROUTES: readonly StorefrontRoute[];
86
+ export declare const SINGLE_LANGUAGE_PAGE_TYPES: readonly StorefrontPageType[];
87
+ /** Whether a pathname (without its language prefix) is a page that exists in the primary language only. */
88
+ export declare function isSingleLanguagePage(rawPathname: string): boolean;
72
89
  /**
73
90
  * Whether the widget belongs on a pathname: the merchant answers "which
74
91
  * surfaces" (`surfaces[surface]`); this answers which surface a pathname *is*,
package/dist/routes.js CHANGED
@@ -11,6 +11,10 @@ export const STOREFRONT_PAGE_PATHS = {
11
11
  thankYou: "/thank-you",
12
12
  /** Where a shopper follows an order by its number and phone; `?order=<number>` fills the number in. */
13
13
  trackOrder: "/track-order",
14
+ /** The store's products matching a query; `?q=<words>` is the query. */
15
+ search: "/search",
16
+ /** How to reach the store: its WhatsApp, phone, email and address. */
17
+ contact: "/contact",
14
18
  };
15
19
  /**
16
20
  * The public path of a page type, its parameter encoded:
@@ -19,13 +23,45 @@ export const STOREFRONT_PAGE_PATHS = {
19
23
  * not a path to render.
20
24
  */
21
25
  export function storefrontPath(type, params) {
22
- return STOREFRONT_PAGE_PATHS[type].replace(/:([a-z]+)/g, (_, name) => {
26
+ return fillPath(STOREFRONT_PAGE_PATHS[type], `storefrontPath("${type}")`, params);
27
+ }
28
+ function fillPath(template, caller, params) {
29
+ return template.replace(/:([a-zA-Z]+)/g, (_, name) => {
23
30
  const value = params?.[name];
24
- if (!value)
25
- throw new Error(`storefrontPath("${type}") needs "${name}"`);
26
- return encodeURIComponent(value);
31
+ if (value === undefined || value === "")
32
+ throw new Error(`${caller} needs "${name}"`);
33
+ return encodeURIComponent(String(value));
27
34
  });
28
35
  }
36
+ /**
37
+ * Where a theme mounts each of `createStorefrontRoutes`' routes
38
+ * (`src/pages/api/…`), and where its browser scripts call them: one table,
39
+ * keyed like `StorefrontRoutes`, so the route files and the scripts never
40
+ * drift. Defaults, not requirements: every browser helper still takes its
41
+ * `endpoint`. `:wilayaId` and `:productId` mark a route's one parameter.
42
+ * `orderStatus` has no path here: a theme follows an order through its
43
+ * `orderStatus` action, not a route.
44
+ */
45
+ export const STOREFRONT_API_PATHS = {
46
+ otpSend: "/api/otp/send",
47
+ otpVerify: "/api/otp/verify",
48
+ cartValidate: "/api/cart/validate",
49
+ abandonedUpsert: "/api/abandoned/upsert",
50
+ abandonedConvert: "/api/abandoned/convert",
51
+ communes: "/api/communes/:wilayaId",
52
+ reviewsList: "/api/reviews/:productId",
53
+ reviewEligibility: "/api/reviews/eligibility",
54
+ reviewUpload: "/api/reviews/upload",
55
+ reviewSubmit: "/api/reviews/submit",
56
+ };
57
+ /**
58
+ * A storefront route's same-origin path, its parameter encoded:
59
+ * `storefrontApiPath("communes", { wilayaId: 16 })` → `/api/communes/16`.
60
+ * Throws when the parameter is missing.
61
+ */
62
+ export function storefrontApiPath(name, params) {
63
+ return fillPath(STOREFRONT_API_PATHS[name], `storefrontApiPath("${name}")`, params);
64
+ }
29
65
  const MATCHERS = Object.entries(STOREFRONT_PAGE_PATHS).map(([type, path]) => {
30
66
  const names = [];
31
67
  const source = path.replace(/:([a-z]+)/g, (_, name) => {
@@ -56,6 +92,18 @@ export function matchStorefrontPath(rawPathname) {
56
92
  }
57
93
  return null;
58
94
  }
95
+ /**
96
+ * The page types that exist in the store's primary language only. A landing
97
+ * page is one campaign — a stack of images and one order form, written once
98
+ * for the ads that point at it — so it has no `/fr/lp/…` address, no language
99
+ * menu and no alternate links.
100
+ */
101
+ export const SINGLE_LANGUAGE_PAGE_TYPES = ["landing"];
102
+ /** Whether a pathname (without its language prefix) is a page that exists in the primary language only. */
103
+ export function isSingleLanguagePage(rawPathname) {
104
+ const match = matchStorefrontPath(rawPathname);
105
+ return match !== null && SINGLE_LANGUAGE_PAGE_TYPES.includes(match.type);
106
+ }
59
107
  /** The WhatsApp widget surface each page type belongs to (the home surface is the root). */
60
108
  const WIDGET_SURFACE = {
61
109
  home: "home",
@@ -68,16 +116,9 @@ const WIDGET_SURFACE = {
68
116
  checkout: "checkout",
69
117
  thankYou: "thankYou",
70
118
  trackOrder: "pages",
119
+ search: "pages",
120
+ contact: "pages",
71
121
  };
72
- /**
73
- * @deprecated Use `STOREFRONT_PAGE_PATHS` (every page type, the home and the
74
- * catalog index included) with `storefrontPath` and `matchStorefrontPath`.
75
- * Kept equal to what it always listed.
76
- */
77
- export const STOREFRONT_ROUTES = ["product", "category", "page", "landing", "checkout", "thankYou"].map((type) => ({
78
- path: STOREFRONT_PAGE_PATHS[type],
79
- surface: WIDGET_SURFACE[type],
80
- }));
81
122
  /**
82
123
  * Whether the widget belongs on a pathname: the merchant answers "which
83
124
  * surfaces" (`surfaces[surface]`); this answers which surface a pathname *is*,