@cimplify/sdk 0.102.0 → 0.104.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 (69) hide show
  1. package/dist/advanced.d.mts +3 -3
  2. package/dist/advanced.d.ts +3 -3
  3. package/dist/advanced.js +23 -22
  4. package/dist/advanced.mjs +4 -3
  5. package/dist/{chunk-DCMXUKDQ.mjs → chunk-2WPVUIHX.mjs} +455 -105
  6. package/dist/{chunk-NIOUSKQQ.js → chunk-4BKOKHE3.js} +9 -0
  7. package/dist/{chunk-YDA46OZ6.js → chunk-5BDYDZ4U.js} +722 -90
  8. package/dist/{chunk-4KNFBPV2.mjs → chunk-5RT4HYMP.mjs} +61 -15
  9. package/dist/{chunk-WMEC5JWN.js → chunk-7PDEX54K.js} +50 -13
  10. package/dist/chunk-CNN7Z2IP.js +125 -0
  11. package/dist/{chunk-DLW3RWRK.mjs → chunk-DYIAX3WI.mjs} +46 -12
  12. package/dist/{chunk-LOWSMGRT.js → chunk-E4K2VQDD.js} +64 -16
  13. package/dist/chunk-GOHSXBKW.mjs +105 -0
  14. package/dist/{chunk-O3YUHLZL.mjs → chunk-H3RATH4B.mjs} +9 -0
  15. package/dist/{chunk-YER7DIOM.js → chunk-IQFFSKE2.js} +753 -594
  16. package/dist/{chunk-Z3K2D3TE.mjs → chunk-OCCNG6MO.mjs} +735 -558
  17. package/dist/{chunk-DKLHCZ5M.mjs → chunk-OKADBZAI.mjs} +652 -25
  18. package/dist/{chunk-EAZGA7LD.js → chunk-YVAEY3VC.js} +457 -107
  19. package/dist/{client-nsiMwuC1.d.ts → client-BVNWjk6W.d.ts} +2 -2
  20. package/dist/{client-B40KFazg.d.ts → client-BuLcOWLv.d.ts} +202 -319
  21. package/dist/{client-BizGfqB7.d.mts → client-D5AoobFc.d.mts} +202 -319
  22. package/dist/{client-BdErclfU.d.mts → client-fM716k7G.d.mts} +2 -2
  23. package/dist/{index-DpmnI__D.d.mts → index-BtcoqrY1.d.ts} +14 -4
  24. package/dist/{index-nEyXWIyR.d.ts → index-D7Tf3v7c.d.mts} +14 -4
  25. package/dist/index.d.mts +83 -8
  26. package/dist/index.d.ts +83 -8
  27. package/dist/index.js +203 -169
  28. package/dist/index.mjs +7 -5
  29. package/dist/link-D9iSVxt5.d.mts +308 -0
  30. package/dist/link-D9iSVxt5.d.ts +308 -0
  31. package/dist/mock/cli.mjs +463 -104
  32. package/dist/mock/library.js +463 -104
  33. package/dist/mock/library.mjs +463 -104
  34. package/dist/mock/msw.js +463 -104
  35. package/dist/mock/msw.mjs +463 -104
  36. package/dist/{product-Byf0unSy.d.mts → payment-g0HFkEDU.d.mts} +708 -61
  37. package/dist/{product-Byf0unSy.d.ts → payment-g0HFkEDU.d.ts} +708 -61
  38. package/dist/{price-BstChV9a.d.ts → price-BLIeAb8K.d.ts} +1 -1
  39. package/dist/{price-CS4E5zLS.d.mts → price-Czq_cTC_.d.mts} +1 -1
  40. package/dist/react.d.mts +4 -4
  41. package/dist/react.d.ts +4 -4
  42. package/dist/react.js +194 -169
  43. package/dist/react.mjs +55 -30
  44. package/dist/{server-DqbZh8Bk.d.mts → server-BkVhOIwn.d.mts} +14 -10
  45. package/dist/{server-Cj40R2ZD.d.ts → server-DKK_D-PP.d.ts} +14 -10
  46. package/dist/server.d.mts +4 -4
  47. package/dist/server.d.ts +4 -4
  48. package/dist/server.js +12 -10
  49. package/dist/server.mjs +6 -4
  50. package/dist/testing/msw.d.mts +2 -2
  51. package/dist/testing/msw.d.ts +2 -2
  52. package/dist/testing/msw.js +4 -3
  53. package/dist/testing/msw.mjs +3 -2
  54. package/dist/testing/suite.d.mts +6 -6
  55. package/dist/testing/suite.d.ts +6 -6
  56. package/dist/testing/suite.js +26 -25
  57. package/dist/testing/suite.mjs +7 -6
  58. package/dist/testing.d.mts +195 -56
  59. package/dist/testing.d.ts +195 -56
  60. package/dist/testing.js +95 -82
  61. package/dist/testing.mjs +14 -9
  62. package/dist/utils.d.mts +4 -4
  63. package/dist/utils.d.ts +4 -4
  64. package/dist/utils.js +37 -29
  65. package/dist/utils.mjs +2 -2
  66. package/package.json +7 -1
  67. package/registry/chat-widget.json +1 -1
  68. package/dist/payment-l0rkieEQ.d.mts +0 -113
  69. package/dist/payment-vzNnIi1n.d.ts +0 -113
package/dist/mock/msw.mjs CHANGED
@@ -2092,10 +2092,14 @@ var ERROR_SUGGESTIONS = {
2092
2092
  PRICE_CHANGED: "Prices changed since the quote was created. Refresh pricing, show the new total to the shopper, and require explicit confirmation before re-submitting.",
2093
2093
  PAYMENT_FAILED: "Payment provider rejected or failed processing. Show retry/change-method options to the shopper.",
2094
2094
  PAYMENT_CANCELLED: "Payment was cancelled by the shopper or provider flow. Allow a safe retry path.",
2095
+ PAYMENT_CAPABILITY_MISMATCH: "Refresh collection capabilities for the exact tenant and presentment currency before retrying.",
2096
+ UNSUPPORTED_CURRENCY: "Choose a supported presentment currency before loading payment methods or submitting checkout.",
2095
2097
  INSUFFICIENT_FUNDS: "Payment method has insufficient funds. Prompt shopper to use another method.",
2096
2098
  CARD_DECLINED: "Card was declined. Ask shopper to retry or switch payment method.",
2097
2099
  INVALID_OTP: "Authorization code is invalid. Let shopper re-enter OTP/PIN and retry.",
2098
2100
  OTP_EXPIRED: "Authorization code expired. Request a new OTP and re-submit authorization.",
2101
+ OTP_CHALLENGE_EXHAUSTED: "This verification challenge has no attempts left. Continue checkout without saved details or request a fresh challenge.",
2102
+ OTP_CHALLENGE_CONSUMED: "This verification challenge has already been used. Continue with the established session or request a fresh challenge.",
2099
2103
  AUTHORIZATION_FAILED: "Additional payment authorization failed. Retry authorization or change payment method.",
2100
2104
  PAYMENT_ACTION_NOT_COMPLETED: "Required payment action was not completed. Resume provider flow and poll for status.",
2101
2105
  SLOT_UNAVAILABLE: "Selected schedule slot is unavailable. Refresh available slots and ask shopper to reselect.",
@@ -2240,6 +2244,12 @@ function getQueryNum(c, key) {
2240
2244
  return Number.isFinite(n) ? n : void 0;
2241
2245
  }
2242
2246
 
2247
+ // src/constants.ts
2248
+ var PAYMENT_METHOD = {
2249
+ MOBILE_MONEY: "mobile_money",
2250
+ CARD: "card"
2251
+ };
2252
+
2243
2253
  // src/mock/routes/v1.ts
2244
2254
  function buildV1(deps) {
2245
2255
  const app = new Hono2();
@@ -2256,10 +2266,22 @@ function buildV1(deps) {
2256
2266
  }));
