@cimplify/sdk 0.102.0 → 0.104.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/dist/advanced.d.mts +3 -3
  2. package/dist/advanced.d.ts +3 -3
  3. package/dist/advanced.js +23 -22
  4. package/dist/advanced.mjs +4 -3
  5. package/dist/{chunk-DCMXUKDQ.mjs → chunk-2WPVUIHX.mjs} +455 -105
  6. package/dist/{chunk-NIOUSKQQ.js → chunk-4BKOKHE3.js} +9 -0
  7. package/dist/{chunk-YDA46OZ6.js → chunk-5BDYDZ4U.js} +722 -90
  8. package/dist/{chunk-4KNFBPV2.mjs → chunk-5RT4HYMP.mjs} +61 -15
  9. package/dist/{chunk-WMEC5JWN.js → chunk-7PDEX54K.js} +50 -13
  10. package/dist/chunk-CNN7Z2IP.js +125 -0
  11. package/dist/{chunk-DLW3RWRK.mjs → chunk-DYIAX3WI.mjs} +46 -12
  12. package/dist/{chunk-LOWSMGRT.js → chunk-E4K2VQDD.js} +64 -16
  13. package/dist/chunk-GOHSXBKW.mjs +105 -0
  14. package/dist/{chunk-O3YUHLZL.mjs → chunk-H3RATH4B.mjs} +9 -0
  15. package/dist/{chunk-YER7DIOM.js → chunk-IQFFSKE2.js} +753 -594
  16. package/dist/{chunk-Z3K2D3TE.mjs → chunk-OCCNG6MO.mjs} +735 -558
  17. package/dist/{chunk-DKLHCZ5M.mjs → chunk-OKADBZAI.mjs} +652 -25
  18. package/dist/{chunk-EAZGA7LD.js → chunk-YVAEY3VC.js} +457 -107
  19. package/dist/{client-nsiMwuC1.d.ts → client-BVNWjk6W.d.ts} +2 -2
  20. package/dist/{client-B40KFazg.d.ts → client-BuLcOWLv.d.ts} +202 -319
  21. package/dist/{client-BizGfqB7.d.mts → client-D5AoobFc.d.mts} +202 -319
  22. package/dist/{client-BdErclfU.d.mts → client-fM716k7G.d.mts} +2 -2
  23. package/dist/{index-DpmnI__D.d.mts → index-BtcoqrY1.d.ts} +14 -4
  24. package/dist/{index-nEyXWIyR.d.ts → index-D7Tf3v7c.d.mts} +14 -4
  25. package/dist/index.d.mts +83 -8
  26. package/dist/index.d.ts +83 -8
  27. package/dist/index.js +203 -169
  28. package/dist/index.mjs +7 -5
  29. package/dist/link-D9iSVxt5.d.mts +308 -0
  30. package/dist/link-D9iSVxt5.d.ts +308 -0
  31. package/dist/mock/cli.mjs +463 -104
  32. package/dist/mock/library.js +463 -104
  33. package/dist/mock/library.mjs +463 -104
  34. package/dist/mock/msw.js +463 -104
  35. package/dist/mock/msw.mjs +463 -104
  36. package/dist/{product-Byf0unSy.d.mts → payment-g0HFkEDU.d.mts} +708 -61
  37. package/dist/{product-Byf0unSy.d.ts → payment-g0HFkEDU.d.ts} +708 -61
  38. package/dist/{price-BstChV9a.d.ts → price-BLIeAb8K.d.ts} +1 -1
  39. package/dist/{price-CS4E5zLS.d.mts → price-Czq_cTC_.d.mts} +1 -1
  40. package/dist/react.d.mts +4 -4
  41. package/dist/react.d.ts +4 -4
  42. package/dist/react.js +194 -169
  43. package/dist/react.mjs +55 -30
  44. package/dist/{server-DqbZh8Bk.d.mts → server-BkVhOIwn.d.mts} +14 -10
  45. package/dist/{server-Cj40R2ZD.d.ts → server-DKK_D-PP.d.ts} +14 -10
  46. package/dist/server.d.mts +4 -4
  47. package/dist/server.d.ts +4 -4
  48. package/dist/server.js +12 -10
  49. package/dist/server.mjs +6 -4
  50. package/dist/testing/msw.d.mts +2 -2
  51. package/dist/testing/msw.d.ts +2 -2
  52. package/dist/testing/msw.js +4 -3
  53. package/dist/testing/msw.mjs +3 -2
  54. package/dist/testing/suite.d.mts +6 -6
  55. package/dist/testing/suite.d.ts +6 -6
  56. package/dist/testing/suite.js +26 -25
  57. package/dist/testing/suite.mjs +7 -6
  58. package/dist/testing.d.mts +195 -56
  59. package/dist/testing.d.ts +195 -56
  60. package/dist/testing.js +95 -82
  61. package/dist/testing.mjs +14 -9
  62. package/dist/utils.d.mts +4 -4
  63. package/dist/utils.d.ts +4 -4
  64. package/dist/utils.js +37 -29
  65. package/dist/utils.mjs +2 -2
  66. package/package.json +7 -1
  67. package/registry/chat-widget.json +1 -1
  68. package/dist/payment-l0rkieEQ.d.mts +0 -113
  69. package/dist/payment-vzNnIi1n.d.ts +0 -113
package/dist/mock/cli.mjs CHANGED
@@ -3034,10 +3034,14 @@ var ERROR_SUGGESTIONS = {
3034
3034
  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.",
3035
3035
  PAYMENT_FAILED: "Payment provider rejected or failed processing. Show retry/change-method options to the shopper.",
3036
3036
  PAYMENT_CANCELLED: "Payment was cancelled by the shopper or provider flow. Allow a safe retry path.",
3037
+ PAYMENT_CAPABILITY_MISMATCH: "Refresh collection capabilities for the exact tenant and presentment currency before retrying.",
3038
+ UNSUPPORTED_CURRENCY: "Choose a supported presentment currency before loading payment methods or submitting checkout.",
3037
3039
  INSUFFICIENT_FUNDS: "Payment method has insufficient funds. Prompt shopper to use another method.",
3038
3040
  CARD_DECLINED: "Card was declined. Ask shopper to retry or switch payment method.",
3039
3041
  INVALID_OTP: "Authorization code is invalid. Let shopper re-enter OTP/PIN and retry.",
3040
3042
  OTP_EXPIRED: "Authorization code expired. Request a new OTP and re-submit authorization.",
3043
+ OTP_CHALLENGE_EXHAUSTED: "This verification challenge has no attempts left. Continue checkout without saved details or request a fresh challenge.",
3044
+ OTP_CHALLENGE_CONSUMED: "This verification challenge has already been used. Continue with the established session or request a fresh challenge.",
3041
3045
  AUTHORIZATION_FAILED: "Additional payment authorization failed. Retry authorization or change payment method.",
3042
3046
  PAYMENT_ACTION_NOT_COMPLETED: "Required payment action was not completed. Resume provider flow and poll for status.",
3043
3047
  SLOT_UNAVAILABLE: "Selected schedule slot is unavailable. Refresh available slots and ask shopper to reselect.",
@@ -3182,6 +3186,12 @@ function getQueryNum(c, key) {
3182
3186
  return Number.isFinite(n) ? n : void 0;
3183
3187
  }
3184
3188
 
3189
+ // src/constants.ts
3190
+ var PAYMENT_METHOD = {
3191
+ MOBILE_MONEY: "mobile_money",
3192
+ CARD: "card"
3193
+ };
3194
+
3185
3195
  // src/mock/routes/v1.ts
3186
3196
  function buildV1(deps) {
3187
3197
  const app = new Hono2();
@@ -3198,10 +3208,22 @@ function buildV1(deps) {
3198
3208
  }));
