@tagadapay/headless-sdk 1.23.0 → 1.24.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 (64) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/core/client.d.ts.map +1 -1
  3. package/dist/core/client.js +1 -1
  4. package/dist/core/client.js.map +1 -1
  5. package/dist/core/helpers/checkoutRisk.d.ts +29 -0
  6. package/dist/core/helpers/checkoutRisk.d.ts.map +1 -0
  7. package/dist/core/helpers/checkoutRisk.js +107 -0
  8. package/dist/core/helpers/checkoutRisk.js.map +1 -0
  9. package/dist/core/modules/checkout.d.ts.map +1 -1
  10. package/dist/core/modules/checkout.js +3 -0
  11. package/dist/core/modules/checkout.js.map +1 -1
  12. package/dist/core/modules/offers.d.ts +2 -1
  13. package/dist/core/modules/offers.d.ts.map +1 -1
  14. package/dist/core/modules/offers.js +6 -2
  15. package/dist/core/modules/offers.js.map +1 -1
  16. package/dist/core/modules/payment.d.ts.map +1 -1
  17. package/dist/core/modules/payment.js +12 -0
  18. package/dist/core/modules/payment.js.map +1 -1
  19. package/dist/core/modules/track.d.ts +10 -1
  20. package/dist/core/modules/track.d.ts.map +1 -1
  21. package/dist/core/modules/track.js +82 -2
  22. package/dist/core/modules/track.js.map +1 -1
  23. package/dist/core/version.d.ts +1 -1
  24. package/dist/core/version.js +1 -1
  25. package/dist/pixels/index.d.ts +3 -3
  26. package/dist/pixels/index.d.ts.map +1 -1
  27. package/dist/pixels/index.js +1 -1
  28. package/dist/pixels/index.js.map +1 -1
  29. package/dist/pixels/pixelIdentity.d.ts +23 -0
  30. package/dist/pixels/pixelIdentity.d.ts.map +1 -1
  31. package/dist/pixels/pixelIdentity.js +23 -0
  32. package/dist/pixels/pixelIdentity.js.map +1 -1
  33. package/dist/pixels/pixelMapping.d.ts +14 -1
  34. package/dist/pixels/pixelMapping.d.ts.map +1 -1
  35. package/dist/pixels/pixelMapping.js +75 -18
  36. package/dist/pixels/pixelMapping.js.map +1 -1
  37. package/dist/pixels/pixelPurchaseHanded.d.ts +5 -0
  38. package/dist/pixels/pixelPurchaseHanded.d.ts.map +1 -0
  39. package/dist/pixels/pixelPurchaseHanded.js +135 -0
  40. package/dist/pixels/pixelPurchaseHanded.js.map +1 -0
  41. package/dist/pixels/pixelTracker.d.ts +17 -5
  42. package/dist/pixels/pixelTracker.d.ts.map +1 -1
  43. package/dist/pixels/pixelTracker.js +129 -22
  44. package/dist/pixels/pixelTracker.js.map +1 -1
  45. package/dist/tagada-headless-commerce.min.js +2 -2
  46. package/dist/tagada-headless-commerce.min.js.map +3 -3
  47. package/dist/tagada-headless-react.min.js +2 -2
  48. package/dist/tagada-headless-react.min.js.map +4 -4
  49. package/dist/tagada-headless.js +184 -10
  50. package/dist/tagada-headless.min.js +2 -2
  51. package/dist/tagada-headless.min.js.map +4 -4
  52. package/dist/tagada-pixels.min.js +2 -2
  53. package/dist/tagada-pixels.min.js.map +4 -4
  54. package/dist/tgd/contract/envelope.d.ts +1 -1
  55. package/dist/tgd/contract/envelope.d.ts.map +1 -1
  56. package/dist/tgd/contract/registry.d.ts +10 -3
  57. package/dist/tgd/contract/registry.d.ts.map +1 -1
  58. package/dist/tgd/contract/registry.js +3 -2
  59. package/dist/tgd/contract/registry.js.map +1 -1
  60. package/dist/tgd/contract/unions.d.ts +1 -1
  61. package/dist/tgd/contract/unions.d.ts.map +1 -1
  62. package/dist/tgd/contract/unions.js +1 -1
  63. package/dist/tgd/contract/unions.js.map +1 -1
  64. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @tagadapay/headless-sdk v1.23.0