2257
2267
  });
2258
2268
  app.get("/business", (c) => tryRoute(c, () => deps.business.primary()));
2259
- app.get("/business/by-handle/:handle", (c) => tryRoute(c, () => deps.business.byHandle(c.req.param("handle"))));
2260
- app.get("/business/by-domain", (c) => tryRoute(c, () => deps.business.byDomain(c.req.query("domain") ?? "")));
2261
- app.get("/business/settings", (c) => tryRoute(c, () => deps.business.settings(deps.defaultBusinessId)));
2262
- app.get("/business/locations", (c) => tryRoute(c, () => deps.business.locations(deps.defaultBusinessId)));
2269
+ app.get(
2270
+ "/business/by-handle/:handle",
2271
+ (c) => tryRoute(c, () => deps.business.byHandle(c.req.param("handle")))
2272
+ );
2273
+ app.get(
2274
+ "/business/by-domain",
2275
+ (c) => tryRoute(c, () => deps.business.byDomain(c.req.query("domain") ?? ""))
2276
+ );
2277
+ app.get(
2278
+ "/business/settings",
2279
+ (c) => tryRoute(c, () => deps.business.settings(deps.defaultBusinessId))
2280
+ );
2281
+ app.get(
2282
+ "/business/locations",
2283
+ (c) => tryRoute(c, () => deps.business.locations(deps.defaultBusinessId))
2284
+ );
2263
2285
  app.get("/business/hours", (c) => tryRoute(c, () => deps.business.hours(deps.defaultBusinessId)));
2264
2286
  app.get("/catalogue", (c) => tryRoute(c, () => deps.catalogue.snapshot(deps.defaultBusinessId)));
2265
2287
  app.get(
@@ -2274,57 +2296,165 @@ function buildV1(deps) {
2274
2296
  })
2275
2297
  )
2276
2298
  );
2277
- app.get("/catalogue/products/:product_id", (c) => tryRoute(c, () => deps.catalogue.getProduct(c.req.param("product_id"))));
2278
- app.get("/catalogue/products/:product_id/variants", (c) => tryRoute(c, () => deps.catalogue.getProductVariants(c.req.param("product_id"))));
2279
- app.get("/catalogue/products/:product_id/variant-axes", (c) => tryRoute(c, () => deps.catalogue.getProductVariantAxes(c.req.param("product_id"))));
2299
+ app.get(
2300
+ "/catalogue/products/:product_id",
2301
+ (c) => tryRoute(c, () => deps.catalogue.getProduct(c.req.param("product_id")))
2302
+ );
2303
+ app.get(
2304
+ "/catalogue/products/:product_id/variants",
2305
+ (c) => tryRoute(c, () => deps.catalogue.getProductVariants(c.req.param("product_id")))
2306
+ );
2307
+ app.get(
2308
+ "/catalogue/products/:product_id/variant-axes",
2309
+ (c) => tryRoute(c, () => deps.catalogue.getProductVariantAxes(c.req.param("product_id")))
2310
+ );
2280
2311
  app.get(
2281
2312
  "/catalogue/products/:product_id/variants/:variant_id",
2282
- (c) => tryRoute(c, () => deps.catalogue.getProductVariantById(c.req.param("product_id"), c.req.param("variant_id")))
2313
+ (c) => tryRoute(
2314
+ c,
2315
+ () => deps.catalogue.getProductVariantById(c.req.param("product_id"), c.req.param("variant_id"))
2316
+ )
2283
2317
  );
2284
2318
  app.post("/catalogue/products/:product_id/variants/find", async (c) => {
2285
2319
  const body = await c.req.json().catch(() => ({}));
2286
2320
  return tryRoute(
2287
2321
  c,
2288
- () => deps.catalogue.findProductVariant(c.req.param("product_id"), body.axis_selections ?? body.properties ?? {})
2322
+ () => deps.catalogue.findProductVariant(
2323
+ c.req.param("product_id"),
2324
+ body.axis_selections ?? body.properties ?? {}
2325
+ )
2289
2326
  );
2290
2327
  });
