@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.
Files changed (65) hide show
  1. package/dist/advanced.d.mts +3 -3
  2. package/dist/advanced.d.ts +3 -3
  3. package/dist/advanced.js +22 -22
  4. package/dist/advanced.mjs +3 -3
  5. package/dist/{chunk-C2JSNJUC.mjs → chunk-2WPVUIHX.mjs} +52 -11
  6. package/dist/{chunk-JG5CQNCB.js → chunk-4BKOKHE3.js} +4 -0
  7. package/dist/{chunk-R6OLQ33I.js → chunk-5BDYDZ4U.js} +239 -87
  8. package/dist/{chunk-H7ACMHM3.mjs → chunk-5RT4HYMP.mjs} +32 -4
  9. package/dist/{chunk-NNG6IFFX.js → chunk-7PDEX54K.js} +3 -3
  10. package/dist/{chunk-M4URVKHE.mjs → chunk-DYIAX3WI.mjs} +1 -1
  11. package/dist/{chunk-QOWPGS7Z.js → chunk-E4K2VQDD.js} +35 -5
  12. package/dist/{chunk-VNPEYLB2.mjs → chunk-H3RATH4B.mjs} +4 -0
  13. package/dist/{chunk-JSWJ4XDE.js → chunk-IQFFSKE2.js} +315 -108
  14. package/dist/{chunk-J6PNHDHL.mjs → chunk-OCCNG6MO.mjs} +284 -77
  15. package/dist/{chunk-GERXZQSX.mjs → chunk-OKADBZAI.mjs} +171 -20
  16. package/dist/{chunk-VIL6IQCG.js → chunk-YVAEY3VC.js} +54 -13
  17. package/dist/{client-Dqg2mc-7.d.ts → client-BVNWjk6W.d.ts} +2 -2
  18. package/dist/{client-BfpNjJ_a.d.mts → client-BuLcOWLv.d.ts} +115 -23
  19. package/dist/{client-DHBwvh7U.d.ts → client-D5AoobFc.d.mts} +115 -23
  20. package/dist/{client-DpqRobY9.d.mts → client-fM716k7G.d.mts} +2 -2
  21. package/dist/{index-C8uDqLwJ.d.ts → index-BtcoqrY1.d.ts} +3 -3
  22. package/dist/{index-e2y6AK70.d.mts → index-D7Tf3v7c.d.mts} +3 -3
  23. package/dist/index.d.mts +10 -8
  24. package/dist/index.d.ts +10 -8
  25. package/dist/index.js +107 -106
  26. package/dist/index.mjs +6 -5
  27. package/dist/{link-cuNVYc2s.d.mts → link-D9iSVxt5.d.mts} +12 -1
  28. package/dist/{link-cuNVYc2s.d.ts → link-D9iSVxt5.d.ts} +12 -1
  29. package/dist/mock/cli.mjs +53 -10
  30. package/dist/mock/library.js +53 -10
  31. package/dist/mock/library.mjs +53 -10
  32. package/dist/mock/msw.js +53 -10
  33. package/dist/mock/msw.mjs +53 -10
  34. package/dist/{payment-H5LoIvXU.d.mts → payment-g0HFkEDU.d.mts} +519 -54
  35. package/dist/{payment-H5LoIvXU.d.ts → payment-g0HFkEDU.d.ts} +519 -54
  36. package/dist/{price-C2RqscMY.d.ts → price-BLIeAb8K.d.ts} +1 -1
  37. package/dist/{price-BvePgDXe.d.mts → price-Czq_cTC_.d.mts} +1 -1
  38. package/dist/react.d.mts +4 -4
  39. package/dist/react.d.ts +4 -4
  40. package/dist/react.js +193 -169
  41. package/dist/react.mjs +54 -30
  42. package/dist/{server-C7FyLdrz.d.mts → server-BkVhOIwn.d.mts} +4 -2
  43. package/dist/{server-DoXIpSd7.d.ts → server-DKK_D-PP.d.ts} +4 -2
  44. package/dist/server.d.mts +4 -4
  45. package/dist/server.d.ts +4 -4
  46. package/dist/server.js +11 -10
  47. package/dist/server.mjs +5 -4
  48. package/dist/testing/msw.d.mts +2 -2
  49. package/dist/testing/msw.d.ts +2 -2
  50. package/dist/testing/msw.js +3 -3
  51. package/dist/testing/msw.mjs +2 -2
  52. package/dist/testing/suite.d.mts +6 -6
  53. package/dist/testing/suite.d.ts +6 -6
  54. package/dist/testing/suite.js +25 -25
  55. package/dist/testing/suite.mjs +6 -6
  56. package/dist/testing.d.mts +46 -6
  57. package/dist/testing.d.ts +46 -6
  58. package/dist/testing.js +94 -82
  59. package/dist/testing.mjs +13 -9
  60. package/dist/utils.d.mts +4 -4
  61. package/dist/utils.d.ts +4 -4
  62. package/dist/utils.js +31 -31
  63. package/dist/utils.mjs +2 -2
  64. package/package.json +1 -1
  65. package/registry/chat-widget.json +1 -1
