@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
@@ -2096,10 +2096,14 @@ var ERROR_SUGGESTIONS = {
2096
2096
  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.",
2097
2097
  PAYMENT_FAILED: "Payment provider rejected or failed processing. Show retry/change-method options to the shopper.",
2098
2098
  PAYMENT_CANCELLED: "Payment was cancelled by the shopper or provider flow. Allow a safe retry path.",
2099
+ PAYMENT_CAPABILITY_MISMATCH: "Refresh collection capabilities for the exact tenant and presentment currency before retrying.",
2100
+ UNSUPPORTED_CURRENCY: "Choose a supported presentment currency before loading payment methods or submitting checkout.",
2099
2101
  INSUFFICIENT_FUNDS: "Payment method has insufficient funds. Prompt shopper to use another method.",
2100
2102
  CARD_DECLINED: "Card was declined. Ask shopper to retry or switch payment method.",
2101
2103
  INVALID_OTP: "Authorization code is invalid. Let shopper re-enter OTP/PIN and retry.",
2102
2104
  OTP_EXPIRED: "Authorization code expired. Request a new OTP and re-submit authorization.",
2105
+ OTP_CHALLENGE_EXHAUSTED: "This verification challenge has no attempts left. Continue checkout without saved details or request a fresh challenge.",
2106
+ OTP_CHALLENGE_CONSUMED: "This verification challenge has already been used. Continue with the established session or request a fresh challenge.",
2103
2107
  AUTHORIZATION_FAILED: "Additional payment authorization failed. Retry authorization or change payment method.",
2104
2108
  PAYMENT_ACTION_NOT_COMPLETED: "Required payment action was not completed. Resume provider flow and poll for status.",
2105
2109
  SLOT_UNAVAILABLE: "Selected schedule slot is unavailable. Refresh available slots and ask shopper to reselect.",
@@ -2244,6 +2248,12 @@ function getQueryNum(c, key) {
2244
2248
  return Number.isFinite(n) ? n : void 0;
2245
2249
  }
2246
2250
 
2251
+ // src/constants.ts
2252
+ var PAYMENT_METHOD = {
2253
+ MOBILE_MONEY: "mobile_money",
2254
+ CARD: "card"
2255
+ };
2256
+
2247
2257
  // src/mock/routes/v1.ts
2248
2258
  function buildV1(deps) {
2249
2259
  const app = new Hono2();
@@ -2260,10 +2270,22 @@ function buildV1(deps) {
2260
2270
  }));
2261
2271
  });
2262
2272
  app.get("/business", (c) => tryRoute(c, () => deps.business.primary()));
2263
- app.get("/business/by-handle/:handle", (c) => tryRoute(c, () => deps.business.byHandle(c.req.param("handle"))));
2264
- app.get("/business/by-domain", (c) => tryRoute(c, () => deps.business.byDomain(c.req.query("domain") ?? "")));
2265
- app.get("/business/settings", (c) => tryRoute(c, () => deps.business.settings(deps.defaultBusinessId)));
2266
- app.get("/business/locations", (c) => tryRoute(c, () => deps.business.locations(deps.defaultBusinessId)));
2273
+ app.get(
2274
+ "/business/by-handle/:handle",
2275
+ (c) => tryRoute(c, () => deps.business.byHandle(c.req.param("handle")))
2276
+ );
2277
+ app.get(
2278
+ "/business/by-domain",
2279
+ (c) => tryRoute(c, () => deps.business.byDomain(c.req.query("domain") ?? ""))
2280
+ );
2281
+ app.get(
2282
+ "/business/settings",
2283
+ (c) => tryRoute(c, () => deps.business.settings(deps.defaultBusinessId))
2284
+ );
2285
+ app.get(
2286
+ "/business/locations",
2287
+ (c) => tryRoute(c, () => deps.business.locations(deps.defaultBusinessId))
2288
+ );
2267
2289
  app.get("/business/hours", (c) => tryRoute(c, () => deps.business.hours(deps.defaultBusinessId)));
2268
2290
  app.get("/catalogue", (c) => tryRoute(c, () => deps.catalogue.snapshot(deps.defaultBusinessId)));
2269
2291
  app.get(
@@ -2278,57 +2300,165 @@ function buildV1(deps) {
2278
2300
  })
2279
2301
  )
2280
2302
  );
2281
- app.get("/catalogue/products/:product_id", (c) => tryRoute(c, () => deps.catalogue.getProduct(c.req.param("product_id"))));
2282
- app.get("/catalogue/products/:product_id/variants", (c) => tryRoute(c, () => deps.catalogue.getProductVariants(c.req.param("product_id"))));
2283
- app.get("/catalogue/products/:product_id/variant-axes", (c) => tryRoute(c, () => deps.catalogue.getProductVariantAxes(c.req.param("product_id"))));
2303
+ app.get(
2304
+ "/catalogue/products/:product_id",
2305
+ (c) => tryRoute(c, () => deps.catalogue.getProduct(c.req.param("product_id")))
2306
+ );
2307
+ app.get(
2308
+ "/catalogue/products/:product_id/variants",
2309
+ (c) => tryRoute(c, () => deps.catalogue.getProductVariants(c.req.param("product_id")))
2310
+ );
2311
+ app.get(
2312
+ "/catalogue/products/:product_id/variant-axes",
2313
+ (c) => tryRoute(c, () => deps.catalogue.getProductVariantAxes(c.req.param("product_id")))
2314
+ );
2284
2315
  app.get(
2285
2316
  "/catalogue/products/:product_id/variants/:variant_id",
2286
- (c) => tryRoute(c, () => deps.catalogue.getProductVariantById(c.req.param("product_id"), c.req.param("variant_id")))
2317
+ (c) => tryRoute(
2318
+ c,
2319
+ () => deps.catalogue.getProductVariantById(c.req.param("product_id"), c.req.param("variant_id"))
2320
+ )
2287
2321
  );
2288
2322
  app.post("/catalogue/products/:product_id/variants/find", async (c) => {
2289
2323
  const body = await c.req.json().catch(() => ({}));
2290
2324
  return tryRoute(
2291
2325
  c,
2292
- () => deps.catalogue.findProductVariant(c.req.param("product_id"), body.axis_selections ?? body.properties ?? {})
2326
+ () => deps.catalogue.findProductVariant(
2327
+ c.req.param("product_id"),
2328
+ body.axis_selections ?? body.properties ?? {}
2329
+ )
2293
2330
  );
2294
2331
  });