2291
- app.get("/catalogue/products/:product_id/add-ons", (c) => tryRoute(c, () => deps.catalogue.getProductAddOns(c.req.param("product_id"))));
2292
- app.get("/catalogue/categories", (c) => tryRoute(c, () => deps.catalogue.listCategories(deps.defaultBusinessId)));
2293
- app.get("/catalogue/categories/:category_id", (c) => tryRoute(c, () => deps.catalogue.getCategory(c.req.param("category_id"))));
2294
- app.get("/catalogue/categories/:category_id/products", (c) => tryRoute(c, () => deps.catalogue.getCategoryProducts(c.req.param("category_id"))));
2295
- app.get("/catalogue/categories/:category_id/attributes", (c) => tryRoute(c, () => deps.catalogue.getCategoryAttributes(c.req.param("category_id"))));
2296
- app.get("/catalogue/categories/:category_id/deals", (c) => tryRoute(c, () => deps.catalogue.getCategoryDeals(c.req.param("category_id"))));
2297
- app.get("/catalogue/collections", (c) => tryRoute(c, () => deps.catalogue.listCollections(deps.defaultBusinessId)));
2298
- app.get("/catalogue/collections/:collection_id", (c) => tryRoute(c, () => deps.catalogue.getCollection(c.req.param("collection_id"))));
2299
- app.get("/catalogue/collections/:collection_id/products", (c) => tryRoute(c, () => deps.catalogue.getCollectionProducts(c.req.param("collection_id"))));
2300
- app.get("/catalogue/collections/:collection_id/attributes", (c) => tryRoute(c, () => deps.catalogue.getCollectionAttributes(c.req.param("collection_id"))));
2301
- app.get("/catalogue/collections/:collection_id/deals", (c) => tryRoute(c, () => deps.catalogue.getCollectionDeals(c.req.param("collection_id"))));
2302
- app.get("/catalogue/bundles", (c) => tryRoute(c, () => deps.catalogue.listBundles(deps.defaultBusinessId)));
2303
- app.get("/catalogue/bundles/:bundle_id", (c) => tryRoute(c, () => deps.catalogue.getBundle(c.req.param("bundle_id"))));
2304
- app.get("/catalogue/composites", (c) => tryRoute(c, () => deps.catalogue.listComposites(deps.defaultBusinessId)));
2305
- app.get("/catalogue/composites/by-product/:product_id", (c) => tryRoute(c, () => deps.catalogue.getCompositeByProduct(c.req.param("product_id"))));
2306
- app.get("/catalogue/composites/:composite_id", (c) => tryRoute(c, () => deps.catalogue.getComposite(c.req.param("composite_id"))));
2328
+ app.get(
2329
+ "/catalogue/products/:product_id/add-ons",
2330
+ (c) => tryRoute(c, () => deps.catalogue.getProductAddOns(c.req.param("product_id")))
2331
+ );
2332
+ app.get(
2333
+ "/catalogue/categories",
2334
+ (c) => tryRoute(c, () => deps.catalogue.listCategories(deps.defaultBusinessId))
2335
+ );
2336
+ app.get(
2337
+ "/catalogue/categories/:category_id",
2338
+ (c) => tryRoute(c, () => deps.catalogue.getCategory(c.req.param("category_id")))
2339
+ );
2340
+ app.get(
2341
+ "/catalogue/categories/:category_id/products",
2342
+ (c) => tryRoute(c, () => deps.catalogue.getCategoryProducts(c.req.param("category_id")))
2343
+ );
2344
+ app.get(
2345
+ "/catalogue/categories/:category_id/attributes",
2346
+ (c) => tryRoute(c, () => deps.catalogue.getCategoryAttributes(c.req.param("category_id")))
2347
+ );
2348
+ app.get(
2349
+ "/catalogue/categories/:category_id/deals",
2350
+ (c) => tryRoute(c, () => deps.catalogue.getCategoryDeals(c.req.param("category_id")))
2351
+ );
2352
+ app.get(
2353
+ "/catalogue/collections",
2354
+ (c) => tryRoute(c, () => deps.catalogue.listCollections(deps.defaultBusinessId))
2355
+ );
2356
+ app.get(
2357
+ "/catalogue/collections/:collection_id",
2358
+ (c) => tryRoute(c, () => deps.catalogue.getCollection(c.req.param("collection_id")))
2359
+ );
2360
+ app.get(
2361
+ "/catalogue/collections/:collection_id/products",
2362
+ (c) => tryRoute(c, () => deps.catalogue.getCollectionProducts(c.req.param("collection_id")))
2363
+ );
2364
+ app.get(
2365
+ "/catalogue/collections/:collection_id/attributes",
2366
+ (c) => tryRoute(c, () => deps.catalogue.getCollectionAttributes(c.req.param("collection_id")))
2367
+ );
2368
+ app.get(
2369
+ "/catalogue/collections/:collection_id/deals",
2370
+ (c) => tryRoute(c, () => deps.catalogue.getCollectionDeals(c.req.param("collection_id")))
2371
+ );
2372
+ app.get(
2373
+ "/catalogue/bundles",
2374
+ (c) => tryRoute(c, () => deps.catalogue.listBundles(deps.defaultBusinessId))
2375
+ );
2376
+ app.get(
2377
+ "/catalogue/bundles/:bundle_id",
2378
+ (c) => tryRoute(c, () => deps.catalogue.getBundle(c.req.param("bundle_id")))
2379
+ );
2380
+ app.get(
2381
+ "/catalogue/composites",
2382
+ (c) => tryRoute(c, () => deps.catalogue.listComposites(deps.defaultBusinessId))
2383
+ );
2384
+ app.get(
2385
+ "/catalogue/composites/by-product/:product_id",
2386
+ (c) => tryRoute(c, () => deps.catalogue.getCompositeByProduct(c.req.param("product_id")))
2387
+ );
2388
+ app.get(
2389
+ "/catalogue/composites/:composite_id",
2390
+ (c) => tryRoute(c, () => deps.catalogue.getComposite(c.req.param("composite_id")))
2391
+ );
2307
2392
  app.post("/catalogue/composites/:composite_id/calculate-price", async (c) => {
2308
2393
  const body = await c.req.json().catch(() => ({}));
2309
- return tryRoute(c, () => deps.catalogue.calculateCompositePrice(c.req.param("composite_id"), body));
2394
+ return tryRoute(
2395
+ c,
2396
+ () => deps.catalogue.calculateCompositePrice(c.req.param("composite_id"), body)
2397
+ );
2310
2398
  });
2311
- app.get("/catalogue/taxonomies", (c) => tryRoute(c, () => deps.catalogue.listTaxonomies(deps.defaultBusinessId)));
2312
- app.get("/catalogue/taxonomies/search", (c) => tryRoute(c, () => deps.catalogue.searchTaxonomies(deps.defaultBusinessId, c.req.query("q") ?? "")));
2313
- app.get("/catalogue/taxonomies/:taxonomy_id", (c) => tryRoute(c, () => deps.catalogue.getTaxonomy(c.req.param("taxonomy_id"))));
2314
- app.get("/catalogue/taxonomies/:taxonomy_id/attributes", (c) => tryRoute(c, () => deps.catalogue.getTaxonomyAttributes(c.req.param("taxonomy_id"))));
2315
- app.get("/catalogue/taxonomies/:taxonomy_id/path", (c) => tryRoute(c, () => deps.catalogue.getTaxonomyPath(c.req.param("taxonomy_id"))));
2316
- app.get("/catalogue/attributes", (c) => tryRoute(c, () => deps.catalogue.listAttributes(deps.defaultBusinessId)));
2317
- app.get("/catalogue/properties/facets", (c) => tryRoute(c, () => deps.catalogue.listPropertyFacets(deps.defaultBusinessId)));
2318
- app.get("/catalogue/tags", (c) => tryRoute(c, () => deps.catalogue.listTags(deps.defaultBusinessId)));
2399
+ app.get(
2400
+ "/catalogue/taxonomies",
2401
+ (c) => tryRoute(c, () => deps.catalogue.listTaxonomies(deps.defaultBusinessId))
2402
+ );
2403
+ app.get(
2404
+ "/catalogue/taxonomies/search",
2405
+ (c) => tryRoute(
2406
+ c,
2407
+ () => deps.catalogue.searchTaxonomies(deps.defaultBusinessId, c.req.query("q") ?? "")
2408
+ )
2409
+ );
2410
+ app.get(
2411
+ "/catalogue/taxonomies/:taxonomy_id",
2412
+ (c) => tryRoute(c, () => deps.catalogue.getTaxonomy(c.req.param("taxonomy_id")))
2413
+ );
2414
+ app.get(
2415
+ "/catalogue/taxonomies/:taxonomy_id/attributes",
2416
+ (c) => tryRoute(c, () => deps.catalogue.getTaxonomyAttributes(c.req.param("taxonomy_id")))
2417
+ );
2418
+ app.get(
2419
+ "/catalogue/taxonomies/:taxonomy_id/path",
2420
+ (c) => tryRoute(c, () => deps.catalogue.getTaxonomyPath(c.req.param("taxonomy_id")))
2421
+ );
2422
+ app.get(
2423
+ "/catalogue/attributes",
2424
+ (c) => tryRoute(c, () => deps.catalogue.listAttributes(deps.defaultBusinessId))
2425
+ );
2426
+ app.get(
2427
+ "/catalogue/properties/facets",
2428
+ (c) => tryRoute(c, () => deps.catalogue.listPropertyFacets(deps.defaultBusinessId))
2429
+ );
2430
+ app.get(
2431
+ "/catalogue/tags",
2432
+ (c) => tryRoute(c, () => deps.catalogue.listTags(deps.defaultBusinessId))
2433
+ );
2319
2434
  app.get("/catalogue/menu", (c) => tryRoute(c, () => deps.lite.getMenu(deps.defaultBusinessId)));
