@tagadapay/headless-sdk 1.20.1 → 1.22.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 (42) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +25 -0
  3. package/dist/core/helpers/paymentsApi.d.ts +139 -0
  4. package/dist/core/helpers/paymentsApi.d.ts.map +1 -0
  5. package/dist/core/helpers/paymentsApi.js +291 -0
  6. package/dist/core/helpers/paymentsApi.js.map +1 -0
  7. package/dist/core/helpers/paymentsApiAnswer.d.ts +26 -0
  8. package/dist/core/helpers/paymentsApiAnswer.d.ts.map +1 -0
  9. package/dist/core/helpers/paymentsApiAnswer.js +56 -0
  10. package/dist/core/helpers/paymentsApiAnswer.js.map +1 -0
  11. package/dist/core/helpers/stripeJs.d.ts +15 -0
  12. package/dist/core/helpers/stripeJs.d.ts.map +1 -0
  13. package/dist/core/helpers/stripeJs.js +24 -0
  14. package/dist/core/helpers/stripeJs.js.map +1 -0
  15. package/dist/core/helpers/stripeRadar.d.ts +14 -0
  16. package/dist/core/helpers/stripeRadar.d.ts.map +1 -0
  17. package/dist/core/helpers/stripeRadar.js +34 -0
  18. package/dist/core/helpers/stripeRadar.js.map +1 -0
  19. package/dist/core/modules/checkout.d.ts.map +1 -1
  20. package/dist/core/modules/checkout.js +1 -0
  21. package/dist/core/modules/checkout.js.map +1 -1
  22. package/dist/core/modules/payment.d.ts +18 -0
  23. package/dist/core/modules/payment.d.ts.map +1 -1
  24. package/dist/core/modules/payment.js +93 -29
  25. package/dist/core/modules/payment.js.map +1 -1
  26. package/dist/core/types.d.ts +5 -0
  27. package/dist/core/types.d.ts.map +1 -1
  28. package/dist/core/version.d.ts +1 -1
  29. package/dist/core/version.js +1 -1
  30. package/dist/react/hooks/usePayment.d.ts +3 -0
  31. package/dist/react/hooks/usePayment.d.ts.map +1 -1
  32. package/dist/react/hooks/usePayment.js.map +1 -1
  33. package/dist/tagada-headless-commerce.min.js +1 -1
  34. package/dist/tagada-headless-react.min.js +2 -2
  35. package/dist/tagada-headless-react.min.js.map +4 -4
  36. package/dist/tagada-headless.js +163 -34
  37. package/dist/tagada-headless.min.js +2 -2
  38. package/dist/tagada-headless.min.js.map +4 -4
  39. package/dist/tagada-pixels.min.js +1 -1
  40. package/dist/tgd/contract/registry.d.ts +1 -1
  41. package/dist/tgd/contract/registry.d.ts.map +1 -1
  42. package/package.json +2 -2
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @tagadapay/headless-sdk v1.20.1
2
+ * @tagadapay/headless-sdk v1.22.0
3
3
  * Headless checkout, payments, offers, and CRM
4
4
  * @license MIT
5
5
  */
