@wocart/storefront 1.23.0 → 2.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.
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>>;
@@ -697,6 +746,11 @@ export declare const LandingPageSchema: z.ZodObject<{
697
746
  rewardUnitPrice: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
698
747
  }, z.core.$strip>>;
699
748
  }, z.core.$strip>>;
749
+ document: z.ZodDefault<z.ZodCatch<z.ZodNullable<z.ZodObject<{
750
+ version: z.ZodNumber;
751
+ surface: z.ZodString;
752
+ sections: z.ZodArray<z.ZodUnknown>;
753
+ }, z.core.$loose>>>>;
700
754
  tracking: z.ZodObject<{
701
755
  pixelId: z.ZodNullable<z.ZodString>;
702
756
  conversionEvent: z.ZodEnum<{
@@ -904,11 +958,11 @@ export declare const ProductPageEnvelopeSchema: z.ZodObject<{
904
958
  variantOptions: z.ZodNullable<z.ZodString>;
905
959
  tags: z.ZodNullable<z.ZodString>;
906
960
  coverImage: z.ZodNullable<z.ZodObject<{
961
+ key: z.ZodString;
962
+ url: z.ZodString;
963
+ width: z.ZodNullable<z.ZodNumber>;
964
+ height: z.ZodNullable<z.ZodNumber>;
907
965
  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
966
  altText: z.ZodNullable<z.ZodString>;
913
967
  position: z.ZodNumber;
914
968
  }, z.core.$strip>>;
package/dist/schemas.js CHANGED
@@ -1,10 +1,17 @@
1
1
  import { z } from "zod";
2
- export const ProductImageSchema = z.object({
2
+ import { MEDIA_DELIVERY_KINDS } from "./utils/image.js";
3
+ export const MediaImageSchema = z.object({
4
+ key: z.string(),
5
+ url: z.string().url(),
6
+ width: z.number().int().nullable(),
7
+ height: z.number().int().nullable(),
8
+ });
9
+ export const MediaDeliverySchema = z.object({
10
+ kind: z.enum(MEDIA_DELIVERY_KINDS),
11
+ origin: z.string().url(),
12
+ });
13
+ export const ProductImageSchema = MediaImageSchema.extend({
3
14
  id: z.string(),
4
- src: z.string().url(),
5
- srcSm: z.string().url().nullable(),
6
- srcMd: z.string().url().nullable(),
7
- srcLg: z.string().url().nullable(),
8
15
  altText: z.string().nullable(),
9
16
  position: z.number().int().min(0),
10
17
  });
@@ -63,7 +70,7 @@ const productCategorySchema = z.object({
63
70
  slug: z.string(),
64
71
  description: z.string().nullable(),
65
72
  parentId: z.string().nullable(),
66
- imageUrl: z.string().url().nullable(),
73
+ image: MediaImageSchema.nullable(),
67
74
  metaTitle: z.string().nullable(),
68
75
  metaDescription: z.string().nullable(),
69
76
  metaKeywords: z.string().nullable(),
@@ -265,7 +272,7 @@ export const StoreConfigSchema = z.object({
265
272
  id: z.string(),
266
273
  name: z.string(),
267
274
  domain: z.string().nullable(),
268
- logoUrl: z.string().nullable(),
275
+ logo: MediaImageSchema.nullable(),
269
276
  themeId: z.string(),
270
277
  primaryColor: z.string(),
271
278
  accentColor: z.string(),
@@ -290,7 +297,8 @@ export const StoreConfigSchema = z.object({
290
297
  currencySymbol: z.string(),
291
298
  metaTitle: z.string().nullable(),
292
299
  metaDescription: z.string().nullable(),
293
- ogImage: z.string().nullable(),
300
+ ogImage: MediaImageSchema.nullable(),
301
+ media: MediaDeliverySchema,
294
302
  announcementBar: z.string().nullable(),
295
303
  reviewsEnabled: z.boolean(),
296
304
  cartEnabled: z.boolean(),
@@ -317,13 +325,10 @@ export const StoreConfigSchema = z.object({
317
325
  legalContact: StoreLegalContactSchema.nullable().default(null),
318
326
  whatsapp: StoreWhatsAppWidgetSchema.nullable().default(null),
319
327
  });
320
- export const LandingPageImageSchema = z.object({
328
+ export const LandingPageImageSchema = MediaImageSchema.extend({
321
329
  id: z.string(),
322
- src: z.string(),
323
330
  altText: z.string().nullable(),
324
331
  position: z.number().int(),
325
- width: z.number().int().nullable().default(null),
326
- height: z.number().int().nullable().default(null),
327
332
  });
328
333
  export const LandingPageSchema = z.object({
329
334
  id: z.string(),
@@ -336,6 +341,7 @@ export const LandingPageSchema = z.object({
336
341
  publishedAt: z.string().nullable(),
337
342
  images: z.array(LandingPageImageSchema),
338
343
  product: ProductSchema.nullable(),
344
+ document: PageDocumentPayloadSchema.nullable().catch(null).default(null),
339
345
  tracking: z.object({
340
346
  pixelId: z.string().nullable(),
341
347
  conversionEvent: z.enum([
package/dist/seo.js CHANGED
@@ -55,7 +55,7 @@ export function productStructuredData(product, options) {
55
55
  ? { "@type": "AggregateOffer", url: options.url, priceCurrency: product.currency, lowPrice: Math.min(...prices), highPrice: Math.max(...prices), offerCount: prices.length, availability }
56
56
  : { "@type": "Offer", url: options.url, priceCurrency: product.currency, price: view.basePrice, availability, itemCondition: "https://schema.org/NewCondition" };
57
57
  const sku = product.sku ?? (product.hasVariants ? initialVariant(product)?.sku : null) ?? null;
58
- const images = [...product.images].sort((a, b) => a.position - b.position).map((image) => image.src);
58
+ const images = [...product.images].sort((a, b) => a.position - b.position).map((image) => image.url);
59
59
  const rating = product.reviewStats && product.reviewStats.reviewCount > 0 ? product.reviewStats : null;
60
60
  return {
61
61
  "@context": "https://schema.org",
package/dist/types.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { COUPON_REFUSAL_REASONS } from "./coupon.js";
2
2
  import type { PRODUCT_SORTS, SHOPPER_ORDER_STAGES } from "./catalog.js";
3
3
  import { z } from "zod";
4
+ import type { MediaDelivery, MediaImage } from "./utils/image.js";
4
5
  import { ProductSchema, ProductListSchema, CategorySchema, ProductImageSchema, ProductVariantSchema, OfferSchema, QuantityPricingSchema, PageDocumentPayloadSchema } from "./schemas.js";
5
6
  export type Product = z.infer<typeof ProductSchema>;
6
7
  export type ProductList = z.infer<typeof ProductListSchema>;
@@ -67,7 +68,7 @@ export interface StoreConfig {
67
68
  id: string;
68
69
  name: string;
69
70
  domain: string | null;
70
- logoUrl: string | null;
71
+ logo: MediaImage | null;
71
72
  themeId: string;
72
73
  /**
73
74
  * @deprecated A store's colors and font are its theme's settings: declare
@@ -124,7 +125,10 @@ export interface StoreConfig {
124
125
  currencySymbol: string;
125
126
  metaTitle: string | null;
126
127
  metaDescription: string | null;
127
- ogImage: string | null;
128
+ /** The image links to the store show when shared. */
129
+ ogImage: MediaImage | null;
130
+ /** Where every image key is served from, and how it is resized: pass it to `mediaUrl`, `mediaImageUrl` and `pictureOf`. */
131
+ media: MediaDelivery;
128
132
  /**
129
133
  * @deprecated Always null. An announcement is a theme's own content: declare
130
134
  * it as a theme setting and read `themeSettings`. Removed in 2.0.
@@ -256,14 +260,10 @@ export interface WilayaRates {
256
260
  stopDesk: number;
257
261
  }
258
262
  /** One image in a landing page's ordered stack. */
259
- export interface LandingPageImage {
263
+ export interface LandingPageImage extends MediaImage {
260
264
  id: string;
261
- src: string;
262
265
  altText: string | null;
263
266
  position: number;
264
- /** Intrinsic dimensions (px), captured at upload — the page reserves the box. */
265
- width: number | null;
266
- height: number | null;
267
267
  }
268
268
  /**
269
269
  * A published landing page — GET /store/landing-pages/{slug}.
@@ -296,6 +296,12 @@ export interface LandingPage {
296
296
  pixelId: string | null;
297
297
  conversionEvent: "Lead" | "Purchase" | "Purchase_Confirmed" | "Purchase_Delivered";
298
298
  };
299
+ /**
300
+ * The page's own composition for the client's `theme` (its `lp:<id>`
301
+ * document), or null when it has none, the client names no theme, or the
302
+ * server predates it: the theme then renders its `landing` default.
303
+ */
304
+ document: PageDocumentPayload | null;
299
305
  }
300
306
  export interface Wilaya {
301
307
  id: number;
@@ -1,88 +1,74 @@
1
1
  /**
2
- * Cloudflare Image Resizing Utility
2
+ * The store's images: where a key is served, and how a photo is asked for at
3
+ * the size a page shows it.
3
4
  *
4
- * Generates optimized image URLs using Cloudflare's Image Resizing service.
5
- * Automatically resizes images to exact dimensions and converts to WebP format.
6
- *
7
- * Deep module: hides Cloudflare CDN-CGI URL construction, fit modes, format
8
- * negotiation, and no-op fallback logic behind a simple interface.
5
+ * Every image the store's server answers is a `MediaImage` — its key and its
6
+ * URL — and the store's config carries its `MediaDelivery`: the origin every
7
+ * key is served from and how that origin resizes. These helpers take that
8
+ * delivery, so one theme works on every host a store can use.
9
9
  */
10
- export interface ImageResizeOptions {
11
- width: number;
12
- height: number;
13
- quality?: number;
14
- format?: "webp" | "avif" | "auto";
15
- fit?: "scale-down" | "contain" | "cover" | "crop" | "pad";
10
+ export declare const MEDIA_DELIVERY_KINDS: readonly ["imagekit", "cloudflare", "direct"];
11
+ /** How a store's images are resized: `imagekit` (`?tr=`), `cloudflare` (`/cdn-cgi/image/`), or `direct` (served as stored). */
12
+ export type MediaDeliveryKind = (typeof MEDIA_DELIVERY_KINDS)[number];
13
+ /** Where a store's images are served from: a key's URL is `origin`, a slash, and the key. */
14
+ export interface MediaDelivery {
15
+ kind: MediaDeliveryKind;
16
+ origin: string;
16
17
  }
17
- /**
18
- * Generate an optimized image URL using Cloudflare Image Resizing
19
- *
20
- * @param originalUrl - The original image URL from R2
21
- * @param options - Resize and optimization options
22
- * @param mediaDomain - Media domain (e.g., "media.example.com" or "https://media.example.com")
23
- * @returns Optimized image URL
24
- *
25
- * @example
26
- * ```ts
27
- * const url = optimizeImage(
28
- * 'https://media.example.com/products/image.jpg',
29
- * { width: 400, height: 400 },
30
- * 'media.example.com'
31
- * );
32
- * // Returns: https://media.example.com/cdn-cgi/image/onerror=redirect,width=400,height=400,format=webp,quality=85,fit=cover/products/image.jpg
33
- * ```
34
- */
35
- export declare function optimizeImage(originalUrl: string, options: ImageResizeOptions, mediaDomain?: string): string;
36
- /** What `mediaImageUrl` can ask Cloudflare for; an omitted value is left to Cloudflare's default. */
18
+ /** An image as the store's server answers it. */
19
+ export interface MediaImage {
20
+ key: string;
21
+ url: string;
22
+ width: number | null;
23
+ height: number | null;
24
+ }
25
+ /** How to show a photo; an omitted value is left to the host's default. */
37
26
  export interface MediaImageParams {
38
27
  width?: number;
39
28
  height?: number;
29
+ /** Encoder quality, 1–100. */
40
30
  quality?: number;
31
+ /** `auto` lets the host pick the best format the browser takes. */
41
32
  format?: string;
33
+ /** CSS `object-fit` words: `cover` and `crop` fill the box, `contain` and `scale-down` fit inside it (`scale-down` never enlarges), `squeeze` stretches, `pad` letterboxes. */
42
34
  fit?: "scale-down" | "contain" | "cover" | "crop" | "pad" | "squeeze";
43
35
  }
36
+ /** Whether `value` can be a Media Key: a store folder, then segments of letters, digits, `.`, `_` and `-` that start with a letter or digit. */
37
+ export declare function isMediaKey(value: unknown): value is string;
44
38
  /**
45
- * The Cloudflare Image Resizing URL of an image on the media domain, served
46
- * by the media domain itself (`https://<media>/cdn-cgi/image/<options>/<path>`)
47
- * — so it works wherever the storefront is hosted, as long as the media
48
- * domain's zone has Image Transformations on.
39
+ * The URL of a key in the store's media — what a theme's `image` field
40
+ * stores (`products/3f2a9c.webp`). The key is the image's identity; its URL
41
+ * depends on the store's delivery, so it is derived at render, never stored.
49
42
  *
50
- * `onerror=redirect` comes first: when a resize fails, Cloudflare redirects to
51
- * the original image instead of answering with an error.
52
- *
53
- * @returns `null` when there is no media domain, or the URL is not on it.
43
+ * @returns `null` without a delivery, or for a value that is not a Media Key.
54
44
  */
55
- export declare function mediaImageUrl(originalUrl: string, params: MediaImageParams, mediaDomain?: string): string | null;
45
+ export declare function mediaUrl(key: string, delivery: MediaDelivery | null | undefined): string | null;
56
46
  /**
57
- * The public URL of an object in the store's media bucket, from its key —
58
- * what a theme's `image` field stores (`products/3f2a9c.webp`). The key is
59
- * the image's identity; the URL depends on where the store serves its media,
60
- * so it is derived here, at render, never stored. Pass the result to
61
- * `mediaImageUrl` or Astro's `<Image>` to resize it.
47
+ * A photo of the store's media at the size and format a page shows it, from
48
+ * the delivery's own resizer: ImageKit's `?tr=` or Cloudflare's
49
+ * `/cdn-cgi/image/` (which falls back to the original when a resize fails).
62
50
  *
63
- * @returns `null` when there is no media domain, or the key cannot name an
64
- * object: empty, too long, an empty, `.` or `..` segment (a leading slash
65
- * makes an empty one), whitespace, control characters, a backslash, `?` or `#`.
51
+ * @returns `null` without a delivery, for a URL not served by it, or for a
52
+ * `direct` delivery, which does not resize — show the original then.
66
53
  */
67
- export declare function mediaUrl(key: string, mediaDomain?: string): string | null;
54
+ export declare function mediaImageUrl(url: string, params: MediaImageParams, delivery: MediaDelivery | null | undefined): string | null;
68
55
  export interface MediaImageSrcsetOptions {
69
- /** The store's media domain; without one there is no srcset. */
70
- mediaDomain?: string;
71
- /** Height ÷ width: given, each size is cropped to it (`fit=cover`); absent, the photo keeps its shape (`fit=scale-down`). */
56
+ /** The store's delivery; without one there is no srcset. */
57
+ delivery: MediaDelivery | null | undefined;
58
+ /** Height ÷ width: given, each size is cropped to it (`cover`); absent, the photo keeps its shape and is never enlarged (`scale-down`). */
72
59
  ratio?: number;
73
- /** Encoder quality, 1–100; Cloudflare's default when absent. */
60
+ /** Encoder quality, 1–100; the host's default when absent. */
74
61
  quality?: number;
75
62
  }
76
63
  /**
77
64
  * The same photo at several widths, with width descriptors
78
65
  * (`… 360w, … 720w`), for an `<img>` whose `sizes` says how wide it shows —
79
- * a phone then downloads a phone-sized file. Each size is converted to the
80
- * best format the browser takes (`format=auto`).
66
+ * a phone then downloads a phone-sized file, in the best format it takes.
81
67
  *
82
- * @returns `null` when there is no media domain, the URL is not on it, or no
68
+ * @returns `null` when the photo cannot be resized (see `mediaImageUrl`) or no
83
69
  * width is a positive whole number.
84
70
  */
85
- export declare function mediaImageSrcset(src: string, widths: readonly number[], options?: MediaImageSrcsetOptions): string | null;
71
+ export declare function mediaImageSrcset(src: string, widths: readonly number[], options: MediaImageSrcsetOptions): string | null;
86
72
  /** An image a merchant picked, by its media key — what a theme's `image` field resolves to. */
87
73
  export interface PickedImage {
88
74
  key: string;
@@ -105,116 +91,11 @@ export interface Picture {
105
91
  position: string | undefined;
106
92
  }
107
93
  /**
108
- * A picked image as a theme draws it: its URL on the store's media domain,
109
- * its alt text (empty when the merchant wrote none), its size, and its focal
110
- * point as `object-position`, so a cropped photo keeps what matters in view.
94
+ * A picked image as a theme draws it: its URL in the store's media, its alt
95
+ * text (empty when the merchant wrote none), its size, and its focal point as
96
+ * `object-position`, so a cropped photo keeps what matters in view.
111
97
  *
112
- * @returns `null` when no image is picked, the key cannot name an object, or
113
- * the store has no media domain.
114
- */
115
- export declare function pictureOf(image: PickedImage | null | undefined, mediaDomain?: string): Picture | null;
116
- /**
117
- * Predefined image sizes for common use cases
98
+ * @returns `null` when no image is picked, the key is not a Media Key, or there
99
+ * is no delivery.
118
100
  */
119
- export declare const IMAGE_SIZES: {
120
- readonly CARD: {
121
- readonly width: 400;
122
- readonly height: 400;
123
- readonly quality: 85;
124
- };
125
- readonly GALLERY_MAIN: {
126
- readonly width: 800;
127
- readonly height: 800;
128
- readonly quality: 90;
129
- };
130
- readonly GALLERY_THUMB: {
131
- readonly width: 80;
132
- readonly height: 80;
133
- readonly quality: 80;
134
- };
135
- readonly HERO: {
136
- readonly width: 1200;
137
- readonly height: 600;
138
- readonly quality: 90;
139
- };
140
- readonly CATEGORY: {
141
- readonly width: 300;
142
- readonly height: 200;
143
- readonly quality: 85;
144
- };
145
- readonly LOGO: {
146
- readonly width: 200;
147
- readonly height: 80;
148
- readonly quality: 90;
149
- readonly fit: "contain";
150
- };
151
- };
152
- /**
153
- * Quick helper functions for common image sizes
154
- *
155
- * These take the media domain per call. Theme code usually binds it once with
156
- * `createImageHelpers(mediaDomain)` and uses the returned helpers, so a call
157
- * site can never forget the domain and silently ship an unoptimized image.
158
- */
159
- export declare const getCardImage: (url: string, mediaDomain?: string) => string;
160
- export declare const getGalleryImage: (url: string, mediaDomain?: string) => string;
161
- export declare const getThumbnailImage: (url: string, mediaDomain?: string) => string;
162
- export declare const getHeroImage: (url: string, mediaDomain?: string) => string;
163
- export declare const getCategoryImage: (url: string, mediaDomain?: string) => string;
164
- export declare const getLogoImage: (url: string, mediaDomain?: string) => string;
165
- /**
166
- * Generate responsive image srcset for different screen sizes
167
- *
168
- * @param originalUrl - The original image URL
169
- * @param baseWidth - Base width for 1x display
170
- * @param baseHeight - Base height for 1x display
171
- * @param mediaDomain - Media domain
172
- * @returns srcset string for responsive images
173
- *
174
- * @example
175
- * ```ts
176
- * const srcset = generateSrcSet(
177
- * 'https://media.example.com/products/image.jpg',
178
- * 400,
179
- * 400,
180
- * 'media.example.com'
181
- * );
182
- * // Returns: "url 1x, url 1.5x, url 2x"
183
- * ```
184
- */
185
- export declare function generateSrcSet(originalUrl: string, baseWidth: number, baseHeight: number, mediaDomain?: string): string;
186
- /**
187
- * Bind a media domain once and get the whole image toolkit back.
188
- *
189
- * The single binding point for theme code: a media domain is configured once
190
- * (an env var, a store setting), and every helper then takes only the URL. A
191
- * per-call domain still wins, so a theme with two media hosts can override.
192
- *
193
- * With no domain bound every helper is a pass-through — the correct behavior
194
- * for a store that has no media domain configured (original R2 URLs).
195
- *
196
- * @param mediaDomain - Media domain (e.g., "media.example.com" or "https://media.example.com")
197
- *
198
- * @example
199
- * ```ts
200
- * const images = createImageHelpers(env.MEDIA_DOMAIN);
201
- * images.getThumbnailImage(product.coverImage.src);
202
- * images.getCardImage(url);
203
- * images.generateSrcSet(url, 400, 400);
204
- * ```
205
- */
206
- export interface ImageHelpers {
207
- /** `optimizeImage` with the media domain bound. */
208
- optimizeImage: (originalUrl: string, options: ImageResizeOptions, mediaDomain?: string) => string;
209
- /** `generateSrcSet` with the media domain bound. */
210
- generateSrcSet: (originalUrl: string, baseWidth: number, baseHeight: number, mediaDomain?: string) => string;
211
- /** The shared size presets, for callers that want the raw dimensions. */
212
- IMAGE_SIZES: typeof IMAGE_SIZES;
213
- getCardImage: (url: string) => string;
214
- getGalleryImage: (url: string) => string;
215
- getThumbnailImage: (url: string) => string;
216
- getHeroImage: (url: string) => string;
217
- getCategoryImage: (url: string) => string;
218
- getLogoImage: (url: string) => string;
219
- }
220
- export declare function createImageHelpers(mediaDomain?: string): ImageHelpers;
101
+ export declare function pictureOf(image: PickedImage | null | undefined, delivery: MediaDelivery | null | undefined): Picture | null;