@cimplify/sdk 0.103.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.
- package/dist/advanced.d.mts +3 -3
- package/dist/advanced.d.ts +3 -3
- package/dist/advanced.js +22 -22
- package/dist/advanced.mjs +3 -3
- package/dist/{chunk-C2JSNJUC.mjs → chunk-2WPVUIHX.mjs} +52 -11
- package/dist/{chunk-JG5CQNCB.js → chunk-4BKOKHE3.js} +4 -0
- package/dist/{chunk-R6OLQ33I.js → chunk-5BDYDZ4U.js} +239 -87
- package/dist/{chunk-H7ACMHM3.mjs → chunk-5RT4HYMP.mjs} +32 -4
- package/dist/{chunk-NNG6IFFX.js → chunk-7PDEX54K.js} +3 -3
- package/dist/{chunk-M4URVKHE.mjs → chunk-DYIAX3WI.mjs} +1 -1
- package/dist/{chunk-QOWPGS7Z.js → chunk-E4K2VQDD.js} +35 -5
- package/dist/{chunk-VNPEYLB2.mjs → chunk-H3RATH4B.mjs} +4 -0
- package/dist/{chunk-JSWJ4XDE.js → chunk-IQFFSKE2.js} +315 -108
- package/dist/{chunk-J6PNHDHL.mjs → chunk-OCCNG6MO.mjs} +284 -77
- package/dist/{chunk-GERXZQSX.mjs → chunk-OKADBZAI.mjs} +171 -20
- package/dist/{chunk-VIL6IQCG.js → chunk-YVAEY3VC.js} +54 -13
- package/dist/{client-Dqg2mc-7.d.ts → client-BVNWjk6W.d.ts} +2 -2
- package/dist/{client-BfpNjJ_a.d.mts → client-BuLcOWLv.d.ts} +115 -23
- package/dist/{client-DHBwvh7U.d.ts → client-D5AoobFc.d.mts} +115 -23
- package/dist/{client-DpqRobY9.d.mts → client-fM716k7G.d.mts} +2 -2
- package/dist/{index-C8uDqLwJ.d.ts → index-BtcoqrY1.d.ts} +3 -3
- package/dist/{index-e2y6AK70.d.mts → index-D7Tf3v7c.d.mts} +3 -3
- package/dist/index.d.mts +10 -8
- package/dist/index.d.ts +10 -8
- package/dist/index.js +107 -106
- package/dist/index.mjs +6 -5
- package/dist/{link-cuNVYc2s.d.mts → link-D9iSVxt5.d.mts} +12 -1
- package/dist/{link-cuNVYc2s.d.ts → link-D9iSVxt5.d.ts} +12 -1
- package/dist/mock/cli.mjs +53 -10
- package/dist/mock/library.js +53 -10
- package/dist/mock/library.mjs +53 -10
- package/dist/mock/msw.js +53 -10
- package/dist/mock/msw.mjs +53 -10
- package/dist/{payment-H5LoIvXU.d.mts → payment-g0HFkEDU.d.mts} +519 -54
- package/dist/{payment-H5LoIvXU.d.ts → payment-g0HFkEDU.d.ts} +519 -54
- package/dist/{price-C2RqscMY.d.ts → price-BLIeAb8K.d.ts} +1 -1
- package/dist/{price-BvePgDXe.d.mts → price-Czq_cTC_.d.mts} +1 -1
- package/dist/react.d.mts +4 -4
- package/dist/react.d.ts +4 -4
- package/dist/react.js +193 -169
- package/dist/react.mjs +54 -30
- package/dist/{server-C7FyLdrz.d.mts → server-BkVhOIwn.d.mts} +4 -2
- package/dist/{server-DoXIpSd7.d.ts → server-DKK_D-PP.d.ts} +4 -2
- package/dist/server.d.mts +4 -4
- package/dist/server.d.ts +4 -4
- package/dist/server.js +11 -10
- package/dist/server.mjs +5 -4
- package/dist/testing/msw.d.mts +2 -2
- package/dist/testing/msw.d.ts +2 -2
- package/dist/testing/msw.js +3 -3
- package/dist/testing/msw.mjs +2 -2
- package/dist/testing/suite.d.mts +6 -6
- package/dist/testing/suite.d.ts +6 -6
- package/dist/testing/suite.js +25 -25
- package/dist/testing/suite.mjs +6 -6
- package/dist/testing.d.mts +46 -6
- package/dist/testing.d.ts +46 -6
- package/dist/testing.js +94 -82
- package/dist/testing.mjs +13 -9
- package/dist/utils.d.mts +4 -4
- package/dist/utils.d.ts +4 -4
- package/dist/utils.js +31 -31
- package/dist/utils.mjs +2 -2
- package/package.json +1 -1
- package/registry/chat-widget.json +1 -1
package/dist/mock/cli.mjs
CHANGED
|
@@ -3040,6 +3040,8 @@ var ERROR_SUGGESTIONS = {
|
|
|
3040
3040
|
CARD_DECLINED: "Card was declined. Ask shopper to retry or switch payment method.",
|
|
3041
3041
|
INVALID_OTP: "Authorization code is invalid. Let shopper re-enter OTP/PIN and retry.",
|
|
3042
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.",
|
|
3043
3045
|
AUTHORIZATION_FAILED: "Additional payment authorization failed. Retry authorization or change payment method.",
|
|
3044
3046
|
PAYMENT_ACTION_NOT_COMPLETED: "Required payment action was not completed. Resume provider flow and poll for status.",
|
|
3045
3047
|
SLOT_UNAVAILABLE: "Selected schedule slot is unavailable. Refresh available slots and ask shopper to reselect.",
|
|
@@ -3452,6 +3454,36 @@ function buildV1(deps) {
|
|
|
3452
3454
|
"/catalogue/quotes/:quote_id/refresh",
|
|
3453
3455
|
(c) => tryRoute(c, () => deps.catalogue.refreshQuote(c.req.param("quote_id")))
|
|
3454
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
|
+
});
|
|
3455
3487
|
app.get("/cart", (c) => tryRoute(c, () => deps.cart.toUICart(deps.cart.get(c.var.session))));
|
|
3456
3488
|
app.delete("/cart", (c) => tryRoute(c, () => deps.cart.clear(c.var.session)));
|
|
3457
3489
|
app.get("/cart/items", (c) => tryRoute(c, () => deps.cart.getItems(c.var.session)));
|
|
@@ -4347,9 +4379,10 @@ function buildLink(deps) {
|
|
|
4347
4379
|
app.post("/auth/request-otp", async (c) => {
|
|
4348
4380
|
const body = await c.req.json().catch(() => ({}));
|
|
4349
4381
|
return tryRoute(c, () => {
|
|
4350
|
-
deps.auth.requestOtp(body.contact ?? "");
|
|
4382
|
+
const challenge = deps.auth.requestOtp(body.contact ?? "");
|
|
4351
4383
|
return {
|
|
4352
4384
|
success: true,
|
|
4385
|
+
challenge_id: challenge.otp_id,
|
|
4353
4386
|
message: `OTP sent to ${body.contact ?? "contact"}`,
|
|
4354
4387
|
expires_in: 300,
|
|
4355
4388
|
is_new_account: false
|
|
@@ -4359,7 +4392,11 @@ function buildLink(deps) {
|
|
|
4359
4392
|
app.post("/auth/verify-otp", async (c) => {
|
|
4360
4393
|
const body = await c.req.json().catch(() => ({}));
|
|
4361
4394
|
return tryRoute(c, () => {
|
|
4362
|
-
const session = deps.auth.verifyOtp(
|
|
4395
|
+
const session = deps.auth.verifyOtp(
|
|
4396
|
+
body.contact ?? "",
|
|
4397
|
+
body.otp_code ?? "",
|
|
4398
|
+
body.challenge_id
|
|
4399
|
+
);
|
|
4363
4400
|
c.header("x-session-token", session.token);
|
|
4364
4401
|
const customer = deps.link.ensureCustomer(session.customer_id ?? session.id, {
|
|
4365
4402
|
email: body.contact?.includes("@") ? body.contact : void 0,
|
|
@@ -4453,10 +4490,7 @@ function buildLink(deps) {
|
|
|
4453
4490
|
};
|
|
4454
4491
|
});
|
|
4455
4492
|
});
|
|
4456
|
-
app.get(
|
|
4457
|
-
"/preferences",
|
|
4458
|
-
(c) => tryRoute(c, () => deps.link.getPreferences(customerId(c)))
|
|
4459
|
-
);
|
|
4493
|
+
app.get("/preferences", (c) => tryRoute(c, () => deps.link.getPreferences(customerId(c))));
|
|
4460
4494
|
app.post("/preferences", async (c) => {
|
|
4461
4495
|
const body = await c.req.json().catch(() => ({}));
|
|
4462
4496
|
return tryRoute(c, () => {
|
|
@@ -4933,9 +4967,16 @@ function createAuthService(opts) {
|
|
|
4933
4967
|
code_hint: options.mode === "permissive" ? code : void 0
|
|
4934
4968
|
};
|
|
4935
4969
|
},
|
|
4936
|
-
verifyOtp(contact, code) {
|
|
4937
|
-
|
|
4938
|
-
|
|
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
|
+
}
|
|
4939
4980
|
if (options.mode === "strict") {
|
|
4940
4981
|
if (!otp) throw new Error("No OTP requested");
|
|
4941
4982
|
if (otp.code !== code && code !== options.defaultOtp) throw new Error("Invalid OTP");
|
|
@@ -6263,7 +6304,7 @@ function createCartService(opts) {
|
|
|
6263
6304
|
|
|
6264
6305
|
// src/mock/domain/checkout.ts
|
|
6265
6306
|
function createCheckoutService(opts) {
|
|
6266
|
-
const { registry, clock, ids, bus} = opts;
|
|
6307
|
+
const { registry, clock, ids, bus } = opts;
|
|
6267
6308
|
return {
|
|
6268
6309
|
process(session, body) {
|
|
6269
6310
|
if (!body.cart_id) throw validation("cart_id required");
|
|
@@ -6750,6 +6791,7 @@ function createDeliveryService() {
|
|
|
6750
6791
|
rate_id: "dlvrt_mock_standard",
|
|
6751
6792
|
name: "Standard",
|
|
6752
6793
|
fee: standardFree ? money(0) : money(15),
|
|
6794
|
+
fee_status: "priced",
|
|
6753
6795
|
currency: "GHS",
|
|
6754
6796
|
free_delivery_applied: standardFree,
|
|
6755
6797
|
free_over_amount: money(200),
|
|
@@ -6763,6 +6805,7 @@ function createDeliveryService() {
|
|
|
6763
6805
|
name: "Express",
|
|
6764
6806
|
description: "Delivered within the hour",
|
|
6765
6807
|
fee: money(25),
|
|
6808
|
+
fee_status: "priced",
|
|
6766
6809
|
currency: "GHS",
|
|
6767
6810
|
free_delivery_applied: false,
|
|
6768
6811
|
eta_min_minutes: 30,
|
package/dist/mock/library.js
CHANGED
|
@@ -2102,6 +2102,8 @@ var ERROR_SUGGESTIONS = {
|
|
|
2102
2102
|
CARD_DECLINED: "Card was declined. Ask shopper to retry or switch payment method.",
|
|
2103
2103
|
INVALID_OTP: "Authorization code is invalid. Let shopper re-enter OTP/PIN and retry.",
|
|
2104
2104
|
OTP_EXPIRED: "Authorization code expired. Request a new OTP and re-submit authorization.",
|
|
2105
|
+
OTP_CHALLENGE_EXHAUSTED: "This verification challenge has no attempts left. Continue checkout without saved details or request a fresh challenge.",
|
|
2106
|
+
OTP_CHALLENGE_CONSUMED: "This verification challenge has already been used. Continue with the established session or request a fresh challenge.",
|
|
2105
2107
|
AUTHORIZATION_FAILED: "Additional payment authorization failed. Retry authorization or change payment method.",
|
|
2106
2108
|
PAYMENT_ACTION_NOT_COMPLETED: "Required payment action was not completed. Resume provider flow and poll for status.",
|
|
2107
2109
|
SLOT_UNAVAILABLE: "Selected schedule slot is unavailable. Refresh available slots and ask shopper to reselect.",
|
|
@@ -2514,6 +2516,36 @@ function buildV1(deps) {
|
|
|
2514
2516
|
"/catalogue/quotes/:quote_id/refresh",
|
|
2515
2517
|
(c) => tryRoute(c, () => deps.catalogue.refreshQuote(c.req.param("quote_id")))
|
|
2516
2518
|
);
|
|
2519
|
+
app.get("/reviews/summary", (c) => {
|
|
2520
|
+
const productId = c.req.query("product_id");
|
|
2521
|
+
if (productId !== void 0 && (productId.length === 0 || productId.trim() !== productId)) {
|
|
2522
|
+
return fail(c, validation("product_id must be a non-empty canonical identifier"));
|
|
2523
|
+
}
|
|
2524
|
+
const response = {
|
|
2525
|
+
data: {
|
|
2526
|
+
ratings: {
|
|
2527
|
+
product_id: productId ?? null,
|
|
2528
|
+
review_count: 0,
|
|
2529
|
+
rating_sum: 0,
|
|
2530
|
+
average_rating: null,
|
|
2531
|
+
distribution: { one: 0, two: 0, three: 0, four: 0, five: 0 }
|
|
2532
|
+
},
|
|
2533
|
+
trust_chips: {
|
|
2534
|
+
on_time_delivery_percent: null,
|
|
2535
|
+
delivery_sample_size: 0,
|
|
2536
|
+
average_first_response_seconds: null,
|
|
2537
|
+
support_sample_size: 0
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2540
|
+
};
|
|
2541
|
+
return c.json(response);
|
|
2542
|
+
});
|
|
2543
|
+
app.get("/reviews", (c) => {
|
|
2544
|
+
const response = {
|
|
2545
|
+
data: { items: [], next_cursor: null }
|
|
2546
|
+
};
|
|
2547
|
+
return c.json(response);
|
|
2548
|
+
});
|
|
2517
2549
|
app.get("/cart", (c) => tryRoute(c, () => deps.cart.toUICart(deps.cart.get(c.var.session))));
|
|
2518
2550
|
app.delete("/cart", (c) => tryRoute(c, () => deps.cart.clear(c.var.session)));
|
|
2519
2551
|
app.get("/cart/items", (c) => tryRoute(c, () => deps.cart.getItems(c.var.session)));
|
|
@@ -3409,9 +3441,10 @@ function buildLink(deps) {
|
|
|
3409
3441
|
app.post("/auth/request-otp", async (c) => {
|
|
3410
3442
|
const body = await c.req.json().catch(() => ({}));
|
|
3411
3443
|
return tryRoute(c, () => {
|
|
3412
|
-
deps.auth.requestOtp(body.contact ?? "");
|
|
3444
|
+
const challenge = deps.auth.requestOtp(body.contact ?? "");
|
|
3413
3445
|
return {
|
|
3414
3446
|
success: true,
|
|
3447
|
+
challenge_id: challenge.otp_id,
|
|
3415
3448
|
message: `OTP sent to ${body.contact ?? "contact"}`,
|
|
3416
3449
|
expires_in: 300,
|
|
3417
3450
|
is_new_account: false
|
|
@@ -3421,7 +3454,11 @@ function buildLink(deps) {
|
|
|
3421
3454
|
app.post("/auth/verify-otp", async (c) => {
|
|
3422
3455
|
const body = await c.req.json().catch(() => ({}));
|
|
3423
3456
|
return tryRoute(c, () => {
|
|
3424
|
-
const session = deps.auth.verifyOtp(
|
|
3457
|
+
const session = deps.auth.verifyOtp(
|
|
3458
|
+
body.contact ?? "",
|
|
3459
|
+
body.otp_code ?? "",
|
|
3460
|
+
body.challenge_id
|
|
3461
|
+
);
|
|
3425
3462
|
c.header("x-session-token", session.token);
|
|
3426
3463
|
const customer = deps.link.ensureCustomer(session.customer_id ?? session.id, {
|
|
3427
3464
|
email: body.contact?.includes("@") ? body.contact : void 0,
|
|
@@ -3515,10 +3552,7 @@ function buildLink(deps) {
|
|
|
3515
3552
|
};
|
|
3516
3553
|
});
|
|
3517
3554
|
});
|
|
3518
|
-
app.get(
|
|
3519
|
-
"/preferences",
|
|
3520
|
-
(c) => tryRoute(c, () => deps.link.getPreferences(customerId(c)))
|
|
3521
|
-
);
|
|
3555
|
+
app.get("/preferences", (c) => tryRoute(c, () => deps.link.getPreferences(customerId(c))));
|
|
3522
3556
|
app.post("/preferences", async (c) => {
|
|
3523
3557
|
const body = await c.req.json().catch(() => ({}));
|
|
3524
3558
|
return tryRoute(c, () => {
|
|
@@ -3995,9 +4029,16 @@ function createAuthService(opts) {
|
|
|
3995
4029
|
code_hint: options.mode === "permissive" ? code : void 0
|
|
3996
4030
|
};
|
|
3997
4031
|
},
|
|
3998
|
-
verifyOtp(contact, code) {
|
|
3999
|
-
|
|
4000
|
-
|
|
4032
|
+
verifyOtp(contact, code, challengeId) {
|
|
4033
|
+
let otp = challengeId ? registry.otps.get(challengeId) : void 0;
|
|
4034
|
+
if (!challengeId) {
|
|
4035
|
+
const matching = registry.otps.list((o) => o.contact === contact);
|
|
4036
|
+
otp = matching[matching.length - 1];
|
|
4037
|
+
}
|
|
4038
|
+
if (challengeId) {
|
|
4039
|
+
if (!otp) throw new Error("No OTP challenge found");
|
|
4040
|
+
if (otp.contact !== contact) throw new Error("OTP challenge does not match contact");
|
|
4041
|
+
}
|
|
4001
4042
|
if (options.mode === "strict") {
|
|
4002
4043
|
if (!otp) throw new Error("No OTP requested");
|
|
4003
4044
|
if (otp.code !== code && code !== options.defaultOtp) throw new Error("Invalid OTP");
|
|
@@ -5325,7 +5366,7 @@ function createCartService(opts) {
|
|
|
5325
5366
|
|
|
5326
5367
|
// src/mock/domain/checkout.ts
|
|
5327
5368
|
function createCheckoutService(opts) {
|
|
5328
|
-
const { registry, clock, ids, bus} = opts;
|
|
5369
|
+
const { registry, clock, ids, bus } = opts;
|
|
5329
5370
|
return {
|
|
5330
5371
|
process(session, body) {
|
|
5331
5372
|
if (!body.cart_id) throw validation("cart_id required");
|
|
@@ -5812,6 +5853,7 @@ function createDeliveryService() {
|
|
|
5812
5853
|
rate_id: "dlvrt_mock_standard",
|
|
5813
5854
|
name: "Standard",
|
|
5814
5855
|
fee: standardFree ? money(0) : money(15),
|
|
5856
|
+
fee_status: "priced",
|
|
5815
5857
|
currency: "GHS",
|
|
5816
5858
|
free_delivery_applied: standardFree,
|
|
5817
5859
|
free_over_amount: money(200),
|
|
@@ -5825,6 +5867,7 @@ function createDeliveryService() {
|
|
|
5825
5867
|
name: "Express",
|
|
5826
5868
|
description: "Delivered within the hour",
|
|
5827
5869
|
fee: money(25),
|
|
5870
|
+
fee_status: "priced",
|
|
5828
5871
|
currency: "GHS",
|
|
5829
5872
|
free_delivery_applied: false,
|
|
5830
5873
|
eta_min_minutes: 30,
|
package/dist/mock/library.mjs
CHANGED
|
@@ -2100,6 +2100,8 @@ var ERROR_SUGGESTIONS = {
|
|
|
2100
2100
|
CARD_DECLINED: "Card was declined. Ask shopper to retry or switch payment method.",
|
|
2101
2101
|
INVALID_OTP: "Authorization code is invalid. Let shopper re-enter OTP/PIN and retry.",
|
|
2102
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.",
|
|
2103
2105
|
AUTHORIZATION_FAILED: "Additional payment authorization failed. Retry authorization or change payment method.",
|
|
2104
2106
|
PAYMENT_ACTION_NOT_COMPLETED: "Required payment action was not completed. Resume provider flow and poll for status.",
|
|
2105
2107
|
SLOT_UNAVAILABLE: "Selected schedule slot is unavailable. Refresh available slots and ask shopper to reselect.",
|
|
@@ -2512,6 +2514,36 @@ function buildV1(deps) {
|
|
|
2512
2514
|
"/catalogue/quotes/:quote_id/refresh",
|
|
2513
2515
|
(c) => tryRoute(c, () => deps.catalogue.refreshQuote(c.req.param("quote_id")))
|
|
2514
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
|
+
});
|
|
2515
2547
|
app.get("/cart", (c) => tryRoute(c, () => deps.cart.toUICart(deps.cart.get(c.var.session))));
|
|
2516
2548
|
app.delete("/cart", (c) => tryRoute(c, () => deps.cart.clear(c.var.session)));
|
|
2517
2549
|
app.get("/cart/items", (c) => tryRoute(c, () => deps.cart.getItems(c.var.session)));
|
|
@@ -3407,9 +3439,10 @@ function buildLink(deps) {
|
|
|
3407
3439
|
app.post("/auth/request-otp", async (c) => {
|
|
3408
3440
|
const body = await c.req.json().catch(() => ({}));
|
|
3409
3441
|
return tryRoute(c, () => {
|
|
3410
|
-
deps.auth.requestOtp(body.contact ?? "");
|
|
3442
|
+
const challenge = deps.auth.requestOtp(body.contact ?? "");
|
|
3411
3443
|
return {
|
|
3412
3444
|
success: true,
|
|
3445
|
+
challenge_id: challenge.otp_id,
|
|
3413
3446
|
message: `OTP sent to ${body.contact ?? "contact"}`,
|
|
3414
3447
|
expires_in: 300,
|
|
3415
3448
|
is_new_account: false
|
|
@@ -3419,7 +3452,11 @@ function buildLink(deps) {
|
|
|
3419
3452
|
app.post("/auth/verify-otp", async (c) => {
|
|
3420
3453
|
const body = await c.req.json().catch(() => ({}));
|
|
3421
3454
|
return tryRoute(c, () => {
|
|
3422
|
-
const session = deps.auth.verifyOtp(
|
|
3455
|
+
const session = deps.auth.verifyOtp(
|
|
3456
|
+
body.contact ?? "",
|
|
3457
|
+
body.otp_code ?? "",
|
|
3458
|
+
body.challenge_id
|
|
3459
|
+
);
|
|
3423
3460
|
c.header("x-session-token", session.token);
|
|
3424
3461
|
const customer = deps.link.ensureCustomer(session.customer_id ?? session.id, {
|
|
3425
3462
|
email: body.contact?.includes("@") ? body.contact : void 0,
|
|
@@ -3513,10 +3550,7 @@ function buildLink(deps) {
|
|
|
3513
3550
|
};
|
|
3514
3551
|
});
|
|
3515
3552
|
});
|
|
3516
|
-
app.get(
|
|
3517
|
-
"/preferences",
|
|
3518
|
-
(c) => tryRoute(c, () => deps.link.getPreferences(customerId(c)))
|
|
3519
|
-
);
|
|
3553
|
+
app.get("/preferences", (c) => tryRoute(c, () => deps.link.getPreferences(customerId(c))));
|
|
3520
3554
|
app.post("/preferences", async (c) => {
|
|
3521
3555
|
const body = await c.req.json().catch(() => ({}));
|
|
3522
3556
|
return tryRoute(c, () => {
|
|
@@ -3993,9 +4027,16 @@ function createAuthService(opts) {
|
|
|
3993
4027
|
code_hint: options.mode === "permissive" ? code : void 0
|
|
3994
4028
|
};
|
|
3995
4029
|
},
|
|
3996
|
-
verifyOtp(contact, code) {
|
|
3997
|
-
|
|
3998
|
-
|
|
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
|
+
}
|
|
3999
4040
|
if (options.mode === "strict") {
|
|
4000
4041
|
if (!otp) throw new Error("No OTP requested");
|
|
4001
4042
|
if (otp.code !== code && code !== options.defaultOtp) throw new Error("Invalid OTP");
|
|
@@ -5323,7 +5364,7 @@ function createCartService(opts) {
|
|
|
5323
5364
|
|
|
5324
5365
|
// src/mock/domain/checkout.ts
|
|
5325
5366
|
function createCheckoutService(opts) {
|
|
5326
|
-
const { registry, clock, ids, bus} = opts;
|
|
5367
|
+
const { registry, clock, ids, bus } = opts;
|
|
5327
5368
|
return {
|
|
5328
5369
|
process(session, body) {
|
|
5329
5370
|
if (!body.cart_id) throw validation("cart_id required");
|
|
@@ -5810,6 +5851,7 @@ function createDeliveryService() {
|
|
|
5810
5851
|
rate_id: "dlvrt_mock_standard",
|
|
5811
5852
|
name: "Standard",
|
|
5812
5853
|
fee: standardFree ? money(0) : money(15),
|
|
5854
|
+
fee_status: "priced",
|
|
5813
5855
|
currency: "GHS",
|
|
5814
5856
|
free_delivery_applied: standardFree,
|
|
5815
5857
|
free_over_amount: money(200),
|
|
@@ -5823,6 +5865,7 @@ function createDeliveryService() {
|
|
|
5823
5865
|
name: "Express",
|
|
5824
5866
|
description: "Delivered within the hour",
|
|
5825
5867
|
fee: money(25),
|
|
5868
|
+
fee_status: "priced",
|
|
5826
5869
|
currency: "GHS",
|
|
5827
5870
|
free_delivery_applied: false,
|
|
5828
5871
|
eta_min_minutes: 30,
|
package/dist/mock/msw.js
CHANGED
|
@@ -2100,6 +2100,8 @@ var ERROR_SUGGESTIONS = {
|
|
|
2100
2100
|
CARD_DECLINED: "Card was declined. Ask shopper to retry or switch payment method.",
|
|
2101
2101
|
INVALID_OTP: "Authorization code is invalid. Let shopper re-enter OTP/PIN and retry.",
|
|
2102
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.",
|
|
2103
2105
|
AUTHORIZATION_FAILED: "Additional payment authorization failed. Retry authorization or change payment method.",
|
|
2104
2106
|
PAYMENT_ACTION_NOT_COMPLETED: "Required payment action was not completed. Resume provider flow and poll for status.",
|
|
2105
2107
|
SLOT_UNAVAILABLE: "Selected schedule slot is unavailable. Refresh available slots and ask shopper to reselect.",
|
|
@@ -2512,6 +2514,36 @@ function buildV1(deps) {
|
|
|
2512
2514
|
"/catalogue/quotes/:quote_id/refresh",
|
|
2513
2515
|
(c) => tryRoute(c, () => deps.catalogue.refreshQuote(c.req.param("quote_id")))
|
|
2514
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
|
+
});
|
|
2515
2547
|
app.get("/cart", (c) => tryRoute(c, () => deps.cart.toUICart(deps.cart.get(c.var.session))));
|
|
2516
2548
|
app.delete("/cart", (c) => tryRoute(c, () => deps.cart.clear(c.var.session)));
|
|
2517
2549
|
app.get("/cart/items", (c) => tryRoute(c, () => deps.cart.getItems(c.var.session)));
|
|
@@ -3407,9 +3439,10 @@ function buildLink(deps) {
|
|
|
3407
3439
|
app.post("/auth/request-otp", async (c) => {
|
|
3408
3440
|
const body = await c.req.json().catch(() => ({}));
|
|
3409
3441
|
return tryRoute(c, () => {
|
|
3410
|
-
deps.auth.requestOtp(body.contact ?? "");
|
|
3442
|
+
const challenge = deps.auth.requestOtp(body.contact ?? "");
|
|
3411
3443
|
return {
|
|
3412
3444
|
success: true,
|
|
3445
|
+
challenge_id: challenge.otp_id,
|
|
3413
3446
|
message: `OTP sent to ${body.contact ?? "contact"}`,
|
|
3414
3447
|
expires_in: 300,
|
|
3415
3448
|
is_new_account: false
|
|
@@ -3419,7 +3452,11 @@ function buildLink(deps) {
|
|
|
3419
3452
|
app.post("/auth/verify-otp", async (c) => {
|
|
3420
3453
|
const body = await c.req.json().catch(() => ({}));
|
|
3421
3454
|
return tryRoute(c, () => {
|
|
3422
|
-
const session = deps.auth.verifyOtp(
|
|
3455
|
+
const session = deps.auth.verifyOtp(
|
|
3456
|
+
body.contact ?? "",
|
|
3457
|
+
body.otp_code ?? "",
|
|
3458
|
+
body.challenge_id
|
|
3459
|
+
);
|
|
3423
3460
|
c.header("x-session-token", session.token);
|
|
3424
3461
|
const customer = deps.link.ensureCustomer(session.customer_id ?? session.id, {
|
|
3425
3462
|
email: body.contact?.includes("@") ? body.contact : void 0,
|
|
@@ -3513,10 +3550,7 @@ function buildLink(deps) {
|
|
|
3513
3550
|
};
|
|
3514
3551
|
});
|
|
3515
3552
|
});
|
|
3516
|
-
app.get(
|
|
3517
|
-
"/preferences",
|
|
3518
|
-
(c) => tryRoute(c, () => deps.link.getPreferences(customerId(c)))
|
|
3519
|
-
);
|
|
3553
|
+
app.get("/preferences", (c) => tryRoute(c, () => deps.link.getPreferences(customerId(c))));
|
|
3520
3554
|
app.post("/preferences", async (c) => {
|
|
3521
3555
|
const body = await c.req.json().catch(() => ({}));
|
|
3522
3556
|
return tryRoute(c, () => {
|
|
@@ -3993,9 +4027,16 @@ function createAuthService(opts) {
|
|
|
3993
4027
|
code_hint: options.mode === "permissive" ? code : void 0
|
|
3994
4028
|
};
|
|
3995
4029
|
},
|
|
3996
|
-
verifyOtp(contact, code) {
|
|
3997
|
-
|
|
3998
|
-
|
|
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
|
+
}
|
|
3999
4040
|
if (options.mode === "strict") {
|
|
4000
4041
|
if (!otp) throw new Error("No OTP requested");
|
|
4001
4042
|
if (otp.code !== code && code !== options.defaultOtp) throw new Error("Invalid OTP");
|
|
@@ -5323,7 +5364,7 @@ function createCartService(opts) {
|
|
|
5323
5364
|
|
|
5324
5365
|
// src/mock/domain/checkout.ts
|
|
5325
5366
|
function createCheckoutService(opts) {
|
|
5326
|
-
const { registry, clock, ids, bus} = opts;
|
|
5367
|
+
const { registry, clock, ids, bus } = opts;
|
|
5327
5368
|
return {
|
|
5328
5369
|
process(session, body) {
|
|
5329
5370
|
if (!body.cart_id) throw validation("cart_id required");
|
|
@@ -5810,6 +5851,7 @@ function createDeliveryService() {
|
|
|
5810
5851
|
rate_id: "dlvrt_mock_standard",
|
|
5811
5852
|
name: "Standard",
|
|
5812
5853
|
fee: standardFree ? money(0) : money(15),
|
|
5854
|
+
fee_status: "priced",
|
|
5813
5855
|
currency: "GHS",
|
|
5814
5856
|
free_delivery_applied: standardFree,
|
|
5815
5857
|
free_over_amount: money(200),
|
|
@@ -5823,6 +5865,7 @@ function createDeliveryService() {
|
|
|
5823
5865
|
name: "Express",
|
|
5824
5866
|
description: "Delivered within the hour",
|
|
5825
5867
|
fee: money(25),
|
|
5868
|
+
fee_status: "priced",
|
|
5826
5869
|
currency: "GHS",
|
|
5827
5870
|
free_delivery_applied: false,
|
|
5828
5871
|
eta_min_minutes: 30,
|
package/dist/mock/msw.mjs
CHANGED
|
@@ -2098,6 +2098,8 @@ var ERROR_SUGGESTIONS = {
|
|
|
2098
2098
|
CARD_DECLINED: "Card was declined. Ask shopper to retry or switch payment method.",
|
|
2099
2099
|
INVALID_OTP: "Authorization code is invalid. Let shopper re-enter OTP/PIN and retry.",
|
|
2100
2100
|
OTP_EXPIRED: "Authorization code expired. Request a new OTP and re-submit authorization.",
|
|
2101
|
+
OTP_CHALLENGE_EXHAUSTED: "This verification challenge has no attempts left. Continue checkout without saved details or request a fresh challenge.",
|
|
2102
|
+
OTP_CHALLENGE_CONSUMED: "This verification challenge has already been used. Continue with the established session or request a fresh challenge.",
|
|
2101
2103
|
AUTHORIZATION_FAILED: "Additional payment authorization failed. Retry authorization or change payment method.",
|
|
2102
2104
|
PAYMENT_ACTION_NOT_COMPLETED: "Required payment action was not completed. Resume provider flow and poll for status.",
|
|
2103
2105
|
SLOT_UNAVAILABLE: "Selected schedule slot is unavailable. Refresh available slots and ask shopper to reselect.",
|
|
@@ -2510,6 +2512,36 @@ function buildV1(deps) {
|
|
|
2510
2512
|
"/catalogue/quotes/:quote_id/refresh",
|
|
2511
2513
|
(c) => tryRoute(c, () => deps.catalogue.refreshQuote(c.req.param("quote_id")))
|
|
2512
2514
|
);
|
|
2515
|
+
app.get("/reviews/summary", (c) => {
|
|
2516
|
+
const productId = c.req.query("product_id");
|
|
2517
|
+
if (productId !== void 0 && (productId.length === 0 || productId.trim() !== productId)) {
|
|
2518
|
+
return fail(c, validation("product_id must be a non-empty canonical identifier"));
|
|
2519
|
+
}
|
|
2520
|
+
const response = {
|
|
2521
|
+
data: {
|
|
2522
|
+
ratings: {
|
|
2523
|
+
product_id: productId ?? null,
|
|
2524
|
+
review_count: 0,
|
|
2525
|
+
rating_sum: 0,
|
|
2526
|
+
average_rating: null,
|
|
2527
|
+
distribution: { one: 0, two: 0, three: 0, four: 0, five: 0 }
|
|
2528
|
+
},
|
|
2529
|
+
trust_chips: {
|
|
2530
|
+
on_time_delivery_percent: null,
|
|
2531
|
+
delivery_sample_size: 0,
|
|
2532
|
+
average_first_response_seconds: null,
|
|
2533
|
+
support_sample_size: 0
|
|
2534
|
+
}
|
|
2535
|
+
}
|
|
2536
|
+
};
|
|
2537
|
+
return c.json(response);
|
|
2538
|
+
});
|
|
2539
|
+
app.get("/reviews", (c) => {
|
|
2540
|
+
const response = {
|
|
2541
|
+
data: { items: [], next_cursor: null }
|
|
2542
|
+
};
|
|
2543
|
+
return c.json(response);
|
|
2544
|
+
});
|
|
2513
2545
|
app.get("/cart", (c) => tryRoute(c, () => deps.cart.toUICart(deps.cart.get(c.var.session))));
|
|
2514
2546
|
app.delete("/cart", (c) => tryRoute(c, () => deps.cart.clear(c.var.session)));
|
|
2515
2547
|
app.get("/cart/items", (c) => tryRoute(c, () => deps.cart.getItems(c.var.session)));
|
|
@@ -3405,9 +3437,10 @@ function buildLink(deps) {
|
|
|
3405
3437
|
app.post("/auth/request-otp", async (c) => {
|
|
3406
3438
|
const body = await c.req.json().catch(() => ({}));
|
|
3407
3439
|
return tryRoute(c, () => {
|
|
3408
|
-
deps.auth.requestOtp(body.contact ?? "");
|
|
3440
|
+
const challenge = deps.auth.requestOtp(body.contact ?? "");
|
|
3409
3441
|
return {
|
|
3410
3442
|
success: true,
|
|
3443
|
+
challenge_id: challenge.otp_id,
|
|
3411
3444
|
message: `OTP sent to ${body.contact ?? "contact"}`,
|
|
3412
3445
|
expires_in: 300,
|
|
3413
3446
|
is_new_account: false
|
|
@@ -3417,7 +3450,11 @@ function buildLink(deps) {
|
|
|
3417
3450
|
app.post("/auth/verify-otp", async (c) => {
|
|
3418
3451
|
const body = await c.req.json().catch(() => ({}));
|
|
3419
3452
|
return tryRoute(c, () => {
|
|
3420
|
-
const session = deps.auth.verifyOtp(
|
|
3453
|
+
const session = deps.auth.verifyOtp(
|
|
3454
|
+
body.contact ?? "",
|
|
3455
|
+
body.otp_code ?? "",
|
|
3456
|
+
body.challenge_id
|
|
3457
|
+
);
|
|
3421
3458
|
c.header("x-session-token", session.token);
|
|
3422
3459
|
const customer = deps.link.ensureCustomer(session.customer_id ?? session.id, {
|
|
3423
3460
|
email: body.contact?.includes("@") ? body.contact : void 0,
|
|
@@ -3511,10 +3548,7 @@ function buildLink(deps) {
|
|
|
3511
3548
|
};
|
|
3512
3549
|
});
|
|
3513
3550
|
});
|
|
3514
|
-
app.get(
|
|
3515
|
-
"/preferences",
|
|
3516
|
-
(c) => tryRoute(c, () => deps.link.getPreferences(customerId(c)))
|
|
3517
|
-
);
|
|
3551
|
+
app.get("/preferences", (c) => tryRoute(c, () => deps.link.getPreferences(customerId(c))));
|
|
3518
3552
|
app.post("/preferences", async (c) => {
|
|
3519
3553
|
const body = await c.req.json().catch(() => ({}));
|
|
3520
3554
|
return tryRoute(c, () => {
|
|
@@ -3991,9 +4025,16 @@ function createAuthService(opts) {
|
|
|
3991
4025
|
code_hint: options.mode === "permissive" ? code : void 0
|
|
3992
4026
|
};
|
|
3993
4027
|
},
|
|
3994
|
-
verifyOtp(contact, code) {
|
|
3995
|
-
|
|
3996
|
-
|
|
4028
|
+
verifyOtp(contact, code, challengeId) {
|
|
4029
|
+
let otp = challengeId ? registry.otps.get(challengeId) : void 0;
|
|
4030
|
+
if (!challengeId) {
|
|
4031
|
+
const matching = registry.otps.list((o) => o.contact === contact);
|
|
4032
|
+
otp = matching[matching.length - 1];
|
|
4033
|
+
}
|
|
4034
|
+
if (challengeId) {
|
|
4035
|
+
if (!otp) throw new Error("No OTP challenge found");
|
|
4036
|
+
if (otp.contact !== contact) throw new Error("OTP challenge does not match contact");
|
|
4037
|
+
}
|
|
3997
4038
|
if (options.mode === "strict") {
|
|
3998
4039
|
if (!otp) throw new Error("No OTP requested");
|
|
3999
4040
|
if (otp.code !== code && code !== options.defaultOtp) throw new Error("Invalid OTP");
|
|
@@ -5321,7 +5362,7 @@ function createCartService(opts) {
|
|
|
5321
5362
|
|
|
5322
5363
|
// src/mock/domain/checkout.ts
|
|
5323
5364
|
function createCheckoutService(opts) {
|
|
5324
|
-
const { registry, clock, ids, bus} = opts;
|
|
5365
|
+
const { registry, clock, ids, bus } = opts;
|
|
5325
5366
|
return {
|
|
5326
5367
|
process(session, body) {
|
|
5327
5368
|
if (!body.cart_id) throw validation("cart_id required");
|
|
@@ -5808,6 +5849,7 @@ function createDeliveryService() {
|
|
|
5808
5849
|
rate_id: "dlvrt_mock_standard",
|
|
5809
5850
|
name: "Standard",
|
|
5810
5851
|
fee: standardFree ? money(0) : money(15),
|
|
5852
|
+
fee_status: "priced",
|
|
5811
5853
|
currency: "GHS",
|
|
5812
5854
|
free_delivery_applied: standardFree,
|
|
5813
5855
|
free_over_amount: money(200),
|
|
@@ -5821,6 +5863,7 @@ function createDeliveryService() {
|
|
|
5821
5863
|
name: "Express",
|
|
5822
5864
|
description: "Delivered within the hour",
|
|
5823
5865
|
fee: money(25),
|
|
5866
|
+
fee_status: "priced",
|
|
5824
5867
|
currency: "GHS",
|
|
5825
5868
|
free_delivery_applied: false,
|
|
5826
5869
|
eta_min_minutes: 30,
|