2295
- app.get("/catalogue/products/:product_id/add-ons", (c) => tryRoute(c, () => deps.catalogue.getProductAddOns(c.req.param("product_id"))));
2296
- app.get("/catalogue/categories", (c) => tryRoute(c, () => deps.catalogue.listCategories(deps.defaultBusinessId)));
2297
- app.get("/catalogue/categories/:category_id", (c) => tryRoute(c, () => deps.catalogue.getCategory(c.req.param("category_id"))));
2298
- app.get("/catalogue/categories/:category_id/products", (c) => tryRoute(c, () => deps.catalogue.getCategoryProducts(c.req.param("category_id"))));
2299
- app.get("/catalogue/categories/:category_id/attributes", (c) => tryRoute(c, () => deps.catalogue.getCategoryAttributes(c.req.param("category_id"))));
2300
- app.get("/catalogue/categories/:category_id/deals", (c) => tryRoute(c, () => deps.catalogue.getCategoryDeals(c.req.param("category_id"))));
2301
- app.get("/catalogue/collections", (c) => tryRoute(c, () => deps.catalogue.listCollections(deps.defaultBusinessId)));
2302
- app.get("/catalogue/collections/:collection_id", (c) => tryRoute(c, () => deps.catalogue.getCollection(c.req.param("collection_id"))));
2303
- app.get("/catalogue/collections/:collection_id/products", (c) => tryRoute(c, () => deps.catalogue.getCollectionProducts(c.req.param("collection_id"))));
2304
- app.get("/catalogue/collections/:collection_id/attributes", (c) => tryRoute(c, () => deps.catalogue.getCollectionAttributes(c.req.param("collection_id"))));
2305
- app.get("/catalogue/collections/:collection_id/deals", (c) => tryRoute(c, () => deps.catalogue.getCollectionDeals(c.req.param("collection_id"))));
2306
- app.get("/catalogue/bundles", (c) => tryRoute(c, () => deps.catalogue.listBundles(deps.defaultBusinessId)));
2307
- app.get("/catalogue/bundles/:bundle_id", (c) => tryRoute(c, () => deps.catalogue.getBundle(c.req.param("bundle_id"))));
2308
- app.get("/catalogue/composites", (c) => tryRoute(c, () => deps.catalogue.listComposites(deps.defaultBusinessId)));
2309
- app.get("/catalogue/composites/by-product/:product_id", (c) => tryRoute(c, () => deps.catalogue.getCompositeByProduct(c.req.param("product_id"))));
2310
- app.get("/catalogue/composites/:composite_id", (c) => tryRoute(c, () => deps.catalogue.getComposite(c.req.param("composite_id"))));
2332
+ app.get(
2333
+ "/catalogue/products/:product_id/add-ons",
2334
+ (c) => tryRoute(c, () => deps.catalogue.getProductAddOns(c.req.param("product_id")))
2335
+ );
2336
+ app.get(
2337
+ "/catalogue/categories",
2338
+ (c) => tryRoute(c, () => deps.catalogue.listCategories(deps.defaultBusinessId))
2339
+ );
2340
+ app.get(
2341
+ "/catalogue/categories/:category_id",
2342
+ (c) => tryRoute(c, () => deps.catalogue.getCategory(c.req.param("category_id")))
2343
+ );
2344
+ app.get(
2345
+ "/catalogue/categories/:category_id/products",
2346
+ (c) => tryRoute(c, () => deps.catalogue.getCategoryProducts(c.req.param("category_id")))
2347
+ );
2348
+ app.get(
2349
+ "/catalogue/categories/:category_id/attributes",
2350
+ (c) => tryRoute(c, () => deps.catalogue.getCategoryAttributes(c.req.param("category_id")))
2351
+ );
2352
+ app.get(
2353
+ "/catalogue/categories/:category_id/deals",
2354
+ (c) => tryRoute(c, () => deps.catalogue.getCategoryDeals(c.req.param("category_id")))
2355
+ );
2356
+ app.get(
2357
+ "/catalogue/collections",
2358
+ (c) => tryRoute(c, () => deps.catalogue.listCollections(deps.defaultBusinessId))
2359
+ );
2360
+ app.get(
2361
+ "/catalogue/collections/:collection_id",
2362
+ (c) => tryRoute(c, () => deps.catalogue.getCollection(c.req.param("collection_id")))
2363
+ );
2364
+ app.get(
2365
+ "/catalogue/collections/:collection_id/products",
2366
+ (c) => tryRoute(c, () => deps.catalogue.getCollectionProducts(c.req.param("collection_id")))
2367
+ );
2368
+ app.get(
2369
+ "/catalogue/collections/:collection_id/attributes",
2370
+ (c) => tryRoute(c, () => deps.catalogue.getCollectionAttributes(c.req.param("collection_id")))
2371
+ );
2372
+ app.get(
2373
+ "/catalogue/collections/:collection_id/deals",
2374
+ (c) => tryRoute(c, () => deps.catalogue.getCollectionDeals(c.req.param("collection_id")))
2375
+ );
2376
+ app.get(
2377
+ "/catalogue/bundles",
2378
+ (c) => tryRoute(c, () => deps.catalogue.listBundles(deps.defaultBusinessId))
2379
+ );
2380
+ app.get(
2381
+ "/catalogue/bundles/:bundle_id",
2382
+ (c) => tryRoute(c, () => deps.catalogue.getBundle(c.req.param("bundle_id")))
2383
+ );
2384
+ app.get(
2385
+ "/catalogue/composites",
2386
+ (c) => tryRoute(c, () => deps.catalogue.listComposites(deps.defaultBusinessId))
2387
+ );
2388
+ app.get(
2389
+ "/catalogue/composites/by-product/:product_id",
2390
+ (c) => tryRoute(c, () => deps.catalogue.getCompositeByProduct(c.req.param("product_id")))
2391
+ );
2392
+ app.get(
2393
+ "/catalogue/composites/:composite_id",
2394
+ (c) => tryRoute(c, () => deps.catalogue.getComposite(c.req.param("composite_id")))
2395
+ );
2311
2396
  app.post("/catalogue/composites/:composite_id/calculate-price", async (c) => {
2312
2397
  const body = await c.req.json().catch(() => ({}));
2313
- return tryRoute(c, () => deps.catalogue.calculateCompositePrice(c.req.param("composite_id"), body));
2398
+ return tryRoute(
2399
+ c,
2400
+ () => deps.catalogue.calculateCompositePrice(c.req.param("composite_id"), body)
2401
+ );
2314
2402
  });