3199
3209
  });
3200
3210
  app.get("/business", (c) => tryRoute(c, () => deps.business.primary()));
3201
- app.get("/business/by-handle/:handle", (c) => tryRoute(c, () => deps.business.byHandle(c.req.param("handle"))));
3202
- app.get("/business/by-domain", (c) => tryRoute(c, () => deps.business.byDomain(c.req.query("domain") ?? "")));
3203
- app.get("/business/settings", (c) => tryRoute(c, () => deps.business.settings(deps.defaultBusinessId)));
3204
- app.get("/business/locations", (c) => tryRoute(c, () => deps.business.locations(deps.defaultBusinessId)));
3211
+ app.get(
3212
+ "/business/by-handle/:handle",
3213
+ (c) => tryRoute(c, () => deps.business.byHandle(c.req.param("handle")))
3214
+ );
3215
+ app.get(
3216
+ "/business/by-domain",
3217
+ (c) => tryRoute(c, () => deps.business.byDomain(c.req.query("domain") ?? ""))
3218
+ );
3219
+ app.get(
3220
+ "/business/settings",
3221
+ (c) => tryRoute(c, () => deps.business.settings(deps.defaultBusinessId))
3222
+ );
3223
+ app.get(
3224
+ "/business/locations",
3225
+ (c) => tryRoute(c, () => deps.business.locations(deps.defaultBusinessId))
3226
+ );
3205
3227
  app.get("/business/hours", (c) => tryRoute(c, () => deps.business.hours(deps.defaultBusinessId)));
3206
3228
  app.get("/catalogue", (c) => tryRoute(c, () => deps.catalogue.snapshot(deps.defaultBusinessId)));
3207
3229
  app.get(
@@ -3216,57 +3238,165 @@ function buildV1(deps) {
3216
3238
  })
3217
3239
  )
3218
3240
  );
3219
- app.get("/catalogue/products/:product_id", (c) => tryRoute(c, () => deps.catalogue.getProduct(c.req.param("product_id"))));
3220
- app.get("/catalogue/products/:product_id/variants", (c) => tryRoute(c, () => deps.catalogue.getProductVariants(c.req.param("product_id"))));
3221
- app.get("/catalogue/products/:product_id/variant-axes", (c) => tryRoute(c, () => deps.catalogue.getProductVariantAxes(c.req.param("product_id"))));
3241
+ app.get(
3242
+ "/catalogue/products/:product_id",
3243
+ (c) => tryRoute(c, () => deps.catalogue.getProduct(c.req.param("product_id")))
3244
+ );
3245
+ app.get(
3246
+ "/catalogue/products/:product_id/variants",
3247
+ (c) => tryRoute(c, () => deps.catalogue.getProductVariants(c.req.param("product_id")))
3248
+ );
3249
+ app.get(
3250
+ "/catalogue/products/:product_id/variant-axes",
3251
+ (c) => tryRoute(c, () => deps.catalogue.getProductVariantAxes(c.req.param("product_id")))
3252
+ );
3222
3253
  app.get(
3223
3254
  "/catalogue/products/:product_id/variants/:variant_id",
3224
- (c) => tryRoute(c, () => deps.catalogue.getProductVariantById(c.req.param("product_id"), c.req.param("variant_id")))
3255
+ (c) => tryRoute(
3256
+ c,
3257
+ () => deps.catalogue.getProductVariantById(c.req.param("product_id"), c.req.param("variant_id"))
3258
+ )
3225
3259
  );
3226
3260
  app.post("/catalogue/products/:product_id/variants/find", async (c) => {
3227
3261
  const body = await c.req.json().catch(() => ({}));
3228
3262
  return tryRoute(
3229
3263
  c,
3230
- () => deps.catalogue.findProductVariant(c.req.param("product_id"), body.axis_selections ?? body.properties ?? {})
3264
+ () => deps.catalogue.findProductVariant(
3265
+ c.req.param("product_id"),
3266
+ body.axis_selections ?? body.properties ?? {}
3267
+ )
3231
3268
  );
3232
3269
  });