2320
- app.get("/catalogue/menu/categories/:category_id", (c) => tryRoute(c, () => deps.lite.getMenuCategory(c.req.param("category_id"))));
2321
- app.get("/catalogue/menu/items/:item_id", (c) => tryRoute(c, () => deps.catalogue.getProduct(c.req.param("item_id"))));
2322
- app.get("/catalogue/knowledge-base/articles", (c) => tryRoute(c, () => ({ articles: deps.catalogue.listKnowledgeArticles(deps.defaultBusinessId) })));
2435
+ app.get(
2436
+ "/catalogue/menu/categories/:category_id",
2437
+ (c) => tryRoute(c, () => deps.lite.getMenuCategory(c.req.param("category_id")))
2438
+ );
2439
+ app.get(
2440
+ "/catalogue/menu/items/:item_id",
2441
+ (c) => tryRoute(c, () => deps.catalogue.getProduct(c.req.param("item_id")))
2442
+ );
2443
+ app.get(
2444
+ "/catalogue/knowledge-base/articles",
2445
+ (c) => tryRoute(c, () => ({ articles: deps.catalogue.listKnowledgeArticles(deps.defaultBusinessId) }))
2446
+ );
2323
2447
  app.get(
2324
2448
  "/catalogue/knowledge-base/search",
2325
- (c) => tryRoute(c, () => ({ results: deps.catalogue.searchKnowledgeBase(deps.defaultBusinessId, c.req.query("q") ?? ""), query: c.req.query("q") ?? "" }))
2449
+ (c) => tryRoute(c, () => ({
2450
+ results: deps.catalogue.searchKnowledgeBase(deps.defaultBusinessId, c.req.query("q") ?? ""),
2451
+ query: c.req.query("q") ?? ""
2452
+ }))
2453
+ );
2454
+ app.get(
2455
+ "/catalogue/products/:product_id/attributes",
2456
+ (c) => tryRoute(c, () => deps.catalogue.getProductAttributes(c.req.param("product_id")))
2326
2457
  );