@@ -1,5 +1,6 @@
1
- import { safe, generateIdempotencyKey, err, ok, CatalogueQueries, CartOperations, CheckoutService, OrderQueries, LinkService, AuthService, BusinessService, InventoryService, SchedulingService, LiteService, FxService, createElements } from './chunk-J6PNHDHL.mjs';
2
- import { CimplifyError, ErrorCode, IdempotencyMismatchError, enrichError } from './chunk-VNPEYLB2.mjs';
1
+ import { messagePreview } from './chunk-U4MW6PYU.mjs';
2
+ import { safe, generateIdempotencyKey, err, ok, CatalogueQueries, CartOperations, CheckoutService, OrderQueries, LinkService, AuthService, BusinessService, InventoryService, SchedulingService, LiteService, FxService, createElements } from './chunk-OCCNG6MO.mjs';
3
+ import { CimplifyError, ErrorCode, IdempotencyMismatchError, enrichError } from './chunk-H3RATH4B.mjs';
3
4
 
4
5
  // src/store-credit.ts
5
6
  var StoreCreditQueries = class {
@@ -206,6 +207,7 @@ var ActivityService = class {
206
207
  utm_campaign: utm("campaign"),
207
208
  utm_term: utm("term"),
208
209
  utm_content: utm("content"),
210
+ social_commerce_ref: params.get("social_commerce_ref") || void 0,
209
211
  screen_width: window.screen?.width,
210
212
  screen_height: window.screen?.height,
211
213
  viewport_width: window.innerWidth,
@@ -414,14 +416,14 @@ var UploadService = class {
414
416
  constructor(client) {
415
417
  this.client = client;
416
418
  }
417
- async init(filename, contentType, sizeBytes, opts) {
419
+ async init(filename, contentType2, sizeBytes, opts) {
418
420
  const idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey();
419
421
  return safe(
420
422
  this.client.post(
421
423
  "/api/v1/uploads/init",
422
424
  {
423
425
  filename,
424
- content_type: contentType,
426
+ content_type: contentType2,
425
427
  size_bytes: sizeBytes
426
428
  },
427
429
  { idempotencyKey }
@@ -522,6 +524,99 @@ var DeliveryService = class {
522
524
  }
523
525
  };
524
526
 
527
+ // src/chat-wire.ts
528
+ function senderType(message) {
529
+ if (message.sender_side === "account") return "customer";
530
+ if (message.sender_side === "system") return "system";
531
+ return message.authorship === "ai" ? "bot" : "agent";
532
+ }
533
+ function contentType(message) {
534
+ if (message.content_type === "rich") {
535
+ return message.structured_content?.["kind"] === "reaction" ? "reaction" : "interactive";
536
+ }
537
+ if (message.content_type === "media") {
538
+ const mime = message.media[0]?.mime_type ?? "";
539
+ if (mime.startsWith("image/")) return "image";
540
+ if (mime.startsWith("video/")) return "video";
541
+ if (mime.startsWith("audio/")) return "audio";
542
+ return "document";
543
+ }
544
+ return "text";
545
+ }
546
+ function unresolvedReply(id) {
547
+ return { id, sender_type: "system", preview: "Earlier message" };
548
+ }
549
+ function chatMessagesFromWire(messages) {
550
+ const converted = messages.map((message) => ({
551
+ id: message.id,
552
+ sequence: message.sequence,
553
+ sender_type: senderType(message),
554
+ content: message.content,
555
+ content_type: contentType(message),
556
+ attachments: Array.isArray(message.media) ? message.media : [],
557
+ metadata: message.structured_content ?? {},
558
+ reply_to: message.reply_to_message_id ? unresolvedReply(message.reply_to_message_id) : void 0,
559
+ edited_at: message.edited_at,
560
+ deleted_at: message.deleted_at,
561
+ created_at: message.created_at
562
+ }));
563
+ const byId = new Map(converted.map((message) => [message.id, message]));
564
+ return converted.map((message) => {
565
+ const targetId = message.reply_to?.id;
566
+ const target = targetId ? byId.get(targetId) : void 0;
567
+ if (!targetId || !target) return message;
568
+ return {
569
+ ...message,
570
+ reply_to: {
571
+ id: targetId,
572
+ sender_type: target.sender_type,
573
+ preview: messagePreview(target.content)
574
+ }
575
+ };
576
+ });
577
+ }
578
+ function chatMessageFromWire(message) {
579
+ return chatMessagesFromWire([message])[0];
580
+ }
581
+ function chatRealtimeUpdateFromWire(envelope) {
582
+ if (envelope.type === "message_created" && envelope.data) {
583
+ return {
584
+ kind: "message",
585
+ message: chatMessageFromWire(envelope.data)
586
+ };
587
+ }
588
+ if (envelope.type === "message_updated" && envelope.data) {
589
+ return {
590
+ kind: "message_updated",
591
+ message: chatMessageFromWire(envelope.data)
592
+ };
593
+ }
594
+ if (envelope.type === "read" && envelope.data) {
595
+ const read = envelope.data;
596
+ if (read.reader_side === "business" && typeof read.occurred_at === "string") {
597
+ return { kind: "business_read", occurredAt: read.occurred_at };
598
+ }
599
+ return { kind: "none" };
600
+ }
601
+ if (envelope.type === "history_imported") {
602
+ return { kind: "reload" };
603
+ }
604
+ if (envelope.type === "ai_mode_changed" && envelope.data) {
605
+ const mode = envelope.data.mode;
606
+ if (mode === "auto" || mode === "assist" || mode === "off") {
607
+ return { kind: "ai_mode", mode };
608
+ }
609
+ return { kind: "none" };
610
+ }
611
+ if (envelope.type === "handoff_requested") {
612
+ return { kind: "handoff" };
613
+ }
614
+ if (envelope.type === "resync") {
615
+ return { kind: "resync", latestSequence: envelope.latest_sequence };
616
+ }
617
+ return { kind: "none" };
618
+ }
619
+
525
620
  // src/internal/events.ts
526
621
  var MUTATION_ERROR = "mutation:error";
527
622
  var AUTH_TOKEN_CHANGED = "auth:token-changed";
@@ -584,11 +679,13 @@ var SupportService = class {
584
679
  * Claim the anonymous session for the verified Link identity: the server
585
680
  * verifies the access token, rotates the session token (adopted here, so
586
681
  * every subsequent request rides the bound session), folds the guest cart
587
- * in, and adopts or merges the widget conversation.
682
+ * in, and opens or reuses the account's canonical direct Chat thread.
588
683
  *
589
684
  * Idempotent and single-flight: concurrent calls share one request, and a
590
685
  * token already claimed by this instance short-circuits without a network
591
- * round trip. Emits `session:claimed` on the client's event channel.
686
+ * round trip. A session already bound to another Link account is rejected
687
+ * rather than transferring that account's cart. Emits `session:claimed` on
688
+ * the client's event channel.
592
689
  */
593
690
  async claimConversation() {
594
691
  const accessToken = this.client.getAccessToken();
@@ -625,7 +722,7 @@ var SupportService = class {
625
722
  this.client.publishSessionClaimed(this.claimedName);
626
723
  this.client.events.emit(SESSION_CLAIMED, {
627
724
  sessionToken: result.value.session_token,
628
- threadId: result.value.thread_id ?? null,
725
+ threadId: result.value.thread.id,
629
726
  customerName: result.value.customer_name
630
727
  });
631
728
  }
@@ -638,6 +735,25 @@ var SupportService = class {
638
735
  this.claimInFlightToken = null;
639
736
  }
640
737
  }
738
+ /**
739
+ * Retry verified external-history discovery for the current storefront.
740
+ * Launch scope is intentionally WhatsApp-only because it is the registered
741
+ * bidirectional transport. Results are per envelope and omit provider ids,
742
+ * contact values, account ids, and message bodies.
743
+ */
744
+ async claimExternalChats() {
745
+ if (!this.client.getAccessToken()) {
746
+ return err(new CimplifyError("not_authenticated", "No access token to claim with"));
747
+ }
748
+ return safe(
749
+ (async () => {
750
+ const businessId = await this.client.resolveBusinessId();
751
+ return this.client.post("/v1/me/chats/external-claims", {
752
+ business_id: businessId
753
+ });
754
+ })()
755
+ );
756
+ }
641
757
  /**
642
758
  * Peek at the conversation without creating one: resolves the existing
643
759
  * thread (or null) so a page load can hydrate history without littering
@@ -651,17 +767,22 @@ var SupportService = class {
651
767
  if (!result.value.conversation) return ok(null);
652
768
  return ok({
653
769
  conversation: result.value.conversation,
654
- messages: result.value.messages
770
+ messages: chatMessagesFromWire(result.value.messages)
655
771
  });
656
772
  }
657
773
  /** Open (or resume) the customer's widget conversation. */
658
774
  async openConversation(opts) {
659
775
  const idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey();
660
- return safe(
776
+ const result = await safe(
661
777
  this.client.post("/api/v1/support/conversation", void 0, {
662
778
  idempotencyKey
663
779
  })
664
780
  );
781
+ if (!result.ok) return result;
782
+ return ok({
783
+ conversation: result.value.conversation,
784
+ messages: chatMessagesFromWire(result.value.messages)
785
+ });
665
786
  }
666
787
  /**
667
788
  * Send a message in the active conversation.
@@ -673,7 +794,7 @@ var SupportService = class {
673
794
  */
674
795
  async sendMessage(content, opts) {
675
796
  const idempotencyKey = opts?.idempotencyKey ?? generateIdempotencyKey();
676
- return safe(
797
+ const result = await safe(
677
798
  this.client.post(
678
799
  "/api/v1/support/conversation/messages",
679
800
  {
@@ -685,6 +806,7 @@ var SupportService = class {
685
806
  { idempotencyKey }
686
807
  )
687
808
  );
809
+ return result.ok ? ok(chatMessageFromWire(result.value.message)) : result;
688
810
  }
689
811
  /**
690
812
  * Poll for messages. `after` pages forward (live updates); `before` pages
@@ -692,21 +814,27 @@ var SupportService = class {
692
814
  */
693
815
  async getMessages(options = {}) {
694
816
  const params = new URLSearchParams();
695
- if (options.after) params.set("after", options.after);
696
- if (options.before) params.set("before", options.before);
817
+ if (options.afterSequence !== void 0)
818
+ params.set("after_sequence", String(options.afterSequence));
819
+ if (options.beforeSequence !== void 0)
820
+ params.set("before_sequence", String(options.beforeSequence));
697
821
  if (options.limit) params.set("limit", String(options.limit));
698
822
  const query = params.toString();
699
823
  const path = query ? `/api/v1/support/conversation/messages?${query}` : "/api/v1/support/conversation/messages";
700
- return safe(this.client.get(path));
824
+ const result = await safe(this.client.get(path));
825
+ return result.ok ? ok(chatMessagesFromWire(result.value)) : result;
701
826
  }
702
827
  /** React to a message in the active conversation by its `ChatMessage.id`. */
703
828
  async reactToMessage(messageId, emoji) {
704
- return safe(
829
+ const clientId = generateIdempotencyKey();
830
+ const result = await safe(
705
831
  this.client.post(
706
832
  `/api/v1/support/conversation/messages/${messageId}/reactions`,
707
- { emoji }
833
+ { emoji, client_id: clientId },
834
+ { idempotencyKey: clientId }
708
835
  )
709
836
  );
837
+ return result.ok ? ok(chatMessageFromWire(result.value.message)) : result;
710
838
  }
711
839
  /** Ask for a person: flags the thread for the merchant's inbox. */
712
840
  async requestHuman(opts) {
@@ -843,10 +971,10 @@ var PaystackAuthorizationAdapter = class {
843
971
  };
844
972
 
845
973
  // src/payment-authorization/providers/stripe.ts
846
- async function loadStripeFromPeer(publicKey) {
974
+ async function loadStripeFromPeer(publicKey, options) {
847
975
  try {
848
976
  const imported = await import('@stripe/stripe-js');
849
- return imported.loadStripe ? imported.loadStripe(publicKey) : null;
977
+ return imported.loadStripe ? imported.loadStripe(publicKey, options) : null;
850
978
  } catch {
851
979
  return null;
852
980
  }
@@ -954,7 +1082,10 @@ var StripeAuthorizationAdapter = class {
954
1082
  }
955
1083
  let stripe;
956
1084
  try {
957
- stripe = await this.loadStripe(context.action.public_key);
1085
+ stripe = await this.loadStripe(
1086
+ context.action.public_key,
1087
+ context.action.provider_account_id ? { stripeAccount: context.action.provider_account_id } : void 0
1088
+ );
958
1089
  } catch (error) {
959
1090
  return {
960
1091
  status: "failed",
@@ -1377,7 +1508,8 @@ var CimplifyClient = class {
1377
1508
  * refresh restore) binds the anonymous session so the conversation, cart
1378
1509
  * and orders survive a cleared browser. Best-effort by design — a failed
1379
1510
  * claim leaves the session anonymous, exactly as it was. Called by the
1380
- * auth flows, never by the raw token setter.
1511
+ * merchant auth flows, never by the raw token setter. Global Link clients
1512
+ * have no storefront tenant and therefore activate without this step.
1381
1513
  */
1382
1514
  autoClaimChatIdentity() {
1383
1515
  if (typeof window === "undefined" || !this.sessionToken || !this.accessToken) return;
@@ -1419,9 +1551,28 @@ var CimplifyClient = class {
1419
1551
  getSessionEpoch() {
1420
1552
  return this.sessionEpoch;
1421
1553
  }
1554
+ /** Monotonic fence for async work scoped to the current storefront tenant. */
1555
+ getPublicKeyEpoch() {
1556
+ return this.publicKeyEpoch;
1557
+ }
1422
1558
  getSessionToken() {
1423
1559
  return this.sessionToken;
1424
1560
  }
1561
+ /** Whether the current transport session is known to have been claimed for
1562
+ * a Link identity, even when its in-memory bearer is absent after reload or
1563
+ * a failed refresh. The sync marker is written only after canonical claim
1564
+ * rotation and is replaced with `cleared` when a fresh session is minted. */
1565
+ hasClaimedSessionAuthority() {
1566
+ if (!this.sessionToken) return false;
1567
+ try {
1568
+ const raw = this.safeStorage()?.getItem(SESSION_SYNC_STORAGE_KEY);
1569
+ if (!raw) return false;
1570
+ const payload = JSON.parse(raw);
1571
+ return payload.type === "claimed" && payload.token === this.sessionToken;
1572
+ } catch {
1573
+ return false;
1574
+ }
1575
+ }
1425
1576
  publishSessionClaimed(customerName) {
1426
1577
  if (!this.sessionToken) return;
1427
1578
  this.broadcastSessionSync({
@@ -2048,4 +2199,4 @@ function createCimplifyClient(config = {}) {
2048
2199
  return new CimplifyClient(config);
2049
2200
  }
2050
2201
 
2051
- export { AUTH_TOKEN_CHANGED, ActivityService, CimplifyClient, DeliveryService, MUTATION_ERROR, PaymentAuthorizationAdapterRegistry, PaystackAuthorizationAdapter, PlacesService, SESSION_CLAIMED, SESSION_CLEARED, StoreCreditQueries, StripeAuthorizationAdapter, SubscriptionService, SupportService, UploadService, createCimplifyClient, createDefaultPaymentAuthorizationAdapterRegistry };
2202
+ export { AUTH_TOKEN_CHANGED, ActivityService, CimplifyClient, DeliveryService, MUTATION_ERROR, PaymentAuthorizationAdapterRegistry, PaystackAuthorizationAdapter, PlacesService, SESSION_CLAIMED, SESSION_CLEARED, StoreCreditQueries, StripeAuthorizationAdapter, SubscriptionService, SupportService, UploadService, chatRealtimeUpdateFromWire, createCimplifyClient, createDefaultPaymentAuthorizationAdapterRegistry };
@@ -2,7 +2,7 @@
2
2
 
3
3
  var chunkXREIZ56K_js = require('./chunk-XREIZ56K.js');
4
4
  var chunkCNN7Z2IP_js = require('./chunk-CNN7Z2IP.js');
5
- var chunkJG5CQNCB_js = require('./chunk-JG5CQNCB.js');
5
+ var chunk4BKOKHE3_js = require('./chunk-4BKOKHE3.js');
6
6
  var chunkOWW5GUSB_js = require('./chunk-OWW5GUSB.js');
7
7
 
8
8
  // ../node_modules/.bun/hono@4.12.25/node_modules/hono/dist/compose.js
@@ -2078,8 +2078,8 @@ var MockError = class extends Error {
2078
2078
  };
2079
2079
  }
2080
2080
  };
2081
- var notFound = (msg) => new MockError(chunkJG5CQNCB_js.ErrorCode.NOT_FOUND, msg, 404);
2082
- var validation = (msg, ctx) => new MockError(chunkJG5CQNCB_js.ErrorCode.VALIDATION_ERROR, msg, 400, ctx);
2081
+ var notFound = (msg) => new MockError(chunk4BKOKHE3_js.ErrorCode.NOT_FOUND, msg, 404);
2082
+ var validation = (msg, ctx) => new MockError(chunk4BKOKHE3_js.ErrorCode.VALIDATION_ERROR, msg, 400, ctx);
2083
2083
 
2084
2084
  // src/mock/routes/_helpers.ts
2085
2085
  function authMiddleware(deps) {
@@ -2437,6 +2437,36 @@ function buildV1(deps) {
2437
2437
  "/catalogue/quotes/:quote_id/refresh",
2438
2438
  (c) => tryRoute(c, () => deps.catalogue.refreshQuote(c.req.param("quote_id")))
2439
2439
  );
2440
+ app.get("/reviews/summary", (c) => {
2441
+ const productId = c.req.query("product_id");
2442
+ if (productId !== void 0 && (productId.length === 0 || productId.trim() !== productId)) {
2443
+ return fail(c, validation("product_id must be a non-empty canonical identifier"));
2444
+ }
2445
+ const response = {
2446
+ data: {
2447
+ ratings: {
2448
+ product_id: productId ?? null,
2449
+ review_count: 0,
2450
+ rating_sum: 0,
2451
+ average_rating: null,
2452
+ distribution: { one: 0, two: 0, three: 0, four: 0, five: 0 }
2453
+ },
2454
+ trust_chips: {
2455
+ on_time_delivery_percent: null,
2456
+ delivery_sample_size: 0,
2457
+ average_first_response_seconds: null,
2458
+ support_sample_size: 0
2459
+ }
2460
+ }
2461
+ };
2462
+ return c.json(response);
2463
+ });
2464
+ app.get("/reviews", (c) => {
2465
+ const response = {
2466
+ data: { items: [], next_cursor: null }
2467
+ };
2468
+ return c.json(response);
2469
+ });
2440
2470
  app.get("/cart", (c) => tryRoute(c, () => deps.cart.toUICart(deps.cart.get(c.var.session))));
2441
2471
  app.delete("/cart", (c) => tryRoute(c, () => deps.cart.clear(c.var.session)));
2442
2472
  app.get("/cart/items", (c) => tryRoute(c, () => deps.cart.getItems(c.var.session)));
@@ -3332,9 +3362,10 @@ function buildLink(deps) {
3332
3362
  app.post("/auth/request-otp", async (c) => {
3333
3363
  const body = await c.req.json().catch(() => ({}));
3334
3364
  return tryRoute(c, () => {
3335
- deps.auth.requestOtp(body.contact ?? "");
3365
+ const challenge = deps.auth.requestOtp(body.contact ?? "");
3336
3366
  return {
3337
3367
  success: true,
3368
+ challenge_id: challenge.otp_id,
3338
3369
  message: `OTP sent to ${body.contact ?? "contact"}`,
3339
3370
  expires_in: 300,
3340
3371
  is_new_account: false
@@ -3344,7 +3375,11 @@ function buildLink(deps) {
3344
3375
  app.post("/auth/verify-otp", async (c) => {
3345
3376
  const body = await c.req.json().catch(() => ({}));
3346
3377
  return tryRoute(c, () => {
3347
- const session = deps.auth.verifyOtp(body.contact ?? "", body.otp_code ?? "");
3378
+ const session = deps.auth.verifyOtp(
3379
+ body.contact ?? "",
3380
+ body.otp_code ?? "",
3381
+ body.challenge_id
3382
+ );
3348
3383
  c.header("x-session-token", session.token);
3349
3384
  const customer = deps.link.ensureCustomer(session.customer_id ?? session.id, {
3350
3385
  email: body.contact?.includes("@") ? body.contact : void 0,
@@ -3438,10 +3473,7 @@ function buildLink(deps) {
3438
3473
  };
3439
3474
  });
3440
3475
  });
3441
- app.get(
3442
- "/preferences",
3443
- (c) => tryRoute(c, () => deps.link.getPreferences(customerId(c)))
3444
- );
3476
+ app.get("/preferences", (c) => tryRoute(c, () => deps.link.getPreferences(customerId(c))));
3445
3477
  app.post("/preferences", async (c) => {
3446
3478
  const body = await c.req.json().catch(() => ({}));
3447
3479
  return tryRoute(c, () => {
@@ -3918,9 +3950,16 @@ function createAuthService(opts) {
3918
3950
  code_hint: options.mode === "permissive" ? code : void 0
3919
3951
  };
3920
3952
  },
3921
- verifyOtp(contact, code) {
3922
- const matching = registry.otps.list((o) => o.contact === contact);
3923
- const otp = matching[matching.length - 1];
3953
+ verifyOtp(contact, code, challengeId) {
3954
+ let otp = challengeId ? registry.otps.get(challengeId) : void 0;
3955
+ if (!challengeId) {
3956
+ const matching = registry.otps.list((o) => o.contact === contact);
3957
+ otp = matching[matching.length - 1];
3958
+ }
3959
+ if (challengeId) {
3960
+ if (!otp) throw new Error("No OTP challenge found");
3961
+ if (otp.contact !== contact) throw new Error("OTP challenge does not match contact");
3962
+ }
3924
3963
  if (options.mode === "strict") {
3925
3964
  if (!otp) throw new Error("No OTP requested");
3926
3965
  if (otp.code !== code && code !== options.defaultOtp) throw new Error("Invalid OTP");
@@ -5248,7 +5287,7 @@ function createCartService(opts) {
5248
5287
 
5249
5288
  // src/mock/domain/checkout.ts
5250
5289
  function createCheckoutService(opts) {
5251
- const { registry, clock, ids, bus} = opts;
5290
+ const { registry, clock, ids, bus } = opts;
5252
5291
  return {
5253
5292
  process(session, body) {
5254
5293
  if (!body.cart_id) throw validation("cart_id required");
@@ -5735,6 +5774,7 @@ function createDeliveryService() {
5735
5774
  rate_id: "dlvrt_mock_standard",
5736
5775
  name: "Standard",
5737
5776
  fee: standardFree ? money(0) : money(15),
5777
+ fee_status: "priced",
5738
5778
  currency: "GHS",
5739
5779
  free_delivery_applied: standardFree,
5740
5780
  free_over_amount: money(200),
@@ -5748,6 +5788,7 @@ function createDeliveryService() {
5748
5788
  name: "Express",
5749
5789
  description: "Delivered within the hour",
5750
5790
  fee: money(25),
5791
+ fee_status: "priced",
5751
5792
  currency: "GHS",
5752
5793
  free_delivery_applied: false,
5753
5794
  eta_min_minutes: 30,
@@ -1,5 +1,5 @@
1
- import { ac as CimplifyClient } from './client-DHBwvh7U.js';
2
- import { A as AppHandle, C as CreateAppOptions } from './server-DoXIpSd7.js';
1
+ import { ac as CimplifyClient } from './client-BuLcOWLv.js';
2
+ import { A as AppHandle, C as CreateAppOptions } from './server-DKK_D-PP.js';
3
3
 
4
4
  /**
5
5
  * Test client + fixtures.