3233
- app.get("/catalogue/products/:product_id/add-ons", (c) => tryRoute(c, () => deps.catalogue.getProductAddOns(c.req.param("product_id"))));
3234
- app.get("/catalogue/categories", (c) => tryRoute(c, () => deps.catalogue.listCategories(deps.defaultBusinessId)));
3235
- app.get("/catalogue/categories/:category_id", (c) => tryRoute(c, () => deps.catalogue.getCategory(c.req.param("category_id"))));
3236
- app.get("/catalogue/categories/:category_id/products", (c) => tryRoute(c, () => deps.catalogue.getCategoryProducts(c.req.param("category_id"))));
3237
- app.get("/catalogue/categories/:category_id/attributes", (c) => tryRoute(c, () => deps.catalogue.getCategoryAttributes(c.req.param("category_id"))));
3238
- app.get("/catalogue/categories/:category_id/deals", (c) => tryRoute(c, () => deps.catalogue.getCategoryDeals(c.req.param("category_id"))));
3239
- app.get("/catalogue/collections", (c) => tryRoute(c, () => deps.catalogue.listCollections(deps.defaultBusinessId)));
3240
- app.get("/catalogue/collections/:collection_id", (c) => tryRoute(c, () => deps.catalogue.getCollection(c.req.param("collection_id"))));
3241
- app.get("/catalogue/collections/:collection_id/products", (c) => tryRoute(c, () => deps.catalogue.getCollectionProducts(c.req.param("collection_id"))));
3242
- app.get("/catalogue/collections/:collection_id/attributes", (c) => tryRoute(c, () => deps.catalogue.getCollectionAttributes(c.req.param("collection_id"))));
3243
- app.get("/catalogue/collections/:collection_id/deals", (c) => tryRoute(c, () => deps.catalogue.getCollectionDeals(c.req.param("collection_id"))));
3244
- app.get("/catalogue/bundles", (c) => tryRoute(c, () => deps.catalogue.listBundles(deps.defaultBusinessId)));
3245
- app.get("/catalogue/bundles/:bundle_id", (c) => tryRoute(c, () => deps.catalogue.getBundle(c.req.param("bundle_id"))));
3246
- app.get("/catalogue/composites", (c) => tryRoute(c, () => deps.catalogue.listComposites(deps.defaultBusinessId)));
3247
- app.get("/catalogue/composites/by-product/:product_id", (c) => tryRoute(c, () => deps.catalogue.getCompositeByProduct(c.req.param("product_id"))));
3248
- app.get("/catalogue/composites/:composite_id", (c) => tryRoute(c, () => deps.catalogue.getComposite(c.req.param("composite_id"))));
3270
+ app.get(
3271
+ "/catalogue/products/:product_id/add-ons",
3272
+ (c) => tryRoute(c, () => deps.catalogue.getProductAddOns(c.req.param("product_id")))
3273
+ );
3274
+ app.get(
3275
+ "/catalogue/categories",
3276
+ (c) => tryRoute(c, () => deps.catalogue.listCategories(deps.defaultBusinessId))
3277
+ );
3278
+ app.get(
3279
+ "/catalogue/categories/:category_id",
3280
+ (c) => tryRoute(c, () => deps.catalogue.getCategory(c.req.param("category_id")))
3281
+ );
3282
+ app.get(
3283
+ "/catalogue/categories/:category_id/products",
3284
+ (c) => tryRoute(c, () => deps.catalogue.getCategoryProducts(c.req.param("category_id")))
3285
+ );
3286
+ app.get(
3287
+ "/catalogue/categories/:category_id/attributes",
3288
+ (c) => tryRoute(c, () => deps.catalogue.getCategoryAttributes(c.req.param("category_id")))
3289
+ );
3290
+ app.get(
3291
+ "/catalogue/categories/:category_id/deals",
3292
+ (c) => tryRoute(c, () => deps.catalogue.getCategoryDeals(c.req.param("category_id")))
3293
+ );
3294
+ app.get(
3295
+ "/catalogue/collections",
3296
+ (c) => tryRoute(c, () => deps.catalogue.listCollections(deps.defaultBusinessId))
3297
+ );
3298
+ app.get(
3299
+ "/catalogue/collections/:collection_id",
3300
+ (c) => tryRoute(c, () => deps.catalogue.getCollection(c.req.param("collection_id")))
3301
+ );
3302
+ app.get(
3303
+ "/catalogue/collections/:collection_id/products",
3304
+ (c) => tryRoute(c, () => deps.catalogue.getCollectionProducts(c.req.param("collection_id")))
3305
+ );
3306
+ app.get(
3307
+ "/catalogue/collections/:collection_id/attributes",
3308
+ (c) => tryRoute(c, () => deps.catalogue.getCollectionAttributes(c.req.param("collection_id")))
3309
+ );
3310
+ app.get(
3311
+ "/catalogue/collections/:collection_id/deals",
3312
+ (c) => tryRoute(c, () => deps.catalogue.getCollectionDeals(c.req.param("collection_id")))
3313
+ );
3314
+ app.get(
3315
+ "/catalogue/bundles",
3316
+ (c) => tryRoute(c, () => deps.catalogue.listBundles(deps.defaultBusinessId))
3317
+ );
3318
+ app.get(
3319
+ "/catalogue/bundles/:bundle_id",
3320
+ (c) => tryRoute(c, () => deps.catalogue.getBundle(c.req.param("bundle_id")))
3321
+ );
3322
+ app.get(
3323
+ "/catalogue/composites",
3324
+ (c) => tryRoute(c, () => deps.catalogue.listComposites(deps.defaultBusinessId))
3325
+ );
3326
+ app.get(
3327
+ "/catalogue/composites/by-product/:product_id",
3328
+ (c) => tryRoute(c, () => deps.catalogue.getCompositeByProduct(c.req.param("product_id")))
3329
+ );
3330
+ app.get(
3331
+ "/catalogue/composites/:composite_id",
3332
+ (c) => tryRoute(c, () => deps.catalogue.getComposite(c.req.param("composite_id")))
3333
+ );
3249
3334
  app.post("/catalogue/composites/:composite_id/calculate-price", async (c) => {
3250
3335
  const body = await c.req.json().catch(() => ({}));
3251
- return tryRoute(c, () => deps.catalogue.calculateCompositePrice(c.req.param("composite_id"), body));
3336
+ return tryRoute(
3337
+ c,
3338
+ () => deps.catalogue.calculateCompositePrice(c.req.param("composite_id"), body)
3339
+ );
3252
3340
  });
3253
- app.get("/catalogue/taxonomies", (c) => tryRoute(c, () => deps.catalogue.listTaxonomies(deps.defaultBusinessId)));
3254
- app.get("/catalogue/taxonomies/search", (c) => tryRoute(c, () => deps.catalogue.searchTaxonomies(deps.defaultBusinessId, c.req.query("q") ?? "")));
3255
- app.get("/catalogue/taxonomies/:taxonomy_id", (c) => tryRoute(c, () => deps.catalogue.getTaxonomy(c.req.param("taxonomy_id"))));
3256
- app.get("/catalogue/taxonomies/:taxonomy_id/attributes", (c) => tryRoute(c, () => deps.catalogue.getTaxonomyAttributes(c.req.param("taxonomy_id"))));
3257
- app.get("/catalogue/taxonomies/:taxonomy_id/path", (c) => tryRoute(c, () => deps.catalogue.getTaxonomyPath(c.req.param("taxonomy_id"))));
3258
- app.get("/catalogue/attributes", (c) => tryRoute(c, () => deps.catalogue.listAttributes(deps.defaultBusinessId)));
3259
- app.get("/catalogue/properties/facets", (c) => tryRoute(c, () => deps.catalogue.listPropertyFacets(deps.defaultBusinessId)));
3260
- app.get("/catalogue/tags", (c) => tryRoute(c, () => deps.catalogue.listTags(deps.defaultBusinessId)));
3341
+ app.get(
3342
+ "/catalogue/taxonomies",
3343
+ (c) => tryRoute(c, () => deps.catalogue.listTaxonomies(deps.defaultBusinessId))
3344
+ );
3345
+ app.get(
3346
+ "/catalogue/taxonomies/search",
3347
+ (c) => tryRoute(
3348
+ c,
3349
+ () => deps.catalogue.searchTaxonomies(deps.defaultBusinessId, c.req.query("q") ?? "")
3350
+ )
3351
+ );
3352
+ app.get(
3353
+ "/catalogue/taxonomies/:taxonomy_id",
3354
+ (c) => tryRoute(c, () => deps.catalogue.getTaxonomy(c.req.param("taxonomy_id")))
3355
+ );
3356
+ app.get(
3357
+ "/catalogue/taxonomies/:taxonomy_id/attributes",
3358
+ (c) => tryRoute(c, () => deps.catalogue.getTaxonomyAttributes(c.req.param("taxonomy_id")))
3359
+ );
3360
+ app.get(
3361
+ "/catalogue/taxonomies/:taxonomy_id/path",
3362
+ (c) => tryRoute(c, () => deps.catalogue.getTaxonomyPath(c.req.param("taxonomy_id")))
3363
+ );
3364
+ app.get(
3365
+ "/catalogue/attributes",
3366
+ (c) => tryRoute(c, () => deps.catalogue.listAttributes(deps.defaultBusinessId))
3367
+ );
3368
+ app.get(
3369
+ "/catalogue/properties/facets",
3370
+ (c) => tryRoute(c, () => deps.catalogue.listPropertyFacets(deps.defaultBusinessId))
3371
+ );
3372
+ app.get(
3373
+ "/catalogue/tags",
3374
+ (c) => tryRoute(c, () => deps.catalogue.listTags(deps.defaultBusinessId))
3375
+ );
3261
3376
  app.get("/catalogue/menu", (c) => tryRoute(c, () => deps.lite.getMenu(deps.defaultBusinessId)));