@@ -142,7 +142,7 @@ var TagadaHeadlessBundle = (() => {
142
142
 
143
143
  // src/core/version.ts
144
144
  var SDK_NAME = "headless";
145
- var SDK_VERSION = "1.20.1";
145
+ var SDK_VERSION = "1.22.0";
146
146
 
147
147
  // src/core/http.ts
148
148
  var BASE_URLS = {
@@ -724,7 +724,8 @@ var TagadaHeadlessBundle = (() => {
724
724
  shippingAddress: this.normalizeAddress(cs.shippingAddress),
725
725
  billingAddress: this.normalizeAddress(cs.billingAddress),
726
726
  selectedShippingRateId: cs.shippingRateId ?? null,
727
- metadata: cs.metadata
727
+ metadata: cs.metadata,
728
+ ...typeof cs.draft === "boolean" ? { draft: cs.draft } : {}
728
729
  };
729
730
  }
730
731
  /**
@@ -804,7 +805,7 @@ var TagadaHeadlessBundle = (() => {
804
805
  }
805
806
 
806
807
  // src/core/modules/track.ts
807
- var CDN_URL = false ? "" : "https://cdn.jsdelivr.net/npm/@tagadapay/headless-sdk@1.20.1/dist/tagada-pixels.min.js";
808
+ var CDN_URL = false ? "" : "https://cdn.jsdelivr.net/npm/@tagadapay/headless-sdk@1.22.0/dist/tagada-pixels.min.js";
808
809
  function loadScript(src, isReady) {
809
810
  if (isReady())
810
811
  return Promise.resolve();
@@ -1430,6 +1431,71 @@ var TagadaHeadlessBundle = (() => {
1430
1431
  return error instanceof Error && error.message ? error.message : UNAVAILABLE;
1431
1432
  }
1432
1433
 
1434
+ // src/core/helpers/paymentsApiAnswer.ts
1435
+ function readStartedPayment(answer) {
1436
+ if (!answer || typeof answer !== "object" || Array.isArray(answer))
1437
+ return null;
1438
+ const { payment, order, paymentId, clientSecret, amount, currency, checkoutSessionId, radar } = answer;
1439
+ if (payment !== void 0 || order !== void 0)
1440
+ return null;
1441
+ if (typeof paymentId !== "string" || !paymentId || typeof clientSecret !== "string" || !clientSecret)
1442
+ return null;
1443
+ return {
1444
+ paymentId,
1445
+ clientSecret,
1446
+ ...typeof amount === "number" ? { amount } : {},
1447
+ ...typeof currency === "string" ? { currency } : {},
1448
+ ...typeof checkoutSessionId === "string" ? { checkoutSessionId } : {},
1449
+ ...radarKey(radar) ? { radar: { publishableKey: radarKey(radar) } } : {}
1450
+ };
1451
+ }
1452
+ function radarKey(radar) {
1453
+ const key = radar && typeof radar === "object" ? radar.publishableKey : null;
1454
+ return typeof key === "string" && key.startsWith("pk_") ? key : null;
1455
+ }
1456
+ var PENDING_KEY = "tgd_payments_api_return";
1457
+ var PENDING_TTL_MS = 60 * 6e4;
1458
+ function takeParkedPaymentsApiReturn(paymentId) {
1459
+ try {
1460
+ const raw = sessionStorage.getItem(PENDING_KEY);
1461
+ if (!raw)
1462
+ return null;
1463
+ const parked = JSON.parse(raw);
1464
+ if (parked.paymentId !== paymentId)
1465
+ return null;
1466
+ sessionStorage.removeItem(PENDING_KEY);
1467
+ if (!parked.checkoutSessionId || !parked.at || Date.now() - parked.at > PENDING_TTL_MS)
1468
+ return null;
1469
+ return { checkoutSessionId: parked.checkoutSessionId };
1470
+ } catch {
1471
+ return null;
1472
+ }
1473
+ }
1474
+
1475
+ // src/core/helpers/stripeJs.ts
1476
+ function loadStripeJs() {
1477
+ if (typeof window === "undefined")
1478
+ return Promise.reject(new Error("Stripe Radar needs a browser"));
1479
+ const fromPage = () => window.Stripe;
1480
+ const loaded = fromPage();
1481
+ if (loaded)
1482
+ return Promise.resolve(loaded);
1483
+ return new Promise((resolve, reject) => {
1484
+ const script2 = document.createElement("script");
1485
+ script2.src = "https://js.stripe.com/v3/";
1486
+ script2.async = true;
1487
+ script2.onload = () => {
1488
+ const stripe = fromPage();
1489
+ if (stripe)
1490
+ resolve(stripe);
1491
+ else
1492
+ reject(new Error("Stripe.js loaded without window.Stripe"));
1493
+ };
1494
+ script2.onerror = () => reject(new Error("Failed to load Stripe.js"));
1495
+ document.head.appendChild(script2);
1496
+ });
1497
+ }
1498
+
1433
1499
  // src/core/helpers/oceanpayment.ts
1434
1500
  var OCEAN_SDK_URL = "https://secure.oceanpayment.com/pages/js/oceanpayment.js";
1435
1501
  var OCEAN_CONTAINER_ID = "oceanpayment-element";
@@ -1512,6 +1578,16 @@ var TagadaHeadlessBundle = (() => {
1512
1578
  }
1513
1579
 
1514
1580
  // src/core/modules/payment.ts
1581
+ function loadPaymentsApiFlow() {
1582
+ if (true) {
1583
+ return Promise.reject(
1584
+ new Error(
1585
+ "This store takes payments through the Payments API, which the CDN build does not support yet: install @tagadapay/headless-sdk and @tagadapay/core-js 3.7.0 or later from npm."
1586
+ )
1587
+ );
1588
+ }
1589
+ return import("../helpers/paymentsApi.js");
1590
+ }
1515
1591
  var FAILED_PAYMENT_STATUSES = /* @__PURE__ */ new Set(["failed", "declined", "rejected", "error"]);
1516
1592
  var oceanSlot = null;
1517
1593
  var oceanSlotTaken = () => !!oceanSlot && (!oceanSlot.attached || oceanSlot.element.isConnected);
@@ -1539,28 +1615,6 @@ var TagadaHeadlessBundle = (() => {
1539
1615
  metadata: entry.metadata ?? void 0
1540
1616
  };
1541
1617
  }
1542
- function loadStripeJs() {
1543
- if (typeof window === "undefined")
1544
- return Promise.reject(new Error("Stripe Radar needs a browser"));
1545
- const fromPage = () => window.Stripe;
1546
- const loaded = fromPage();
1547
- if (loaded)
1548
- return Promise.resolve(loaded);
1549
- return new Promise((resolve, reject) => {
1550
- const script2 = document.createElement("script");
1551
- script2.src = "https://js.stripe.com/v3/";
1552
- script2.async = true;
1553
- script2.onload = () => {
1554
- const stripe = fromPage();
1555
- if (stripe)
1556
- resolve(stripe);
1557
- else
1558
- reject(new Error("Stripe.js loaded without window.Stripe"));
1559
- };
1560
- script2.onerror = () => reject(new Error("Failed to load Stripe.js"));
1561
- document.head.appendChild(script2);
1562
- });
1563
- }
1564
1618
  var PaymentModule = class {
1565
1619
  constructor(http, storeId, environment, checkout, onPaid, onSignal) {
1566
1620
  this.http = http;
@@ -1575,6 +1629,11 @@ var TagadaHeadlessBundle = (() => {
1575
1629
  * without a second network round-trip inside Apple's authorization window.
1576
1630
  */
1577
1631
  this.lastPaymentSetup = null;
1632
+ /**
1633
+ * Payments API (V3) store: what the pay call knew about each payment it started (the session it
1634
+ * pays, the shopper's method), so `finalize()` can confirm it from the bare pay answer.
1635
+ */
1636
+ this.paymentsApiStarts = /* @__PURE__ */ new Map();
1578
1637
  }
1579
1638
  // ---------------------------------------------------------------------------
1580
1639
  // Discovery: what payment methods are available?
@@ -1785,7 +1844,7 @@ var TagadaHeadlessBundle = (() => {
1785
1844
  */
1786
1845
  async pay(opts) {
1787
1846
  if (opts.tagadaToken && !opts.paymentInstrumentId) {
1788
- return this.http.post("/api/v1/payment/pay-with-token", {
1847
+ return this.rememberPaymentsApiStart(await this.http.post("/api/v1/payment/pay-with-token", {
1789
1848
  tagadaToken: opts.tagadaToken,
1790
1849
  checkoutSessionId: opts.checkoutSessionId,
1791
1850
  returnUrl: opts.returnUrl,
@@ -1794,9 +1853,9 @@ var TagadaHeadlessBundle = (() => {
1794
1853
  paymentMethod: opts.paymentMethod,
1795
1854
  isExpress: opts.isExpress,
1796
1855
  metadata: opts.metadata
1797
- });
1856
+ }), opts);
1798
1857
  }
1799
- return this.http.post("/api/public/v1/checkout/pay-v2", {
1858
+ return this.rememberPaymentsApiStart(await this.http.post("/api/public/v1/checkout/pay-v2", {
1800
1859
  checkoutSessionId: opts.checkoutSessionId,
1801
1860
  paymentInstrumentId: opts.paymentInstrumentId,
1802
1861
  storeId: this.storeId,
@@ -1807,14 +1866,14 @@ var TagadaHeadlessBundle = (() => {
1807
1866
  isExpress: opts.isExpress,
1808
1867
  metadata: opts.metadata,
1809
1868
  returnUrl: opts.returnUrl
1810
- });
1869
+ }), opts);
1811
1870
  }
1812
1871
  /**
1813
1872
  * Low-level pay: process payment with an existing instrument or for APM/express flows
1814
1873
  * where no instrument is needed (redirect-based methods).
1815
1874
  */
1816
1875
  async payDirect(opts) {
1817
- return this.http.post("/api/public/v1/checkout/pay-v2", {
1876
+ return this.rememberPaymentsApiStart(await this.http.post("/api/public/v1/checkout/pay-v2", {
1818
1877
  checkoutSessionId: opts.checkoutSessionId,
1819
1878
  paymentInstrumentId: opts.paymentInstrumentId ?? "",
1820
1879
  storeId: this.storeId,
@@ -1824,7 +1883,7 @@ var TagadaHeadlessBundle = (() => {
1824
1883
  isExpress: opts.isExpress,
1825
1884
  threedsSessionId: opts.threedsSessionId,
1826
1885
  returnUrl: opts.returnUrl
1827
- });
1886
+ }), opts);
1828
1887
  }
1829
1888
  /**
1830
1889
  * Persist a wallet contact onto the session before the charge.
@@ -2001,13 +2060,18 @@ var TagadaHeadlessBundle = (() => {
2001
2060
  /**
2002
2061
  * Process an APM payment (Klarna, iDEAL, etc.) via redirect.
2003
2062
  * These typically don't require a payment instrument -- the processor handles the redirect.
2063
+ *
2064
+ * `returnUrl` is the page that runs `maybeResumeFromUrl()` after the redirect. It defaults to the
2065
+ * current page, like `processPayment()`. pay-v2 still prefers the session's checkout page when it
2066
+ * has a live one, so this applies to headless pages. Pass the same value to `finalize()`.
2004
2067
  */
2005
2068
  async processApm(opts) {
2006
2069
  return this.payDirect({
2007
2070
  checkoutSessionId: opts.checkoutSessionId,
2008
2071
  paymentMethod: opts.paymentMethod,
2009
2072
  processorId: opts.processorId,
2010
- paymentFlowId: opts.paymentFlowId
2073
+ paymentFlowId: opts.paymentFlowId,
2074
+ returnUrl: opts.returnUrl ?? (typeof window !== "undefined" ? window.location.href : void 0)
2011
2075
  });
2012
2076
  }
2013
2077
  /**
@@ -2307,6 +2371,11 @@ var TagadaHeadlessBundle = (() => {
2307
2371
  var _a, _b, _c;
2308
2372
  const payment = input.payment;
2309
2373
  const returnUrl = (opts == null ? void 0 : opts.returnUrl) ?? (typeof window !== "undefined" ? window.location.href : void 0);
2374
+ if (!payment) {
2375
+ const started = readStartedPayment(input);
2376
+ if (started)
2377
+ return this.finalizeOnPaymentsApi(started, returnUrl);
2378
+ }
2310
2379
  if (payment.status === "succeeded") {
2311
2380
  this.emitPaid((_a = input.order) == null ? void 0 : _a.id, payment);
2312
2381
  return { status: "succeeded", payment, order: input.order };
@@ -2327,6 +2396,11 @@ var TagadaHeadlessBundle = (() => {
2327
2396
  * You can also call it manually in non-React apps.
2328
2397
  */
2329
2398
  async resumeAfterRedirect(paymentId) {
2399
+ const parked = takeParkedPaymentsApiReturn(paymentId);
2400
+ if (parked) {
2401
+ const url2 = typeof window !== "undefined" ? window.location.href : void 0;
2402
+ return this.onPaymentsApi((flow, host) => flow.resumeOnPaymentsApi(host, paymentId, parked.checkoutSessionId, url2));
2403
+ }
2330
2404
  return this.pollUntilDone(paymentId);
2331
2405
  }
2332
2406
  /**
@@ -2616,6 +2690,48 @@ var TagadaHeadlessBundle = (() => {
2616
2690
  return { status: "pending", paymentId };
2617
2691
  }
2618
2692
  // ---------------------------------------------------------------------------
2693
+ // Internal: Payments API (V3) stores
2694
+ // ---------------------------------------------------------------------------
2695
+ /** Keeps what a V3 pay answer does not say (its session, the method); returns the answer as is. */
2696
+ rememberPaymentsApiStart(answer, opts) {
2697
+ const started = answer && !answer.payment ? readStartedPayment(answer) : null;
2698
+ if (started) {
2699
+ this.paymentsApiStarts.set(started.paymentId, {
2700
+ checkoutSessionId: started.checkoutSessionId ?? opts.checkoutSessionId,
2701
+ ...opts.paymentMethod ? { paymentMethod: opts.paymentMethod } : {}
2702
+ });
2703
+ }
2704
+ return answer;
2705
+ }
2706
+ /** Confirms a started V3 payment with payments-js and runs it to the V2-shaped result. */
2707
+ finalizeOnPaymentsApi(started, returnUrl) {
2708
+ const known = this.paymentsApiStarts.get(started.paymentId);
2709
+ this.paymentsApiStarts.delete(started.paymentId);
2710
+ return this.onPaymentsApi(
2711
+ (flow, host) => flow.finalizeOnPaymentsApi(host, started, {
2712
+ checkoutSessionId: known == null ? void 0 : known.checkoutSessionId,
2713
+ paymentMethod: known == null ? void 0 : known.paymentMethod,
2714
+ returnUrl
2715
+ })
2716
+ );
2717
+ }
2718
+ /** Runs `run` with the lazily imported V3 flow; a flow that cannot load is a failed payment. */
2719
+ async onPaymentsApi(run) {
2720
+ let flow;
2721
+ try {
2722
+ flow = await loadPaymentsApiFlow();
2723
+ } catch (error) {
2724
+ return { status: "failed", error: error instanceof Error ? error.message : String(error) };
2725
+ }
2726
+ return run(flow, {
2727
+ http: this.http,
2728
+ storeId: this.storeId,
2729
+ checkout: this.checkout,
2730
+ stepConfig: this.readInjectedStepConfigRaw(),
2731
+ onPaid: (orderId, payment) => this.emitPaid(orderId, payment)
2732
+ });
2733
+ }
2734
+ // ---------------------------------------------------------------------------
2619
2735
  // Internal helpers
2620
2736
  // ---------------------------------------------------------------------------
2621
2737
  /**
@@ -2635,6 +2751,19 @@ var TagadaHeadlessBundle = (() => {
2635
2751
  return null;
2636
2752
  }
2637
2753
  }
2754
+ /** The whole injected step config (Tagada-hosted pages), or null. */
2755
+ readInjectedStepConfigRaw() {
2756
+ if (typeof window === "undefined")
2757
+ return null;
2758
+ const raw = window.__TGD_STEP_CONFIG__;
2759
+ if (!raw)
2760
+ return null;
2761
+ try {
2762
+ return typeof raw === "string" ? JSON.parse(raw) : raw;
2763
+ } catch {
2764
+ return null;
2765
+ }
2766
+ }
2638
2767
  /** Tracking hook. Never throws, never awaits: a pixel must not be able to break a payment. */
2639
2768
  emitPaid(orderId, payment) {
2640
2769
  var _a;
@@ -2667,7 +2796,7 @@ var TagadaHeadlessBundle = (() => {
2667
2796
 
2668
2797
  // src/core/modules/lazyCommerce.ts
2669
2798
  var script = typeof document === "undefined" ? null : document.currentScript;
2670
- var url = (script == null ? void 0 : script.src) ? new URL("tagada-headless-commerce.min.js", script.src).href : "https://cdn.jsdelivr.net/npm/@tagadapay/headless-sdk@1.20.1/dist/tagada-headless-commerce.min.js";
2799
+ var url = (script == null ? void 0 : script.src) ? new URL("tagada-headless-commerce.min.js", script.src).href : "https://cdn.jsdelivr.net/npm/@tagadapay/headless-sdk@1.22.0/dist/tagada-headless-commerce.min.js";
2671
2800
  var loading;
2672
2801
  function loadCommerce() {
2673
2802
  if (window.TagadaHeadlessCommerce)