@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.
- package/dist/advanced.d.mts +3 -3
- package/dist/advanced.d.ts +3 -3
- package/dist/advanced.js +23 -22
- package/dist/advanced.mjs +4 -3
- package/dist/{chunk-DCMXUKDQ.mjs → chunk-2WPVUIHX.mjs} +455 -105
- package/dist/{chunk-NIOUSKQQ.js → chunk-4BKOKHE3.js} +9 -0
- package/dist/{chunk-YDA46OZ6.js → chunk-5BDYDZ4U.js} +722 -90
- package/dist/{chunk-4KNFBPV2.mjs → chunk-5RT4HYMP.mjs} +61 -15
- package/dist/{chunk-WMEC5JWN.js → chunk-7PDEX54K.js} +50 -13
- package/dist/chunk-CNN7Z2IP.js +125 -0
- package/dist/{chunk-DLW3RWRK.mjs → chunk-DYIAX3WI.mjs} +46 -12
- package/dist/{chunk-LOWSMGRT.js → chunk-E4K2VQDD.js} +64 -16
- package/dist/chunk-GOHSXBKW.mjs +105 -0
- package/dist/{chunk-O3YUHLZL.mjs → chunk-H3RATH4B.mjs} +9 -0
- package/dist/{chunk-YER7DIOM.js → chunk-IQFFSKE2.js} +753 -594
- package/dist/{chunk-Z3K2D3TE.mjs → chunk-OCCNG6MO.mjs} +735 -558
- package/dist/{chunk-DKLHCZ5M.mjs → chunk-OKADBZAI.mjs} +652 -25
- package/dist/{chunk-EAZGA7LD.js → chunk-YVAEY3VC.js} +457 -107
- package/dist/{client-nsiMwuC1.d.ts → client-BVNWjk6W.d.ts} +2 -2
- package/dist/{client-B40KFazg.d.ts → client-BuLcOWLv.d.ts} +202 -319
- package/dist/{client-BizGfqB7.d.mts → client-D5AoobFc.d.mts} +202 -319
- package/dist/{client-BdErclfU.d.mts → client-fM716k7G.d.mts} +2 -2
- package/dist/{index-DpmnI__D.d.mts → index-BtcoqrY1.d.ts} +14 -4
- package/dist/{index-nEyXWIyR.d.ts → index-D7Tf3v7c.d.mts} +14 -4
- package/dist/index.d.mts +83 -8
- package/dist/index.d.ts +83 -8
- package/dist/index.js +203 -169
- package/dist/index.mjs +7 -5
- package/dist/link-D9iSVxt5.d.mts +308 -0
- package/dist/link-D9iSVxt5.d.ts +308 -0
- package/dist/mock/cli.mjs +463 -104
- package/dist/mock/library.js +463 -104
- package/dist/mock/library.mjs +463 -104
- package/dist/mock/msw.js +463 -104
- package/dist/mock/msw.mjs +463 -104
- package/dist/{product-Byf0unSy.d.mts → payment-g0HFkEDU.d.mts} +708 -61
- package/dist/{product-Byf0unSy.d.ts → payment-g0HFkEDU.d.ts} +708 -61
- package/dist/{price-BstChV9a.d.ts → price-BLIeAb8K.d.ts} +1 -1
- package/dist/{price-CS4E5zLS.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 +194 -169
- package/dist/react.mjs +55 -30
- package/dist/{server-DqbZh8Bk.d.mts → server-BkVhOIwn.d.mts} +14 -10
- package/dist/{server-Cj40R2ZD.d.ts → server-DKK_D-PP.d.ts} +14 -10
- package/dist/server.d.mts +4 -4
- package/dist/server.d.ts +4 -4
- package/dist/server.js +12 -10
- package/dist/server.mjs +6 -4
- package/dist/testing/msw.d.mts +2 -2
- package/dist/testing/msw.d.ts +2 -2
- package/dist/testing/msw.js +4 -3
- package/dist/testing/msw.mjs +3 -2
- package/dist/testing/suite.d.mts +6 -6
- package/dist/testing/suite.d.ts +6 -6
- package/dist/testing/suite.js +26 -25
- package/dist/testing/suite.mjs +7 -6
- package/dist/testing.d.mts +195 -56
- package/dist/testing.d.ts +195 -56
- package/dist/testing.js +95 -82
- package/dist/testing.mjs +14 -9
- package/dist/utils.d.mts +4 -4
- package/dist/utils.d.ts +4 -4
- package/dist/utils.js +37 -29
- package/dist/utils.mjs +2 -2
- package/package.json +7 -1
- package/registry/chat-widget.json +1 -1
- package/dist/payment-l0rkieEQ.d.mts +0 -113
- package/dist/payment-vzNnIi1n.d.ts +0 -113
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
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,
|
|
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:
|
|
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
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
696
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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) {
|
|
@@ -721,6 +849,456 @@ var SupportService = class {
|
|
|
721
849
|
}
|
|
722
850
|
};
|
|
723
851
|
|
|
852
|
+
// src/payment-authorization/providers/paystack.ts
|
|
853
|
+
async function openPaystackPopup(options, signal) {
|
|
854
|
+
if (typeof window === "undefined") {
|
|
855
|
+
return { success: false, error: "PROVIDER_UNAVAILABLE" };
|
|
856
|
+
}
|
|
857
|
+
let PaystackPop;
|
|
858
|
+
try {
|
|
859
|
+
const imported = await import('@paystack/inline-js');
|
|
860
|
+
PaystackPop = imported.default;
|
|
861
|
+
} catch {
|
|
862
|
+
return { success: false, error: "PROVIDER_UNAVAILABLE" };
|
|
863
|
+
}
|
|
864
|
+
return new Promise((resolve) => {
|
|
865
|
+
let settled = false;
|
|
866
|
+
let providerStarted = false;
|
|
867
|
+
const resolveOnce = (result) => {
|
|
868
|
+
if (settled) {
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
settled = true;
|
|
872
|
+
if (signal) {
|
|
873
|
+
signal.removeEventListener("abort", onAbort);
|
|
874
|
+
}
|
|
875
|
+
resolve(result);
|
|
876
|
+
};
|
|
877
|
+
const onAbort = () => {
|
|
878
|
+
resolveOnce({
|
|
879
|
+
success: false,
|
|
880
|
+
// Once Paystack owns the transaction, cancellation is ambiguous. The
|
|
881
|
+
// adapter converts this into submitted so Cimplify polling decides.
|
|
882
|
+
error: providerStarted ? "SUBMISSION_UNKNOWN" : "CANCELLED"
|
|
883
|
+
});
|
|
884
|
+
};
|
|
885
|
+
if (signal?.aborted) {
|
|
886
|
+
resolveOnce({ success: false, error: "CANCELLED" });
|
|
887
|
+
return;
|
|
888
|
+
}
|
|
889
|
+
if (signal) {
|
|
890
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
891
|
+
}
|
|
892
|
+
try {
|
|
893
|
+
const popup = new PaystackPop();
|
|
894
|
+
popup.newTransaction({
|
|
895
|
+
key: options.key,
|
|
896
|
+
email: options.email,
|
|
897
|
+
amount: options.amount,
|
|
898
|
+
currency: options.currency,
|
|
899
|
+
reference: options.reference,
|
|
900
|
+
accessCode: options.accessCode,
|
|
901
|
+
onSuccess: (transaction) => {
|
|
902
|
+
resolveOnce({
|
|
903
|
+
success: true,
|
|
904
|
+
reference: transaction.reference ?? options.reference
|
|
905
|
+
});
|
|
906
|
+
},
|
|
907
|
+
onCancel: () => {
|
|
908
|
+
resolveOnce({ success: false, error: "PAYMENT_CANCELLED" });
|
|
909
|
+
},
|
|
910
|
+
onError: (error) => {
|
|
911
|
+
resolveOnce({
|
|
912
|
+
success: false,
|
|
913
|
+
error: error?.message || "PAYMENT_FAILED"
|
|
914
|
+
});
|
|
915
|
+
}
|
|
916
|
+
});
|
|
917
|
+
providerStarted = true;
|
|
918
|
+
} catch {
|
|
919
|
+
resolveOnce({ success: false, error: "POPUP_BLOCKED" });
|
|
920
|
+
}
|
|
921
|
+
});
|
|
922
|
+
}
|
|
923
|
+
var PaystackAuthorizationAdapter = class {
|
|
924
|
+
constructor(openPopup = openPaystackPopup) {
|
|
925
|
+
this.openPopup = openPopup;
|
|
926
|
+
this.provider = "paystack";
|
|
927
|
+
}
|
|
928
|
+
async authorize(context) {
|
|
929
|
+
const result = await this.openPopup(
|
|
930
|
+
{
|
|
931
|
+
key: context.action.public_key,
|
|
932
|
+
email: context.email,
|
|
933
|
+
accessCode: context.action.client_secret,
|
|
934
|
+
reference: context.reference || context.action.client_secret,
|
|
935
|
+
currency: context.currency
|
|
936
|
+
},
|
|
937
|
+
context.signal
|
|
938
|
+
);
|
|
939
|
+
if (result.success) {
|
|
940
|
+
return { status: "submitted", reference: result.reference || context.reference };
|
|
941
|
+
}
|
|
942
|
+
if (result.error === "SUBMISSION_UNKNOWN") {
|
|
943
|
+
return { status: "submitted", reference: context.reference };
|
|
944
|
+
}
|
|
945
|
+
if (!result.error || result.error === "CANCELLED" || result.error === "PAYMENT_CANCELLED") {
|
|
946
|
+
return { status: "cancelled" };
|
|
947
|
+
}
|
|
948
|
+
if (result.error === "POPUP_BLOCKED") {
|
|
949
|
+
return {
|
|
950
|
+
status: "failed",
|
|
951
|
+
code: "POPUP_BLOCKED",
|
|
952
|
+
message: "Unable to open the Paystack payment popup. Please allow popups and try again.",
|
|
953
|
+
recoverable: true
|
|
954
|
+
};
|
|
955
|
+
}
|
|
956
|
+
if (result.error === "PROVIDER_UNAVAILABLE") {
|
|
957
|
+
return {
|
|
958
|
+
status: "failed",
|
|
959
|
+
code: "PROVIDER_UNAVAILABLE",
|
|
960
|
+
message: "Paystack is unavailable in this environment.",
|
|
961
|
+
recoverable: false
|
|
962
|
+
};
|
|
963
|
+
}
|
|
964
|
+
return {
|
|
965
|
+
status: "failed",
|
|
966
|
+
code: "PAYMENT_FAILED",
|
|
967
|
+
message: result.error || "Paystack payment could not be submitted.",
|
|
968
|
+
recoverable: true
|
|
969
|
+
};
|
|
970
|
+
}
|
|
971
|
+
};
|
|
972
|
+
|
|
973
|
+
// src/payment-authorization/providers/stripe.ts
|
|
974
|
+
async function loadStripeFromPeer(publicKey, options) {
|
|
975
|
+
try {
|
|
976
|
+
const imported = await import('@stripe/stripe-js');
|
|
977
|
+
return imported.loadStripe ? imported.loadStripe(publicKey, options) : null;
|
|
978
|
+
} catch {
|
|
979
|
+
return null;
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
function createStripeModal() {
|
|
983
|
+
if (typeof document === "undefined" || !document.body) return null;
|
|
984
|
+
const previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
985
|
+
const root = document.createElement("div");
|
|
986
|
+
root.setAttribute("role", "dialog");
|
|
987
|
+
root.setAttribute("aria-modal", "true");
|
|
988
|
+
root.setAttribute("aria-label", "Secure card payment");
|
|
989
|
+
Object.assign(root.style, {
|
|
990
|
+
position: "fixed",
|
|
991
|
+
inset: "0",
|
|
992
|
+
zIndex: "2147483647",
|
|
993
|
+
display: "grid",
|
|
994
|
+
placeItems: "center",
|
|
995
|
+
padding: "16px",
|
|
996
|
+
background: "rgba(15, 23, 42, 0.58)"
|
|
997
|
+
});
|
|
998
|
+
const form = document.createElement("form");
|
|
999
|
+
Object.assign(form.style, {
|
|
1000
|
+
width: "min(100%, 480px)",
|
|
1001
|
+
maxHeight: "calc(100vh - 32px)",
|
|
1002
|
+
overflow: "auto",
|
|
1003
|
+
borderRadius: "12px",
|
|
1004
|
+
padding: "24px",
|
|
1005
|
+
background: "#fff",
|
|
1006
|
+
boxShadow: "0 24px 80px rgba(15, 23, 42, 0.32)"
|
|
1007
|
+
});
|
|
1008
|
+
const title = document.createElement("h2");
|
|
1009
|
+
title.textContent = "Complete card payment";
|
|
1010
|
+
Object.assign(title.style, { margin: "0 0 18px", font: "600 18px/1.4 system-ui" });
|
|
1011
|
+
const paymentMount = document.createElement("div");
|
|
1012
|
+
paymentMount.setAttribute("data-cimplify-stripe-payment-element", "");
|
|
1013
|
+
const error = document.createElement("p");
|
|
1014
|
+
error.setAttribute("role", "alert");
|
|
1015
|
+
Object.assign(error.style, {
|
|
1016
|
+
minHeight: "20px",
|
|
1017
|
+
margin: "14px 0 0",
|
|
1018
|
+
color: "#b91c1c",
|
|
1019
|
+
font: "14px/1.4 system-ui"
|
|
1020
|
+
});
|
|
1021
|
+
const actions = document.createElement("div");
|
|
1022
|
+
Object.assign(actions.style, {
|
|
1023
|
+
display: "flex",
|
|
1024
|
+
justifyContent: "flex-end",
|
|
1025
|
+
gap: "10px",
|
|
1026
|
+
marginTop: "18px"
|
|
1027
|
+
});
|
|
1028
|
+
const cancelButton = document.createElement("button");
|
|
1029
|
+
cancelButton.type = "button";
|
|
1030
|
+
cancelButton.textContent = "Cancel";
|
|
1031
|
+
Object.assign(cancelButton.style, {
|
|
1032
|
+
border: "1px solid #cbd5e1",
|
|
1033
|
+
borderRadius: "8px",
|
|
1034
|
+
padding: "10px 16px",
|
|
1035
|
+
background: "#fff",
|
|
1036
|
+
color: "#0f172a",
|
|
1037
|
+
cursor: "pointer"
|
|
1038
|
+
});
|
|
1039
|
+
const submitButton = document.createElement("button");
|
|
1040
|
+
submitButton.type = "submit";
|
|
1041
|
+
submitButton.textContent = "Pay securely";
|
|
1042
|
+
Object.assign(submitButton.style, {
|
|
1043
|
+
border: "0",
|
|
1044
|
+
borderRadius: "8px",
|
|
1045
|
+
padding: "10px 16px",
|
|
1046
|
+
background: "#0f172a",
|
|
1047
|
+
color: "#fff",
|
|
1048
|
+
cursor: "pointer"
|
|
1049
|
+
});
|
|
1050
|
+
actions.append(cancelButton, submitButton);
|
|
1051
|
+
form.append(title, paymentMount, error, actions);
|
|
1052
|
+
root.append(form);
|
|
1053
|
+
document.body.append(root);
|
|
1054
|
+
cancelButton.focus();
|
|
1055
|
+
return { root, form, paymentMount, submitButton, cancelButton, error, previousFocus };
|
|
1056
|
+
}
|
|
1057
|
+
function stripeFailure(error) {
|
|
1058
|
+
const message = error?.message || "Stripe could not authorize this payment.";
|
|
1059
|
+
if (error?.code === "payment_intent_authentication_failure" || error?.type === "invalid_request_error") {
|
|
1060
|
+
return {
|
|
1061
|
+
status: "failed",
|
|
1062
|
+
code: "AUTHORIZATION_FAILED",
|
|
1063
|
+
message,
|
|
1064
|
+
recoverable: true
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1067
|
+
return { status: "failed", code: "PAYMENT_FAILED", message, recoverable: true };
|
|
1068
|
+
}
|
|
1069
|
+
var StripeAuthorizationAdapter = class {
|
|
1070
|
+
constructor(loadStripe = loadStripeFromPeer) {
|
|
1071
|
+
this.loadStripe = loadStripe;
|
|
1072
|
+
this.provider = "stripe";
|
|
1073
|
+
}
|
|
1074
|
+
async authorize(context) {
|
|
1075
|
+
if (typeof window === "undefined" || typeof document === "undefined" || context.signal?.aborted) {
|
|
1076
|
+
return context.signal?.aborted ? { status: "cancelled" } : {
|
|
1077
|
+
status: "failed",
|
|
1078
|
+
code: "PROVIDER_UNAVAILABLE",
|
|
1079
|
+
message: "Stripe Payment Element is unavailable in this environment.",
|
|
1080
|
+
recoverable: false
|
|
1081
|
+
};
|
|
1082
|
+
}
|
|
1083
|
+
let stripe;
|
|
1084
|
+
try {
|
|
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
|
+
);
|
|
1089
|
+
} catch (error) {
|
|
1090
|
+
return {
|
|
1091
|
+
status: "failed",
|
|
1092
|
+
code: "PROVIDER_UNAVAILABLE",
|
|
1093
|
+
message: error instanceof Error ? error.message : "Stripe.js could not be loaded.",
|
|
1094
|
+
recoverable: true
|
|
1095
|
+
};
|
|
1096
|
+
}
|
|
1097
|
+
if (context.signal?.aborted) {
|
|
1098
|
+
return { status: "cancelled" };
|
|
1099
|
+
}
|
|
1100
|
+
if (!stripe) {
|
|
1101
|
+
return {
|
|
1102
|
+
status: "failed",
|
|
1103
|
+
code: "PROVIDER_UNAVAILABLE",
|
|
1104
|
+
message: "Stripe.js could not be loaded.",
|
|
1105
|
+
recoverable: false
|
|
1106
|
+
};
|
|
1107
|
+
}
|
|
1108
|
+
const modal = createStripeModal();
|
|
1109
|
+
if (!modal) {
|
|
1110
|
+
return {
|
|
1111
|
+
status: "failed",
|
|
1112
|
+
code: "PROVIDER_UNAVAILABLE",
|
|
1113
|
+
message: "Stripe Payment Element could not be mounted.",
|
|
1114
|
+
recoverable: false
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
1117
|
+
let paymentElement;
|
|
1118
|
+
let elements;
|
|
1119
|
+
try {
|
|
1120
|
+
elements = stripe.elements({ clientSecret: context.action.client_secret });
|
|
1121
|
+
paymentElement = elements.create("payment");
|
|
1122
|
+
paymentElement.mount(modal.paymentMount);
|
|
1123
|
+
} catch {
|
|
1124
|
+
modal.root.remove();
|
|
1125
|
+
modal.previousFocus?.focus();
|
|
1126
|
+
return {
|
|
1127
|
+
status: "failed",
|
|
1128
|
+
code: "PROVIDER_UNAVAILABLE",
|
|
1129
|
+
message: "Stripe Payment Element could not be initialized.",
|
|
1130
|
+
recoverable: false
|
|
1131
|
+
};
|
|
1132
|
+
}
|
|
1133
|
+
if (context.signal?.aborted) {
|
|
1134
|
+
if (paymentElement.destroy) paymentElement.destroy();
|
|
1135
|
+
else paymentElement.unmount?.();
|
|
1136
|
+
modal.root.remove();
|
|
1137
|
+
modal.previousFocus?.focus();
|
|
1138
|
+
return { status: "cancelled" };
|
|
1139
|
+
}
|
|
1140
|
+
return new Promise((resolve) => {
|
|
1141
|
+
let settled = false;
|
|
1142
|
+
let submitting = false;
|
|
1143
|
+
let confirmationStarted = false;
|
|
1144
|
+
const cleanup = () => {
|
|
1145
|
+
context.signal?.removeEventListener("abort", onAbort);
|
|
1146
|
+
modal.form.removeEventListener("submit", onSubmit);
|
|
1147
|
+
modal.cancelButton.removeEventListener("click", onCancel);
|
|
1148
|
+
if (paymentElement.destroy) paymentElement.destroy();
|
|
1149
|
+
else paymentElement.unmount?.();
|
|
1150
|
+
modal.root.remove();
|
|
1151
|
+
modal.previousFocus?.focus();
|
|
1152
|
+
};
|
|
1153
|
+
const settle = (outcome) => {
|
|
1154
|
+
if (settled) return;
|
|
1155
|
+
settled = true;
|
|
1156
|
+
cleanup();
|
|
1157
|
+
resolve(outcome);
|
|
1158
|
+
};
|
|
1159
|
+
const onAbort = () => {
|
|
1160
|
+
if (confirmationStarted) {
|
|
1161
|
+
settle({ status: "submitted", reference: context.reference });
|
|
1162
|
+
return;
|
|
1163
|
+
}
|
|
1164
|
+
settle({ status: "cancelled" });
|
|
1165
|
+
};
|
|
1166
|
+
const onCancel = () => {
|
|
1167
|
+
if (!confirmationStarted) settle({ status: "cancelled" });
|
|
1168
|
+
};
|
|
1169
|
+
const onSubmit = async (event) => {
|
|
1170
|
+
event.preventDefault();
|
|
1171
|
+
if (submitting || settled) return;
|
|
1172
|
+
submitting = true;
|
|
1173
|
+
modal.submitButton.disabled = true;
|
|
1174
|
+
modal.error.textContent = "";
|
|
1175
|
+
try {
|
|
1176
|
+
const validation = elements.submit ? await elements.submit() : {};
|
|
1177
|
+
if (validation.error) {
|
|
1178
|
+
modal.error.textContent = validation.error.message || "Check your payment details.";
|
|
1179
|
+
submitting = false;
|
|
1180
|
+
modal.submitButton.disabled = false;
|
|
1181
|
+
return;
|
|
1182
|
+
}
|
|
1183
|
+
if (settled || context.signal?.aborted) {
|
|
1184
|
+
settle({ status: "cancelled" });
|
|
1185
|
+
return;
|
|
1186
|
+
}
|
|
1187
|
+
confirmationStarted = true;
|
|
1188
|
+
modal.cancelButton.disabled = true;
|
|
1189
|
+
const confirmation = await stripe.confirmPayment({
|
|
1190
|
+
elements,
|
|
1191
|
+
confirmParams: { return_url: context.returnUrl || window.location.href },
|
|
1192
|
+
redirect: "if_required"
|
|
1193
|
+
});
|
|
1194
|
+
if (settled) return;
|
|
1195
|
+
if (confirmation.error) {
|
|
1196
|
+
settle(stripeFailure(confirmation.error));
|
|
1197
|
+
return;
|
|
1198
|
+
}
|
|
1199
|
+
settle({
|
|
1200
|
+
status: "submitted",
|
|
1201
|
+
reference: confirmation.paymentIntent?.id || context.reference
|
|
1202
|
+
});
|
|
1203
|
+
} catch (error) {
|
|
1204
|
+
if (confirmationStarted) {
|
|
1205
|
+
settle({ status: "submitted", reference: context.reference });
|
|
1206
|
+
return;
|
|
1207
|
+
}
|
|
1208
|
+
settle(
|
|
1209
|
+
stripeFailure({
|
|
1210
|
+
message: error instanceof Error ? error.message : "Stripe confirmation failed."
|
|
1211
|
+
})
|
|
1212
|
+
);
|
|
1213
|
+
}
|
|
1214
|
+
};
|
|
1215
|
+
modal.form.addEventListener("submit", onSubmit);
|
|
1216
|
+
modal.cancelButton.addEventListener("click", onCancel);
|
|
1217
|
+
context.signal?.addEventListener("abort", onAbort, { once: true });
|
|
1218
|
+
paymentElement.on?.("escape", onCancel);
|
|
1219
|
+
paymentElement.on?.("loaderror", (event) => {
|
|
1220
|
+
if (confirmationStarted) return;
|
|
1221
|
+
settle({
|
|
1222
|
+
status: "failed",
|
|
1223
|
+
code: "PROVIDER_UNAVAILABLE",
|
|
1224
|
+
message: event?.error?.message || "Stripe Payment Element failed to load.",
|
|
1225
|
+
recoverable: true
|
|
1226
|
+
});
|
|
1227
|
+
});
|
|
1228
|
+
});
|
|
1229
|
+
}
|
|
1230
|
+
};
|
|
1231
|
+
|
|
1232
|
+
// src/payment-authorization/registry.ts
|
|
1233
|
+
function normalizeProvider(provider) {
|
|
1234
|
+
return typeof provider === "string" ? provider.trim().toLowerCase() : "";
|
|
1235
|
+
}
|
|
1236
|
+
var PaymentAuthorizationAdapterRegistry = class {
|
|
1237
|
+
constructor(adapters = []) {
|
|
1238
|
+
this.adapters = /* @__PURE__ */ new Map();
|
|
1239
|
+
for (const adapter of adapters) {
|
|
1240
|
+
this.register(adapter);
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
register(adapter) {
|
|
1244
|
+
const provider = normalizeProvider(adapter.provider);
|
|
1245
|
+
if (!provider) {
|
|
1246
|
+
throw new TypeError("Payment authorization adapter provider cannot be empty.");
|
|
1247
|
+
}
|
|
1248
|
+
this.adapters.set(provider, adapter);
|
|
1249
|
+
return this;
|
|
1250
|
+
}
|
|
1251
|
+
unregister(provider) {
|
|
1252
|
+
return this.adapters.delete(normalizeProvider(provider));
|
|
1253
|
+
}
|
|
1254
|
+
get(provider) {
|
|
1255
|
+
return this.adapters.get(normalizeProvider(provider));
|
|
1256
|
+
}
|
|
1257
|
+
supports(provider) {
|
|
1258
|
+
return this.adapters.has(normalizeProvider(provider));
|
|
1259
|
+
}
|
|
1260
|
+
providers() {
|
|
1261
|
+
return [...this.adapters.keys()];
|
|
1262
|
+
}
|
|
1263
|
+
async authorize(action, options) {
|
|
1264
|
+
const provider = normalizeProvider(action.provider);
|
|
1265
|
+
if (!provider) {
|
|
1266
|
+
return {
|
|
1267
|
+
status: "failed",
|
|
1268
|
+
code: "PROVIDER_UNAVAILABLE",
|
|
1269
|
+
message: "Card authorization response did not identify a payment provider.",
|
|
1270
|
+
recoverable: false
|
|
1271
|
+
};
|
|
1272
|
+
}
|
|
1273
|
+
const adapter = this.adapters.get(provider);
|
|
1274
|
+
if (!adapter) {
|
|
1275
|
+
return {
|
|
1276
|
+
status: "failed",
|
|
1277
|
+
code: "PROVIDER_UNAVAILABLE",
|
|
1278
|
+
message: `Card authorization provider '${provider}' is not supported by this SDK client.`,
|
|
1279
|
+
recoverable: false
|
|
1280
|
+
};
|
|
1281
|
+
}
|
|
1282
|
+
try {
|
|
1283
|
+
const normalizedAction = action.provider === provider ? action : { ...action, provider };
|
|
1284
|
+
return await adapter.authorize({ ...options, action: normalizedAction });
|
|
1285
|
+
} catch (error) {
|
|
1286
|
+
return {
|
|
1287
|
+
status: "failed",
|
|
1288
|
+
code: "PAYMENT_FAILED",
|
|
1289
|
+
message: error instanceof Error ? error.message : `Card authorization provider '${provider}' failed unexpectedly.`,
|
|
1290
|
+
recoverable: true
|
|
1291
|
+
};
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
};
|
|
1295
|
+
function createDefaultPaymentAuthorizationAdapterRegistry() {
|
|
1296
|
+
return new PaymentAuthorizationAdapterRegistry([
|
|
1297
|
+
new PaystackAuthorizationAdapter(),
|
|
1298
|
+
new StripeAuthorizationAdapter()
|
|
1299
|
+
]);
|
|
1300
|
+
}
|
|
1301
|
+
|
|
724
1302
|
// src/client.ts
|
|
725
1303
|
var SESSION_TOKEN_STORAGE_KEY = "cimplify_session_token";
|
|
726
1304
|
var SESSION_SYNC_STORAGE_KEY = "cimplify_session_sync";
|
|
@@ -845,6 +1423,7 @@ var CimplifyClient = class {
|
|
|
845
1423
|
this.context = {};
|
|
846
1424
|
this.businessId = null;
|
|
847
1425
|
this.businessIdResolvePromise = null;
|
|
1426
|
+
this.publicKeyEpoch = 0;
|
|
848
1427
|
this.inflightRequests = /* @__PURE__ */ new Map();
|
|
849
1428
|
/**
|
|
850
1429
|
* App-level event channel. Subscribe to surface mutation rollbacks, outbox
|
|
@@ -863,6 +1442,7 @@ var CimplifyClient = class {
|
|
|
863
1442
|
this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
864
1443
|
this.retryDelay = config.retryDelay ?? DEFAULT_RETRY_DELAY_MS;
|
|
865
1444
|
this.hooks = config.hooks ?? {};
|
|
1445
|
+
this.authorizationAdapters = config.authorizationAdapterRegistry ?? createDefaultPaymentAuthorizationAdapterRegistry();
|
|
866
1446
|
this.fetchImpl = (config.fetch ?? globalThis.fetch).bind(globalThis);
|
|
867
1447
|
this.sessionToken = this.loadSessionToken() ?? this.mintSessionToken();
|
|
868
1448
|
this.watchCrossTabSession();
|
|
@@ -928,7 +1508,8 @@ var CimplifyClient = class {
|
|
|
928
1508
|
* refresh restore) binds the anonymous session so the conversation, cart
|
|
929
1509
|
* and orders survive a cleared browser. Best-effort by design — a failed
|
|
930
1510
|
* claim leaves the session anonymous, exactly as it was. Called by the
|
|
931
|
-
* 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.
|
|
932
1513
|
*/
|
|
933
1514
|
autoClaimChatIdentity() {
|
|
934
1515
|
if (typeof window === "undefined" || !this.sessionToken || !this.accessToken) return;
|
|
@@ -970,9 +1551,28 @@ var CimplifyClient = class {
|
|
|
970
1551
|
getSessionEpoch() {
|
|
971
1552
|
return this.sessionEpoch;
|
|
972
1553
|
}
|
|
1554
|
+
/** Monotonic fence for async work scoped to the current storefront tenant. */
|
|
1555
|
+
getPublicKeyEpoch() {
|
|
1556
|
+
return this.publicKeyEpoch;
|
|
1557
|
+
}
|
|
973
1558
|
getSessionToken() {
|
|
974
1559
|
return this.sessionToken;
|
|
975
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
|
+
}
|
|
976
1576
|
publishSessionClaimed(customerName) {
|
|
977
1577
|
if (!this.sessionToken) return;
|
|
978
1578
|
this.broadcastSessionSync({
|
|
@@ -1079,10 +1679,18 @@ var CimplifyClient = class {
|
|
|
1079
1679
|
// X-API-Key and the business can't be resolved.
|
|
1080
1680
|
setPublicKey(publicKey) {
|
|
1081
1681
|
const normalized = publicKey.trim();
|
|
1082
|
-
if (
|
|
1083
|
-
return;
|
|
1084
|
-
}
|
|
1682
|
+
if (normalized === this.publicKey) return;
|
|
1085
1683
|
this.publicKey = normalized;
|
|
1684
|
+
this.publicKeyEpoch += 1;
|
|
1685
|
+
this.businessId = null;
|
|
1686
|
+
this.businessIdResolvePromise = null;
|
|
1687
|
+
this.inflightRequests.clear();
|
|
1688
|
+
this._activity?.resetSession();
|
|
1689
|
+
delete this.context.location_id;
|
|
1690
|
+
if (this.accessToken !== null) {
|
|
1691
|
+
this.setAccessToken(null);
|
|
1692
|
+
}
|
|
1693
|
+
this.events.emit(SESSION_CLEARED, {});
|
|
1086
1694
|
}
|
|
1087
1695
|
getBusinessId() {
|
|
1088
1696
|
return this.businessId;
|
|
@@ -1094,7 +1702,8 @@ var CimplifyClient = class {
|
|
|
1094
1702
|
if (this.businessIdResolvePromise) {
|
|
1095
1703
|
return this.businessIdResolvePromise;
|
|
1096
1704
|
}
|
|
1097
|
-
|
|
1705
|
+
const publicKeyEpoch = this.publicKeyEpoch;
|
|
1706
|
+
const resolution = (async () => {
|
|
1098
1707
|
const result = await this.business.getInfo();
|
|
1099
1708
|
if (!result.ok || !result.value?.id) {
|
|
1100
1709
|
throw new CimplifyError(
|
|
@@ -1103,13 +1712,23 @@ var CimplifyClient = class {
|
|
|
1103
1712
|
true
|
|
1104
1713
|
);
|
|
1105
1714
|
}
|
|
1715
|
+
if (this.publicKeyEpoch !== publicKeyEpoch) {
|
|
1716
|
+
throw new CimplifyError(
|
|
1717
|
+
ErrorCode.TENANT_CONTEXT_CHANGED,
|
|
1718
|
+
"The storefront tenant changed while resolving its business identity.",
|
|
1719
|
+
true
|
|
1720
|
+
);
|
|
1721
|
+
}
|
|
1106
1722
|
this.businessId = result.value.id;
|
|
1107
1723
|
return result.value.id;
|
|
1108
1724
|
})();
|
|
1725
|
+
this.businessIdResolvePromise = resolution;
|
|
1109
1726
|
try {
|
|
1110
|
-
return await
|
|
1727
|
+
return await resolution;
|
|
1111
1728
|
} finally {
|
|
1112
|
-
this.businessIdResolvePromise
|
|
1729
|
+
if (this.businessIdResolvePromise === resolution) {
|
|
1730
|
+
this.businessIdResolvePromise = null;
|
|
1731
|
+
}
|
|
1113
1732
|
}
|
|
1114
1733
|
}
|
|
1115
1734
|
async authedFetch(url, options, timeoutMs) {
|
|
@@ -1312,7 +1931,13 @@ var CimplifyClient = class {
|
|
|
1312
1931
|
}
|
|
1313
1932
|
getDedupeKey(type, payload, cacheOptions) {
|
|
1314
1933
|
const cacheKey = cacheOptions ? `|${JSON.stringify(cacheOptions)}` : "";
|
|
1315
|
-
|
|
1934
|
+
const identityKey = JSON.stringify([
|
|
1935
|
+
this.publicKey.trim(),
|
|
1936
|
+
this.publicKeyEpoch,
|
|
1937
|
+
this.sessionEpoch,
|
|
1938
|
+
this.context.location_id ?? null
|
|
1939
|
+
]);
|
|
1940
|
+
return `${type}:${identityKey}:${JSON.stringify(payload)}${cacheKey}`;
|
|
1316
1941
|
}
|
|
1317
1942
|
async deduplicatedRequest(key, requestFn) {
|
|
1318
1943
|
const existing = this.inflightRequests.get(key);
|
|
@@ -1320,7 +1945,9 @@ var CimplifyClient = class {
|
|
|
1320
1945
|
return existing;
|
|
1321
1946
|
}
|
|
1322
1947
|
const request = requestFn().finally(() => {
|
|
1323
|
-
this.inflightRequests.
|
|
1948
|
+
if (this.inflightRequests.get(key) === request) {
|
|
1949
|
+
this.inflightRequests.delete(key);
|
|
1950
|
+
}
|
|
1324
1951
|
});
|
|
1325
1952
|
this.inflightRequests.set(key, request);
|
|
1326
1953
|
return request;
|
|
@@ -1572,4 +2199,4 @@ function createCimplifyClient(config = {}) {
|
|
|
1572
2199
|
return new CimplifyClient(config);
|
|
1573
2200
|
}
|
|
1574
2201
|
|
|
1575
|
-
export { AUTH_TOKEN_CHANGED, ActivityService, CimplifyClient, DeliveryService, MUTATION_ERROR, PlacesService, SESSION_CLAIMED, SESSION_CLEARED, StoreCreditQueries, SubscriptionService, SupportService, UploadService, createCimplifyClient };
|
|
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 };
|