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