@flopay/js 1.0.0 → 1.0.2
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/index.cjs +176 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +141 -15
- package/dist/index.d.ts +141 -15
- package/dist/index.mjs +183 -38
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -34,8 +34,11 @@ __export(index_exports, {
|
|
|
34
34
|
FloPayElements: () => FloPayElements,
|
|
35
35
|
PaymentAPI: () => PaymentAPI,
|
|
36
36
|
StripeAdapter: () => StripeAdapter,
|
|
37
|
+
cacheSessionDisplayData: () => cacheSessionDisplayData,
|
|
38
|
+
clearSessionDisplayData: () => clearSessionDisplayData,
|
|
37
39
|
createCheckoutSession: () => createCheckoutSession,
|
|
38
40
|
createCheckoutSessionWithRetries: () => createCheckoutSessionWithRetries,
|
|
41
|
+
getSessionDisplayData: () => getSessionDisplayData,
|
|
39
42
|
loadFloPay: () => loadFloPay
|
|
40
43
|
});
|
|
41
44
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -490,6 +493,74 @@ var FloPayElements = class {
|
|
|
490
493
|
|
|
491
494
|
// src/payment-api.ts
|
|
492
495
|
var import_shared3 = require("@flopay/shared");
|
|
496
|
+
|
|
497
|
+
// src/session-display-cache.ts
|
|
498
|
+
var STORAGE_KEY_PREFIX = "flopay_session_display:";
|
|
499
|
+
var DEFAULT_TTL_MS = 60 * 60 * 1e3;
|
|
500
|
+
var memoryStore = /* @__PURE__ */ new Map();
|
|
501
|
+
function storageKey(sessionId) {
|
|
502
|
+
return `${STORAGE_KEY_PREFIX}${sessionId}`;
|
|
503
|
+
}
|
|
504
|
+
function getSessionStorage() {
|
|
505
|
+
if (typeof window === "undefined") return null;
|
|
506
|
+
try {
|
|
507
|
+
return window.sessionStorage;
|
|
508
|
+
} catch {
|
|
509
|
+
return null;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
function cacheSessionDisplayData(sessionId, data, options) {
|
|
513
|
+
if (!sessionId) return;
|
|
514
|
+
const ttl = options?.ttlMs ?? DEFAULT_TTL_MS;
|
|
515
|
+
const entry = { data, expiresAt: Date.now() + ttl };
|
|
516
|
+
const storage = getSessionStorage();
|
|
517
|
+
if (storage) {
|
|
518
|
+
try {
|
|
519
|
+
storage.setItem(storageKey(sessionId), JSON.stringify(entry));
|
|
520
|
+
return;
|
|
521
|
+
} catch {
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
memoryStore.set(sessionId, entry);
|
|
525
|
+
}
|
|
526
|
+
function getSessionDisplayData(sessionId) {
|
|
527
|
+
if (!sessionId) return null;
|
|
528
|
+
const storage = getSessionStorage();
|
|
529
|
+
if (storage) {
|
|
530
|
+
try {
|
|
531
|
+
const raw = storage.getItem(storageKey(sessionId));
|
|
532
|
+
if (raw) {
|
|
533
|
+
const entry = JSON.parse(raw);
|
|
534
|
+
if (entry && typeof entry.expiresAt === "number" && entry.expiresAt > Date.now()) {
|
|
535
|
+
return entry.data;
|
|
536
|
+
}
|
|
537
|
+
storage.removeItem(storageKey(sessionId));
|
|
538
|
+
}
|
|
539
|
+
} catch {
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
const memEntry = memoryStore.get(sessionId);
|
|
543
|
+
if (memEntry) {
|
|
544
|
+
if (memEntry.expiresAt > Date.now()) {
|
|
545
|
+
return memEntry.data;
|
|
546
|
+
}
|
|
547
|
+
memoryStore.delete(sessionId);
|
|
548
|
+
}
|
|
549
|
+
return null;
|
|
550
|
+
}
|
|
551
|
+
function clearSessionDisplayData(sessionId) {
|
|
552
|
+
if (!sessionId) return;
|
|
553
|
+
memoryStore.delete(sessionId);
|
|
554
|
+
const storage = getSessionStorage();
|
|
555
|
+
if (storage) {
|
|
556
|
+
try {
|
|
557
|
+
storage.removeItem(storageKey(sessionId));
|
|
558
|
+
} catch {
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// src/payment-api.ts
|
|
493
564
|
var DEFAULT_PROCESSING_RETRY_AFTER_MS = 1e3;
|
|
494
565
|
var MIN_PROCESSING_RETRY_AFTER_MS = 500;
|
|
495
566
|
var DEFAULT_PROCESSING_TIMEOUT_MS = 15e3;
|
|
@@ -537,7 +608,37 @@ var PaymentAPI = class {
|
|
|
537
608
|
if (!response.ok) {
|
|
538
609
|
throw await buildApiErrorFromResponse(response, "Failed to get checkout session");
|
|
539
610
|
}
|
|
540
|
-
|
|
611
|
+
const body = await response.json();
|
|
612
|
+
return { ...body, data: this.mergeCachedDisplayData(body.data) };
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
615
|
+
* Stash display-only data for a session so subsequent fetches can fill in
|
|
616
|
+
* fields the backend no longer persists (`overrideAmount`, `totalAmount`,
|
|
617
|
+
* `providerItemName`, `providerPlanName`).
|
|
618
|
+
*
|
|
619
|
+
* Backed by `sessionStorage` in the browser, with an in-memory fallback in
|
|
620
|
+
* Node/SSR contexts. Default TTL: 1 hour.
|
|
621
|
+
*
|
|
622
|
+
* Server-returned values always win — cached values fill in only where the
|
|
623
|
+
* server returned `null` / `undefined`.
|
|
624
|
+
*
|
|
625
|
+
* @example
|
|
626
|
+
* ```ts
|
|
627
|
+
* paymentAPI.cacheSessionDisplayData(sessionId, {
|
|
628
|
+
* currency: 'USD',
|
|
629
|
+
* items: [{ code: 'pro_plan', overrideAmount: 24.99, providerItemName: 'Pro' }],
|
|
630
|
+
* });
|
|
631
|
+
* ```
|
|
632
|
+
*/
|
|
633
|
+
cacheSessionDisplayData(sessionId, data, options) {
|
|
634
|
+
cacheSessionDisplayData(sessionId, data, options);
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Drop any cached display data for a session. Call after the payment
|
|
638
|
+
* completes; otherwise the TTL handles cleanup.
|
|
639
|
+
*/
|
|
640
|
+
clearSessionDisplayData(sessionId) {
|
|
641
|
+
clearSessionDisplayData(sessionId);
|
|
541
642
|
}
|
|
542
643
|
/**
|
|
543
644
|
* Fetch and normalize a checkout session.
|
|
@@ -641,27 +742,19 @@ var PaymentAPI = class {
|
|
|
641
742
|
* Falls back to create + GET if the backend doesn't support `expand`.
|
|
642
743
|
*/
|
|
643
744
|
async createAndFetchSession(params) {
|
|
745
|
+
const sessionCurrency = (0, import_shared3.resolveSessionCurrency)(
|
|
746
|
+
params.currency,
|
|
747
|
+
params.items,
|
|
748
|
+
params.subscriptions
|
|
749
|
+
);
|
|
644
750
|
const payload = {
|
|
645
751
|
clientId: params.clientId,
|
|
646
752
|
successUrl: params.successUrl,
|
|
647
753
|
cancelUrl: params.cancelUrl,
|
|
754
|
+
currency: sessionCurrency,
|
|
648
755
|
checkoutMode: params.checkoutMode ?? "full",
|
|
649
|
-
items: (params.items ?? []).map((item) => (
|
|
650
|
-
|
|
651
|
-
providerItemName: item.providerItemName ?? null,
|
|
652
|
-
quantity: item.quantity ?? 1,
|
|
653
|
-
totalAmount: item.totalAmount,
|
|
654
|
-
overrideAmount: item.overrideAmount ?? null,
|
|
655
|
-
currency: item.currency ?? "USD"
|
|
656
|
-
})),
|
|
657
|
-
subscriptions: (params.subscriptions ?? []).map((sub) => ({
|
|
658
|
-
providerPlanId: sub.providerPlanId,
|
|
659
|
-
providerPlanName: sub.providerPlanName ?? null,
|
|
660
|
-
quantity: sub.quantity ?? 1,
|
|
661
|
-
totalAmount: sub.totalAmount,
|
|
662
|
-
overrideAmount: sub.overrideAmount ?? null,
|
|
663
|
-
currency: sub.currency ?? "USD"
|
|
664
|
-
})),
|
|
756
|
+
items: (params.items ?? []).map((item) => (0, import_shared3.buildItemPayload)(item, sessionCurrency)),
|
|
757
|
+
subscriptions: (params.subscriptions ?? []).map((sub) => (0, import_shared3.buildSubscriptionPayload)(sub, sessionCurrency)),
|
|
665
758
|
accountData: {
|
|
666
759
|
userId: params.account.userId,
|
|
667
760
|
firstName: params.account.firstName ?? null,
|
|
@@ -704,8 +797,9 @@ var PaymentAPI = class {
|
|
|
704
797
|
}
|
|
705
798
|
const body = await response.json();
|
|
706
799
|
if (body.data && "gateway" in body.data) {
|
|
800
|
+
const merged = this.mergeCachedDisplayData(body.data);
|
|
707
801
|
return {
|
|
708
|
-
...this.normalizeRawSession(
|
|
802
|
+
...this.normalizeRawSession(merged),
|
|
709
803
|
autoProcessingError: body.autoProcessingError,
|
|
710
804
|
autoProcessingAttempted: body.autoProcessingAttempted,
|
|
711
805
|
autoProcessingPending: body.autoProcessingPending
|
|
@@ -794,10 +888,11 @@ var PaymentAPI = class {
|
|
|
794
888
|
/** Convert raw session to the SDK CheckoutSession shape. */
|
|
795
889
|
toCheckoutSession(raw) {
|
|
796
890
|
const totalAmount = [
|
|
797
|
-
...raw.subscriptions.map((s) => s.overrideAmount
|
|
798
|
-
...raw.items.map((i) => i.overrideAmount
|
|
891
|
+
...raw.subscriptions.map((s) => s.overrideAmount ?? s.totalAmount ?? 0),
|
|
892
|
+
...raw.items.map((i) => i.overrideAmount ?? i.totalAmount ?? 0)
|
|
799
893
|
].reduce((sum, val) => sum + val, 0);
|
|
800
894
|
const amountInCents = Math.round(totalAmount * 100);
|
|
895
|
+
const currency = raw.currency ?? raw.subscriptions[0]?.currency ?? raw.items[0]?.currency ?? "USD";
|
|
801
896
|
return {
|
|
802
897
|
// Core fields (backward compat)
|
|
803
898
|
id: raw.uuid,
|
|
@@ -805,7 +900,7 @@ var PaymentAPI = class {
|
|
|
805
900
|
mode: raw.subscriptions.length > 0 ? "subscription" : "payment",
|
|
806
901
|
status: this.toCheckoutSessionStatus(raw.status),
|
|
807
902
|
amount: amountInCents,
|
|
808
|
-
currency
|
|
903
|
+
currency,
|
|
809
904
|
customer: {
|
|
810
905
|
id: raw.accountData.userId,
|
|
811
906
|
email: raw.accountData.email,
|
|
@@ -882,6 +977,57 @@ var PaymentAPI = class {
|
|
|
882
977
|
clampRetryAfterMs(retryAfterMs) {
|
|
883
978
|
return Math.max(0, Math.min(retryAfterMs, MAX_PROCESSING_RETRY_AFTER_MS));
|
|
884
979
|
}
|
|
980
|
+
/**
|
|
981
|
+
* Merge cached display-only fields (set by {@link cacheSessionDisplayData})
|
|
982
|
+
* into a raw session response and mirror the new/legacy name aliases so
|
|
983
|
+
* readers using either field always get a value when one exists.
|
|
984
|
+
*
|
|
985
|
+
* Server values always win — cache fills in only where the server returned
|
|
986
|
+
* `null` / `undefined`.
|
|
987
|
+
*/
|
|
988
|
+
mergeCachedDisplayData(raw) {
|
|
989
|
+
const cached = getSessionDisplayData(raw.uuid);
|
|
990
|
+
const cachedItems = /* @__PURE__ */ new Map();
|
|
991
|
+
for (const item of cached?.items ?? []) {
|
|
992
|
+
const key = item.code ?? item.providerItemId;
|
|
993
|
+
if (key) cachedItems.set(key, item);
|
|
994
|
+
}
|
|
995
|
+
const cachedSubs = /* @__PURE__ */ new Map();
|
|
996
|
+
for (const sub of cached?.subscriptions ?? []) {
|
|
997
|
+
const key = sub.code ?? sub.providerPlanId;
|
|
998
|
+
if (key) cachedSubs.set(key, sub);
|
|
999
|
+
}
|
|
1000
|
+
return {
|
|
1001
|
+
...raw,
|
|
1002
|
+
currency: raw.currency ?? cached?.currency,
|
|
1003
|
+
items: raw.items.map((item) => {
|
|
1004
|
+
const key = item.code ?? item.providerItemId;
|
|
1005
|
+
const fallback = key ? cachedItems.get(key) : void 0;
|
|
1006
|
+
const resolvedName = item.itemName ?? item.providerItemName ?? fallback?.itemName ?? fallback?.providerItemName;
|
|
1007
|
+
return {
|
|
1008
|
+
...item,
|
|
1009
|
+
itemName: resolvedName,
|
|
1010
|
+
providerItemName: resolvedName,
|
|
1011
|
+
totalAmount: item.totalAmount ?? fallback?.totalAmount,
|
|
1012
|
+
overrideAmount: item.overrideAmount ?? fallback?.overrideAmount,
|
|
1013
|
+
currency: item.currency ?? fallback?.currency
|
|
1014
|
+
};
|
|
1015
|
+
}),
|
|
1016
|
+
subscriptions: raw.subscriptions.map((sub) => {
|
|
1017
|
+
const key = sub.code ?? sub.providerPlanId;
|
|
1018
|
+
const fallback = key ? cachedSubs.get(key) : void 0;
|
|
1019
|
+
const resolvedName = sub.subscriptionName ?? sub.providerPlanName ?? fallback?.subscriptionName ?? fallback?.providerPlanName;
|
|
1020
|
+
return {
|
|
1021
|
+
...sub,
|
|
1022
|
+
subscriptionName: resolvedName,
|
|
1023
|
+
providerPlanName: resolvedName,
|
|
1024
|
+
totalAmount: sub.totalAmount ?? fallback?.totalAmount,
|
|
1025
|
+
overrideAmount: sub.overrideAmount ?? fallback?.overrideAmount,
|
|
1026
|
+
currency: sub.currency ?? fallback?.currency
|
|
1027
|
+
};
|
|
1028
|
+
})
|
|
1029
|
+
};
|
|
1030
|
+
}
|
|
885
1031
|
};
|
|
886
1032
|
|
|
887
1033
|
// src/flopay.ts
|
|
@@ -1015,6 +1161,7 @@ async function loadFloPay(publishableKey, options) {
|
|
|
1015
1161
|
}
|
|
1016
1162
|
|
|
1017
1163
|
// src/create-checkout-session.ts
|
|
1164
|
+
var import_shared6 = require("@flopay/shared");
|
|
1018
1165
|
async function createCheckoutSession(options) {
|
|
1019
1166
|
const {
|
|
1020
1167
|
billingApiUrl,
|
|
@@ -1031,29 +1178,18 @@ async function createCheckoutSession(options) {
|
|
|
1031
1178
|
setCookie = true,
|
|
1032
1179
|
timeoutMs = 12e3,
|
|
1033
1180
|
clientId,
|
|
1181
|
+
currency,
|
|
1034
1182
|
utmMetadata
|
|
1035
1183
|
} = options;
|
|
1184
|
+
const sessionCurrency = (0, import_shared6.resolveSessionCurrency)(currency, items, subscriptions);
|
|
1036
1185
|
const payload = {
|
|
1037
1186
|
clientId,
|
|
1038
1187
|
successUrl,
|
|
1039
1188
|
cancelUrl,
|
|
1189
|
+
currency: sessionCurrency,
|
|
1040
1190
|
checkoutMode,
|
|
1041
|
-
items: items.map((item) => (
|
|
1042
|
-
|
|
1043
|
-
providerItemName: item.providerItemName ?? null,
|
|
1044
|
-
quantity: item.quantity ?? 1,
|
|
1045
|
-
totalAmount: item.totalAmount,
|
|
1046
|
-
overrideAmount: item.overrideAmount ?? null,
|
|
1047
|
-
currency: item.currency ?? "USD"
|
|
1048
|
-
})),
|
|
1049
|
-
subscriptions: subscriptions.map((sub) => ({
|
|
1050
|
-
providerPlanId: sub.providerPlanId,
|
|
1051
|
-
providerPlanName: sub.providerPlanName ?? null,
|
|
1052
|
-
quantity: sub.quantity ?? 1,
|
|
1053
|
-
totalAmount: sub.totalAmount,
|
|
1054
|
-
overrideAmount: sub.overrideAmount ?? null,
|
|
1055
|
-
currency: sub.currency ?? "USD"
|
|
1056
|
-
})),
|
|
1191
|
+
items: items.map((item) => (0, import_shared6.buildItemPayload)(item, sessionCurrency)),
|
|
1192
|
+
subscriptions: subscriptions.map((sub) => (0, import_shared6.buildSubscriptionPayload)(sub, sessionCurrency)),
|
|
1057
1193
|
accountData: {
|
|
1058
1194
|
userId: account.userId,
|
|
1059
1195
|
firstName: account.firstName ?? null,
|
|
@@ -1149,8 +1285,11 @@ async function createCheckoutSessionWithRetries(options) {
|
|
|
1149
1285
|
FloPayElements,
|
|
1150
1286
|
PaymentAPI,
|
|
1151
1287
|
StripeAdapter,
|
|
1288
|
+
cacheSessionDisplayData,
|
|
1289
|
+
clearSessionDisplayData,
|
|
1152
1290
|
createCheckoutSession,
|
|
1153
1291
|
createCheckoutSessionWithRetries,
|
|
1292
|
+
getSessionDisplayData,
|
|
1154
1293
|
loadFloPay
|
|
1155
1294
|
});
|
|
1156
1295
|
//# sourceMappingURL=index.cjs.map
|