3262
- app.get("/catalogue/menu/categories/:category_id", (c) => tryRoute(c, () => deps.lite.getMenuCategory(c.req.param("category_id"))));
3263
- app.get("/catalogue/menu/items/:item_id", (c) => tryRoute(c, () => deps.catalogue.getProduct(c.req.param("item_id"))));
3264
- app.get("/catalogue/knowledge-base/articles", (c) => tryRoute(c, () => ({ articles: deps.catalogue.listKnowledgeArticles(deps.defaultBusinessId) })));
3377
+ app.get(
3378
+ "/catalogue/menu/categories/:category_id",
3379
+ (c) => tryRoute(c, () => deps.lite.getMenuCategory(c.req.param("category_id")))
3380
+ );
3381
+ app.get(
3382
+ "/catalogue/menu/items/:item_id",
3383
+ (c) => tryRoute(c, () => deps.catalogue.getProduct(c.req.param("item_id")))
3384
+ );
3385
+ app.get(
3386
+ "/catalogue/knowledge-base/articles",
3387
+ (c) => tryRoute(c, () => ({ articles: deps.catalogue.listKnowledgeArticles(deps.defaultBusinessId) }))
3388
+ );
3265
3389
  app.get(
3266
3390
  "/catalogue/knowledge-base/search",
3267
- (c) => tryRoute(c, () => ({ results: deps.catalogue.searchKnowledgeBase(deps.defaultBusinessId, c.req.query("q") ?? ""), query: c.req.query("q") ?? "" }))
3391
+ (c) => tryRoute(c, () => ({
3392
+ results: deps.catalogue.searchKnowledgeBase(deps.defaultBusinessId, c.req.query("q") ?? ""),
3393
+ query: c.req.query("q") ?? ""
3394
+ }))
3395
+ );
3396
+ app.get(
3397
+ "/catalogue/products/:product_id/attributes",
3398
+ (c) => tryRoute(c, () => deps.catalogue.getProductAttributes(c.req.param("product_id")))
3268
3399
  );
