@flopay/js 0.5.19 → 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 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
- return response.json();
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
- providerItemId: item.providerItemId,
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(body.data),
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 || s.totalAmount),
798
- ...raw.items.map((i) => i.overrideAmount || i.totalAmount)
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: raw.subscriptions[0]?.currency ?? raw.items[0]?.currency ?? "USD",
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
- providerItemId: item.providerItemId,
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