2315
- app.get("/catalogue/taxonomies", (c) => tryRoute(c, () => deps.catalogue.listTaxonomies(deps.defaultBusinessId)));
2316
- app.get("/catalogue/taxonomies/search", (c) => tryRoute(c, () => deps.catalogue.searchTaxonomies(deps.defaultBusinessId, c.req.query("q") ?? "")));
2317
- app.get("/catalogue/taxonomies/:taxonomy_id", (c) => tryRoute(c, () => deps.catalogue.getTaxonomy(c.req.param("taxonomy_id"))));
2318
- app.get("/catalogue/taxonomies/:taxonomy_id/attributes", (c) => tryRoute(c, () => deps.catalogue.getTaxonomyAttributes(c.req.param("taxonomy_id"))));
2319
- app.get("/catalogue/taxonomies/:taxonomy_id/path", (c) => tryRoute(c, () => deps.catalogue.getTaxonomyPath(c.req.param("taxonomy_id"))));
2320
- app.get("/catalogue/attributes", (c) => tryRoute(c, () => deps.catalogue.listAttributes(deps.defaultBusinessId)));
2321
- app.get("/catalogue/properties/facets", (c) => tryRoute(c, () => deps.catalogue.listPropertyFacets(deps.defaultBusinessId)));
2322
- app.get("/catalogue/tags", (c) => tryRoute(c, () => deps.catalogue.listTags(deps.defaultBusinessId)));
2403
+ app.get(
2404
+ "/catalogue/taxonomies",
2405
+ (c) => tryRoute(c, () => deps.catalogue.listTaxonomies(deps.defaultBusinessId))
2406
+ );
2407
+ app.get(
2408
+ "/catalogue/taxonomies/search",
2409
+ (c) => tryRoute(
2410
+ c,
2411
+ () => deps.catalogue.searchTaxonomies(deps.defaultBusinessId, c.req.query("q") ?? "")
2412
+ )
2413
+ );
2414
+ app.get(
2415
+ "/catalogue/taxonomies/:taxonomy_id",
2416
+ (c) => tryRoute(c, () => deps.catalogue.getTaxonomy(c.req.param("taxonomy_id")))
2417
+ );
2418
+ app.get(
2419
+ "/catalogue/taxonomies/:taxonomy_id/attributes",
2420
+ (c) => tryRoute(c, () => deps.catalogue.getTaxonomyAttributes(c.req.param("taxonomy_id")))
2421
+ );
2422
+ app.get(
2423
+ "/catalogue/taxonomies/:taxonomy_id/path",
2424
+ (c) => tryRoute(c, () => deps.catalogue.getTaxonomyPath(c.req.param("taxonomy_id")))
2425
+ );
2426
+ app.get(
2427
+ "/catalogue/attributes",
2428
+ (c) => tryRoute(c, () => deps.catalogue.listAttributes(deps.defaultBusinessId))
2429
+ );
2430
+ app.get(
2431
+ "/catalogue/properties/facets",
2432
+ (c) => tryRoute(c, () => deps.catalogue.listPropertyFacets(deps.defaultBusinessId))
2433
+ );
2434
+ app.get(
2435
+ "/catalogue/tags",
2436
+ (c) => tryRoute(c, () => deps.catalogue.listTags(deps.defaultBusinessId))
2437
+ );
2323
2438
  app.get("/catalogue/menu", (c) => tryRoute(c, () => deps.lite.getMenu(deps.defaultBusinessId)));
2324
- app.get("/catalogue/menu/categories/:category_id", (c) => tryRoute(c, () => deps.lite.getMenuCategory(c.req.param("category_id"))));
2325
- app.get("/catalogue/menu/items/:item_id", (c) => tryRoute(c, () => deps.catalogue.getProduct(c.req.param("item_id"))));
2326
- app.get("/catalogue/knowledge-base/articles", (c) => tryRoute(c, () => ({ articles: deps.catalogue.listKnowledgeArticles(deps.defaultBusinessId) })));
2439
+ app.get(
2440
+ "/catalogue/menu/categories/:category_id",
2441
+ (c) => tryRoute(c, () => deps.lite.getMenuCategory(c.req.param("category_id")))
2442
+ );
2443
+ app.get(
2444
+ "/catalogue/menu/items/:item_id",
2445
+ (c) => tryRoute(c, () => deps.catalogue.getProduct(c.req.param("item_id")))
2446
+ );
2447
+ app.get(
2448
+ "/catalogue/knowledge-base/articles",
2449
+ (c) => tryRoute(c, () => ({ articles: deps.catalogue.listKnowledgeArticles(deps.defaultBusinessId) }))
2450
+ );
2327
2451
  app.get(
2328
2452
  "/catalogue/knowledge-base/search",
2329
- (c) => tryRoute(c, () => ({ results: deps.catalogue.searchKnowledgeBase(deps.defaultBusinessId, c.req.query("q") ?? ""), query: c.req.query("q") ?? "" }))
2453
+ (c) => tryRoute(c, () => ({
2454
+ results: deps.catalogue.searchKnowledgeBase(deps.defaultBusinessId, c.req.query("q") ?? ""),
2455
+ query: c.req.query("q") ?? ""
2456
+ }))
2457
+ );
2458
+ app.get(
2459
+ "/catalogue/products/:product_id/attributes",
2460
+ (c) => tryRoute(c, () => deps.catalogue.getProductAttributes(c.req.param("product_id")))
2330
2461
  );