3269
- app.get("/catalogue/products/:product_id/attributes", (c) => tryRoute(c, () => deps.catalogue.getProductAttributes(c.req.param("product_id"))));
3270
3400
  app.get(
3271
3401
  "/catalogue/products/:product_id/available-now",
3272
3402
  (c) => tryRoute(c, () => {
@@ -3285,22 +3415,75 @@ function buildV1(deps) {
3285
3415
  "/catalogue/products/:product_id/schedules",
3286
3416
  (c) => tryRoute(c, () => {
3287
3417
  const p = deps.registry.products.get(c.req.param("product_id"));
3288
- return { schedules: p?.metadata?.["time_profiles"] ?? [] };
3418
+ return {
3419
+ schedules: p?.metadata?.["time_profiles"] ?? []
3420
+ };
3289
3421
  })
3290
3422
  );
3291
- app.get("/catalogue/deals", (c) => tryRoute(c, () => deps.catalogue.listDeals(deps.defaultBusinessId)));
3292
- app.get("/catalogue/deals/on-sale", (c) => tryRoute(c, () => deps.catalogue.listOnSale(deps.defaultBusinessId)));
3423
+ app.get(
3424
+ "/catalogue/deals",
3425
+ (c) => tryRoute(c, () => deps.catalogue.listDeals(deps.defaultBusinessId))
3426
+ );
3427
+ app.get(
3428
+ "/catalogue/deals/on-sale",
3429
+ (c) => tryRoute(c, () => deps.catalogue.listOnSale(deps.defaultBusinessId))
3430
+ );
3293
3431
  app.post("/catalogue/deals/validate", async (c) => {
3294
3432
  const body = await c.req.json().catch(() => ({}));
3295
- return tryRoute(c, () => deps.catalogue.validateDiscount(body.discount_code ?? body.code ?? "", deps.defaultBusinessId));
3433
+ return tryRoute(
3434
+ c,
3435
+ () => deps.catalogue.validateDiscount(
3436
+ body.discount_code ?? body.code ?? "",
3437
+ deps.defaultBusinessId
3438
+ )
3439
+ );
3296
3440
  });
3297
- app.get("/catalogue/products/:product_id/deals", (c) => tryRoute(c, () => deps.catalogue.getProductDeals(c.req.param("product_id"))));
3441
+ app.get(
3442
+ "/catalogue/products/:product_id/deals",
3443
+ (c) => tryRoute(c, () => deps.catalogue.getProductDeals(c.req.param("product_id")))
3444
+ );
3298
3445
  app.post("/catalogue/quotes", async (c) => {
3299
3446
  const body = await c.req.json().catch(() => ({}));
3300
3447
  return tryRoute(c, () => deps.catalogue.createQuote(deps.defaultBusinessId, body));
3301
3448
  });
3302
- app.get("/catalogue/quotes/:quote_id", (c) => tryRoute(c, () => deps.catalogue.getQuote(c.req.param("quote_id"))));
3303
- app.post("/catalogue/quotes/:quote_id/refresh", (c) => tryRoute(c, () => deps.catalogue.refreshQuote(c.req.param("quote_id"))));
3449
+ app.get(
3450
+ "/catalogue/quotes/:quote_id",
3451
+ (c) => tryRoute(c, () => deps.catalogue.getQuote(c.req.param("quote_id")))
3452
+ );
3453
+ app.post(
3454
+ "/catalogue/quotes/:quote_id/refresh",
3455
+ (c) => tryRoute(c, () => deps.catalogue.refreshQuote(c.req.param("quote_id")))
3456
+ );
3457
+ app.get("/reviews/summary", (c) => {
3458
+ const productId = c.req.query("product_id");
3459
+ if (productId !== void 0 && (productId.length === 0 || productId.trim() !== productId)) {
3460
+ return fail(c, validation("product_id must be a non-empty canonical identifier"));
3461
+ }
3462
+ const response = {
3463
+ data: {
3464
+ ratings: {
3465
+ product_id: productId ?? null,
3466
+ review_count: 0,
3467
+ rating_sum: 0,
3468
+ average_rating: null,
3469
+ distribution: { one: 0, two: 0, three: 0, four: 0, five: 0 }
3470
+ },
3471
+ trust_chips: {
3472
+ on_time_delivery_percent: null,
3473
+ delivery_sample_size: 0,
3474
+ average_first_response_seconds: null,
3475
+ support_sample_size: 0
3476
+ }
3477
+ }
3478
+ };
3479
+ return c.json(response);
3480
+ });
3481
+ app.get("/reviews", (c) => {
3482
+ const response = {
3483
+ data: { items: [], next_cursor: null }
3484
+ };
3485
+ return c.json(response);
3486
+ });
3304
3487
  app.get("/cart", (c) => tryRoute(c, () => deps.cart.toUICart(deps.cart.get(c.var.session))));
3305
3488
  app.delete("/cart", (c) => tryRoute(c, () => deps.cart.clear(c.var.session)));
3306
3489
  app.get("/cart/items", (c) => tryRoute(c, () => deps.cart.getItems(c.var.session)));
@@ -3311,9 +3494,15 @@ function buildV1(deps) {
3311
3494
  app.patch("/cart/items/:cart_item_id", async (c) => {
3312
3495
  const body = await c.req.json().catch(() => ({}));
3313
3496
  if (typeof body.quantity !== "number") return fail(c, validation("quantity required"));
3314
- return tryRoute(c, () => deps.cart.updateQuantity(c.var.session, c.req.param("cart_item_id"), body.quantity));
3497
+ return tryRoute(
3498
+ c,
3499
+ () => deps.cart.updateQuantity(c.var.session, c.req.param("cart_item_id"), body.quantity)
3500
+ );
3315
3501
  });
3316
- app.delete("/cart/items/:cart_item_id", (c) => tryRoute(c, () => deps.cart.removeItem(c.var.session, c.req.param("cart_item_id"))));
3502
+ app.delete(
3503
+ "/cart/items/:cart_item_id",
3504
+ (c) => tryRoute(c, () => deps.cart.removeItem(c.var.session, c.req.param("cart_item_id")))
3505
+ );
3317
3506
  app.get("/cart/count", (c) => tryRoute(c, () => deps.cart.getCount(c.var.session)));
3318
3507
  app.get("/cart/total", (c) => tryRoute(c, () => deps.cart.getTotal(c.var.session)));
3319
3508
  app.post("/cart/destination-quote", async (c) => {
@@ -3324,10 +3513,25 @@ function buildV1(deps) {
3324
3513
  const body = await c.req.json().catch(() => ({}));
3325
3514
  return tryRoute(c, () => deps.cart.applyCoupon(c.var.session, body.coupon_code ?? ""));
3326
3515
  });
3327
- app.delete("/cart/coupons/current", (c) => tryRoute(c, () => deps.cart.removeCoupon(c.var.session)));
3328
- app.get("/orders", (c) => tryRoute(c, () => deps.orders.list(c.var.session, { limit: getQueryNum(c, "limit"), status: c.req.query("status") })));
3516
+ app.delete(
3517
+ "/cart/coupons/current",
3518
+ (c) => tryRoute(c, () => deps.cart.removeCoupon(c.var.session))
3519
+ );
3520
+ app.get(
3521
+ "/orders",
3522
+ (c) => tryRoute(
3523
+ c,
3524
+ () => deps.orders.list(c.var.session, {
3525
+ limit: getQueryNum(c, "limit"),
3526
+ status: c.req.query("status")
3527
+ })
3528
+ )
3529
+ );
3329
3530
  app.get("/orders/:order_id", (c) => tryRoute(c, () => deps.orders.get(c.req.param("order_id"))));
3330
- app.get("/orders/:order_id/payment-status", (c) => tryRoute(c, () => deps.orders.getPaymentStatus(c.req.param("order_id"))));
3531
+ app.get(
3532
+ "/orders/:order_id/payment-status",
3533
+ (c) => tryRoute(c, () => deps.orders.getPaymentStatus(c.req.param("order_id")))
3534
+ );
3331
3535
  app.post("/orders/:order_id/cancel", async (c) => {
3332
3536
  const body = await c.req.json().catch(() => ({}));
3333
3537
  return tryRoute(c, () => deps.orders.cancel(c.req.param("order_id"), body.reason));
@@ -3336,13 +3540,46 @@ function buildV1(deps) {
3336
3540
  const body = await c.req.json().catch(() => ({}));
3337
3541
  return tryRoute(c, () => deps.orders.updateCustomer(c.req.param("order_id"), body));
3338
3542
  });
3339
- app.post("/orders/:order_id/verify-payment", (c) => tryRoute(c, () => deps.orders.verifyPayment(c.req.param("order_id"))));
3543
+ app.post(
3544
+ "/orders/:order_id/verify-payment",
3545
+ (c) => tryRoute(c, () => deps.orders.verifyPayment(c.req.param("order_id")))
3546
+ );
3340
3547
  app.get("/subscriptions", (c) => tryRoute(c, () => deps.subscriptions.list(c.var.session)));
3341
- app.get("/subscriptions/:subscription_id", (c) => tryRoute(c, () => deps.subscriptions.get(c.req.param("subscription_id"))));
3342
- app.post("/subscriptions/:subscription_id/cancel", (c) => tryRoute(c, () => deps.subscriptions.cancel(c.req.param("subscription_id"))));
3343
- app.post("/subscriptions/:subscription_id/pause", (c) => tryRoute(c, () => deps.subscriptions.pause(c.req.param("subscription_id"))));
3344
- app.post("/subscriptions/:subscription_id/resume", (c) => tryRoute(c, () => deps.subscriptions.resume(c.req.param("subscription_id"))));
3345
- app.post("/subscriptions/:subscription_id/skip", (c) => tryRoute(c, () => deps.subscriptions.skipNext(c.req.param("subscription_id"))));
3548
+ app.get(
3549
+ "/subscriptions/:subscription_id",
3550
+ (c) => tryRoute(c, () => deps.subscriptions.get(c.req.param("subscription_id")))
3551
+ );
3552
+ app.post(
3553
+ "/subscriptions/:subscription_id/cancel",
3554
+ (c) => tryRoute(c, () => deps.subscriptions.cancel(c.req.param("subscription_id")))
3555
+ );
3556
+ app.post(
3557
+ "/subscriptions/:subscription_id/pause",
3558
+ (c) => tryRoute(c, () => deps.subscriptions.pause(c.req.param("subscription_id")))
3559
+ );
3560
+ app.post(
3561
+ "/subscriptions/:subscription_id/resume",
3562
+ (c) => tryRoute(c, () => deps.subscriptions.resume(c.req.param("subscription_id")))
3563
+ );
3564
+ app.post(
3565
+ "/subscriptions/:subscription_id/skip",
3566
+ (c) => tryRoute(c, () => deps.subscriptions.skipNext(c.req.param("subscription_id")))
3567
+ );
3568
+ app.get("/payments/collection-options", (c) => {
3569
+ const currency = c.req.query("currency")?.trim().toUpperCase();
3570
+ if (!currency || !/^[A-Z]{3}$/.test(currency)) {
3571
+ return fail(c, validation("currency must be a canonical three-letter code"));
3572
+ }
3573
+ return tryRoute(c, () => ({
3574
+ presentment_currency: currency,
3575
+ options: currency === "GHS" ? [
3576
+ { method: PAYMENT_METHOD.CARD, network: null },
3577
+ { method: PAYMENT_METHOD.MOBILE_MONEY, network: "mtn" },
3578
+ { method: PAYMENT_METHOD.MOBILE_MONEY, network: "telecel" },
3579
+ { method: PAYMENT_METHOD.MOBILE_MONEY, network: "airteltigo" }
3580
+ ] : currency === "USD" ? [{ method: PAYMENT_METHOD.CARD, network: null }] : []
3581
+ }));
3582
+ });
3346
3583
  app.post("/checkout", async (c) => {
3347
3584
  const body = await c.req.json().catch(() => ({}));
3348
3585
  return tryRoute(c, () => deps.checkout.process(c.var.session, body));
@@ -3396,15 +3633,33 @@ function buildV1(deps) {
3396
3633
  return { success: true, message: "Profile updated successfully" };
3397
3634
  });
3398
3635
  });
3399
- app.get("/inventory/products/:product_id/stock", (c) => tryRoute(c, () => deps.inventory.productStock(c.req.param("product_id"))));
3400
- app.get("/inventory/variants/:variant_id/stock", (c) => tryRoute(c, () => deps.inventory.variantStock(c.req.param("variant_id"))));
3636
+ app.get(
3637
+ "/inventory/products/:product_id/stock",
3638
+ (c) => tryRoute(c, () => deps.inventory.productStock(c.req.param("product_id")))
3639
+ );
3640
+ app.get(
3641
+ "/inventory/variants/:variant_id/stock",
3642
+ (c) => tryRoute(c, () => deps.inventory.variantStock(c.req.param("variant_id")))
3643
+ );
3401
3644
  app.get(
3402
3645
  "/inventory/products/:product_id/availability",
3403
- (c) => tryRoute(c, () => deps.inventory.productAvailability(c.req.param("product_id"), getQueryNum(c, "quantity") ?? 1))
3646
+ (c) => tryRoute(
3647
+ c,
3648
+ () => deps.inventory.productAvailability(
3649
+ c.req.param("product_id"),
3650
+ getQueryNum(c, "quantity") ?? 1
3651
+ )
3652
+ )
3404
3653
  );
3405
3654
  app.get(
3406
3655
  "/inventory/variants/:variant_id/availability",
3407
- (c) => tryRoute(c, () => deps.inventory.variantAvailability(c.req.param("variant_id"), getQueryNum(c, "quantity") ?? 1))
3656
+ (c) => tryRoute(
3657
+ c,
3658
+ () => deps.inventory.variantAvailability(
3659
+ c.req.param("variant_id"),
3660
+ getQueryNum(c, "quantity") ?? 1
3661
+ )
3662
+ )
3408
3663
  );
3409
3664
  app.get(
3410
3665
  "/delivery/fee",
@@ -3431,35 +3686,75 @@ function buildV1(deps) {
3431
3686
  );
3432
3687
  app.post("/places/autocomplete", async (c) => {
3433
3688
  const body = await c.req.json().catch(() => ({}));
3434
- return tryRoute(c, () => deps.places.autocomplete({ query: body.input ?? body.query ?? "", country: body.country }));
3689
+ return tryRoute(
3690
+ c,
3691
+ () => deps.places.autocomplete({ query: body.input ?? body.query ?? "", country: body.country })
3692
+ );
3435
3693
  });
3436
3694
  app.post("/places/details", async (c) => {
3437
3695
  const body = await c.req.json().catch(() => ({}));
3438
3696
  return tryRoute(c, () => deps.places.details({ place_id: body.place_id ?? "" }));
3439
3697
  });
3440
- app.get("/scheduling/services", (c) => tryRoute(c, () => deps.scheduling.listServices(deps.defaultBusinessId)));
3441
- app.get("/scheduling/services/:service_id", (c) => tryRoute(c, () => deps.scheduling.getService(c.req.param("service_id"))));
3442
- app.get("/scheduling/slots", (c) => tryRoute(c, () => deps.scheduling.getSlots(c.req.query("service_id") ?? "", { date: c.req.query("date") })));
3698
+ app.get(
3699
+ "/scheduling/services",
3700
+ (c) => tryRoute(c, () => deps.scheduling.listServices(deps.defaultBusinessId))
3701
+ );
3702
+ app.get(
3703
+ "/scheduling/services/:service_id",
3704
+ (c) => tryRoute(c, () => deps.scheduling.getService(c.req.param("service_id")))
3705
+ );
3706
+ app.get(
3707
+ "/scheduling/slots",
3708
+ (c) => tryRoute(
3709
+ c,
3710
+ () => deps.scheduling.getSlots(c.req.query("service_id") ?? "", { date: c.req.query("date") })
3711
+ )
3712
+ );
3443
3713
  app.get(
3444
3714
  "/scheduling/slots/check",
3445
- (c) => tryRoute(c, () => deps.scheduling.checkSlot(c.req.query("service_id") ?? "", c.req.query("start") ?? "", c.req.query("end") ?? ""))
3715
+ (c) => tryRoute(
3716
+ c,
3717
+ () => deps.scheduling.checkSlot(
3718
+ c.req.query("service_id") ?? "",
3719
+ c.req.query("start") ?? "",
3720
+ c.req.query("end") ?? ""
3721
+ )
3722
+ )
3723
+ );
3724
+ app.get(
3725
+ "/scheduling/availability",
3726
+ (c) => tryRoute(c, () => deps.scheduling.getServiceAvailability(c.req.query("service_id") ?? ""))
3727
+ );
3728
+ app.get(
3729
+ "/scheduling/bookings",
3730
+ (c) => tryRoute(c, () => deps.scheduling.getCustomerBookings(c.var.session))
3446
3731
  );
3447
- app.get("/scheduling/availability", (c) => tryRoute(c, () => deps.scheduling.getServiceAvailability(c.req.query("service_id") ?? "")));
3448
- app.get("/scheduling/bookings", (c) => tryRoute(c, () => deps.scheduling.getCustomerBookings(c.var.session)));
3449
3732
  app.post("/scheduling/bookings/reschedule", async (c) => {
3450
3733
  const body = await c.req.json().catch(() => ({}));
3451
3734
  return tryRoute(c, () => deps.scheduling.rescheduleBooking(body));
3452
3735
  });
3453
- app.get("/scheduling/bookings/:booking_id", (c) => tryRoute(c, () => deps.scheduling.getBooking(c.req.param("booking_id"))));
3736
+ app.get(
3737
+ "/scheduling/bookings/:booking_id",
3738
+ (c) => tryRoute(c, () => deps.scheduling.getBooking(c.req.param("booking_id")))
3739
+ );
3454
3740
  app.post("/scheduling/bookings/:booking_id/cancel", async (c) => {
3455
3741
  const body = await c.req.json().catch(() => ({}));
3456
3742
  return tryRoute(c, () => deps.scheduling.cancelBooking(c.req.param("booking_id"), body.reason));
3457
3743
  });
3458
3744
  app.get("/lite/bootstrap", (c) => tryRoute(c, () => deps.lite.bootstrap(deps.defaultBusinessId)));
3459
- app.get("/lite/resources/:resource_id", (c) => tryRoute(c, () => deps.lite.getResource(c.req.param("resource_id"))));
3745
+ app.get(
3746
+ "/lite/resources/:resource_id",
3747
+ (c) => tryRoute(c, () => deps.lite.getResource(c.req.param("resource_id")))
3748
+ );
3460
3749
  app.get("/lite/menu", (c) => tryRoute(c, () => deps.lite.getMenu(deps.defaultBusinessId)));
3461
- app.get("/lite/menu/categories/:category_id", (c) => tryRoute(c, () => deps.lite.getMenuCategory(c.req.param("category_id"))));
3462
- app.get("/fx/rate", (c) => tryRoute(c, () => deps.fx.getRate(c.req.query("from") ?? "USD", c.req.query("to") ?? "GHS")));
3750
+ app.get(
3751
+ "/lite/menu/categories/:category_id",
3752
+ (c) => tryRoute(c, () => deps.lite.getMenuCategory(c.req.param("category_id")))
3753
+ );
3754
+ app.get(
3755
+ "/fx/rate",
3756
+ (c) => tryRoute(c, () => deps.fx.getRate(c.req.query("from") ?? "USD", c.req.query("to") ?? "GHS"))
3757
+ );
3463
3758
  app.post("/fx/quotes", async (c) => {
3464
3759
  const body = await c.req.json().catch(() => ({}));
3465
3760
  return tryRoute(c, () => deps.fx.lockQuote(body));
@@ -3472,31 +3767,47 @@ function buildV1(deps) {
3472
3767
  const body = await c.req.json().catch(() => ({}));
3473
3768
  return tryRoute(c, () => deps.uploads.confirm(body));
3474
3769
  });
3475
- app.get(
3476
- "/store-credit/balance",
3477
- (c) => c.json({ data: { balance: "0.00", currency: "USD" } })
3478
- );
3770
+ app.get("/store-credit/balance", (c) => c.json({ data: { balance: "0.00", currency: "USD" } }));
3479
3771
  app.post("/activity/session", async (c) => {
3480
3772
  await c.req.json().catch(() => ({}));
3481
3773
  return c.json({ data: { recorded: true } });
3482
3774
  });
3483
3775
  app.post("/activity/events", async (c) => {
3484
3776
  const body = await c.req.json().catch(() => ({}));
3485
- return tryRoute(c, () => deps.activity.recordEvents(deps.defaultBusinessId, body.analytics_session_id ?? c.var.session.id, body.events ?? []));
3777
+ return tryRoute(
3778
+ c,
3779
+ () => deps.activity.recordEvents(
3780
+ deps.defaultBusinessId,
3781
+ body.analytics_session_id ?? c.var.session.id,
3782
+ body.events ?? []
3783
+ )
3784
+ );
3486
3785
  });
3487
- app.get("/activity/state", (c) => tryRoute(c, () => deps.activity.getState(deps.defaultBusinessId, c.var.session.id)));
3488
- app.get("/activity/recommendations", (c) => tryRoute(c, () => deps.activity.getRecommendations(deps.defaultBusinessId)));
3786
+ app.get(
3787
+ "/activity/state",
3788
+ (c) => tryRoute(c, () => deps.activity.getState(deps.defaultBusinessId, c.var.session.id))
3789
+ );
3790
+ app.get(
3791
+ "/activity/recommendations",
3792
+ (c) => tryRoute(c, () => deps.activity.getRecommendations(deps.defaultBusinessId))
3793
+ );
3489
3794
  app.post("/activity/messages/dismiss", async (c) => {
3490
3795
  const body = await c.req.json().catch(() => ({}));
3491
3796
  return tryRoute(c, () => deps.activity.dismissMessage(body.code ?? body.message_id ?? ""));
3492
3797
  });
3493
3798
  app.post(
3494
3799
  "/support/conversation",
3495
- (c) => tryRoute(c, () => deps.support.openConversation(deps.defaultBusinessId, c.var.session.customer_id))
3800
+ (c) => tryRoute(
3801
+ c,
3802
+ () => deps.support.openConversation(deps.defaultBusinessId, c.var.session.customer_id)
3803
+ )
3496
3804
  );
3497
3805
  app.get(
3498
3806
  "/support/conversation",
3499
- (c) => tryRoute(c, () => deps.support.peekConversation(deps.defaultBusinessId, c.var.session.customer_id))
3807
+ (c) => tryRoute(
3808
+ c,
3809
+ () => deps.support.peekConversation(deps.defaultBusinessId, c.var.session.customer_id)
3810
+ )
3500
3811
  );
3501
3812
  app.post("/support/conversation/messages", async (c) => {
3502
3813
  const body = await c.req.json().catch(() => ({}));
@@ -3512,7 +3823,12 @@ function buildV1(deps) {
3512
3823
  });
3513
3824
  app.get(
3514
3825
  "/support/conversation/messages",
3515
- (c) => tryRoute(c, () => deps.support.listMessages(c.req.query("conversation_id") ?? "", { limit: getQueryNum(c, "limit") }))
3826
+ (c) => tryRoute(
3827
+ c,
3828
+ () => deps.support.listMessages(c.req.query("conversation_id") ?? "", {
3829
+ limit: getQueryNum(c, "limit")
3830
+ })
3831
+ )
3516
3832
  );
3517
3833
  app.post("/support/conversation/messages/:messageId/reactions", async (c) => {
3518
3834
  const body = await c.req.json().catch(() => ({}));
@@ -3533,7 +3849,10 @@ function buildV1(deps) {
3533
3849
  });
3534
3850
  app.get(
3535
3851
  "/support/conversation/ws",
3536
- (c) => c.json({ note: "WebSocket connection \u2014 connect via ws:// at the same path", supported: false }, 426)
3852
+ (c) => c.json(
3853
+ { note: "WebSocket connection \u2014 connect via ws:// at the same path", supported: false },
3854
+ 426
3855
+ )
3537
3856
  );
3538
3857
  return app;
3539
3858
  }
@@ -4060,9 +4379,10 @@ function buildLink(deps) {
4060
4379
  app.post("/auth/request-otp", async (c) => {
4061
4380
  const body = await c.req.json().catch(() => ({}));
4062
4381
  return tryRoute(c, () => {
4063
- deps.auth.requestOtp(body.contact ?? "");
4382
+ const challenge = deps.auth.requestOtp(body.contact ?? "");
4064
4383
  return {
4065
4384
  success: true,
4385
+ challenge_id: challenge.otp_id,
4066
4386
  message: `OTP sent to ${body.contact ?? "contact"}`,
4067
4387
  expires_in: 300,
4068
4388
  is_new_account: false
@@ -4072,7 +4392,11 @@ function buildLink(deps) {
4072
4392
  app.post("/auth/verify-otp", async (c) => {
4073
4393
  const body = await c.req.json().catch(() => ({}));
4074
4394
  return tryRoute(c, () => {
4075
- const session = deps.auth.verifyOtp(body.contact ?? "", body.otp_code ?? "");
4395
+ const session = deps.auth.verifyOtp(
4396
+ body.contact ?? "",
4397
+ body.otp_code ?? "",
4398
+ body.challenge_id
4399
+ );
4076
4400
  c.header("x-session-token", session.token);
4077
4401
  const customer = deps.link.ensureCustomer(session.customer_id ?? session.id, {
4078
4402
  email: body.contact?.includes("@") ? body.contact : void 0,
@@ -4166,10 +4490,7 @@ function buildLink(deps) {
4166
4490
  };
4167
4491
  });
4168
4492
  });
4169
- app.get(
4170
- "/preferences",
4171
- (c) => tryRoute(c, () => deps.link.getPreferences(customerId(c)))
4172
- );
4493
+ app.get("/preferences", (c) => tryRoute(c, () => deps.link.getPreferences(customerId(c))));
4173
4494
  app.post("/preferences", async (c) => {
4174
4495
  const body = await c.req.json().catch(() => ({}));
4175
4496
  return tryRoute(c, () => {
@@ -4646,9 +4967,16 @@ function createAuthService(opts) {
4646
4967
  code_hint: options.mode === "permissive" ? code : void 0
4647
4968
  };
4648
4969
  },
4649
- verifyOtp(contact, code) {
4650
- const matching = registry.otps.list((o) => o.contact === contact);
4651
- const otp = matching[matching.length - 1];
4970
+ verifyOtp(contact, code, challengeId) {
4971
+ let otp = challengeId ? registry.otps.get(challengeId) : void 0;
4972
+ if (!challengeId) {
4973
+ const matching = registry.otps.list((o) => o.contact === contact);
4974
+ otp = matching[matching.length - 1];
4975
+ }
4976
+ if (challengeId) {
4977
+ if (!otp) throw new Error("No OTP challenge found");
4978
+ if (otp.contact !== contact) throw new Error("OTP challenge does not match contact");
4979
+ }
4652
4980
  if (options.mode === "strict") {
4653
4981
  if (!otp) throw new Error("No OTP requested");
4654
4982
  if (otp.code !== code && code !== options.defaultOtp) throw new Error("Invalid OTP");
@@ -5976,7 +6304,7 @@ function createCartService(opts) {
5976
6304
 
5977
6305
  // src/mock/domain/checkout.ts
5978
6306
  function createCheckoutService(opts) {
5979
- const { registry, clock, ids, bus} = opts;
6307
+ const { registry, clock, ids, bus } = opts;
5980
6308
  return {
5981
6309
  process(session, body) {
5982
6310
  if (!body.cart_id) throw validation("cart_id required");
@@ -5985,9 +6313,11 @@ function createCheckoutService(opts) {
5985
6313
  if (c.items.length === 0) throw validation("Cart is empty", { code: "CART_EMPTY" });
5986
6314
  const orderId = ids.order();
5987
6315
  const orderNumber = ids.orderNumber();
6316
+ const paymentId = ids.payment();
5988
6317
  const reference = ids.payment();
5989
6318
  const requiresAuth = body.payment_method === "mobile_money";
5990
6319
  const isCard = body.payment_method === "card" || body.payment_method === "stripe";
6320
+ const cardProvider = body.payment_method === "stripe" || body.pay_currency?.toUpperCase() === "USD" ? "stripe" : "paystack";
5991
6321
  const order = {
5992
6322
  id: orderId,
5993
6323
  business_id: c.business_id,
@@ -6011,6 +6341,7 @@ function createCheckoutService(opts) {
6011
6341
  items: c.items,
6012
6342
  applied_discount_ids: c.applied_discount_ids,
6013
6343
  applied_discount_codes: c.applied_discount_codes,
6344
+ payment_id: paymentId,
6014
6345
  payment_reference: reference,
6015
6346
  metadata: body.metadata,
6016
6347
  created_at: clock.iso(),
@@ -6027,31 +6358,57 @@ function createCheckoutService(opts) {
6027
6358
  const result = {
6028
6359
  order_id: orderId,
6029
6360
  order_number: orderNumber,
6030
- payment_status: requiresAuth ? "pending" : "succeeded",
6361
+ payment_id: paymentId,
6362
+ payment_status: requiresAuth || isCard ? "pending" : "succeeded",
6031
6363
  payment_reference: reference,
6032
6364
  requires_authorization: requiresAuth,
6033
6365
  authorization_type: requiresAuth ? "otp" : void 0,
6034
- next_action: requiresAuth ? { type: "authorization", authorization_type: "otp", display_text: "Approve on your mobile money app" } : { type: "none" },
6035
- provider: body.payment_method,
6366
+ next_action: requiresAuth ? {
6367
+ type: "authorization",
6368
+ authorization_type: "otp",
6369
+ display_text: "Approve on your mobile money app"
6370
+ } : { type: "none" },
6371
+ provider: isCard ? cardProvider : body.payment_method,
6036
6372
  bill_token: billToken
6037
6373
  };
6038
6374
  if (isCard) {
6039
- result.next_action = { type: "redirect", authorization_url: `https://mock.cimplify.io/pay/${reference}` };
6040
- result.authorization_url = `https://mock.cimplify.io/pay/${reference}`;
6041
- result.client_secret = `pi_${orderId.slice(-12)}_secret_${Math.random().toString(36).slice(2, 18)}`;
6042
6375
  const proc = globalThis.process;
6043
- result.public_key = proc?.env?.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY ?? "pk_test_mock_publishable_key";
6376
+ result.client_secret = cardProvider === "stripe" ? `pi_${orderId.slice(-12)}_secret_${Math.random().toString(36).slice(2, 18)}` : `access_${reference}`;
6377
+ 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";
6378
+ result.next_action = {
6379
+ type: "card_popup",
6380
+ provider: cardProvider,
6381
+ client_secret: result.client_secret,
6382
+ public_key: result.public_key
6383
+ };
6044
6384
  }
6045
6385
  return result;
6046
6386
  },
6047
6387
  authorize(body) {
6048
- const order = registry.orders.get(body.order_id);
6049
- if (!order) throw notFound(`Order ${body.order_id} not found`);
6050
- const updated = { ...order, payment_state: "paid", status: "confirmed", updated_at: clock.iso() };
6388
+ if (!body.payment_id?.trim()) throw validation("payment_id required");
6389
+ if (!body.authorization) throw validation("authorization required");
6390
+ const order = registry.orders.list(
6391
+ (candidate) => candidate.payment_id === body.payment_id
6392
+ )[0];
6393
+ if (!order) throw notFound(`Payment ${body.payment_id} not found`);
6394
+ const updated = {
6395
+ ...order,
6396
+ payment_state: "paid",
6397
+ status: "confirmed",
6398
+ updated_at: clock.iso()
6399
+ };
6051
6400
  registry.orders.put(order.id, updated);
6052
6401
  bus.emit("order.payment.captured", { order_id: order.id }, order.business_id);
6053
6402
  bus.emit("order.confirmed", { order_id: order.id }, order.business_id);
6054
- return { status: "succeeded", order_id: order.id };
6403
+ return {
6404
+ order_id: order.id,
6405
+ order_number: order.user_friendly_id,
6406
+ payment_id: body.payment_id,
6407
+ payment_reference: order.payment_reference,
6408
+ payment_status: "succeeded",
6409
+ requires_authorization: false,
6410
+ next_action: { type: "none" }
6411
+ };
6055
6412
  }
6056
6413
  };
6057
6414
  }
@@ -6434,6 +6791,7 @@ function createDeliveryService() {
6434
6791
  rate_id: "dlvrt_mock_standard",
6435
6792
  name: "Standard",
6436
6793
  fee: standardFree ? money(0) : money(15),
6794
+ fee_status: "priced",
6437
6795
  currency: "GHS",
6438
6796
  free_delivery_applied: standardFree,
6439
6797
  free_over_amount: money(200),
@@ -6447,6 +6805,7 @@ function createDeliveryService() {
6447
6805
  name: "Express",
6448
6806
  description: "Delivered within the hour",
6449
6807
  fee: money(25),
6808
+ fee_status: "priced",
6450
6809
  currency: "GHS",
6451
6810
  free_delivery_applied: false,
6452
6811
  eta_min_minutes: 30,