@cimplify/sdk 0.38.0 → 0.38.2

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/mock/msw.js CHANGED
@@ -3325,6 +3325,15 @@ function percent(a, pct) {
3325
3325
  function createCatalogueService(opts) {
3326
3326
  const { registry, clock, ids } = opts;
3327
3327
  const productsForBusiness = (businessId) => registry.products.list((p) => p.business_id === businessId);
3328
+ const defaultPriceInfo = (price, currency) => ({
3329
+ base_price: price,
3330
+ final_price: price,
3331
+ markup_percentage: "0.00",
3332
+ markup_amount: "0.00",
3333
+ markup_discount_percentage: "0.00",
3334
+ markup_discount_amount: "0.00",
3335
+ currency
3336
+ });
3328
3337
  const toApiProduct = (p) => ({
3329
3338
  id: p.id,
3330
3339
  business_id: p.business_id,
@@ -3333,10 +3342,15 @@ function createCatalogueService(opts) {
3333
3342
  description: p.description ?? "",
3334
3343
  product_type: p.product_type,
3335
3344
  base_price: p.base_price,
3345
+ default_price: p.base_price,
3346
+ default_price_info: defaultPriceInfo(p.base_price, p.currency),
3347
+ price_info: defaultPriceInfo(p.base_price, p.currency),
3336
3348
  currency: p.currency,
3337
3349
  image: p.image,
3350
+ image_url: p.image,
3338
3351
  images: p.images,
3339
3352
  is_available: p.is_available,
3353
+ category_id: p.category_ids[0],
3340
3354
  category_ids: p.category_ids,
3341
3355
  collection_ids: p.collection_ids,
3342
3356
  add_on_ids: p.add_on_ids,
@@ -3346,6 +3360,7 @@ function createCatalogueService(opts) {
3346
3360
  custom_attributes: [],
3347
3361
  properties: [],
3348
3362
  has_variants: p.variant_ids.length > 0,
3363
+ type: p.product_type,
3349
3364
  render_hint: "general"
3350
3365
  });
3351
3366
  const variantsForProduct = (productId) => registry.variants.list((v) => v.product_id === productId);
@@ -4612,26 +4627,26 @@ function createLiteService(opts) {
4612
4627
  // src/mock/seeds/default.ts
4613
4628
  var ISO = "2026-01-01T00:00:00.000Z";
4614
4629
  var PRODUCTS = [
4615
- { name: "Sourdough Loaf", slug: "sourdough-loaf", price: "25.00", category: "breads", description: "Artisanal 24-hour fermented sourdough.", image: "https://mock.cimplify.io/img/sourdough.jpg" },
4616
- { name: "Whole Wheat Bread", slug: "whole-wheat", price: "20.00", category: "breads", description: "Hearty whole wheat with seeds.", image: "https://mock.cimplify.io/img/wheat.jpg" },
4617
- { name: "Baguette", slug: "baguette", price: "15.00", category: "breads", description: "Crispy crust, soft inside.", image: "https://mock.cimplify.io/img/baguette.jpg" },
4618
- { name: "Focaccia", slug: "focaccia", price: "30.00", category: "breads", description: "Olive oil and rosemary focaccia.", image: "https://mock.cimplify.io/img/focaccia.jpg" },
4619
- { name: "Croissant", slug: "croissant", price: "12.00", category: "pastries", description: "Buttery French croissant.", image: "https://mock.cimplify.io/img/croissant.jpg" },
4620
- { name: "Pain au Chocolat", slug: "pain-au-chocolat", price: "14.00", category: "pastries", description: "Croissant with dark chocolate.", image: "https://mock.cimplify.io/img/pac.jpg" },
4621
- { name: "Almond Danish", slug: "almond-danish", price: "16.00", category: "pastries", description: "Flaky pastry with almond cream.", image: "https://mock.cimplify.io/img/danish.jpg" },
4622
- { name: "Cinnamon Roll", slug: "cinnamon-roll", price: "13.00", category: "pastries", description: "Soft roll with cinnamon glaze.", image: "https://mock.cimplify.io/img/cinnamon.jpg" },
4623
- { name: "Chocolate Cake (Slice)", slug: "chocolate-cake", price: "22.00", category: "cakes", description: "Rich dark chocolate cake.", image: "https://mock.cimplify.io/img/choc-cake.jpg" },
4624
- { name: "Red Velvet (Slice)", slug: "red-velvet", price: "22.00", category: "cakes", description: "Classic red velvet with cream cheese.", image: "https://mock.cimplify.io/img/red-velvet.jpg" },
4625
- { name: "Carrot Cake (Slice)", slug: "carrot-cake", price: "20.00", category: "cakes", description: "Spiced carrot cake with walnut.", image: "https://mock.cimplify.io/img/carrot.jpg" },
4626
- { name: "Cheesecake (Slice)", slug: "cheesecake", price: "24.00", category: "cakes", description: "New York style cheesecake.", image: "https://mock.cimplify.io/img/cheesecake.jpg" },
4627
- { name: "Coffee", slug: "coffee", price: "10.00", category: "drinks", description: "Locally roasted Arabica.", image: "https://mock.cimplify.io/img/coffee.jpg" },
4628
- { name: "Tea", slug: "tea", price: "8.00", category: "drinks", description: "Black, green, or herbal.", image: "https://mock.cimplify.io/img/tea.jpg" },
4629
- { name: "Hibiscus Tea (Sobolo)", slug: "sobolo", price: "12.00", category: "drinks", description: "Iced hibiscus drink.", image: "https://mock.cimplify.io/img/sobolo.jpg" },
4630
- { name: "Fresh Orange Juice", slug: "orange-juice", price: "15.00", category: "drinks", description: "Cold-pressed orange juice.", image: "https://mock.cimplify.io/img/oj.jpg" },
4631
- { name: "Banana Bread", slug: "banana-bread", price: "18.00", category: "breads", description: "Moist banana loaf.", image: "https://mock.cimplify.io/img/banana.jpg" },
4632
- { name: "Brownie", slug: "brownie", price: "12.00", category: "pastries", description: "Fudgy chocolate brownie.", image: "https://mock.cimplify.io/img/brownie.jpg" },
4633
- { name: "Macaron Box (6)", slug: "macaron-box", price: "60.00", category: "pastries", description: "Six assorted macarons.", image: "https://mock.cimplify.io/img/macaron.jpg" },
4634
- { name: "Custom Birthday Cake", slug: "birthday-cake", price: "250.00", category: "cakes", description: "Made-to-order. Min 48h notice.", image: "https://mock.cimplify.io/img/birthday.jpg" }
4630
+ { name: "Sourdough Loaf", slug: "sourdough-loaf", price: "25.00", category: "breads", description: "Artisanal 24-hour fermented sourdough.", image: "/img/sourdough.jpg" },
4631
+ { name: "Whole Wheat Bread", slug: "whole-wheat", price: "20.00", category: "breads", description: "Hearty whole wheat with seeds.", image: "/img/wheat.jpg" },
4632
+ { name: "Baguette", slug: "baguette", price: "15.00", category: "breads", description: "Crispy crust, soft inside.", image: "/img/baguette.jpg" },
4633
+ { name: "Focaccia", slug: "focaccia", price: "30.00", category: "breads", description: "Olive oil and rosemary focaccia.", image: "/img/focaccia.jpg" },
4634
+ { name: "Croissant", slug: "croissant", price: "12.00", category: "pastries", description: "Buttery French croissant.", image: "/img/croissant.jpg" },
4635
+ { name: "Pain au Chocolat", slug: "pain-au-chocolat", price: "14.00", category: "pastries", description: "Croissant with dark chocolate.", image: "/img/pac.jpg" },
4636
+ { name: "Almond Danish", slug: "almond-danish", price: "16.00", category: "pastries", description: "Flaky pastry with almond cream.", image: "/img/danish.jpg" },
4637
+ { name: "Cinnamon Roll", slug: "cinnamon-roll", price: "13.00", category: "pastries", description: "Soft roll with cinnamon glaze.", image: "/img/cinnamon.jpg" },
4638
+ { name: "Chocolate Cake (Slice)", slug: "chocolate-cake", price: "22.00", category: "cakes", description: "Rich dark chocolate cake.", image: "/img/choc-cake.jpg" },
4639
+ { name: "Red Velvet (Slice)", slug: "red-velvet", price: "22.00", category: "cakes", description: "Classic red velvet with cream cheese.", image: "/img/red-velvet.jpg" },
4640
+ { name: "Carrot Cake (Slice)", slug: "carrot-cake", price: "20.00", category: "cakes", description: "Spiced carrot cake with walnut.", image: "/img/carrot.jpg" },
4641
+ { name: "Cheesecake (Slice)", slug: "cheesecake", price: "24.00", category: "cakes", description: "New York style cheesecake.", image: "/img/cheesecake.jpg" },
4642
+ { name: "Coffee", slug: "coffee", price: "10.00", category: "drinks", description: "Locally roasted Arabica.", image: "/img/coffee.jpg" },
4643
+ { name: "Tea", slug: "tea", price: "8.00", category: "drinks", description: "Black, green, or herbal.", image: "/img/tea.jpg" },
4644
+ { name: "Hibiscus Tea (Sobolo)", slug: "sobolo", price: "12.00", category: "drinks", description: "Iced hibiscus drink.", image: "/img/sobolo.jpg" },
4645
+ { name: "Fresh Orange Juice", slug: "orange-juice", price: "15.00", category: "drinks", description: "Cold-pressed orange juice.", image: "/img/oj.jpg" },
4646
+ { name: "Banana Bread", slug: "banana-bread", price: "18.00", category: "breads", description: "Moist banana loaf.", image: "/img/banana.jpg" },
4647
+ { name: "Brownie", slug: "brownie", price: "12.00", category: "pastries", description: "Fudgy chocolate brownie.", image: "/img/brownie.jpg" },
4648
+ { name: "Macaron Box (6)", slug: "macaron-box", price: "60.00", category: "pastries", description: "Six assorted macarons.", image: "/img/macaron.jpg" },
4649
+ { name: "Custom Birthday Cake", slug: "birthday-cake", price: "250.00", category: "cakes", description: "Made-to-order. Min 48h notice.", image: "/img/birthday.jpg" }
4635
4650
  ];
4636
4651
  var CATEGORIES = [
4637
4652
  { slug: "breads", name: "Breads", description: "Sourdough, baguettes, focaccia." },
@@ -4652,7 +4667,7 @@ function seedDefault(registry) {
4652
4667
  default_address: "12 Independence Ave, Accra",
4653
4668
  default_offers_table_service: true,
4654
4669
  default_accepts_online_orders: true,
4655
- image: "https://mock.cimplify.io/img/akua-logo.png",
4670
+ image: "/img/akua-logo.png",
4656
4671
  status: "active",
4657
4672
  created_at: ISO,
4658
4673
  updated_at: ISO,
@@ -4912,8 +4927,8 @@ function seedDefault(registry) {
4912
4927
  product_type: "bundle",
4913
4928
  base_price: "30.00",
4914
4929
  currency: "GHS",
4915
- image: "https://mock.cimplify.io/img/breakfast-box.jpg",
4916
- images: ["https://mock.cimplify.io/img/breakfast-box.jpg"],
4930
+ image: "/img/breakfast-box.jpg",
4931
+ images: ["/img/breakfast-box.jpg"],
4917
4932
  is_available: true,
4918
4933
  category_ids: [categoryIdsBySlug.get("pastries")],
4919
4934
  collection_ids: [],
@@ -4953,8 +4968,8 @@ function seedDefault(registry) {
4953
4968
  product_type: "composite",
4954
4969
  base_price: "60.00",
4955
4970
  currency: "GHS",
4956
- image: "https://mock.cimplify.io/img/pastry-box.jpg",
4957
- images: ["https://mock.cimplify.io/img/pastry-box.jpg"],
4971
+ image: "/img/pastry-box.jpg",
4972
+ images: ["/img/pastry-box.jpg"],
4958
4973
  is_available: true,
4959
4974
  category_ids: [categoryIdsBySlug.get("pastries")],
4960
4975
  collection_ids: [],
@@ -5140,7 +5155,7 @@ function seedReesa(registry) {
5140
5155
  default_address: "5 Allen Avenue, Ikeja, Lagos",
5141
5156
  default_offers_table_service: false,
5142
5157
  default_accepts_online_orders: true,
5143
- image: "https://mock.cimplify.io/img/reesa-logo.png",
5158
+ image: "/img/reesa-logo.png",
5144
5159
  status: "active",
5145
5160
  created_at: ISO3,
5146
5161
  updated_at: ISO3,
@@ -5196,8 +5211,8 @@ function seedReesa(registry) {
5196
5211
  product_type: "product",
5197
5212
  base_price: p.price,
5198
5213
  currency: "NGN",
5199
- image: `https://mock.cimplify.io/img/reesa/${p.slug}.jpg`,
5200
- images: [`https://mock.cimplify.io/img/reesa/${p.slug}.jpg`],
5214
+ image: `/img/reesa/${p.slug}.jpg`,
5215
+ images: [`/img/reesa/${p.slug}.jpg`],
5201
5216
  is_available: true,
5202
5217
  category_ids: [catId],
5203
5218
  collection_ids: [],
@@ -5420,8 +5435,8 @@ function seedReesa(registry) {
5420
5435
  product_type: "bundle",
5421
5436
  base_price: "55000.00",
5422
5437
  currency: "NGN",
5423
- image: "https://mock.cimplify.io/img/reesa/owambe.jpg",
5424
- images: ["https://mock.cimplify.io/img/reesa/owambe.jpg"],
5438
+ image: "/img/reesa/owambe.jpg",
5439
+ images: ["/img/reesa/owambe.jpg"],
5425
5440
  is_available: true,
5426
5441
  category_ids: [catIdsBySlug.get("apparel")],
5427
5442
  collection_ids: [],
@@ -5552,7 +5567,7 @@ function seedRestaurant(registry) {
5552
5567
  default_address: "8 Ring Road, East Legon, Accra",
5553
5568
  default_offers_table_service: true,
5554
5569
  default_accepts_online_orders: true,
5555
- image: "https://mock.cimplify.io/img/mamas-logo.png",
5570
+ image: "/img/mamas-logo.png",
5556
5571
  status: "active",
5557
5572
  created_at: ISO4,
5558
5573
  updated_at: ISO4,
@@ -5623,8 +5638,8 @@ function seedRestaurant(registry) {
5623
5638
  product_type: "product",
5624
5639
  base_price: p.price,
5625
5640
  currency: "GHS",
5626
- image: `https://mock.cimplify.io/img/mamas/${p.slug}.jpg`,
5627
- images: [`https://mock.cimplify.io/img/mamas/${p.slug}.jpg`],
5641
+ image: `/img/mamas/${p.slug}.jpg`,
5642
+ images: [`/img/mamas/${p.slug}.jpg`],
5628
5643
  is_available: true,
5629
5644
  category_ids: [catId],
5630
5645
  collection_ids: [],
@@ -5862,8 +5877,8 @@ function seedRestaurant(registry) {
5862
5877
  product_type: "bundle",
5863
5878
  base_price: "180.00",
5864
5879
  currency: "GHS",
5865
- image: "https://mock.cimplify.io/img/mamas/feast.jpg",
5866
- images: ["https://mock.cimplify.io/img/mamas/feast.jpg"],
5880
+ image: "/img/mamas/feast.jpg",
5881
+ images: ["/img/mamas/feast.jpg"],
5867
5882
  is_available: true,
5868
5883
  category_ids: [catIds.get("mains")],
5869
5884
  collection_ids: [],
@@ -5898,8 +5913,8 @@ function seedRestaurant(registry) {
5898
5913
  product_type: "composite",
5899
5914
  base_price: "0.00",
5900
5915
  currency: "GHS",
5901
- image: "https://mock.cimplify.io/img/mamas/byo.jpg",
5902
- images: ["https://mock.cimplify.io/img/mamas/byo.jpg"],
5916
+ image: "/img/mamas/byo.jpg",
5917
+ images: ["/img/mamas/byo.jpg"],
5903
5918
  is_available: true,
5904
5919
  category_ids: [catIds.get("mains")],
5905
5920
  collection_ids: [],
@@ -6011,7 +6026,7 @@ function seedRetail(registry) {
6011
6026
  default_address: "Atomic Junction, Accra",
6012
6027
  default_offers_table_service: false,
6013
6028
  default_accepts_online_orders: true,
6014
- image: "https://mock.cimplify.io/img/currents-logo.png",
6029
+ image: "/img/currents-logo.png",
6015
6030
  status: "active",
6016
6031
  created_at: ISO5,
6017
6032
  updated_at: ISO5,
@@ -6081,8 +6096,8 @@ function seedRetail(registry) {
6081
6096
  product_type: "product",
6082
6097
  base_price: p.price,
6083
6098
  currency: "GHS",
6084
- image: `https://mock.cimplify.io/img/currents/${p.slug}.jpg`,
6085
- images: [`https://mock.cimplify.io/img/currents/${p.slug}.jpg`],
6099
+ image: `/img/currents/${p.slug}.jpg`,
6100
+ images: [`/img/currents/${p.slug}.jpg`],
6086
6101
  is_available: true,
6087
6102
  category_ids: [catId],
6088
6103
  collection_ids: [],
@@ -6345,8 +6360,8 @@ function seedRetail(registry) {
6345
6360
  product_type: "bundle",
6346
6361
  base_price: "11910.00",
6347
6362
  currency: "GHS",
6348
- image: "https://mock.cimplify.io/img/currents/wfh.jpg",
6349
- images: ["https://mock.cimplify.io/img/currents/wfh.jpg"],
6363
+ image: "/img/currents/wfh.jpg",
6364
+ images: ["/img/currents/wfh.jpg"],
6350
6365
  is_available: true,
6351
6366
  category_ids: [catIds.get("laptops")],
6352
6367
  collection_ids: [],
@@ -6379,8 +6394,8 @@ function seedRetail(registry) {
6379
6394
  product_type: "bundle",
6380
6395
  base_price: "4200.00",
6381
6396
  currency: "GHS",
6382
- image: "https://mock.cimplify.io/img/currents/game-pack.jpg",
6383
- images: ["https://mock.cimplify.io/img/currents/game-pack.jpg"],
6397
+ image: "/img/currents/game-pack.jpg",
6398
+ images: ["/img/currents/game-pack.jpg"],
6384
6399
  is_available: true,
6385
6400
  category_ids: [catIds.get("gaming")],
6386
6401
  collection_ids: [],
@@ -6483,7 +6498,7 @@ function seedServices(registry) {
6483
6498
  default_address: "12 Cantonments Road, Accra",
6484
6499
  default_offers_table_service: false,
6485
6500
  default_accepts_online_orders: true,
6486
- image: "https://mock.cimplify.io/img/serene-logo.png",
6501
+ image: "/img/serene-logo.png",
6487
6502
  status: "active",
6488
6503
  created_at: ISO6,
6489
6504
  updated_at: ISO6,
@@ -6551,8 +6566,8 @@ function seedServices(registry) {
6551
6566
  product_type: "service",
6552
6567
  base_price: s.price,
6553
6568
  currency: "GHS",
6554
- image: `https://mock.cimplify.io/img/serene/${s.slug}.jpg`,
6555
- images: [`https://mock.cimplify.io/img/serene/${s.slug}.jpg`],
6569
+ image: `/img/serene/${s.slug}.jpg`,
6570
+ images: [`/img/serene/${s.slug}.jpg`],
6556
6571
  is_available: true,
6557
6572
  category_ids: [catId],
6558
6573
  collection_ids: [],
@@ -6688,8 +6703,8 @@ function seedServices(registry) {
6688
6703
  product_type: "bundle",
6689
6704
  base_price: "480.00",
6690
6705
  currency: "GHS",
6691
- image: "https://mock.cimplify.io/img/serene/spa-day.jpg",
6692
- images: ["https://mock.cimplify.io/img/serene/spa-day.jpg"],
6706
+ image: "/img/serene/spa-day.jpg",
6707
+ images: ["/img/serene/spa-day.jpg"],
6693
6708
  is_available: true,
6694
6709
  category_ids: [catIds.get("wellness")],
6695
6710
  collection_ids: [],
@@ -6722,8 +6737,8 @@ function seedServices(registry) {
6722
6737
  product_type: "bundle",
6723
6738
  base_price: "850.50",
6724
6739
  currency: "GHS",
6725
- image: "https://mock.cimplify.io/img/serene/couples.jpg",
6726
- images: ["https://mock.cimplify.io/img/serene/couples.jpg"],
6740
+ image: "/img/serene/couples.jpg",
6741
+ images: ["/img/serene/couples.jpg"],
6727
6742
  is_available: true,
6728
6743
  category_ids: [catIds.get("wellness")],
6729
6744
  collection_ids: [],
@@ -6758,8 +6773,8 @@ function seedServices(registry) {
6758
6773
  product_type: "composite",
6759
6774
  base_price: "0.00",
6760
6775
  currency: "GHS",
6761
- image: "https://mock.cimplify.io/img/serene/custom.jpg",
6762
- images: ["https://mock.cimplify.io/img/serene/custom.jpg"],
6776
+ image: "/img/serene/custom.jpg",
6777
+ images: ["/img/serene/custom.jpg"],
6763
6778
  is_available: true,
6764
6779
  category_ids: [catIds.get("wellness")],
6765
6780
  collection_ids: [],
@@ -6862,7 +6877,7 @@ function seedGrocery(registry) {
6862
6877
  default_address: "Spintex Road, Accra",
6863
6878
  default_offers_table_service: false,
6864
6879
  default_accepts_online_orders: true,
6865
- image: "https://mock.cimplify.io/img/freshmart-logo.png",
6880
+ image: "/img/freshmart-logo.png",
6866
6881
  status: "active",
6867
6882
  created_at: ISO7,
6868
6883
  updated_at: ISO7,
@@ -6937,8 +6952,8 @@ function seedGrocery(registry) {
6937
6952
  product_type: "product",
6938
6953
  base_price: p.price,
6939
6954
  currency: "GHS",
6940
- image: `https://mock.cimplify.io/img/freshmart/${p.slug}.jpg`,
6941
- images: [`https://mock.cimplify.io/img/freshmart/${p.slug}.jpg`],
6955
+ image: `/img/freshmart/${p.slug}.jpg`,
6956
+ images: [`/img/freshmart/${p.slug}.jpg`],
6942
6957
  is_available: true,
6943
6958
  category_ids: [catId],
6944
6959
  collection_ids: [],
@@ -7021,8 +7036,8 @@ function seedGrocery(registry) {
7021
7036
  product_type: "bundle",
7022
7037
  base_price: "199.50",
7023
7038
  currency: "GHS",
7024
- image: "https://mock.cimplify.io/img/freshmart/essentials.jpg",
7025
- images: ["https://mock.cimplify.io/img/freshmart/essentials.jpg"],
7039
+ image: "/img/freshmart/essentials.jpg",
7040
+ images: ["/img/freshmart/essentials.jpg"],
7026
7041
  is_available: true,
7027
7042
  category_ids: [catIds.get("pantry")],
7028
7043
  collection_ids: [],
@@ -7205,11 +7220,19 @@ function createMockApp(options = {}) {
7205
7220
  app.use("*", async (c, next) => {
7206
7221
  const origin = c.req.header("origin") ?? "";
7207
7222
  const allow = corsOrigins === "*" ? "*" : corsOrigins.includes(origin) ? origin : corsOrigins[0] ?? "*";
7208
- c.header("Access-Control-Allow-Origin", allow);
7209
- c.header("Access-Control-Allow-Headers", "content-type,authorization,x-session-token,idempotency-key");
7210
- c.header("Access-Control-Allow-Methods", "GET,POST,PATCH,DELETE,OPTIONS");
7211
- c.header("Access-Control-Expose-Headers", "x-session-token");
7212
- if (c.req.method === "OPTIONS") return new Response(null, { status: 204 });
7223
+ const headers = {
7224
+ "Access-Control-Allow-Origin": allow,
7225
+ "Access-Control-Allow-Credentials": "true",
7226
+ "Access-Control-Allow-Headers": c.req.header("access-control-request-headers") ?? "content-type,authorization,x-session-token,idempotency-key",
7227
+ "Access-Control-Allow-Methods": "GET,POST,PATCH,DELETE,OPTIONS",
7228
+ "Access-Control-Expose-Headers": "x-session-token",
7229
+ "Access-Control-Max-Age": "86400",
7230
+ Vary: "Origin"
7231
+ };
7232
+ if (c.req.method === "OPTIONS") {
7233
+ return new Response(null, { status: 204, headers });
7234
+ }
7235
+ for (const [k, v] of Object.entries(headers)) c.header(k, v);
7213
7236
  await next();
7214
7237
  });
7215
7238
  }
@@ -7226,6 +7249,158 @@ function createMockApp(options = {}) {
7226
7249
  })
7227
7250
  );
7228
7251
  app.get("/healthz", (c) => c.json({ ok: true, time: deps.clock.iso() }));
7252
+ const UNSPLASH_PHOTOS = {
7253
+ // Akua's Bakery (default seed)
7254
+ sourdough: "1509440159596-0249088772ff",
7255
+ wheat: "1486887396153-fa416526c108",
7256
+ baguette: "1568471173242-461f0a730452",
7257
+ focaccia: "1573472635068-fd9b1abdd8e5",
7258
+ croissant: "1555507036-ab1f4038808a",
7259
+ pac: "1530610476181-d83430b64dcd",
7260
+ danish: "1517433367423-c7e5b0f35086",
7261
+ cinnamon: "1583527976767-50068e72b7a3",
7262
+ "choc-cake": "1565958011703-44f9829ba187",
7263
+ "red-velvet": "1586788680434-30d324b2d46f",
7264
+ carrot: "1568827999250-3f6afff96e66",
7265
+ cheesecake: "1567306226416-28f0efdc88ce",
7266
+ coffee: "1495474472287-4d71bcdd2085",
7267
+ tea: "1576092768241-dec231879fc3",
7268
+ sobolo: "1556679343-c7306c1976bc",
7269
+ oj: "1600271886742-f049b969dc7a",
7270
+ banana: "1632931057819-4eefffa8e007",
7271
+ brownie: "1551024506-0bccd828d307",
7272
+ macaron: "1558326567-98ae2405596b",
7273
+ birthday: "1535254973040-607b474cb50d",
7274
+ "breakfast-box": "1533089860892-a7c6f0a88666",
7275
+ "pastry-box": "1486427944299-d1955d23e34d",
7276
+ // Mama's Kitchen (restaurant seed)
7277
+ kelewele: "1585536830049-aedf5c1b98a4",
7278
+ "spring-rolls": "1606755962773-d324e0a13086",
7279
+ "soup-of-the-day": "1547592180-85f173990554",
7280
+ "jollof-rice": "1604329760661-e71dc83f8f26",
7281
+ "banku-tilapia": "1559847844-5315695dadae",
7282
+ "fufu-light-soup": "1547928576-b822bcced36e",
7283
+ waakye: "1604329760661-e71dc83f8f26",
7284
+ "grilled-chicken": "1532550907401-a500c9a57435",
7285
+ burger: "1568901346375-23c9450c58cd",
7286
+ "yam-fries": "1573080496219-bb080dd4f877",
7287
+ "fried-plantain": "1604329760661-e71dc83f8f26",
7288
+ salad: "1512621776951-a57141f2eefd",
7289
+ "ice-cream": "1497034825429-c343d7c6a68f",
7290
+ "cake-slice": "1565958011703-44f9829ba187",
7291
+ "fruit-bowl": "1490474418585-ba9bad8fd0ea",
7292
+ "soft-drink": "1497534446932-c925b458314e",
7293
+ "fresh-juice": "1622597467836-f3285f2131b8",
7294
+ water: "1548839140-29a749e1cf4d",
7295
+ feast: "1546069901-ba9599a7e63c",
7296
+ byo: "1546069901-ba9599a7e63c",
7297
+ // Currents Electronics
7298
+ "android-flagship": "1511707171634-5f897ff02aa9",
7299
+ "android-mid": "1592899677977-9c10ca588bbd",
7300
+ "phone-budget": "1574944985070-8f3ebc6b79d2",
7301
+ "laptop-pro": "1496181133206-80ce9b88a853",
7302
+ "laptop-air": "1517336714731-489689fd1ca8",
7303
+ "laptop-budget": "1541807084-5c52b6b3adef",
7304
+ "headphones-anc": "1583394838336-acd977736f90",
7305
+ "earbuds-pro": "1606220945770-b5b6c2c55bf1",
7306
+ "speaker-bt": "1608043152269-423dbba4e7e1",
7307
+ "phone-case": "1601593346740-925612772716",
7308
+ "screen-protector": "1592890288564-76628a30a657",
7309
+ "fast-charger": "1583394838336-acd977736f90",
7310
+ "laptop-sleeve": "1525547719571-a2d4ac8945e2",
7311
+ "wireless-mouse": "1527864550417-7fd91fc51a46",
7312
+ "mech-keyboard": "1587829741301-dc798b83add3",
7313
+ "gaming-controller": "1592840496694-26d035b52b48",
7314
+ "gaming-headset": "1591105327764-407a4a06e768",
7315
+ "console-handheld": "1606144042614-b2417e99c4e3",
7316
+ wfh: "1593642632559-0c6d3fc62b89",
7317
+ "game-pack": "1606144042614-b2417e99c4e3",
7318
+ // Reesa apparel
7319
+ "ankara-shirt": "1591047139829-d91aecb6caea",
7320
+ "agbada-set": "1605497788044-5a32c7078486",
7321
+ kaftan: "1554412933-514a83d2f3c8",
7322
+ "leather-tote": "1584917865442-de89df76afd3",
7323
+ sandals: "1543163521-1bf539c55dd2",
7324
+ "beaded-bracelet": "1611591437281-460bfbe1220a",
7325
+ owambe: "1605497788044-5a32c7078486",
7326
+ // FreshMart
7327
+ "tomatoes-1kg": "1546470427-227f1c75a9ef",
7328
+ "onions-1kg": "1620574387735-3624d75b2dbc",
7329
+ "ginger-200g": "1606937330526-f5e6a2a83555",
7330
+ "bananas-bunch": "1571771894821-ce9b6c11b08e",
7331
+ pineapple: "1550258987-190a2d41a8ba",
7332
+ "spinach-bunch": "1576045057995-568f588f82fb",
7333
+ "milk-1l": "1550583724-b2692b85b150",
7334
+ "yogurt-500g": "1571212515416-fef01fc43637",
7335
+ "eggs-12": "1582722872445-44dc5f7e3c8f",
7336
+ "cheese-200g": "1486297678162-eb2a19b0a32d",
7337
+ "chicken-1kg": "1604503468506-a8da13d82791",
7338
+ "beef-mince-500g": "1607623814075-e51df1bdc82f",
7339
+ "tilapia-each": "1546069901-ba9599a7e63c",
7340
+ "rice-5kg": "1586201375761-83865001e31c",
7341
+ "garri-2kg": "1604329760661-e71dc83f8f26",
7342
+ "palm-oil-1l": "1474979266404-7eaacbcd87c5",
7343
+ "vegetable-oil-1l": "1474979266404-7eaacbcd87c5",
7344
+ "salt-1kg": "1612531386530-97286d97c2d2",
7345
+ "sugar-1kg": "1581281697996-3aef0c3b9b12",
7346
+ "tomato-paste": "1546470427-227f1c75a9ef",
7347
+ "soap-bar": "1583912267550-d6c2ac3196c0",
7348
+ "detergent-1kg": "1583912267550-d6c2ac3196c0",
7349
+ "tissue-pack": "1610557892470-55d9e80c0bce",
7350
+ "trash-bags": "1583912267550-d6c2ac3196c0",
7351
+ essentials: "1542838132-92c53300491e",
7352
+ // Serene Spa services
7353
+ "swedish-massage-60": "1544161515-4ab6ce6db874",
7354
+ "swedish-massage-90": "1544161515-4ab6ce6db874",
7355
+ "deep-tissue-60": "1600334129128-685c5582fd35",
7356
+ "couples-massage": "1540555700478-4be289fbecef",
7357
+ "hot-stone-90": "1600334129128-685c5582fd35",
7358
+ "facial-classic": "1570172619644-dfd03ed5d881",
7359
+ "facial-anti-aging": "1571019613454-1cb2f99b2d8b",
7360
+ "facial-acne": "1571019613454-1cb2f99b2d8b",
7361
+ manicure: "1604654894610-df63bc536371",
7362
+ pedicure: "1610701596007-11502861dcfa",
7363
+ "gel-manicure": "1604654894610-df63bc536371",
7364
+ haircut: "1562322140-8baeececf3df",
7365
+ "hair-treatment": "1522337360788-8b13dee7a37e",
7366
+ color: "1562322140-8baeececf3df",
7367
+ "yoga-session": "1545205597-3d9d02c29597",
7368
+ meditation: "1545389336-cf090694435e",
7369
+ "spa-day": "1540555700478-4be289fbecef",
7370
+ "couples-retreat": "1540555700478-4be289fbecef",
7371
+ "custom-experience": "1545389336-cf090694435e"
7372
+ };
7373
+ app.get("/img/*", (c) => {
7374
+ const path = c.req.path.replace(/^\/img\//, "").replace(/\.[a-z0-9]+$/i, "");
7375
+ const slug = path.split("/").pop() ?? "";
7376
+ const photoId = UNSPLASH_PHOTOS[slug];
7377
+ if (photoId) {
7378
+ return c.redirect(`https://images.unsplash.com/photo-${photoId}?w=600&h=600&fit=crop&auto=format&q=80`, 302);
7379
+ }
7380
+ const label = slug.replace(/[-_]+/g, " ").trim() || "product";
7381
+ let hash = 0;
7382
+ for (let i = 0; i < slug.length; i++) hash = hash * 31 + slug.charCodeAt(i) >>> 0;
7383
+ const hue = hash % 360;
7384
+ const display = label.length > 20 ? label.slice(0, 20) + "\u2026" : label;
7385
+ const svg = `<?xml version="1.0" encoding="UTF-8"?>
7386
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400" width="400" height="400">
7387
+ <defs>
7388
+ <linearGradient id="g" x1="0" y1="0" x2="1" y2="1">
7389
+ <stop offset="0%" stop-color="hsl(${hue}, 65%, 65%)"/>
7390
+ <stop offset="100%" stop-color="hsl(${(hue + 40) % 360}, 70%, 45%)"/>
7391
+ </linearGradient>
7392
+ </defs>
7393
+ <rect width="400" height="400" fill="url(#g)"/>
7394
+ <text x="200" y="210" font-family="-apple-system, BlinkMacSystemFont, Inter, sans-serif" font-size="22" font-weight="600" fill="white" text-anchor="middle" dominant-baseline="middle" style="text-transform: capitalize">${display.replace(/[<>&]/g, "")}</text>
7395
+ </svg>`;
7396
+ return new Response(svg, {
7397
+ headers: {
7398
+ "Content-Type": "image/svg+xml; charset=utf-8",
7399
+ "Cache-Control": "public, max-age=3600",
7400
+ "Access-Control-Allow-Origin": "*"
7401
+ }
7402
+ });
7403
+ });
7229
7404
  app.route("/api/v1", buildV1(deps));
7230
7405
  app.route("/_mock", buildAdmin(deps));
7231
7406
  app.route("/elements", buildElements(deps));