@wocart/storefront 1.23.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/CHANGELOG.md CHANGED
@@ -5,6 +5,47 @@ 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
+ ## 2.0.0 — 2026-10-30
9
+
10
+ A store's images can live on any media host. The server answers every image
11
+ as a `MediaImage` and the store's config says how its images are delivered;
12
+ the image helpers take that delivery instead of a media domain. Requires a
13
+ store server that answers this shape.
14
+
15
+ ### Changed (breaking)
16
+
17
+ - Every image is a `MediaImage`, `{ key, url, width, height }`: a product
18
+ image (`ProductImageSchema`) and a landing image carry `key` and `url`
19
+ (`src`, `srcSm`, `srcMd`, `srcLg` are gone); a category has `image` (was
20
+ `imageUrl`); `StoreConfig` has `logo` (was `logoUrl`) and `ogImage` as
21
+ images.
22
+ - `StoreConfig.media` (`MediaDelivery`, `{ kind, origin }`): where every key is
23
+ served from, and how it is resized — `imagekit`, `cloudflare`, or `direct`.
24
+ - `mediaUrl(key, delivery)`, `mediaImageUrl(url, params, delivery)`,
25
+ `mediaImageSrcset(url, widths, { delivery })` and `pictureOf(image,
26
+ delivery)` take the store's delivery (was a media domain). `mediaImageUrl`
27
+ builds ImageKit's `?tr=` or Cloudflare's `/cdn-cgi/image/`, and answers
28
+ `null` for a `direct` delivery.
29
+ - `productImageSource` reads `url`.
30
+
31
+ ### Removed
32
+
33
+ - `optimizeImage`, `generateSrcSet`, `IMAGE_SIZES`, `getCardImage`,
34
+ `getGalleryImage`, `getThumbnailImage`, `getHeroImage`, `getCategoryImage`,
35
+ `getLogoImage`, `createImageHelpers` and their types: each took a media
36
+ domain, which no longer exists. Use `mediaImageUrl` and `mediaImageSrcset`
37
+ with the size a page shows. They are removed without a deprecating minor
38
+ because no media domain is left for them to take.
39
+
40
+ ### Added
41
+
42
+ - `isMediaKey`, `MediaImage`, `MediaDelivery`, `MediaDeliveryKind`,
43
+ `MediaImageSchema` and `MediaDeliverySchema`.
44
+
45
+ ### Changed
46
+
47
+ - The README is short and points to the documentation at docs.wocart.store.
48
+
8
49
  ## 1.23.0 — 2026-10-25
9
50
 
10
51
  One checkout, one order: a double click, a refreshed submission or a retry
package/README.md CHANGED
@@ -1,20 +1,13 @@
1
1
  # @wocart/storefront
2
2
 