2327
- app.get("/catalogue/products/:product_id/attributes", (c) => tryRoute(c, () => deps.catalogue.getProductAttributes(c.req.param("product_id"))));
2328
2458
  app.get(
2329
2459
  "/catalogue/products/:product_id/available-now",
2330
2460
  (c) => tryRoute(c, () => {
@@ -2343,22 +2473,75 @@ function buildV1(deps) {
2343
2473
  "/catalogue/products/:product_id/schedules",
2344
2474
  (c) => tryRoute(c, () => {
2345
2475
  const p = deps.registry.products.get(c.req.param("product_id"));
2346
- return { schedules: p?.metadata?.["time_profiles"] ?? [] };
2476
+ return {
2477
+ schedules: p?.metadata?.["time_profiles"] ?? []
2478
+ };
2347
2479
  })
2348
2480
  );
2349
- app.get("/catalogue/deals", (c) => tryRoute(c, () => deps.catalogue.listDeals(deps.defaultBusinessId)));
2350
- app.get("/catalogue/deals/on-sale", (c) => tryRoute(c, () => deps.catalogue.listOnSale(deps.defaultBusinessId)));
2481
+ app.get(
2482
+ "/catalogue/deals",
2483
+ (c) => tryRoute(c, () => deps.catalogue.listDeals(deps.defaultBusinessId))
2484
+ );
2485
+ app.get(
2486
+ "/catalogue/deals/on-sale",
2487
+ (c) => tryRoute(c, () => deps.catalogue.listOnSale(deps.defaultBusinessId))
2488
+ );
2351
2489
  app.post("/catalogue/deals/validate", async (c) => {
2352
2490
  const body = await c.req.json().catch(() => ({}));
2353
- return tryRoute(c, () => deps.catalogue.validateDiscount(body.discount_code ?? body.code ?? "", deps.defaultBusinessId));
2491
+ return tryRoute(
2492
+ c,
2493
+ () => deps.catalogue.validateDiscount(
2494
+ body.discount_code ?? body.code ?? "",
2495
+ deps.defaultBusinessId
2496
+ )
2497
+ );
2354
2498
  });
2355
- app.get("/catalogue/products/:product_id/deals", (c) => tryRoute(c, () => deps.catalogue.getProductDeals(c.req.param("product_id"))));
2499
+ app.get(
2500
+ "/catalogue/products/:product_id/deals",
2501
+ (c) => tryRoute(c, () => deps.catalogue.getProductDeals(c.req.param("product_id")))
2502
+ );
2356
2503
  app.post("/catalogue/quotes", async (c) => {
2357
2504
  const body = await c.req.json().catch(() => ({}));
2358
2505
  return tryRoute(c, () => deps.catalogue.createQuote(deps.defaultBusinessId, body));
2359
2506
  });
2360
- app.get("/catalogue/quotes/:quote_id", (c) => tryRoute(c, () => deps.catalogue.getQuote(c.req.param("quote_id"))));
2361
- app.post("/catalogue/quotes/:quote_id/refresh", (c) => tryRoute(c, () => deps.catalogue.refreshQuote(c.req.param("quote_id"))));
2507
+ app.get(
2508
+ "/catalogue/quotes/:quote_id",
2509
+ (c) => tryRoute(c, () => deps.catalogue.getQuote(c.req.param("quote_id")))
2510
+ );
2511
+ app.post(
2512
+ "/catalogue/quotes/:quote_id/refresh",
2513
+ (c) => tryRoute(c, () => deps.catalogue.refreshQuote(c.req.param("quote_id")))
2514
+ );
2515
+ app.get("/reviews/summary", (c) => {
2516
+ const productId = c.req.query("product_id");
2517
+ if (productId !== void 0 && (productId.length === 0 || productId.trim() !== productId)) {
2518
+ return fail(c, validation("product_id must be a non-empty canonical identifier"));
2519
+ }
2520
+ const response = {
2521
+ data: {
2522
+ ratings: {
2523
+ product_id: productId ?? null,
2524
+ review_count: 0,
2525
+ rating_sum: 0,
2526
+ average_rating: null,
2527
+ distribution: { one: 0, two: 0, three: 0, four: 0, five: 0 }
2528
+ },
2529
+ trust_chips: {
2530
+ on_time_delivery_percent: null,
2531
+ delivery_sample_size: 0,
2532
+ average_first_response_seconds: null,
2533
+ support_sample_size: 0
2534
+ }
2535
+ }
2536
+ };
2537
+ return c.json(response);
2538
+ });
2539
+ app.get("/reviews", (c) => {
2540
+ const response = {
2541
+ data: { items: [], next_cursor: null }
2542
+ };
2543
+ return c.json(response);
2544
+ });
2362
2545
  app.get("/cart", (c) => tryRoute(c, () => deps.cart.toUICart(deps.cart.get(c.var.session))));
2363
2546
  app.delete("/cart", (c) => tryRoute(c, () => deps.cart.clear(c.var.session)));
2364
2547
  app.get("/cart/items", (c) => tryRoute(c, () => deps.cart.getItems(c.var.session)));
@@ -2369,9 +2552,15 @@ function buildV1(deps) {
2369
2552
  app.patch("/cart/items/:cart_item_id", async (c) => {
2370
2553
  const body = await c.req.json().catch(() => ({}));
2371
2554
  if (typeof body.quantity !== "number") return fail(c, validation("quantity required"));
2372
- return tryRoute(c, () => deps.cart.updateQuantity(c.var.session, c.req.param("cart_item_id"), body.quantity));
2555
+ return tryRoute(
2556
+ c,
2557
+ () => deps.cart.updateQuantity(c.var.session, c.req.param("cart_item_id"), body.quantity)
2558
+ );
2373
2559
  });
2374
- app.delete("/cart/items/:cart_item_id", (c) => tryRoute(c, () => deps.cart.removeItem(c.var.session, c.req.param("cart_item_id"))));
2560
+ app.delete(
2561
+ "/cart/items/:cart_item_id",
2562
+ (c) => tryRoute(c, () => deps.cart.removeItem(c.var.session, c.req.param("cart_item_id")))
2563
+ );
2375
2564
  app.get("/cart/count", (c) => tryRoute(c, () => deps.cart.getCount(c.var.session)));
2376
2565
  app.get("/cart/total", (c) => tryRoute(c, () => deps.cart.getTotal(c.var.session)));
2377
2566
  app.post("/cart/destination-quote", async (c) => {
@@ -2382,10 +2571,25 @@ function buildV1(deps) {
2382
2571
  const body = await c.req.json().catch(() => ({}));
2383
2572
  return tryRoute(c, () => deps.cart.applyCoupon(c.var.session, body.coupon_code ?? ""));
2384
2573
  });
2385
- app.delete("/cart/coupons/current", (c) => tryRoute(c, () => deps.cart.removeCoupon(c.var.session)));
2386
- app.get("/orders", (c) => tryRoute(c, () => deps.orders.list(c.var.session, { limit: getQueryNum(c, "limit"), status: c.req.query("status") })));
2574
+ app.delete(
2575
+ "/cart/coupons/current",
2576
+ (c) => tryRoute(c, () => deps.cart.removeCoupon(c.var.session))
2577
+ );
2578
+ app.get(
2579
+ "/orders",
2580
+ (c) => tryRoute(
2581
+ c,
2582
+ () => deps.orders.list(c.var.session, {
2583
+ limit: getQueryNum(c, "limit"),
2584
+ status: c.req.query("status")
2585
+ })
2586
+ )
2587
+ );
2387
2588
  app.get("/orders/:order_id", (c) => tryRoute(c, () => deps.orders.get(c.req.param("order_id"))));
2388
- app.get("/orders/:order_id/payment-status", (c) => tryRoute(c, () => deps.orders.getPaymentStatus(c.req.param("order_id"))));
2589
+ app.get(
2590
+ "/orders/:order_id/payment-status",
2591
+ (c) => tryRoute(c, () => deps.orders.getPaymentStatus(c.req.param("order_id")))
2592
+ );
2389
2593
  app.post("/orders/:order_id/cancel", async (c) => {
2390
2594
  const body = await c.req.json().catch(() => ({}));
2391
2595
  return tryRoute(c, () => deps.orders.cancel(c.req.param("order_id"), body.reason));
@@ -2394,13 +2598,46 @@ function buildV1(deps) {
2394
2598
  const body = await c.req.json().catch(() => ({}));
2395
2599
  return tryRoute(c, () => deps.orders.updateCustomer(c.req.param("order_id"), body));
2396
2600
  });
2397
- app.post("/orders/:order_id/verify-payment", (c) => tryRoute(c, () => deps.orders.verifyPayment(c.req.param("order_id"))));
2601
+ app.post(
2602
+ "/orders/:order_id/verify-payment",
2603
+ (c) => tryRoute(c, () => deps.orders.verifyPayment(c.req.param("order_id")))
2604
+ );
2398
2605
  app.get("/subscriptions", (c) => tryRoute(c, () => deps.subscriptions.list(c.var.session)));
2399
- app.get("/subscriptions/:subscription_id", (c) => tryRoute(c, () => deps.subscriptions.get(c.req.param("subscription_id"))));
2400
- app.post("/subscriptions/:subscription_id/cancel", (c) => tryRoute(c, () => deps.subscriptions.cancel(c.req.param("subscription_id"))));
2401
- app.post("/subscriptions/:subscription_id/pause", (c) => tryRoute(c, () => deps.subscriptions.pause(c.req.param("subscription_id"))));
2402
- app.post("/subscriptions/:subscription_id/resume", (c) => tryRoute(c, () => deps.subscriptions.resume(c.req.param("subscription_id"))));
2403
- app.post("/subscriptions/:subscription_id/skip", (c) => tryRoute(c, () => deps.subscriptions.skipNext(c.req.param("subscription_id"))));
2606
+ app.get(
2607
+ "/subscriptions/:subscription_id",
2608
+ (c) => tryRoute(c, () => deps.subscriptions.get(c.req.param("subscription_id")))
2609
+ );
2610
+ app.post(
2611
+ "/subscriptions/:subscription_id/cancel",
2612
+ (c) => tryRoute(c, () => deps.subscriptions.cancel(c.req.param("subscription_id")))
2613
+ );
2614
+ app.post(
2615
+ "/subscriptions/:subscription_id/pause",
2616
+ (c) => tryRoute(c, () => deps.subscriptions.pause(c.req.param("subscription_id")))
2617
+ );
2618
+ app.post(
2619
+ "/subscriptions/:subscription_id/resume",
2620
+ (c) => tryRoute(c, () => deps.subscriptions.resume(c.req.param("subscription_id")))
2621
+ );
2622
+ app.post(
2623
+ "/subscriptions/:subscription_id/skip",
2624
+ (c) => tryRoute(c, () => deps.subscriptions.skipNext(c.req.param("subscription_id")))
2625
+ );
2626
+ app.get("/payments/collection-options", (c) => {
2627
+ const currency = c.req.query("currency")?.trim().toUpperCase();
2628
+ if (!currency || !/^[A-Z]{3}$/.test(currency)) {
2629
+ return fail(c, validation("currency must be a canonical three-letter code"));
2630
+ }
2631
+ return tryRoute(c, () => ({
2632
+ presentment_currency: currency,
2633
+ options: currency === "GHS" ? [
2634
+ { method: PAYMENT_METHOD.CARD, network: null },
2635
+ { method: PAYMENT_METHOD.MOBILE_MONEY, network: "mtn" },
2636
+ { method: PAYMENT_METHOD.MOBILE_MONEY, network: "telecel" },
2637
+ { method: PAYMENT_METHOD.MOBILE_MONEY, network: "airteltigo" }
2638
+ ] : currency === "USD" ? [{ method: PAYMENT_METHOD.CARD, network: null }] : []
2639
+ }));
2640
+ });
2404
2641
  app.post("/checkout", async (c) => {
2405
2642
  const body = await c.req.json().catch(() => ({}));
2406
2643
  return tryRoute(c, () => deps.checkout.process(c.var.session, body));
@@ -2454,15 +2691,33 @@ function buildV1(deps) {
2454
2691
  return { success: true, message: "Profile updated successfully" };
2455
2692
  });
2456
2693
  });
2457
- app.get("/inventory/products/:product_id/stock", (c) => tryRoute(c, () => deps.inventory.productStock(c.req.param("product_id"))));
2458
- app.get("/inventory/variants/:variant_id/stock", (c) => tryRoute(c, () => deps.inventory.variantStock(c.req.param("variant_id"))));
2694
+ app.get(
2695
+ "/inventory/products/:product_id/stock",
2696
+ (c) => tryRoute(c, () => deps.inventory.productStock(c.req.param("product_id")))
2697
+ );
2698
+ app.get(
2699
+ "/inventory/variants/:variant_id/stock",
2700
+ (c) => tryRoute(c, () => deps.inventory.variantStock(c.req.param("variant_id")))
2701
+ );
2459
2702
  app.get(
2460
2703
  "/inventory/products/:product_id/availability",
2461
- (c) => tryRoute(c, () => deps.inventory.productAvailability(c.req.param("product_id"), getQueryNum(c, "quantity") ?? 1))
2704
+ (c) => tryRoute(
2705
+ c,
2706
+ () => deps.inventory.productAvailability(
2707
+ c.req.param("product_id"),
2708
+ getQueryNum(c, "quantity") ?? 1
2709
+ )
2710
+ )
2462
2711
  );
2463
2712
  app.get(
2464
2713
  "/inventory/variants/:variant_id/availability",
2465
- (c) => tryRoute(c, () => deps.inventory.variantAvailability(c.req.param("variant_id"), getQueryNum(c, "quantity") ?? 1))
2714
+ (c) => tryRoute(
2715
+ c,
2716
+ () => deps.inventory.variantAvailability(
2717
+ c.req.param("variant_id"),
2718
+ getQueryNum(c, "quantity") ?? 1
2719
+ )
2720
+ )
2466
2721
  );
2467
2722
  app.get(
2468
2723
  "/delivery/fee",
@@ -2489,35 +2744,75 @@ function buildV1(deps) {
2489
2744
  );
2490
2745
  app.post("/places/autocomplete", async (c) => {
2491
2746
  const body = await c.req.json().catch(() => ({}));
2492
- return tryRoute(c, () => deps.places.autocomplete({ query: body.input ?? body.query ?? "", country: body.country }));
2747
+ return tryRoute(
2748
+ c,
2749
+ () => deps.places.autocomplete({ query: body.input ?? body.query ?? "", country: body.country })
2750
+ );
2493
2751
  });
2494
2752
  app.post("/places/details", async (c) => {
2495
2753
  const body = await c.req.json().catch(() => ({}));
2496
2754
  return tryRoute(c, () => deps.places.details({ place_id: body.place_id ?? "" }));
2497
2755
  });
2498
- app.get("/scheduling/services", (c) => tryRoute(c, () => deps.scheduling.listServices(deps.defaultBusinessId)));
2499
- app.get("/scheduling/services/:service_id", (c) => tryRoute(c, () => deps.scheduling.getService(c.req.param("service_id"))));
2500
- app.get("/scheduling/slots", (c) => tryRoute(c, () => deps.scheduling.getSlots(c.req.query("service_id") ?? "", { date: c.req.query("date") })));
2756
+ app.get(
2757
+ "/scheduling/services",
2758
+ (c) => tryRoute(c, () => deps.scheduling.listServices(deps.defaultBusinessId))
2759
+ );
2760
+ app.get(
2761
+ "/scheduling/services/:service_id",
2762
+ (c) => tryRoute(c, () => deps.scheduling.getService(c.req.param("service_id")))
2763
+ );
2764
+ app.get(
2765
+ "/scheduling/slots",
2766
+ (c) => tryRoute(
2767
+ c,
2768
+ () => deps.scheduling.getSlots(c.req.query("service_id") ?? "", { date: c.req.query("date") })
2769
+ )
2770
+ );
2501
2771
  app.get(
2502
2772
  "/scheduling/slots/check",
2503
- (c) => tryRoute(c, () => deps.scheduling.checkSlot(c.req.query("service_id") ?? "", c.req.query("start") ?? "", c.req.query("end") ?? ""))
2773
+ (c) => tryRoute(
2774
+ c,
2775
+ () => deps.scheduling.checkSlot(
2776
+ c.req.query("service_id") ?? "",
2777
+ c.req.query("start") ?? "",
2778
+ c.req.query("end") ?? ""
2779
+ )
2780
+ )
2781
+ );
2782
+ app.get(
2783
+ "/scheduling/availability",
2784
+ (c) => tryRoute(c, () => deps.scheduling.getServiceAvailability(c.req.query("service_id") ?? ""))
2785
+ );
2786
+ app.get(
2787
+ "/scheduling/bookings",
2788
+ (c) => tryRoute(c, () => deps.scheduling.getCustomerBookings(c.var.session))
2504
2789
  );
2505
- app.get("/scheduling/availability", (c) => tryRoute(c, () => deps.scheduling.getServiceAvailability(c.req.query("service_id") ?? "")));
2506
- app.get("/scheduling/bookings", (c) => tryRoute(c, () => deps.scheduling.getCustomerBookings(c.var.session)));
2507
2790
  app.post("/scheduling/bookings/reschedule", async (c) => {
2508
2791
  const body = await c.req.json().catch(() => ({}));
2509
2792
  return tryRoute(c, () => deps.scheduling.rescheduleBooking(body));
2510
2793
  });
2511
- app.get("/scheduling/bookings/:booking_id", (c) => tryRoute(c, () => deps.scheduling.getBooking(c.req.param("booking_id"))));
2794
+ app.get(
2795
+ "/scheduling/bookings/:booking_id",
2796
+ (c) => tryRoute(c, () => deps.scheduling.getBooking(c.req.param("booking_id")))
2797
+ );
2512
2798
  app.post("/scheduling/bookings/:booking_id/cancel", async (c) => {
2513
2799
  const body = await c.req.json().catch(() => ({}));
2514
2800
  return tryRoute(c, () => deps.scheduling.cancelBooking(c.req.param("booking_id"), body.reason));
2515
2801
  });
2516
2802
  app.get("/lite/bootstrap", (c) => tryRoute(c, () => deps.lite.bootstrap(deps.defaultBusinessId)));
2517
- app.get("/lite/resources/:resource_id", (c) => tryRoute(c, () => deps.lite.getResource(c.req.param("resource_id"))));
2803
+ app.get(
2804
+ "/lite/resources/:resource_id",
2805
+ (c) => tryRoute(c, () => deps.lite.getResource(c.req.param("resource_id")))
2806
+ );
2518
2807
  app.get("/lite/menu", (c) => tryRoute(c, () => deps.lite.getMenu(deps.defaultBusinessId)));
2519
- app.get("/lite/menu/categories/:category_id", (c) => tryRoute(c, () => deps.lite.getMenuCategory(c.req.param("category_id"))));
2520
- app.get("/fx/rate", (c) => tryRoute(c, () => deps.fx.getRate(c.req.query("from") ?? "USD", c.req.query("to") ?? "GHS")));
2808
+ app.get(
2809
+ "/lite/menu/categories/:category_id",
2810
+ (c) => tryRoute(c, () => deps.lite.getMenuCategory(c.req.param("category_id")))
2811
+ );
2812
+ app.get(
2813
+ "/fx/rate",
2814
+ (c) => tryRoute(c, () => deps.fx.getRate(c.req.query("from") ?? "USD", c.req.query("to") ?? "GHS"))
2815
+ );
2521
2816
  app.post("/fx/quotes", async (c) => {
2522
2817
  const body = await c.req.json().catch(() => ({}));
2523
2818
  return tryRoute(c, () => deps.fx.lockQuote(body));
@@ -2530,31 +2825,47 @@ function buildV1(deps) {
2530
2825
  const body = await c.req.json().catch(() => ({}));
2531
2826
  return tryRoute(c, () => deps.uploads.confirm(body));
2532
2827
  });
2533
- app.get(
2534
- "/store-credit/balance",
2535
- (c) => c.json({ data: { balance: "0.00", currency: "USD" } })
2536
- );
2828
+ app.get("/store-credit/balance", (c) => c.json({ data: { balance: "0.00", currency: "USD" } }));
2537
2829
  app.post("/activity/session", async (c) => {
2538
2830
  await c.req.json().catch(() => ({}));
2539
2831
  return c.json({ data: { recorded: true } });
2540
2832
  });
2541
2833
  app.post("/activity/events", async (c) => {
2542
2834
  const body = await c.req.json().catch(() => ({}));
2543
- return tryRoute(c, () => deps.activity.recordEvents(deps.defaultBusinessId, body.analytics_session_id ?? c.var.session.id, body.events ?? []));
2835
+ return tryRoute(
2836
+ c,
2837
+ () => deps.activity.recordEvents(
2838
+ deps.defaultBusinessId,
2839
+ body.analytics_session_id ?? c.var.session.id,
2840
+ body.events ?? []
2841
+ )
2842
+ );
2544
2843
  });
2545
- app.get("/activity/state", (c) => tryRoute(c, () => deps.activity.getState(deps.defaultBusinessId, c.var.session.id)));
2546
- app.get("/activity/recommendations", (c) => tryRoute(c, () => deps.activity.getRecommendations(deps.defaultBusinessId)));
2844
+ app.get(
2845
+ "/activity/state",
2846
+ (c) => tryRoute(c, () => deps.activity.getState(deps.defaultBusinessId, c.var.session.id))
2847
+ );
2848
+ app.get(
2849
+ "/activity/recommendations",
2850
+ (c) => tryRoute(c, () => deps.activity.getRecommendations(deps.defaultBusinessId))
2851
+ );
2547
2852
  app.post("/activity/messages/dismiss", async (c) => {
2548
2853
  const body = await c.req.json().catch(() => ({}));
2549
2854
  return tryRoute(c, () => deps.activity.dismissMessage(body.code ?? body.message_id ?? ""));
2550
2855
  });
2551
2856
  app.post(
2552
2857
  "/support/conversation",
2553
- (c) => tryRoute(c, () => deps.support.openConversation(deps.defaultBusinessId, c.var.session.customer_id))
2858
+ (c) => tryRoute(
2859
+ c,
2860
+ () => deps.support.openConversation(deps.defaultBusinessId, c.var.session.customer_id)
2861
+ )
2554
2862
  );
2555
2863
  app.get(
2556
2864
  "/support/conversation",
2557
- (c) => tryRoute(c, () => deps.support.peekConversation(deps.defaultBusinessId, c.var.session.customer_id))
2865
+ (c) => tryRoute(
2866
+ c,
2867
+ () => deps.support.peekConversation(deps.defaultBusinessId, c.var.session.customer_id)
2868
+ )
2558
2869
  );
2559
2870
  app.post("/support/conversation/messages", async (c) => {
2560
2871
  const body = await c.req.json().catch(() => ({}));
@@ -2570,7 +2881,12 @@ function buildV1(deps) {
2570
2881
  });
2571
2882
  app.get(
2572
2883
  "/support/conversation/messages",
2573
- (c) => tryRoute(c, () => deps.support.listMessages(c.req.query("conversation_id") ?? "", { limit: getQueryNum(c, "limit") }))
2884
+ (c) => tryRoute(
2885
+ c,
2886
+ () => deps.support.listMessages(c.req.query("conversation_id") ?? "", {
2887
+ limit: getQueryNum(c, "limit")
2888
+ })
2889
+ )
2574
2890
  );
2575
2891
  app.post("/support/conversation/messages/:messageId/reactions", async (c) => {
2576
2892
  const body = await c.req.json().catch(() => ({}));
@@ -2591,7 +2907,10 @@ function buildV1(deps) {
2591
2907
  });
2592
2908
  app.get(
2593
2909
  "/support/conversation/ws",
2594
- (c) => c.json({ note: "WebSocket connection \u2014 connect via ws:// at the same path", supported: false }, 426)
2910
+ (c) => c.json(
2911
+ { note: "WebSocket connection \u2014 connect via ws:// at the same path", supported: false },
2912
+ 426
2913
+ )
2595
2914
  );
2596
2915
  return app;
2597
2916
  }
@@ -3118,9 +3437,10 @@ function buildLink(deps) {
3118
3437
  app.post("/auth/request-otp", async (c) => {
3119
3438
  const body = await c.req.json().catch(() => ({}));
3120
3439
  return tryRoute(c, () => {
3121
- deps.auth.requestOtp(body.contact ?? "");
3440
+ const challenge = deps.auth.requestOtp(body.contact ?? "");
3122
3441
  return {
3123
3442
  success: true,
3443
+ challenge_id: challenge.otp_id,
3124
3444
  message: `OTP sent to ${body.contact ?? "contact"}`,
3125
3445
  expires_in: 300,
3126
3446
  is_new_account: false
@@ -3130,7 +3450,11 @@ function buildLink(deps) {
3130
3450
  app.post("/auth/verify-otp", async (c) => {
3131
3451
  const body = await c.req.json().catch(() => ({}));
3132
3452
  return tryRoute(c, () => {
3133
- const session = deps.auth.verifyOtp(body.contact ?? "", body.otp_code ?? "");
3453
+ const session = deps.auth.verifyOtp(
3454
+ body.contact ?? "",
3455
+ body.otp_code ?? "",
3456
+ body.challenge_id
3457
+ );
3134
3458
  c.header("x-session-token", session.token);
3135
3459
  const customer = deps.link.ensureCustomer(session.customer_id ?? session.id, {
3136
3460
  email: body.contact?.includes("@") ? body.contact : void 0,
@@ -3224,10 +3548,7 @@ function buildLink(deps) {
3224
3548
  };
3225
3549
  });
3226
3550
  });
3227
- app.get(
3228
- "/preferences",
3229
- (c) => tryRoute(c, () => deps.link.getPreferences(customerId(c)))
3230
- );
3551
+ app.get("/preferences", (c) => tryRoute(c, () => deps.link.getPreferences(customerId(c))));
3231
3552
  app.post("/preferences", async (c) => {
3232
3553
  const body = await c.req.json().catch(() => ({}));
3233
3554
  return tryRoute(c, () => {
@@ -3704,9 +4025,16 @@ function createAuthService(opts) {
3704
4025
  code_hint: options.mode === "permissive" ? code : void 0
3705
4026
  };
3706
4027
  },
3707
- verifyOtp(contact, code) {
3708
- const matching = registry.otps.list((o) => o.contact === contact);
3709
- const otp = matching[matching.length - 1];
4028
+ verifyOtp(contact, code, challengeId) {
4029
+ let otp = challengeId ? registry.otps.get(challengeId) : void 0;
4030
+ if (!challengeId) {
4031
+ const matching = registry.otps.list((o) => o.contact === contact);
4032
+ otp = matching[matching.length - 1];
4033
+ }
4034
+ if (challengeId) {
4035
+ if (!otp) throw new Error("No OTP challenge found");
4036
+ if (otp.contact !== contact) throw new Error("OTP challenge does not match contact");
4037
+ }
3710
4038
  if (options.mode === "strict") {
3711
4039
  if (!otp) throw new Error("No OTP requested");
3712
4040
  if (otp.code !== code && code !== options.defaultOtp) throw new Error("Invalid OTP");
@@ -5034,7 +5362,7 @@ function createCartService(opts) {
5034
5362
 
5035
5363
  // src/mock/domain/checkout.ts
5036
5364
  function createCheckoutService(opts) {
5037
- const { registry, clock, ids, bus} = opts;
5365
+ const { registry, clock, ids, bus } = opts;
5038
5366
  return {
5039
5367
  process(session, body) {
5040
5368
  if (!body.cart_id) throw validation("cart_id required");
@@ -5043,9 +5371,11 @@ function createCheckoutService(opts) {
5043
5371
  if (c.items.length === 0) throw validation("Cart is empty", { code: "CART_EMPTY" });
5044
5372
  const orderId = ids.order();
5045
5373
  const orderNumber = ids.orderNumber();
5374
+ const paymentId = ids.payment();
5046
5375
  const reference = ids.payment();
5047
5376
  const requiresAuth = body.payment_method === "mobile_money";
5048
5377
  const isCard = body.payment_method === "card" || body.payment_method === "stripe";
5378
+ const cardProvider = body.payment_method === "stripe" || body.pay_currency?.toUpperCase() === "USD" ? "stripe" : "paystack";
5049
5379
  const order = {
5050
5380
  id: orderId,
5051
5381
  business_id: c.business_id,
@@ -5069,6 +5399,7 @@ function createCheckoutService(opts) {
5069
5399
  items: c.items,
5070
5400
  applied_discount_ids: c.applied_discount_ids,
5071
5401
  applied_discount_codes: c.applied_discount_codes,
5402
+ payment_id: paymentId,
5072
5403
  payment_reference: reference,
5073
5404
  metadata: body.metadata,
5074
5405
  created_at: clock.iso(),
@@ -5085,31 +5416,57 @@ function createCheckoutService(opts) {
5085
5416
  const result = {
5086
5417
  order_id: orderId,
5087
5418
  order_number: orderNumber,
5088
- payment_status: requiresAuth ? "pending" : "succeeded",
5419
+ payment_id: paymentId,
5420
+ payment_status: requiresAuth || isCard ? "pending" : "succeeded",
5089
5421
  payment_reference: reference,
5090
5422
  requires_authorization: requiresAuth,
5091
5423
  authorization_type: requiresAuth ? "otp" : void 0,
5092
- next_action: requiresAuth ? { type: "authorization", authorization_type: "otp", display_text: "Approve on your mobile money app" } : { type: "none" },
5093
- provider: body.payment_method,
5424
+ next_action: requiresAuth ? {
5425
+ type: "authorization",
5426
+ authorization_type: "otp",
5427
+ display_text: "Approve on your mobile money app"
5428
+ } : { type: "none" },
5429
+ provider: isCard ? cardProvider : body.payment_method,
5094
5430
  bill_token: billToken
5095
5431
  };
5096
5432
  if (isCard) {
5097
- result.next_action = { type: "redirect", authorization_url: `https://mock.cimplify.io/pay/${reference}` };
5098
- result.authorization_url = `https://mock.cimplify.io/pay/${reference}`;
5099
- result.client_secret = `pi_${orderId.slice(-12)}_secret_${Math.random().toString(36).slice(2, 18)}`;
5100
5433
  const proc = globalThis.process;
5101
- result.public_key = proc?.env?.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY ?? "pk_test_mock_publishable_key";
5434
+ result.client_secret = cardProvider === "stripe" ? `pi_${orderId.slice(-12)}_secret_${Math.random().toString(36).slice(2, 18)}` : `access_${reference}`;
5435
+ result.public_key = cardProvider === "stripe" ? proc?.env?.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY ?? "pk_test_mock_stripe" : proc?.env?.NEXT_PUBLIC_PAYSTACK_PUBLIC_KEY ?? "pk_test_mock_paystack";
5436
+ result.next_action = {
5437
+ type: "card_popup",
5438
+ provider: cardProvider,
5439
+ client_secret: result.client_secret,
5440
+ public_key: result.public_key
5441
+ };
5102
5442
  }
5103
5443
  return result;
5104
5444
  },
5105
5445
  authorize(body) {
5106
- const order = registry.orders.get(body.order_id);
5107
- if (!order) throw notFound(`Order ${body.order_id} not found`);
5108
- const updated = { ...order, payment_state: "paid", status: "confirmed", updated_at: clock.iso() };
5446
+ if (!body.payment_id?.trim()) throw validation("payment_id required");
5447
+ if (!body.authorization) throw validation("authorization required");
5448
+ const order = registry.orders.list(
5449
+ (candidate) => candidate.payment_id === body.payment_id
5450
+ )[0];
5451
+ if (!order) throw notFound(`Payment ${body.payment_id} not found`);
5452
+ const updated = {
5453
+ ...order,
5454
+ payment_state: "paid",
5455
+ status: "confirmed",
5456
+ updated_at: clock.iso()
5457
+ };
5109
5458
  registry.orders.put(order.id, updated);
5110
5459
  bus.emit("order.payment.captured", { order_id: order.id }, order.business_id);
5111
5460
  bus.emit("order.confirmed", { order_id: order.id }, order.business_id);
5112
- return { status: "succeeded", order_id: order.id };
5461
+ return {
5462
+ order_id: order.id,
5463
+ order_number: order.user_friendly_id,
5464
+ payment_id: body.payment_id,
5465
+ payment_reference: order.payment_reference,
5466
+ payment_status: "succeeded",
5467
+ requires_authorization: false,
5468
+ next_action: { type: "none" }
5469
+ };
5113
5470
  }
5114
5471
  };
5115
5472
  }
@@ -5492,6 +5849,7 @@ function createDeliveryService() {
5492
5849
  rate_id: "dlvrt_mock_standard",
5493
5850
  name: "Standard",
5494
5851
  fee: standardFree ? money(0) : money(15),
5852
+ fee_status: "priced",
5495
5853
  currency: "GHS",
5496
5854
  free_delivery_applied: standardFree,
5497
5855
  free_over_amount: money(200),
@@ -5505,6 +5863,7 @@ function createDeliveryService() {
5505
5863
  name: "Express",
5506
5864
  description: "Delivered within the hour",
5507
5865
  fee: money(25),
5866
+ fee_status: "priced",
5508
5867
  currency: "GHS",
5509
5868
  free_delivery_applied: false,
5510
5869
  eta_min_minutes: 30,