2
+ * @tagadapay/headless-sdk v1.24.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.23.0";
145
+ var SDK_VERSION = "1.24.0";
146
146
 
147
147
  // src/core/http.ts
148
148
  var BASE_URLS = {
@@ -270,6 +270,86 @@ var TagadaHeadlessBundle = (() => {
270
270
  }
271
271
  }
272
272
 
273
+ // src/core/helpers/checkoutRisk.ts
274
+ var RISK_JS_SRC = {
275
+ live: "https://risk.checkout.com/cdn/risk/1/risk.js",
276
+ sandbox: "https://risk.sandbox.checkout.com/cdn/risk/1/risk.js"
277
+ };
278
+ var CHECKOUT_RISK_WAIT_MS = 1500;
279
+ var SLOT = "__tagadaCheckoutRisk";
280
+ var DEVICE_SESSION_ID = /^dsid_\w{26}$/;
281
+ var PUBLIC_KEY = /^pk_(sbox_)?[\w-]+$/;
282
+ function browserWindow() {
283
+ return typeof window === "undefined" || typeof document === "undefined" ? void 0 : window;
284
+ }
285
+ function publicKeyOf(config) {
286
+ const key = config && typeof config === "object" ? config.publicKey : void 0;
287
+ return typeof key === "string" && PUBLIC_KEY.test(key) ? key : void 0;
288
+ }
289
+ function loadRiskJs(win, src) {
290
+ if (win.Risk)
291
+ return Promise.resolve(win.Risk);
292
+ return new Promise((resolve, reject) => {
293
+ const settle = () => win.Risk ? resolve(win.Risk) : reject(new Error("Risk.js loaded without window.Risk"));
294
+ const fail = () => reject(new Error("Risk.js did not load"));
295
+ const existing = document.querySelector(`script[src="${src}"]`);
296
+ if (existing) {
297
+ existing.addEventListener("load", settle);
298
+ existing.addEventListener("error", fail);
299
+ return;
300
+ }
301
+ const script2 = document.createElement("script");
302
+ script2.src = src;
303
+ script2.async = true;
304
+ script2.addEventListener("load", settle);
305
+ script2.addEventListener("error", fail);
306
+ document.head.appendChild(script2);
307
+ });
308
+ }
309
+ async function collect(win, publicKey) {
310
+ const src = publicKey.startsWith("pk_sbox_") ? RISK_JS_SRC.sandbox : RISK_JS_SRC.live;
311
+ const Risk = await loadRiskJs(win, src);
312
+ const risk = Risk.init(publicKey);
313
+ const id = await (risk == null ? void 0 : risk.publishRiskData());
314
+ return typeof id === "string" && DEVICE_SESSION_ID.test(id) ? id : void 0;
315
+ }
316
+ function startCheckoutRisk(config) {
317
+ var _a;
318
+ try {
319
+ const win = browserWindow();
320
+ const publicKey = publicKeyOf(config);
321
+ if (!win || !publicKey || ((_a = win[SLOT]) == null ? void 0 : _a.publicKey) === publicKey)
322
+ return;
323
+ win[SLOT] = {
324
+ publicKey,
325
+ deviceSessionId: collect(win, publicKey).catch((error) => {
326
+ console.warn("[tagada] Checkout.com Risk.js skipped:", error instanceof Error ? error.message : error);
327
+ return void 0;
328
+ })
329
+ };
330
+ } catch {
331
+ }
332
+ }
333
+ async function checkoutRiskSessionId(waitMs = CHECKOUT_RISK_WAIT_MS) {
334
+ var _a, _b;
335
+ let timer;
336
+ try {
337
+ const pending = (_b = (_a = browserWindow()) == null ? void 0 : _a[SLOT]) == null ? void 0 : _b.deviceSessionId;
338
+ if (!pending)
339
+ return void 0;
340
+ const late = new Promise((resolve) => {
341
+ timer = setTimeout(() => resolve(void 0), waitMs);
342
+ });
343
+ const id = await Promise.race([pending, late]);
344
+ return typeof id === "string" && DEVICE_SESSION_ID.test(id) ? id : void 0;
345
+ } catch {
346
+ return void 0;
347
+ } finally {
348
+ if (timer)
349
+ clearTimeout(timer);
350
+ }
351
+ }
352
+
273
353
  // src/core/modules/checkout.ts
274
354
  var CheckoutModule = class _CheckoutModule {
275
355
  constructor(http, storeId, onTokenChange, onSession) {
@@ -316,6 +396,7 @@ var TagadaHeadlessBundle = (() => {
316
396
  token: this.sessionToken
317
397
  }
318
398
  );
399
+ startCheckoutRisk(raw == null ? void 0 : raw.checkoutRisk);
319
400
  const session = this.normalizeSession(raw);
320
401
  this._currentSession = session;
321
402
  try {
@@ -805,7 +886,7 @@ var TagadaHeadlessBundle = (() => {
805
886
  }
806
887
 
807
888
  // src/core/modules/track.ts
808
- var CDN_URL = false ? "" : "https://cdn.jsdelivr.net/npm/@tagadapay/headless-sdk@1.23.0/dist/tagada-pixels.min.js";
889
+ var CDN_URL = false ? "" : "https://cdn.jsdelivr.net/npm/@tagadapay/headless-sdk@1.24.0/dist/tagada-pixels.min.js";
809
890
  function loadScript(src, isReady) {
810
891
  if (isReady())
811
892
  return Promise.resolve();
@@ -837,6 +918,10 @@ var TagadaHeadlessBundle = (() => {
837
918
  var FLUSH_MS = 2e3;
838
919
  var DEDUP_MS = 1e3;
839
920
  var STEP_MEMORY = 64;
921
+ var VISITS_KEY = "__tgd_visits";
922
+ var VISIT_MEMORY = 20;
923
+ var LINK_MEMORY = 50;
924
+ var THANK_YOU = "thankyou";
840
925
  function toContents(items) {
841
926
  if (!Array.isArray(items) || items.length === 0)
842
927
  return void 0;
@@ -857,6 +942,25 @@ var TagadaHeadlessBundle = (() => {
857
942
  product_viewed: "ViewContent",
858
943
  added_to_cart: "AddToCart"
859
944
  };
945
+ function readVisits() {
946
+ try {
947
+ const parsed = JSON.parse(localStorage.getItem(VISITS_KEY) ?? "");
948
+ if (parsed && typeof parsed.links === "object" && Array.isArray(parsed.visits))
949
+ return parsed;
950
+ } catch {
951
+ }
952
+ return { links: {}, visits: [] };
953
+ }
954
+ function writeVisits(memory) {
955
+ const links = Object.entries(memory.links).slice(-LINK_MEMORY);
956
+ try {
957
+ localStorage.setItem(
958
+ VISITS_KEY,
959
+ JSON.stringify({ links: Object.fromEntries(links), visits: memory.visits.slice(-VISIT_MEMORY) })
960
+ );
961
+ } catch {
962
+ }
963
+ }
860
964
  function uuid() {
861
965
  try {
862
966
  return crypto.randomUUID();
@@ -934,6 +1038,11 @@ var TagadaHeadlessBundle = (() => {
934
1038
  this.listen();
935
1039
  this.push({ kind: "step", stepId, at, path });
936
1040
  void this.pixels().then((engine) => engine == null ? void 0 : engine.pageView(path, { stepId }));
1041
+ void this.config().then((config) => {
1042
+ var _a, _b;
1043
+ if (((_b = (_a = config == null ? void 0 : config.steps) == null ? void 0 : _a[stepId]) == null ? void 0 : _b.type) === THANK_YOU)
1044
+ this.deliverVisits();
1045
+ });
937
1046
  void this.core().then((t) => t == null ? void 0 : t.page({ step_id: stepId })).catch(() => void 0);
938
1047
  }
939
1048
  event(name, data) {
@@ -989,9 +1098,60 @@ var TagadaHeadlessBundle = (() => {
989
1098
  noteCheckout(input) {
990
1099
  this.notePixel("InitiateCheckout", input.checkoutSessionId, input);
991
1100
  }
992
- /** @internal */
1101
+ /** @internal An upsell order and the order it was bought on, known before its payment is confirmed. */
1102
+ noteUpsell(orderId, parentOrderId) {
1103
+ if (this.off())
1104
+ return;
1105
+ const memory = readVisits();
1106
+ memory.links[orderId] = parentOrderId;
1107
+ writeVisits(memory);
1108
+ }
1109
+ /**
1110
+ * One Purchase per paid visit, as the hosted thank-you page sends it: the main order's id and
1111
+ * the visit's total. A paid upsell only adds its amount to its visit. The Purchase leaves on the
1112
+ * funnel's thank-you step, or at the main payment when the funnel declares none.
1113
+ * @internal
1114
+ */
993
1115
  notePaid(input) {
994
- this.notePixel("Purchase", input.orderId, input);
1116
+ if (this.off())
1117
+ return;
1118
+ const memory = readVisits();
1119
+ let root = input.orderId;
1120
+ const seen = /* @__PURE__ */ new Set();
1121
+ while (memory.links[root] !== void 0 && !seen.has(root)) {
1122
+ seen.add(root);
1123
+ root = memory.links[root];
1124
+ }
1125
+ const visit = memory.visits.find((known) => known.id === root);
1126
+ if (root !== input.orderId) {
1127
+ if (visit && !visit.delivered && !visit.expired && visit.currency === input.currency && input.amount !== void 0) {
1128
+ visit.amount = (visit.amount ?? 0) + input.amount;
1129
+ writeVisits(memory);
1130
+ }
1131
+ return;
1132
+ }
1133
+ if (visit)
1134
+ return;
1135
+ memory.visits.push({ id: input.orderId, amount: input.amount, currency: input.currency, items: input.items });
1136
+ writeVisits(memory);
1137
+ void this.config().then((config) => {
1138
+ if (config && !Object.values(config.steps ?? {}).some((step) => step.type === THANK_YOU))
1139
+ this.deliverVisits();
1140
+ });
1141
+ }
1142
+ /** Only the current visit, the latest still open, leaves: an older one never reached its thank-you step. */
1143
+ deliverVisits() {
1144
+ const memory = readVisits();
1145
+ const open = memory.visits.filter((visit) => !visit.delivered && !visit.expired);
1146
+ const current = open[open.length - 1];
1147
+ if (!current)
1148
+ return;
1149
+ for (const visit of open)
1150
+ visit.expired = true;
1151
+ delete current.expired;
1152
+ current.delivered = true;
1153
+ writeVisits(memory);
1154
+ this.notePixel("Purchase", current.id, current);
995
1155
  }
996
1156
  /** The `eventId` formula is the server's `makeMetaEventId`, so Meta and TikTok dedup. */
997
1157
  notePixel(event, id, input) {
@@ -1594,6 +1754,10 @@ var TagadaHeadlessBundle = (() => {
1594
1754
  }
1595
1755
  return import("../helpers/paymentsApi.js");
1596
1756
  }
1757
+ async function checkoutRiskBody() {
1758
+ const id = await checkoutRiskSessionId();
1759
+ return id ? { checkoutRiskSessionId: id } : {};
1760
+ }
1597
1761
  var FAILED_PAYMENT_STATUSES = /* @__PURE__ */ new Set(["failed", "declined", "rejected", "error"]);
1598
1762
  var oceanSlot = null;
1599
1763
  var oceanSlotTaken = () => !!oceanSlot && (!oceanSlot.attached || oceanSlot.element.isConnected);
@@ -1849,6 +2013,7 @@ var TagadaHeadlessBundle = (() => {
1849
2013
  * Also accepts `paymentInstrumentId` directly for pre-created instruments.
1850
2014
  */
1851
2015
  async pay(opts) {
2016
+ const risk = await checkoutRiskBody();
1852
2017
  if (opts.tagadaToken && !opts.paymentInstrumentId) {
1853
2018
  return this.rememberPaymentsApiStart(await this.http.post("/api/v1/payment/pay-with-token", {
1854
2019
  tagadaToken: opts.tagadaToken,
@@ -1858,7 +2023,8 @@ var TagadaHeadlessBundle = (() => {
1858
2023
  processorId: opts.processorId,
1859
2024
  paymentMethod: opts.paymentMethod,
1860
2025
  isExpress: opts.isExpress,
1861
- metadata: opts.metadata
2026
+ metadata: opts.metadata,
2027
+ ...risk
1862
2028
  }), opts);
1863
2029
  }
1864
2030
  return this.rememberPaymentsApiStart(await this.http.post("/api/public/v1/checkout/pay-v2", {
@@ -1871,7 +2037,8 @@ var TagadaHeadlessBundle = (() => {
1871
2037
  paymentMethod: opts.paymentMethod,
1872
2038
  isExpress: opts.isExpress,
1873
2039
  metadata: opts.metadata,
1874
- returnUrl: opts.returnUrl
2040
+ returnUrl: opts.returnUrl,
2041
+ ...risk
1875
2042
  }), opts);
1876
2043
  }
1877
2044
  /**
@@ -1879,6 +2046,7 @@ var TagadaHeadlessBundle = (() => {
1879
2046
  * where no instrument is needed (redirect-based methods).
1880
2047
  */
1881
2048
  async payDirect(opts) {
2049
+ const risk = await checkoutRiskBody();
1882
2050
  return this.rememberPaymentsApiStart(await this.http.post("/api/public/v1/checkout/pay-v2", {
1883
2051
  checkoutSessionId: opts.checkoutSessionId,
1884
2052
  paymentInstrumentId: opts.paymentInstrumentId ?? "",
@@ -1888,7 +2056,8 @@ var TagadaHeadlessBundle = (() => {
1888
2056
  paymentMethod: opts.paymentMethod,
1889
2057
  isExpress: opts.isExpress,
1890
2058
  threedsSessionId: opts.threedsSessionId,
1891
- returnUrl: opts.returnUrl
2059
+ returnUrl: opts.returnUrl,
2060
+ ...risk
1892
2061
  }), opts);
1893
2062
  }
1894
2063
  /**
@@ -2802,7 +2971,7 @@ var TagadaHeadlessBundle = (() => {
2802
2971
 
2803
2972
  // src/core/modules/lazyCommerce.ts
2804
2973
  var script = typeof document === "undefined" ? null : document.currentScript;
2805
- 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.23.0/dist/tagada-headless-commerce.min.js";
2974
+ 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.24.0/dist/tagada-headless-commerce.min.js";
2806
2975
  var loading;
2807
2976
  function loadCommerce() {
2808
2977
  if (window.TagadaHeadlessCommerce)
@@ -3337,7 +3506,12 @@ var TagadaHeadlessBundle = (() => {
3337
3506
  (p) => this.track.notePaid(p),
3338
3507
  (v, d) => this.track.noteSignal("wallet_unavailable", v, d)
3339
3508
  );
3340
- this.offers = new OffersModule(this.http, this.config.storeId, this.payment);
3509
+ this.offers = new OffersModule(
3510
+ this.http,
3511
+ this.config.storeId,
3512
+ this.payment,
3513
+ (orderId, parentOrderId) => this.track.noteUpsell(orderId, parentOrderId)
3514
+ );
3341
3515
  this.customer = new CustomerModule(this.http, this.config.storeId);
3342
3516
  this.portal = new CustomerPortalModule(this.http, this.config.storeId, setToken);
3343
3517
  this.catalog = new CatalogModule(this.http, this.config.storeId);