3
3
  The storefront SDK for [Wocart](https://github.com/bighadj22/codflow), the
4
- cash-on-delivery commerce platform for Algeria. It gives a storefront theme
5
- typed, validated access to a store's catalog, delivery prices, basket,
6
- checkout, OTP and order tracking — and keeps prices, rules and secrets on the
7
- server.
4
+ cash-on-delivery commerce platform for Algeria. It gives a storefront typed,
5
+ validated access to a store's catalog, delivery prices, basket, checkout, OTP,
6
+ order tracking and images — and keeps prices, rules and secrets on the server.
8
7
 
9
- - **Typed and validated.** Every server response is parsed against a schema
10
- before your code sees it.
11
- - **Predictable failures.** Reads never throw: they resolve to `null`, `[]` or
12
- `{}` and report through `onError`. Writes return a result whose failure always
13
- carries a structured `DomainError`.
14
- - **Browser-safe by construction.** The root entry exports no client and no
15
- secret; the store API key lives behind `@wocart/storefront/server`.
16
- - **Framework-neutral core, Astro adapters.** Proxy routes, form actions and
17
- the POST/Redirect/GET middleware decision for Astro, with no Astro import.
8
+ **Documentation: [docs.wocart.store/sdk/storefront](https://docs.wocart.store/sdk/storefront)**
9
+ — also in [French](https://docs.wocart.store/fr/sdk/storefront) and
10
+ [Arabic](https://docs.wocart.store/ar/sdk/storefront).
18
11
 
19
12
  ## Install
20
13
 
@@ -22,123 +15,35 @@ server.
22
15
  npm install @wocart/storefront zod
23
16
  ```
24
17
 
25
- `zod` (4.x) is a peer dependency: the SDK's schemas are part of its API — you
26
- can validate with them, and you pass your own schemas to `createProxyEndpoint` —
27
- so your app and the SDK share one copy. npm 7 and later install it
28
- automatically. ESM only. Runs in browsers, Cloudflare Workers, Node and Astro server
29
- runtimes; tooling needs Node 22.12 or newer.
18
+ `zod` 4 is a peer dependency. ESM only; Node 22.12 or newer for tooling.
30
19
 
31
20
  ## Quick start
32
21
 
33
22
  ```ts
34
23
  import { createStoreClient } from "@wocart/storefront/server";
24
+ import { mediaImageUrl } from "@wocart/storefront";
35
25
 
36
- // Server-side only: a page frontmatter, endpoint, action or middleware.
37
- const store = createStoreClient({
38
- serverUrl: env.COD_SERVER_URL, // your store's API origin
39
- apiKey: env.STORE_API_KEY, // server-only secret
40
- onError: (error) => console.warn(error.operation, error.code, error.requestId),
41
- });
26
+ const store = createStoreClient({ serverUrl: env.COD_SERVER_URL, apiKey: env.STORE_API_KEY });
42
27
 
43
- // Reads: typed, validated, safe to render straight away.
44
- const [config, products] = await Promise.all([
45
- store.config.get(), // StoreConfig | null
46
- store.products.list({ featured: true, limit: 8 }), // ProductList[]
47
- ]);
48
- const product = await store.products.get("blue-t-shirt"); // Product | null
49
-
50
- // Writes: a discriminated result, never a thrown HTTP error.
51
- const result = await store.orders.create({
52
- customerName: "أمين",
53
- phone: "0555123456",
54
- wilayaId: 16,
55
- communeId: "c-16-001",
56
- items: [{ productId: "p-1", productName: "Blue T-Shirt", quantity: 1 }],
57
- });
58
-
59
- if (result.success) {
60
- console.log(result.data.orderNumber, result.data.total);
61
- } else {
62
- console.error(result.domainError.category, result.domainError.message);
63
- }
64
- ```
65
-
66
- ## Entry points
67
-
68
- | Import | Runs in | What it holds |
69
- | --- | --- | --- |
70
- | `@wocart/storefront` | browser and server | read-model types and schemas, reference data (58 wilayas, 1,551 communes), money and image helpers, the basket and OTP state machines, language routing, Meta pixel payloads |
71
- | `@wocart/storefront/server` | server only | `createStoreClient`, `StoreClient`, `ClientResult`, `StorefrontError` — the API key lives here — the preview checks (`readPreviewRequest`, `verifyPreviewToken`, `previewResponseHeaders`, `previewConfig`) and revalidation (`readRevalidateRequest`) |
72
- | `@wocart/storefront/astro` | server only | `createStorefrontRoutes`, `createProxyEndpoint`, `placeOrderInput`, `executePlaceOrder`, `collectForwardedHeaders`, `runFormAction` |
73
-
74
- Browser code never receives the key. It calls your own same-origin routes
75
- (for example `src/pages/api/cart.ts`), which call the SDK on the server:
76
-
77
- ```ts
78
- // In the browser: no client, no key.
79
- import { createBasketStore, formatMoney } from "@wocart/storefront";
28
+ const config = await store.config.get();
29
+ const product = await store.products.get("blue-t-shirt");
30
+ const photo = product?.images[0];
31
+ const src = photo && config ? mediaImageUrl(photo.url, { width: 480, fit: "cover", format: "auto" }, config.media) ?? photo.url : null;
80
32
  ```
81
33
 
82
- ## What the client covers
83
-
84
- | Namespace | Use it for |
85
- | --- | --- |
86
- | `config` | store identity, branding, languages, checkout policy, feature flags |
87
- | `products` | catalog lists, product detail, reviews |
88
- | `categories` | catalog navigation |
89
- | `pages` | legal and CMS pages, landing pages |
90
- | `pageData` | the store's saved page document for a surface (render it with [`@wocart/theme`](https://www.npmjs.com/package/@wocart/theme)) |
91
- | `shipping` | home and stop-desk delivery prices per wilaya |
92
- | `geo` | wilayas and communes |
93
- | `cart` | server re-pricing and validation of a browser basket |
94
- | `orders` | order creation, OTP, abandoned checkout, conversion tracking |
95
-
96
- ## How errors work
34
+ Reads never throw: they resolve to `null`, `[]` or `{}` and report through
35
+ `onError`. Writes return `{ success, data }` or a structured `domainError`.
97
36
 
98
- - **Reads** resolve to the empty value (`null`, `[]`, `{}`) so a page still
99
- renders, and report the cause to `onError` as a `DomainError` with
100
- `category`, `code`, `retryable`, `sideEffect`, `operation` and `requestId`.
101
- - **Writes** return `ClientResult<T>`: `{ success: true, data }` or
102
- `{ success: false, error, domainError }`. Branch on
103
- `result.domainError.category` — `validation`, `authentication`, `business`,
104
- `system`, `transport` — instead of status codes.
105
- - **Setup errors are loud.** An empty `serverUrl` or `apiKey` throws
106
- `MISSING_CONFIGURATION` when the client is created, instead of quietly
107
- turning every read into an empty store.
108
-
109
- ## Configuration
37
+ ## Entry points
110
38
 
111
- | Option | Required | Notes |
39
+ | Import | Runs in | Holds |
112
40
  | --- | --- | --- |
113
- | `serverUrl` | yes | your store's API origin |
114
- | `apiKey` | yes | the store API key, sent as `X-Store-API-Key`; server-only |
115
- | `locale` | no | read merchant text in a published store language (`"fr"`); one client per language |
116
- | `theme` | no | your theme's key (`defineTheme({ key })`), to receive the merchant's edits to your theme's text |
117
- | `onError` | no | observability hook for degraded reads |
118
- | `readTimeoutMs` | no | how long one read may take, retries included, before it degrades (default 10 000; `0` for no limit) |
119
-
120
- A storefront deployed by Wocart receives its origin and key as the
121
- `COD_SERVER_URL` and `STORE_API_KEY` environment variables. The SDK reads no
122
- environment variables itself; pass the values in. In Astro, declare the key as
123
- a server secret (`envField.string({ context: "server", access: "secret" })`)
124
- and never expose it as a public variable.
125
-
126
- ## Documentation
127
-
128
- - [USAGE.md](./USAGE.md) — the full guide: every namespace and the UI decisions
129
- it implies, checkout and OTP, Astro actions and proxy routes, languages,
130
- images, and a definition of done for a new theme.
131
- - [CHANGELOG.md](./CHANGELOG.md) — what changed in each release.
132
-
133
- ## Compatibility
41
+ | `@wocart/storefront` | browser and server | types and schemas, reference data, money and image helpers, basket and OTP state |
42
+ | `@wocart/storefront/server` | server only | `createStoreClient` — the store API key lives here — preview and revalidation checks |
43
+ | `@wocart/storefront/astro` | server only | proxy routes, form actions, `placeOrderInput` |
134
44
 
135
- - Follows [semantic versioning](https://semver.org/). Breaking changes ship
136
- only in a new major version and are listed in the changelog.
137
- - Response schemas ignore fields they do not know, so a newer server never
138
- breaks an older SDK; a response missing a required field degrades the read
139
- and reports it.
140
- - Astro 7 is verified. The Astro adapters are structural and import nothing
141
- from Astro.
45
+ [USAGE.md](./USAGE.md) ships with the package for offline reading;
46
+ [CHANGELOG.md](./CHANGELOG.md) lists every release.
142
47
 
143
48
  ## License
144
49
 
package/USAGE.md CHANGED
@@ -214,10 +214,11 @@ server directly.
214
214
 
215
215
  | Export | Use it for |
216
216
  | --- | --- |
217
- | `formatMoney`, `optimizeImage`, `generateSrcSet` | Money text and image URLs |
218
- | `mediaImageUrl` | The Cloudflare resizing URL of a media-domain image, served by the media domain itself (any storefront host); `null` for any other image — the builder behind every image helper and `@wocart/theme/image-service` |
219
- | `mediaUrl(key, mediaDomain)` | The public URL of a stored media key — what a theme's `image` field holds (`{ key: "products/…" }`): `mediaUrl(image.key, MEDIA_DOMAIN)`; `null` with no media domain or a key that cannot name an object. The key is the identity; the URL is derived at render |
220
- | `createImageHelpers(mediaDomain)`, `getCardImage`, `getGalleryImage`, `getThumbnailImage`, `getHeroImage`, `getCategoryImage`, `getLogoImage` | The bound image toolkit (`IMAGE_SIZES` holds the presets) |
217
+ | `formatMoney` | Money text |
218
+ | `mediaImageUrl(url, params, config.media)` | A store image at the size and format a page shows it, from the store's delivery (ImageKit `?tr=` or Cloudflare `/cdn-cgi/image/`); `null` for an image the delivery does not serve, or a `direct` delivery — the builder behind `@wocart/theme/image-service` |
219
+ | `mediaImageSrcset(url, widths, { delivery })` | The same image at several widths, for `srcset` |
220
+ | `mediaUrl(key, config.media)`, `isMediaKey` | The URL of a Media Key — what a theme's `image` field holds (`{ key: "products/…" }`); `null` without a delivery or for a value that is not a key |
221
+ | `pictureOf(image, config.media)` | A picked image ready for an `<img>`: URL, alt, size, focal point |
221
222
  | `WILAYAS`, `ALGERIA_COMMUNES`, `communesForWilaya` | Reference data: 58 wilayas, 1,551 communes, one wilaya's rows |
222
223
  | `isWilayaId` | Whether a value is a wilaya id — the range `WilayaIdSchema` checks on the server, without a schema in the browser |
223
224
  | `readShippingRates`, `readCouponOutcome` | Read in the browser what the server handed it — the rates a page carries, a quote's coupon outcome — accepting exactly what `ShippingRatesSchema` / `CouponOutcomeSchema` accept, without Zod |
@@ -290,7 +291,6 @@ storefront deployed by Wocart receives these:
290
291
  | --- | --- | --- |
291
292
  | `COD_SERVER_URL` | server variable | the store's API origin, e.g. `https://api.your-store.com` |
292
293
  | `STORE_API_KEY` | server secret | the store API key |
293
- | `MEDIA_DOMAIN` | server variable (optional) | media domain for `createImageHelpers(mediaDomain)`; unset → image URLs pass through unchanged |
294
294
 
295
295
  Never put `STORE_API_KEY` in a browser-exposed variable (no `PUBLIC_*`, no
296
296
  `import.meta.env` in client code, no HTML attribute). In Astro, declare it in
@@ -518,11 +518,13 @@ const currencySymbol = config?.currencySymbol ?? "دج";
518
518
  StoreConfig contains the current store identity and presentation fields,
519
519
  including:
520
520
 
521
- - name, domain, logoUrl and themeId (the colors, fontFamily and fontUrl
521
+ - name, domain, logo (a MediaImage) and themeId (the colors, fontFamily and fontUrl
522
522
  fields are deprecated: colors and fonts are theme settings, read from
523
523
  themeSettings);
524
524
  - lang (the primary language), locales, contentOverrides, themeSettings,
525
- currency, currencySymbol, metaTitle, metaDescription, and ogImage;
525
+ currency, currencySymbol, metaTitle, metaDescription, and ogImage (a
526
+ MediaImage);
527
+ - media, the store's MediaDelivery, which every image helper takes;
526
528
  - reviewsEnabled (announcementBar is deprecated and always null: an
527
529
  announcement is a theme's own setting);
528
530
  - cartEnabled, freeShippingThreshold, and cartShippingMode;
@@ -1827,53 +1829,46 @@ price presentation does not drift between cards, product pages, and checkout.
1827
1829
 
1828
1830
  ### Images
1829
1831
 
1832
+ Every image the store's server answers is a `MediaImage` — `{ key, url,
1833
+ width, height }` — and the store's config carries `media`, its
1834
+ `MediaDelivery`: the origin every key is served from and how that origin
1835
+ resizes (`imagekit`, `cloudflare`, or `direct` for files served as stored).
1836
+ Pass `config.media` to the image helpers; one theme then works on every host a
1837
+ store can use.
1838
+
1830
1839
  ~~~ts
1831
- import {
1832
- generateSrcSet,
1833
- getCardImage,
1834
- optimizeImage,
1835
- } from "@wocart/storefront";
1840
+ import { mediaImageUrl } from "@wocart/storefront";
1836
1841
 
1837
- const mediaDomain = env.MEDIA_DOMAIN;
1838
- const originalImage = product.images[0]?.src ?? "";
1839
- const cardImage = getCardImage(originalImage, mediaDomain);
1840
- const src = optimizeImage(originalImage, {
1841
- width: 480,
1842
- height: 480,
1843
- quality: 82,
1844
- format: "auto",
1845
- fit: "cover",
1846
- }, mediaDomain);
1847
- const srcSet = generateSrcSet(originalImage, 480, 480, mediaDomain);
1842
+ const photo = product.images[0];
1843
+ const card = photo ? mediaImageUrl(photo.url, { width: 480, height: 480, fit: "cover", format: "auto", quality: 82 }, config.media) ?? photo.url : null;
1848
1844
  ~~~
1849
1845
 
1850
- The image utility accepts the original media URL and can target a media
1851
- domain. Use it to produce appropriately sized URLs rather than downloading
1852
- original assets into every card.
1846
+ `mediaImageUrl` answers `null` for an image its delivery does not serve and
1847
+ for a `direct` delivery, which does not resize: show the original then.
1853
1848
 
1854
1849
  For an image whose width changes with the screen, give the browser widths and
1855
1850
  let `sizes` choose — a phone then downloads a phone-sized file.
1856
- `mediaImageSrcset(src, widths, { mediaDomain, ratio, quality })` gives one
1857
- size per width with width descriptors, cropped to `ratio` (height ÷ width)
1858
- when given; null off the media domain:
1851
+ `mediaImageSrcset(src, widths, { delivery, ratio, quality })` gives one size
1852
+ per width with width descriptors, cropped to `ratio` (height ÷ width) when
1853
+ given and never enlarged past the original otherwise:
1859
1854
 
1860
1855
  ~~~astro
1861
1856
  <img
1862
- src={mediaImageUrl(src, { width: 720, format: "auto" }, mediaDomain) ?? src}
1863
- srcset={mediaImageSrcset(src, [360, 540, 720, 1080], { mediaDomain, ratio: 1.25 }) ?? undefined}
1857
+ src={mediaImageUrl(src, { width: 720, fit: "scale-down", format: "auto" }, config.media) ?? src}
1858
+ srcset={mediaImageSrcset(src, [360, 540, 720, 1080], { delivery: config.media, ratio: 1.25 }) ?? undefined}
1864
1859
  sizes="(min-width: 1024px) 25vw, 50vw"
1865
1860
  alt="" loading="lazy" />
1866
1861
  ~~~
1867
1862
 
1868
- A photo a merchant picks for a section is stored as a media key with its alt
1869
- text, size and focal point. `pictureOf(image, mediaDomain)` turns it into what
1863
+ A photo a merchant picks for a section is stored as a Media Key with its alt
1864
+ text, size and focal point. `pictureOf(image, config.media)` turns it into what
1870
1865
  an `<img>` needs — `src`, `alt` (empty when none was written), `width`,
1871
1866
  `height` and `position`, the focal point as CSS `object-position` — or null
1872
1867
  when none is picked:
1873
1868
 
1874
1869
  ~~~astro
1875
1870
  ---
1876
- const picture = pictureOf(props.image, mediaDomain);
1871
+ const picture = pictureOf(props.image, config.media);
1877
1872
  ---
1878
1873
  {picture && <img src={picture.src} alt={picture.alt} width={picture.width} height={picture.height} style={{ objectPosition: picture.position }} />}
1879
1874
  ~~~
@@ -1886,10 +1881,10 @@ thumbnail. `productImageSource` answers which image represents the product, so
1886
1881
  a cart drawer, a checkout summary and a product card cannot disagree:
1887
1882
 
1888
1883
  ~~~ts
1889
- import { getThumbnailImage, productImageSource } from "@wocart/storefront";
1884
+ import { mediaImageUrl, productImageSource } from "@wocart/storefront";
1890
1885
 
1891
1886
  const src = productImageSource(product); // Product | ProductList
1892
- const thumbnail = src ? getThumbnailImage(src) : null;
1887
+ const thumbnail = src ? mediaImageUrl(src, { width: 160, height: 160, fit: "cover", format: "auto" }, config.media) ?? src : null;
1893
1888
  ~~~
1894
1889
 
1895
1890
  It prefers the merchant's cover and falls back to the first usable gallery
@@ -1897,40 +1892,6 @@ image; `null` means the product genuinely has no photograph, so that is the
1897
1892
  moment to render a placeholder. The list model carries no gallery at all, so a
1898
1893
  card gets the cover or `null`.
1899
1894
 
1900
- Available semantic helpers include:
1901
-
1902
- - getCardImage;
1903
- - getGalleryImage;
1904
- - getThumbnailImage;
1905
- - getHeroImage;
1906
- - getCategoryImage;
1907
- - getLogoImage.
1908
-
1909
- The helper chooses the appropriate image role. The theme still owns layout,
1910
- aspect ratio, alt text, lazy loading, placeholders, and art direction.
1911
-
1912
- #### Bind the media domain once
1913
-
1914
- Do not thread the media domain through every call site — a missed argument
1915
- silently ships an unoptimized image. Bind it once and use the URL-only helper
1916
- set:
1917
-
1918
- ~~~ts
1919
- import { createImageHelpers } from "@wocart/storefront";
1920
-
1921
- const images = createImageHelpers(env.MEDIA_DOMAIN);
1922
-
1923
- const thumbnail = images.getThumbnailImage(product.images[0].src);
1924
- const preview = images.getCardImage(product.images[0].src);
1925
- const srcSet = images.generateSrcSet(product.images[0].src, 480, 480);
1926
- ~~~
1927
-
1928
- The returned toolkit exposes the same helpers plus `optimizeImage`,
1929
- `generateSrcSet`, and `IMAGE_SIZES`. With no domain bound, every helper returns
1930
- the original URL unchanged, so a store without a media domain needs no branch —
1931
- and `optimizeImage` / `generateSrcSet` still take a per-call domain that
1932
- overrides the bound one.
1933
-
1934
1895
  ## WhatsApp prefill messages
1935
1896
 
1936
1897
  The storefront's WhatsApp launcher hands the shopper to WhatsApp with a message
package/dist/index.d.ts CHANGED
@@ -11,8 +11,8 @@
11
11
  */
12
12
  export { formatMoney } from "./utils/money.js";
13
13
  export type { MoneyFormatOptions } from "./utils/money.js";
14
- export { optimizeImage, generateSrcSet, IMAGE_SIZES, getCardImage, getGalleryImage, getThumbnailImage, getHeroImage, getCategoryImage, getLogoImage, createImageHelpers, mediaImageUrl, mediaImageSrcset, mediaUrl, pictureOf, } from "./utils/image.js";
15
- export type { ImageHelpers, ImageResizeOptions, MediaImageParams, MediaImageSrcsetOptions, PickedImage, Picture } from "./utils/image.js";
14
+ export { isMediaKey, mediaImageSrcset, mediaImageUrl, mediaUrl, pictureOf } from "./utils/image.js";
15
+ export type { MediaDelivery, MediaDeliveryKind, MediaImage, MediaImageParams, MediaImageSrcsetOptions, PickedImage, Picture } from "./utils/image.js";
16
16
  export { productImageSource } from "./utils/product-image.js";
17
17
  export type { ProductImageSourceInput } from "./utils/product-image.js";
18
18
  export { MAX_RESOLVED_PREFILL_LENGTH, PREFILL_TOKENS, stripTrackingParams, truncateAtWordBoundary, resolvePrefillText, buildWhatsAppHref, } from "./whatsapp.js";
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@
10
10
  * Internal modules stay reachable only through their intentional entry points.
11
11
  */
12
12
  export { formatMoney } from "./utils/money.js";
13
- export { optimizeImage, generateSrcSet, IMAGE_SIZES, getCardImage, getGalleryImage, getThumbnailImage, getHeroImage, getCategoryImage, getLogoImage, createImageHelpers, mediaImageUrl, mediaImageSrcset, mediaUrl, pictureOf, } from "./utils/image.js";
13
+ export { isMediaKey, mediaImageSrcset, mediaImageUrl, mediaUrl, pictureOf } from "./utils/image.js";
14
14
  export { productImageSource } from "./utils/product-image.js";
15
15
  export { MAX_RESOLVED_PREFILL_LENGTH, PREFILL_TOKENS, stripTrackingParams, truncateAtWordBoundary, resolvePrefillText, buildWhatsAppHref, } from "./whatsapp.js";
16
16
  export { STOREFRONT_PAGE_PATHS, STOREFRONT_ROUTES, matchStorefrontPath, showsWidgetOn, storefrontPath } from "./routes.js";
package/dist/schemas.d.ts CHANGED
@@ -1,10 +1,24 @@
1
1
  import { z } from "zod";
2
+ export declare const MediaImageSchema: z.ZodObject<{
3
+ key: z.ZodString;
4
+ url: z.ZodString;
5
+ width: z.ZodNullable<z.ZodNumber>;
6
+ height: z.ZodNullable<z.ZodNumber>;
7
+ }, z.core.$strip>;
8
+ export declare const MediaDeliverySchema: z.ZodObject<{
9
+ kind: z.ZodEnum<{
10
+ cloudflare: "cloudflare";
11
+ direct: "direct";
12
+ imagekit: "imagekit";
13
+ }>;
14
+ origin: z.ZodString;
15
+ }, z.core.$strip>;
2
16
  export declare const ProductImageSchema: z.ZodObject<{
17
+ key: z.ZodString;
18
+ url: z.ZodString;
19
+ width: z.ZodNullable<z.ZodNumber>;
20
+ height: z.ZodNullable<z.ZodNumber>;
3
21
  id: z.ZodString;
4
- src: z.ZodString;
5
- srcSm: z.ZodNullable<z.ZodString>;
6
- srcMd: z.ZodNullable<z.ZodString>;
7
- srcLg: z.ZodNullable<z.ZodString>;
8
22
  altText: z.ZodNullable<z.ZodString>;
9
23
  position: z.ZodNumber;
10
24
  }, z.core.$strip>;
@@ -64,7 +78,12 @@ export declare const CategorySchema: z.ZodObject<{
64
78
  slug: z.ZodString;
65
79
  description: z.ZodNullable<z.ZodString>;
66
80
  parentId: z.ZodNullable<z.ZodString>;
67
- imageUrl: z.ZodNullable<z.ZodString>;
81
+ image: z.ZodNullable<z.ZodObject<{
82
+ key: z.ZodString;
83
+ url: z.ZodString;
84
+ width: z.ZodNullable<z.ZodNumber>;
85
+ height: z.ZodNullable<z.ZodNumber>;
86
+ }, z.core.$strip>>;
68
87
  metaTitle: z.ZodNullable<z.ZodString>;
69
88
  metaDescription: z.ZodNullable<z.ZodString>;
70
89
  metaKeywords: z.ZodNullable<z.ZodString>;
@@ -114,11 +133,11 @@ export declare const ProductListSchema: z.ZodObject<{
114
133
  variantOptions: z.ZodNullable<z.ZodString>;
115
134
  tags: z.ZodNullable<z.ZodString>;
116
135
  coverImage: z.ZodNullable<z.ZodObject<{
136
+ key: z.ZodString;
137
+ url: z.ZodString;
138
+ width: z.ZodNullable<z.ZodNumber>;
139
+ height: z.ZodNullable<z.ZodNumber>;
117
140
  id: z.ZodString;
118
- src: z.ZodString;
119
- srcSm: z.ZodNullable<z.ZodString>;
120
- srcMd: z.ZodNullable<z.ZodString>;
121
- srcLg: z.ZodNullable<z.ZodString>;
122
141
  altText: z.ZodNullable<z.ZodString>;
123
142
  position: z.ZodNumber;
124
143
  }, z.core.$strip>>;
@@ -180,7 +199,12 @@ export declare const ProductSchema: z.ZodObject<{
180
199
  slug: z.ZodString;
181
200
  description: z.ZodNullable<z.ZodString>;
182
201
  parentId: z.ZodNullable<z.ZodString>;
183
- imageUrl: z.ZodNullable<z.ZodString>;
202
+ image: z.ZodNullable<z.ZodObject<{
203
+ key: z.ZodString;
204
+ url: z.ZodString;
205
+ width: z.ZodNullable<z.ZodNumber>;
206
+ height: z.ZodNullable<z.ZodNumber>;
207
+ }, z.core.$strip>>;
184
208
  metaTitle: z.ZodNullable<z.ZodString>;
185
209
  metaDescription: z.ZodNullable<z.ZodString>;
186
210
  metaKeywords: z.ZodNullable<z.ZodString>;
@@ -208,11 +232,11 @@ export declare const ProductSchema: z.ZodObject<{
208
232
  updatedAt: z.ZodString;
209
233
  }, z.core.$strip>>;
210
234
  images: z.ZodArray<z.ZodObject<{
235
+ key: z.ZodString;
236
+ url: z.ZodString;
237
+ width: z.ZodNullable<z.ZodNumber>;
238
+ height: z.ZodNullable<z.ZodNumber>;
211
239
  id: z.ZodString;
212
- src: z.ZodString;
213
- srcSm: z.ZodNullable<z.ZodString>;
214
- srcMd: z.ZodNullable<z.ZodString>;
215
- srcLg: z.ZodNullable<z.ZodString>;
216
240
  altText: z.ZodNullable<z.ZodString>;
217
241
  position: z.ZodNumber;
218
242
  }, z.core.$strip>>;
@@ -282,11 +306,11 @@ export declare const StoreCollectionSchema: z.ZodObject<{
282
306
  description: z.ZodNullable<z.ZodString>;
283
307
  productCount: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
284
308
  image: z.ZodOptional<z.ZodNullable<z.ZodObject<{
309
+ key: z.ZodString;
310
+ url: z.ZodString;
311
+ width: z.ZodNullable<z.ZodNumber>;
312
+ height: z.ZodNullable<z.ZodNumber>;
285
313
  id: z.ZodString;
286
- src: z.ZodString;
287
- srcSm: z.ZodNullable<z.ZodString>;
288
- srcMd: z.ZodNullable<z.ZodString>;
289
- srcLg: z.ZodNullable<z.ZodString>;
290
314
  altText: z.ZodNullable<z.ZodString>;
291
315
  position: z.ZodNumber;
292
316
  }, z.core.$strip>>>;
@@ -417,7 +441,12 @@ export declare const StoreConfigSchema: z.ZodObject<{
417
441
  id: z.ZodString;
418
442
  name: z.ZodString;
419
443
  domain: z.ZodNullable<z.ZodString>;
420
- logoUrl: z.ZodNullable<z.ZodString>;
444
+ logo: z.ZodNullable<z.ZodObject<{
445
+ key: z.ZodString;
446
+ url: z.ZodString;
447
+ width: z.ZodNullable<z.ZodNumber>;
448
+ height: z.ZodNullable<z.ZodNumber>;
449
+ }, z.core.$strip>>;
421
450
  themeId: z.ZodString;
422
451
  primaryColor: z.ZodString;
423
452
  accentColor: z.ZodString;
@@ -440,7 +469,20 @@ export declare const StoreConfigSchema: z.ZodObject<{
440
469
  currencySymbol: z.ZodString;
441
470
  metaTitle: z.ZodNullable<z.ZodString>;
442
471
  metaDescription: z.ZodNullable<z.ZodString>;
443
- ogImage: z.ZodNullable<z.ZodString>;
472
+ ogImage: z.ZodNullable<z.ZodObject<{
473
+ key: z.ZodString;
474
+ url: z.ZodString;
475
+ width: z.ZodNullable<z.ZodNumber>;
476
+ height: z.ZodNullable<z.ZodNumber>;
477
+ }, z.core.$strip>>;
478
+ media: z.ZodObject<{
479
+ kind: z.ZodEnum<{
480
+ cloudflare: "cloudflare";
481
+ direct: "direct";
482
+ imagekit: "imagekit";
483
+ }>;
484
+ origin: z.ZodString;
485
+ }, z.core.$strip>;
444
486
  announcementBar: z.ZodNullable<z.ZodString>;
445
487
  reviewsEnabled: z.ZodBoolean;
446
488
  cartEnabled: z.ZodBoolean;
@@ -549,12 +591,13 @@ export declare const StoreConfigSchema: z.ZodObject<{
549
591
  }, z.core.$strip>>>;
550
592
  }, z.core.$strip>;
551
593
  export declare const LandingPageImageSchema: z.ZodObject<{
594
+ key: z.ZodString;
595
+ url: z.ZodString;
596
+ width: z.ZodNullable<z.ZodNumber>;
597
+ height: z.ZodNullable<z.ZodNumber>;
552
598
  id: z.ZodString;
553
- src: z.ZodString;
554
599
  altText: z.ZodNullable<z.ZodString>;
555
600
  position: z.ZodNumber;
556
- width: z.ZodDefault<z.ZodNullable<z.ZodNumber>>;
557
- height: z.ZodDefault<z.ZodNullable<z.ZodNumber>>;
558
601
  }, z.core.$strip>;
559
602
  export declare const LandingPageSchema: z.ZodObject<{
560
603
  id: z.ZodString;
@@ -570,12 +613,13 @@ export declare const LandingPageSchema: z.ZodObject<{
570
613
  metaDescription: z.ZodNullable<z.ZodString>;
571
614
  publishedAt: z.ZodNullable<z.ZodString>;
572
615
  images: z.ZodArray<z.ZodObject<{
616
+ key: z.ZodString;
617
+ url: z.ZodString;
618
+ width: z.ZodNullable<z.ZodNumber>;
619
+ height: z.ZodNullable<z.ZodNumber>;
573
620
  id: z.ZodString;
574
- src: z.ZodString;
575
621
  altText: z.ZodNullable<z.ZodString>;
576
622
  position: z.ZodNumber;
577
- width: z.ZodDefault<z.ZodNullable<z.ZodNumber>>;
578
- height: z.ZodDefault<z.ZodNullable<z.ZodNumber>>;
579
623
  }, z.core.$strip>>;
580
624
  product: z.ZodNullable<z.ZodObject<{
581
625
  id: z.ZodString;
@@ -630,7 +674,12 @@ export declare const LandingPageSchema: z.ZodObject<{
630
674
  slug: z.ZodString;
631
675
  description: z.ZodNullable<z.ZodString>;
632
676
  parentId: z.ZodNullable<z.ZodString>;
633
- imageUrl: z.ZodNullable<z.ZodString>;
677
+ image: z.ZodNullable<z.ZodObject<{
678
+ key: z.ZodString;
679
+ url: z.ZodString;
680
+ width: z.ZodNullable<z.ZodNumber>;
681
+ height: z.ZodNullable<z.ZodNumber>;
682
+ }, z.core.$strip>>;
634
683
  metaTitle: z.ZodNullable<z.ZodString>;
635
684
  metaDescription: z.ZodNullable<z.ZodString>;
636
685
  metaKeywords: z.ZodNullable<z.ZodString>;
@@ -658,11 +707,11 @@ export declare const LandingPageSchema: z.ZodObject<{
658
707
  updatedAt: z.ZodString;
659
708
  }, z.core.$strip>>;
660
709
  images: z.ZodArray<z.ZodObject<{
710
+ key: z.ZodString;
711
+ url: z.ZodString;
712
+ width: z.ZodNullable<z.ZodNumber>;
713
+ height: z.ZodNullable<z.ZodNumber>;
661
714
  id: z.ZodString;
662
- src: z.ZodString;
663
- srcSm: z.ZodNullable<z.ZodString>;
664
- srcMd: z.ZodNullable<z.ZodString>;
665
- srcLg: z.ZodNullable<z.ZodString>;
666
715
  altText: z.ZodNullable<z.ZodString>;
667
716
  position: z.ZodNumber;
668
717
  }, z.core.$strip>>;
@@ -904,11 +953,11 @@ export declare const ProductPageEnvelopeSchema: z.ZodObject<{
904
953
  variantOptions: z.ZodNullable<z.ZodString>;
905
954
  tags: z.ZodNullable<z.ZodString>;
906
955
  coverImage: z.ZodNullable<z.ZodObject<{
956
+ key: z.ZodString;
957
+ url: z.ZodString;
958
+ width: z.ZodNullable<z.ZodNumber>;
959
+ height: z.ZodNullable<z.ZodNumber>;
907
960
  id: z.ZodString;
908
- src: z.ZodString;
909
- srcSm: z.ZodNullable<z.ZodString>;
910
- srcMd: z.ZodNullable<z.ZodString>;
911
- srcLg: z.ZodNullable<z.ZodString>;
912
961
  altText: z.ZodNullable<z.ZodString>;
913
962
  position: z.ZodNumber;
914
963
  }, z.core.$strip>>;