2331
- app.get("/catalogue/products/:product_id/attributes", (c) => tryRoute(c, () => deps.catalogue.getProductAttributes(c.req.param("product_id"))));
2332
2462
  app.get(
2333
2463
  "/catalogue/products/:product_id/available-now",
2334
2464
  (c) => tryRoute(c, () => {
@@ -2347,22 +2477,75 @@ function buildV1(deps) {
2347
2477
  "/catalogue/products/:product_id/schedules",
2348
2478
  (c) => tryRoute(c, () => {
2349
2479
  const p = deps.registry.products.get(c.req.param("product_id"));
2350
- return { schedules: p?.metadata?.["time_profiles"] ?? [] };
2480
+ return {
2481
+ schedules: p?.metadata?.["time_profiles"] ?? []
2482
+ };
2351
2483
  })
2352
2484
  );
2353
- app.get("/catalogue/deals", (c) => tryRoute(c, () => deps.catalogue.listDeals(deps.defaultBusinessId)));
2354
- app.get("/catalogue/deals/on-sale", (c) => tryRoute(c, () => deps.catalogue.listOnSale(deps.defaultBusinessId)));
2485
+ app.get(
2486
+ "/catalogue/deals",
2487
+ (c) => tryRoute(c, () => deps.catalogue.listDeals(deps.defaultBusinessId))
2488
+ );
2489
+ app.get(
2490
+ "/catalogue/deals/on-sale",
2491
+ (c) => tryRoute(c, () => deps.catalogue.listOnSale(deps.defaultBusinessId))
2492
+ );
2355
2493
  app.post("/catalogue/deals/validate", async (c) => {
2356
2494
  const body = await c.req.json().catch(() => ({}));
2357
- return tryRoute(c, () => deps.catalogue.validateDiscount(body.discount_code ?? body.code ?? "", deps.defaultBusinessId));
2495
+ return tryRoute(
2496
+ c,
2497
+ () => deps.catalogue.validateDiscount(
2498
+ body.discount_code ?? body.code ?? "",
2499
+ deps.defaultBusinessId
2500
+ )
2501
+ );
2358
2502
  });
2359
- app.get("/catalogue/products/:product_id/deals", (c) => tryRoute(c, () => deps.catalogue.getProductDeals(c.req.param("product_id"))));
2503
+ app.get(
2504
+ "/catalogue/products/:product_id/deals",
2505
+ (c) => tryRoute(c, () => deps.catalogue.getProductDeals(c.req.param("product_id")))
2506
+ );
2360
2507
  app.post("/catalogue/quotes", async (c) => {
2361
2508
  const body = await c.req.json().catch(() => ({}));
2362
2509
  return tryRoute(c, () => deps.catalogue.createQuote(deps.defaultBusinessId, body));
2363
2510
  });
2364
- app.get("/catalogue/quotes/:quote_id", (c) => tryRoute(c, () => deps.catalogue.getQuote(c.req.param("quote_id"))));
2365
- app.post("/catalogue/quotes/:quote_id/refresh", (c) => tryRoute(c, () => deps.catalogue.refreshQuote(c.req.param("quote_id"))));
2511
+ app.get(
2512
+ "/catalogue/quotes/:quote_id",
2513
+ (c) => tryRoute(c, () => deps.catalogue.getQuote(c.req.param("quote_id")))
2514
+ );
2515
+ app.post(
2516
+ "/catalogue/quotes/:quote_id/refresh",
2517
+ (c) => tryRoute(c, () => deps.catalogue.refreshQuote(c.req.param("quote_id")))
2518
+ );
2519
+ app.get("/reviews/summary", (c) => {
2520
+ const productId = c.req.query("product_id");
2521
+ if (productId !== void 0 && (productId.length === 0 || productId.trim() !== productId)) {
2522
+ return fail(c, validation("product_id must be a non-empty canonical identifier"));
2523
+ }
2524
+ const response = {
2525
+ data: {
2526
+ ratings: {
2527
+ product_id: productId ?? null,
2528
+ review_count: 0,
2529
+ rating_sum: 0,
2530
+ average_rating: null,
2531
+ distribution: { one: 0, two: 0, three: 0, four: 0, five: 0 }
2532
+ },
2533
+ trust_chips: {
2534
+ on_time_delivery_percent: null,
2535
+ delivery_sample_size: 0,
2536
+ average_first_response_seconds: null,
2537
+ support_sample_size: 0
2538
+ }
2539
+ }
2540
+ };
2541
+ return c.json(response);
2542
+ });
2543
+ app.get("/reviews", (c) => {
2544
+ const response = {
2545
+ data: { items: [], next_cursor: null }
2546
+ };
2547
+ return c.json(response);
2548
+ });
2366
2549
  app.get("/cart", (c) => tryRoute(c, () => deps.cart.toUICart(deps.cart.get(c.var.session))));
2367
2550
  app.delete("/cart", (c) => tryRoute(c, () => deps.cart.clear(c.var.session)));
2368
2551
  app.get("/cart/items", (c) => tryRoute(c, () => deps.cart.getItems(c.var.session)));
@@ -2373,9 +2556,15 @@ function buildV1(deps) {
2373
2556
  app.patch("/cart/items/:cart_item_id", async (c) => {
2374
2557
  const body = await c.req.json().catch(() => ({}));
2375
2558
  if (typeof body.quantity !== "number") return fail(c, validation("quantity required"));
2376
- return tryRoute(c, () => deps.cart.updateQuantity(c.var.session, c.req.param("cart_item_id"), body.quantity));
2559
+ return tryRoute(
2560
+ c,
2561
+ () => deps.cart.updateQuantity(c.var.session, c.req.param("cart_item_id"), body.quantity)
2562
+ );
2377
2563
  });
2378
- app.delete("/cart/items/:cart_item_id", (c) => tryRoute(c, () => deps.cart.removeItem(c.var.session, c.req.param("cart_item_id"))));
2564
+ app.delete(
2565
+ "/cart/items/:cart_item_id",
2566
+ (c) => tryRoute(c, () => deps.cart.removeItem(c.var.session, c.req.param("cart_item_id")))
2567
+ );
2379
2568
  app.get("/cart/count", (c) => tryRoute(c, () => deps.cart.getCount(c.var.session)));
2380
2569
  app.get("/cart/total", (c) => tryRoute(c, () => deps.cart.getTotal(c.var.session)));
2381
2570
  app.post("/cart/destination-quote", async (c) => {
@@ -2386,10 +2575,25 @@ function buildV1(deps) {
2386
2575
  const body = await c.req.json().catch(() => ({}));
2387
2576
  return tryRoute(c, () => deps.cart.applyCoupon(c.var.session, body.coupon_code ?? ""));
2388
2577
  });
2389
- app.delete("/cart/coupons/current", (c) => tryRoute(c, () => deps.cart.removeCoupon(c.var.session)));
2390
- app.get("/orders", (c) => tryRoute(c, () => deps.orders.list(c.var.session, { limit: getQueryNum(c, "limit"), status: c.req.query("status") })));
2578
+ app.delete(
2579
+ "/cart/coupons/current",
2580
+ (c) => tryRoute(c, () => deps.cart.removeCoupon(c.var.session))
2581
+ );
2582
+ app.get(
2583
+ "/orders",
2584
+ (c) => tryRoute(
2585
+ c,
2586
+ () => deps.orders.list(c.var.session, {
2587
+ limit: getQueryNum(c, "limit"),
2588
+ status: c.req.query("status")
2589
+ })
2590
+ )
2591
+ );
2391
2592
  app.get("/orders/:order_id", (c) => tryRoute(c, () => deps.orders.get(c.req.param("order_id"))));
2392
- app.get("/orders/:order_id/payment-status", (c) => tryRoute(c, () => deps.orders.getPaymentStatus(c.req.param("order_id"))));
2593
+ app.get(
2594
+ "/orders/:order_id/payment-status",
2595
+ (c) => tryRoute(c, () => deps.orders.getPaymentStatus(c.req.param("order_id")))
2596
+ );
2393
2597
  app.post("/orders/:order_id/cancel", async (c) => {
2394
2598
  const body = await c.req.json().catch(() => ({}));
2395
2599
  return tryRoute(c, () => deps.orders.cancel(c.req.param("order_id"), body.reason));
@@ -2398,13 +2602,46 @@ function buildV1(deps) {
2398
2602
  const body = await c.req.json().catch(() => ({}));
2399
2603
  return tryRoute(c, () => deps.orders.updateCustomer(c.req.param("order_id"), body));
2400
2604
  });
2401
- app.post("/orders/:order_id/verify-payment", (c) => tryRoute(c, () => deps.orders.verifyPayment(c.req.param("order_id"))));
2605
+ app.post(
2606
+ "/orders/:order_id/verify-payment",
2607
+ (c) => tryRoute(c, () => deps.orders.verifyPayment(c.req.param("order_id")))
2608
+ );
2402
2609
  app.get("/subscriptions", (c) => tryRoute(c, () => deps.subscriptions.list(c.var.session)));
2403
- app.get("/subscriptions/:subscription_id", (c) => tryRoute(c, () => deps.subscriptions.get(c.req.param("subscription_id"))));
2404
- app.post("/subscriptions/:subscription_id/cancel", (c) => tryRoute(c, () => deps.subscriptions.cancel(c.req.param("subscription_id"))));
2405
- app.post("/subscriptions/:subscription_id/pause", (c) => tryRoute(c, () => deps.subscriptions.pause(c.req.param("subscription_id"))));
2406
- app.post("/subscriptions/:subscription_id/resume", (c) => tryRoute(c, () => deps.subscriptions.resume(c.req.param("subscription_id"))));
2407
- app.post("/subscriptions/:subscription_id/skip", (c) => tryRoute(c, () => deps.subscriptions.skipNext(c.req.param("subscription_id"))));
2610
+ app.get(
2611
+ "/subscriptions/:subscription_id",
2612
+ (c) => tryRoute(c, () => deps.subscriptions.get(c.req.param("subscription_id")))
2613
+ );
2614
+ app.post(
2615
+ "/subscriptions/:subscription_id/cancel",
2616
+ (c) => tryRoute(c, () => deps.subscriptions.cancel(c.req.param("subscription_id")))
2617
+ );
2618
+ app.post(
2619
+ "/subscriptions/:subscription_id/pause",
2620
+ (c) => tryRoute(c, () => deps.subscriptions.pause(c.req.param("subscription_id")))
2621
+ );
2622
+ app.post(
2623
+ "/subscriptions/:subscription_id/resume",
2624
+ (c) => tryRoute(c, () => deps.subscriptions.resume(c.req.param("subscription_id")))
2625
+ );
2626
+ app.post(
2627
+ "/subscriptions/:subscription_id/skip",
2628
+ (c) => tryRoute(c, () => deps.subscriptions.skipNext(c.req.param("subscription_id")))
2629
+ );
2630
+ app.get("/payments/collection-options", (c) => {
2631
+ const currency = c.req.query("currency")?.trim().toUpperCase();
2632
+ if (!currency || !/^[A-Z]{3}$/.test(currency)) {
2633
+ return fail(c, validation("currency must be a canonical three-letter code"));
2634
+ }
2635
+ return tryRoute(c, () => ({
2636
+ presentment_currency: currency,
2637
+ options: currency === "GHS" ? [
2638
+ { method: PAYMENT_METHOD.CARD, network: null },
2639
+ { method: PAYMENT_METHOD.MOBILE_MONEY, network: "mtn" },
2640
+ { method: PAYMENT_METHOD.MOBILE_MONEY, network: "telecel" },
2641
+ { method: PAYMENT_METHOD.MOBILE_MONEY, network: "airteltigo" }
2642
+ ] : currency === "USD" ? [{ method: PAYMENT_METHOD.CARD, network: null }] : []
2643
+ }));
2644
+ });
2408
2645
  app.post("/checkout", async (c) => {
2409
2646
  const body = await c.req.json().catch(() => ({}));
2410
2647
  return tryRoute(c, () => deps.checkout.process(c.var.session, body));
@@ -2458,15 +2695,33 @@ function buildV1(deps) {
2458
2695
  return { success: true, message: "Profile updated successfully" };
2459
2696
  });
2460
2697
  });
2461
- app.get("/inventory/products/:product_id/stock", (c) => tryRoute(c, () => deps.inventory.productStock(c.req.param("product_id"))));
2462
- app.get("/inventory/variants/:variant_id/stock", (c) => tryRoute(c, () => deps.inventory.variantStock(c.req.param("variant_id"))));
2698
+ app.get(
2699
+ "/inventory/products/:product_id/stock",
2700
+ (c) => tryRoute(c, () => deps.inventory.productStock(c.req.param("product_id")))
2701
+ );
2702
+ app.get(
2703
+ "/inventory/variants/:variant_id/stock",
2704
+ (c) => tryRoute(c, () => deps.inventory.variantStock(c.req.param("variant_id")))
2705
+ );
2463
2706
  app.get(
2464
2707
  "/inventory/products/:product_id/availability",
2465
- (c) => tryRoute(c, () => deps.inventory.productAvailability(c.req.param("product_id"), getQueryNum(c, "quantity") ?? 1))
2708
+ (c) => tryRoute(
2709
+ c,
2710
+ () => deps.inventory.productAvailability(
2711
+ c.req.param("product_id"),
2712
+ getQueryNum(c, "quantity") ?? 1
2713
+ )
2714
+ )
2466
2715
  );
2467
2716
  app.get(
2468
2717
  "/inventory/variants/:variant_id/availability",
2469
- (c) => tryRoute(c, () => deps.inventory.variantAvailability(c.req.param("variant_id"), getQueryNum(c, "quantity") ?? 1))
2718
+ (c) => tryRoute(
2719
+ c,
2720
+ () => deps.inventory.variantAvailability(
2721
+ c.req.param("variant_id"),
2722
+ getQueryNum(c, "quantity") ?? 1
2723
+ )
2724
+ )
2470
2725
  );
2471
2726
  app.get(
2472
2727
  "/delivery/fee",
@@ -2493,35 +2748,75 @@ function buildV1(deps) {
2493
2748
  );
2494
2749
  app.post("/places/autocomplete", async (c) => {
2495
2750
  const body = await c.req.json().catch(() => ({}));
2496
- return tryRoute(c, () => deps.places.autocomplete({ query: body.input ?? body.query ?? "", country: body.country }));
2751
+ return tryRoute(
2752
+ c,
2753
+ () => deps.places.autocomplete({ query: body.input ?? body.query ?? "", country: body.country })
2754
+ );
2497
2755
  });
2498
2756
  app.post("/places/details", async (c) => {
2499
2757
  const body = await c.req.json().catch(() => ({}));
2500
2758
  return tryRoute(c, () => deps.places.details({ place_id: body.place_id ?? "" }));
2501
2759
  });
2502
- app.get("/scheduling/services", (c) => tryRoute(c, () => deps.scheduling.listServices(deps.defaultBusinessId)));
2503
- app.get("/scheduling/services/:service_id", (c) => tryRoute(c, () => deps.scheduling.getService(c.req.param("service_id"))));
2504
- app.get("/scheduling/slots", (c) => tryRoute(c, () => deps.scheduling.getSlots(c.req.query("service_id") ?? "", { date: c.req.query("date") })));
2760
+ app.get(
2761
+ "/scheduling/services",
2762
+ (c) => tryRoute(c, () => deps.scheduling.listServices(deps.defaultBusinessId))
2763
+ );
2764
+ app.get(
2765
+ "/scheduling/services/:service_id",
2766
+ (c) => tryRoute(c, () => deps.scheduling.getService(c.req.param("service_id")))
2767
+ );
2768
+ app.get(
2769
+ "/scheduling/slots",
2770
+ (c) => tryRoute(
2771
+ c,
2772
+ () => deps.scheduling.getSlots(c.req.query("service_id") ?? "", { date: c.req.query("date") })
2773
+ )
2774
+ );
2505
2775
  app.get(
2506
2776
  "/scheduling/slots/check",
2507
- (c) => tryRoute(c, () => deps.scheduling.checkSlot(c.req.query("service_id") ?? "", c.req.query("start") ?? "", c.req.query("end") ?? ""))
2777
+ (c) => tryRoute(
2778
+ c,
2779
+ () => deps.scheduling.checkSlot(
2780
+ c.req.query("service_id") ?? "",
2781
+ c.req.query("start") ?? "",
2782
+ c.req.query("end") ?? ""
2783
+ )
2784
+ )
2785
+ );
2786
+ app.get(
2787
+ "/scheduling/availability",
2788
+ (c) => tryRoute(c, () => deps.scheduling.getServiceAvailability(c.req.query("service_id") ?? ""))
2789
+ );
2790
+ app.get(
2791
+ "/scheduling/bookings",
2792
+ (c) => tryRoute(c, () => deps.scheduling.getCustomerBookings(c.var.session))
2508
2793
  );
2509
- app.get("/scheduling/availability", (c) => tryRoute(c, () => deps.scheduling.getServiceAvailability(c.req.query("service_id") ?? "")));
2510
- app.get("/scheduling/bookings", (c) => tryRoute(c, () => deps.scheduling.getCustomerBookings(c.var.session)));
2511
2794
  app.post("/scheduling/bookings/reschedule", async (c) => {
2512
2795
  const body = await c.req.json().catch(() => ({}));
2513
2796
  return tryRoute(c, () => deps.scheduling.rescheduleBooking(body));
2514
2797
  });
2515
- app.get("/scheduling/bookings/:booking_id", (c) => tryRoute(c, () => deps.scheduling.getBooking(c.req.param("booking_id"))));
2798
+ app.get(
2799
+ "/scheduling/bookings/:booking_id",
2800
+ (c) => tryRoute(c, () => deps.scheduling.getBooking(c.req.param("booking_id")))
2801
+ );
2516
2802
  app.post("/scheduling/bookings/:booking_id/cancel", async (c) => {
2517
2803
  const body = await c.req.json().catch(() => ({}));
2518
2804
  return tryRoute(c, () => deps.scheduling.cancelBooking(c.req.param("booking_id"), body.reason));
2519
2805
  });
2520
2806
  app.get("/lite/bootstrap", (c) => tryRoute(c, () => deps.lite.bootstrap(deps.defaultBusinessId)));
2521
- app.get("/lite/resources/:resource_id", (c) => tryRoute(c, () => deps.lite.getResource(c.req.param("resource_id"))));
2807
+ app.get(
2808
+ "/lite/resources/:resource_id",
2809
+ (c) => tryRoute(c, () => deps.lite.getResource(c.req.param("resource_id")))
2810
+ );
2522
2811
  app.get("/lite/menu", (c) => tryRoute(c, () => deps.lite.getMenu(deps.defaultBusinessId)));
2523
- app.get("/lite/menu/categories/:category_id", (c) => tryRoute(c, () => deps.lite.getMenuCategory(c.req.param("category_id"))));
2524
- app.get("/fx/rate", (c) => tryRoute(c, () => deps.fx.getRate(c.req.query("from") ?? "USD", c.req.query("to") ?? "GHS")));
2812
+ app.get(
2813
+ "/lite/menu/categories/:category_id",
2814
+ (c) => tryRoute(c, () => deps.lite.getMenuCategory(c.req.param("category_id")))
2815
+ );
2816
+ app.get(
2817
+ "/fx/rate",
2818
+ (c) => tryRoute(c, () => deps.fx.getRate(c.req.query("from") ?? "USD", c.req.query("to") ?? "GHS"))
2819
+ );
2525
2820
  app.post("/fx/quotes", async (c) => {
2526
2821
  const body = await c.req.json().catch(() => ({}));
2527
2822
  return tryRoute(c, () => deps.fx.lockQuote(body));
@@ -2534,31 +2829,47 @@ function buildV1(deps) {
2534
2829
  const body = await c.req.json().catch(() => ({}));
2535
2830
  return tryRoute(c, () => deps.uploads.confirm(body));
2536
2831
  });
2537
- app.get(
2538
- "/store-credit/balance",
2539
- (c) => c.json({ data: { balance: "0.00", currency: "USD" } })
2540
- );
2832
+ app.get("/store-credit/balance", (c) => c.json({ data: { balance: "0.00", currency: "USD" } }));
2541
2833
  app.post("/activity/session", async (c) => {
2542
2834
  await c.req.json().catch(() => ({}));
2543
2835
  return c.json({ data: { recorded: true } });
2544
2836
  });
2545
2837
  app.post("/activity/events", async (c) => {
2546
2838
  const body = await c.req.json().catch(() => ({}));
2547
- return tryRoute(c, () => deps.activity.recordEvents(deps.defaultBusinessId, body.analytics_session_id ?? c.var.session.id, body.events ?? []));
2839
+ return tryRoute(
2840
+ c,
2841
+ () => deps.activity.recordEvents(
2842
+ deps.defaultBusinessId,
2843
+ body.analytics_session_id ?? c.var.session.id,
2844
+ body.events ?? []
2845
+ )
2846
+ );
2548
2847
  });
2549
- app.get("/activity/state", (c) => tryRoute(c, () => deps.activity.getState(deps.defaultBusinessId, c.var.session.id)));
2550
- app.get("/activity/recommendations", (c) => tryRoute(c, () => deps.activity.getRecommendations(deps.defaultBusinessId)));
2848
+ app.get(
2849
+ "/activity/state",
2850
+ (c) => tryRoute(c, () => deps.activity.getState(deps.defaultBusinessId, c.var.session.id))
2851
+ );
2852
+ app.get(
2853
+ "/activity/recommendations",
2854
+ (c) => tryRoute(c, () => deps.activity.getRecommendations(deps.defaultBusinessId))
2855
+ );
2551
2856
  app.post("/activity/messages/dismiss", async (c) => {
2552
2857
  const body = await c.req.json().catch(() => ({}));
2553
2858
  return tryRoute(c, () => deps.activity.dismissMessage(body.code ?? body.message_id ?? ""));
2554
2859
  });
2555
2860
  app.post(
2556
2861
  "/support/conversation",
2557
- (c) => tryRoute(c, () => deps.support.openConversation(deps.defaultBusinessId, c.var.session.customer_id))
2862
+ (c) => tryRoute(
2863
+ c,
2864
+ () => deps.support.openConversation(deps.defaultBusinessId, c.var.session.customer_id)
2865
+ )
2558
2866
  );
2559
2867
  app.get(
2560
2868
  "/support/conversation",
2561
- (c) => tryRoute(c, () => deps.support.peekConversation(deps.defaultBusinessId, c.var.session.customer_id))
2869
+ (c) => tryRoute(
2870
+ c,
2871
+ () => deps.support.peekConversation(deps.defaultBusinessId, c.var.session.customer_id)
2872
+ )
2562
2873
  );
2563
2874
  app.post("/support/conversation/messages", async (c) => {
2564
2875
  const body = await c.req.json().catch(() => ({}));
@@ -2574,7 +2885,12 @@ function buildV1(deps) {
2574
2885
  });
2575
2886
  app.get(
2576
2887
  "/support/conversation/messages",
2577
- (c) => tryRoute(c, () => deps.support.listMessages(c.req.query("conversation_id") ?? "", { limit: getQueryNum(c, "limit") }))
2888
+ (c) => tryRoute(
2889
+ c,
2890
+ () => deps.support.listMessages(c.req.query("conversation_id") ?? "", {
2891
+ limit: getQueryNum(c, "limit")
2892
+ })
2893
+ )
2578
2894
  );
2579
2895
  app.post("/support/conversation/messages/:messageId/reactions", async (c) => {
2580
2896
  const body = await c.req.json().catch(() => ({}));
@@ -2595,7 +2911,10 @@ function buildV1(deps) {
2595
2911
  });
2596
2912
  app.get(
2597
2913
  "/support/conversation/ws",
2598
- (c) => c.json({ note: "WebSocket connection \u2014 connect via ws:// at the same path", supported: false }, 426)
2914
+ (c) => c.json(
2915
+ { note: "WebSocket connection \u2014 connect via ws:// at the same path", supported: false },
2916
+ 426
2917
+ )
2599
2918
  );
2600
2919
  return app;
2601
2920
  }
@@ -3122,9 +3441,10 @@ function buildLink(deps) {
3122
3441
  app.post("/auth/request-otp", async (c) => {
3123
3442
  const body = await c.req.json().catch(() => ({}));
3124
3443
  return tryRoute(c, () => {
3125
- deps.auth.requestOtp(body.contact ?? "");
3444
+ const challenge = deps.auth.requestOtp(body.contact ?? "");
3126
3445
  return {
3127
3446
  success: true,
3447
+ challenge_id: challenge.otp_id,
3128
3448
  message: `OTP sent to ${body.contact ?? "contact"}`,
3129
3449
  expires_in: 300,
3130
3450
  is_new_account: false
@@ -3134,7 +3454,11 @@ function buildLink(deps) {
3134
3454
  app.post("/auth/verify-otp", async (c) => {
3135
3455
  const body = await c.req.json().catch(() => ({}));
3136
3456
  return tryRoute(c, () => {
3137
- const session = deps.auth.verifyOtp(body.contact ?? "", body.otp_code ?? "");
3457
+ const session = deps.auth.verifyOtp(
3458
+ body.contact ?? "",
3459
+ body.otp_code ?? "",
3460
+ body.challenge_id
3461
+ );
3138
3462
  c.header("x-session-token", session.token);
3139
3463
  const customer = deps.link.ensureCustomer(session.customer_id ?? session.id, {
3140
3464
  email: body.contact?.includes("@") ? body.contact : void 0,
@@ -3228,10 +3552,7 @@ function buildLink(deps) {
3228
3552
  };
3229
3553
  });
3230
3554
  });
3231
- app.get(
3232
- "/preferences",
3233
- (c) => tryRoute(c, () => deps.link.getPreferences(customerId(c)))
3234
- );
3555
+ app.get("/preferences", (c) => tryRoute(c, () => deps.link.getPreferences(customerId(c))));
3235
3556
  app.post("/preferences", async (c) => {
3236
3557
  const body = await c.req.json().catch(() => ({}));
3237
3558
  return tryRoute(c, () => {
@@ -3708,9 +4029,16 @@ function createAuthService(opts) {
3708
4029
  code_hint: options.mode === "permissive" ? code : void 0
3709
4030
  };
3710
4031
  },
3711
- verifyOtp(contact, code) {
3712
- const matching = registry.otps.list((o) => o.contact === contact);
3713
- const otp = matching[matching.length - 1];
4032
+ verifyOtp(contact, code, challengeId) {
4033
+ let otp = challengeId ? registry.otps.get(challengeId) : void 0;
4034
+ if (!challengeId) {
4035
+ const matching = registry.otps.list((o) => o.contact === contact);
4036
+ otp = matching[matching.length - 1];
4037
+ }
4038
+ if (challengeId) {
4039
+ if (!otp) throw new Error("No OTP challenge found");
4040
+ if (otp.contact !== contact) throw new Error("OTP challenge does not match contact");
4041
+ }
3714
4042
  if (options.mode === "strict") {
3715
4043
  if (!otp) throw new Error("No OTP requested");
3716
4044
  if (otp.code !== code && code !== options.defaultOtp) throw new Error("Invalid OTP");
@@ -5038,7 +5366,7 @@ function createCartService(opts) {
5038
5366
 
5039
5367
  // src/mock/domain/checkout.ts
5040
5368
  function createCheckoutService(opts) {
5041
- const { registry, clock, ids, bus} = opts;
5369
+ const { registry, clock, ids, bus } = opts;
5042
5370
  return {
5043
5371
  process(session, body) {
5044
5372
  if (!body.cart_id) throw validation("cart_id required");
@@ -5047,9 +5375,11 @@ function createCheckoutService(opts) {
5047
5375
  if (c.items.length === 0) throw validation("Cart is empty", { code: "CART_EMPTY" });
5048
5376
  const orderId = ids.order();
5049
5377
  const orderNumber = ids.orderNumber();
5378
+ const paymentId = ids.payment();
5050
5379
  const reference = ids.payment();
5051
5380
  const requiresAuth = body.payment_method === "mobile_money";
5052
5381
  const isCard = body.payment_method === "card" || body.payment_method === "stripe";
5382
+ const cardProvider = body.payment_method === "stripe" || body.pay_currency?.toUpperCase() === "USD" ? "stripe" : "paystack";
5053
5383
  const order = {
5054
5384
  id: orderId,
5055
5385
  business_id: c.business_id,
@@ -5073,6 +5403,7 @@ function createCheckoutService(opts) {
5073
5403
  items: c.items,
5074
5404
  applied_discount_ids: c.applied_discount_ids,
5075
5405
  applied_discount_codes: c.applied_discount_codes,
5406
+ payment_id: paymentId,
5076
5407
  payment_reference: reference,
5077
5408
  metadata: body.metadata,
5078
5409
  created_at: clock.iso(),
@@ -5089,31 +5420,57 @@ function createCheckoutService(opts) {
5089
5420
  const result = {
5090
5421
  order_id: orderId,
5091
5422
  order_number: orderNumber,
5092
- payment_status: requiresAuth ? "pending" : "succeeded",
5423
+ payment_id: paymentId,
5424
+ payment_status: requiresAuth || isCard ? "pending" : "succeeded",
5093
5425
  payment_reference: reference,
5094
5426
  requires_authorization: requiresAuth,
5095
5427
  authorization_type: requiresAuth ? "otp" : void 0,
5096
- next_action: requiresAuth ? { type: "authorization", authorization_type: "otp", display_text: "Approve on your mobile money app" } : { type: "none" },
5097
- provider: body.payment_method,
5428
+ next_action: requiresAuth ? {
5429
+ type: "authorization",
5430
+ authorization_type: "otp",
5431
+ display_text: "Approve on your mobile money app"
5432
+ } : { type: "none" },
5433
+ provider: isCard ? cardProvider : body.payment_method,
5098
5434
  bill_token: billToken
5099
5435
  };
5100
5436
  if (isCard) {
5101
- result.next_action = { type: "redirect", authorization_url: `https://mock.cimplify.io/pay/${reference}` };
5102
- result.authorization_url = `https://mock.cimplify.io/pay/${reference}`;
5103
- result.client_secret = `pi_${orderId.slice(-12)}_secret_${Math.random().toString(36).slice(2, 18)}`;
5104
5437
  const proc = globalThis.process;
5105
- result.public_key = proc?.env?.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY ?? "pk_test_mock_publishable_key";
5438
+ result.client_secret = cardProvider === "stripe" ? `pi_${orderId.slice(-12)}_secret_${Math.random().toString(36).slice(2, 18)}` : `access_${reference}`;
5439
+ 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";
5440
+ result.next_action = {
5441
+ type: "card_popup",
5442
+ provider: cardProvider,
5443
+ client_secret: result.client_secret,
5444
+ public_key: result.public_key
5445
+ };
5106
5446
  }
5107
5447
  return result;
5108
5448
  },
5109
5449
  authorize(body) {
5110
- const order = registry.orders.get(body.order_id);
5111
- if (!order) throw notFound(`Order ${body.order_id} not found`);
5112
- const updated = { ...order, payment_state: "paid", status: "confirmed", updated_at: clock.iso() };
5450
+ if (!body.payment_id?.trim()) throw validation("payment_id required");
5451
+ if (!body.authorization) throw validation("authorization required");
5452
+ const order = registry.orders.list(
5453
+ (candidate) => candidate.payment_id === body.payment_id
5454
+ )[0];
5455
+ if (!order) throw notFound(`Payment ${body.payment_id} not found`);
5456
+ const updated = {
5457
+ ...order,
5458
+ payment_state: "paid",
5459
+ status: "confirmed",
5460
+ updated_at: clock.iso()
5461
+ };
5113
5462
  registry.orders.put(order.id, updated);
5114
5463
  bus.emit("order.payment.captured", { order_id: order.id }, order.business_id);
5115
5464
  bus.emit("order.confirmed", { order_id: order.id }, order.business_id);
5116
- return { status: "succeeded", order_id: order.id };
5465
+ return {
5466
+ order_id: order.id,
5467
+ order_number: order.user_friendly_id,
5468
+ payment_id: body.payment_id,
5469
+ payment_reference: order.payment_reference,
5470
+ payment_status: "succeeded",
5471
+ requires_authorization: false,
5472
+ next_action: { type: "none" }
5473
+ };
5117
5474
  }
5118
5475
  };
5119
5476
  }
@@ -5496,6 +5853,7 @@ function createDeliveryService() {
5496
5853
  rate_id: "dlvrt_mock_standard",
5497
5854
  name: "Standard",
5498
5855
  fee: standardFree ? money(0) : money(15),
5856
+ fee_status: "priced",
5499
5857
  currency: "GHS",
5500
5858
  free_delivery_applied: standardFree,
5501
5859
  free_over_amount: money(200),
@@ -5509,6 +5867,7 @@ function createDeliveryService() {
5509
5867
  name: "Express",
5510
5868
  description: "Delivered within the hour",
5511
5869
  fee: money(25),
5870
+ fee_status: "priced",
5512
5871
  currency: "GHS",
5513
5872
  free_delivery_applied: false,
5514
5873
  eta_min_minutes: 30,