@tagadapay/headless-sdk 1.22.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 (76) hide show
  1. package/CHANGELOG.md +45 -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/helpers/paymentsApi.d.ts +5 -0
  10. package/dist/core/helpers/paymentsApi.d.ts.map +1 -1
  11. package/dist/core/helpers/paymentsApi.js +30 -0
  12. package/dist/core/helpers/paymentsApi.js.map +1 -1
  13. package/dist/core/modules/checkout.d.ts.map +1 -1
  14. package/dist/core/modules/checkout.js +3 -0
  15. package/dist/core/modules/checkout.js.map +1 -1
  16. package/dist/core/modules/offers.d.ts +2 -1
  17. package/dist/core/modules/offers.d.ts.map +1 -1
  18. package/dist/core/modules/offers.js +6 -2
  19. package/dist/core/modules/offers.js.map +1 -1
  20. package/dist/core/modules/payment.d.ts.map +1 -1
  21. package/dist/core/modules/payment.js +12 -0
  22. package/dist/core/modules/payment.js.map +1 -1
  23. package/dist/core/modules/track.d.ts +10 -1
  24. package/dist/core/modules/track.d.ts.map +1 -1
  25. package/dist/core/modules/track.js +89 -3
  26. package/dist/core/modules/track.js.map +1 -1
  27. package/dist/core/version.d.ts +1 -1
  28. package/dist/core/version.js +1 -1
  29. package/dist/pixels/engine.d.ts +3 -3
  30. package/dist/pixels/engine.d.ts.map +1 -1
  31. package/dist/pixels/engine.js +12 -8
  32. package/dist/pixels/engine.js.map +1 -1
  33. package/dist/pixels/index.d.ts +3 -3
  34. package/dist/pixels/index.d.ts.map +1 -1
  35. package/dist/pixels/index.js +1 -1
  36. package/dist/pixels/index.js.map +1 -1
  37. package/dist/pixels/pixelIdentity.d.ts +23 -0
  38. package/dist/pixels/pixelIdentity.d.ts.map +1 -1
  39. package/dist/pixels/pixelIdentity.js +23 -0
  40. package/dist/pixels/pixelIdentity.js.map +1 -1
  41. package/dist/pixels/pixelMapping.d.ts +50 -6
  42. package/dist/pixels/pixelMapping.d.ts.map +1 -1
  43. package/dist/pixels/pixelMapping.js +259 -11
  44. package/dist/pixels/pixelMapping.js.map +1 -1
  45. package/dist/pixels/pixelPurchaseHanded.d.ts +5 -0
  46. package/dist/pixels/pixelPurchaseHanded.d.ts.map +1 -0
  47. package/dist/pixels/pixelPurchaseHanded.js +135 -0
  48. package/dist/pixels/pixelPurchaseHanded.js.map +1 -0
  49. package/dist/pixels/pixelTracker.d.ts +26 -8
  50. package/dist/pixels/pixelTracker.d.ts.map +1 -1
  51. package/dist/pixels/pixelTracker.js +292 -28
  52. package/dist/pixels/pixelTracker.js.map +1 -1
  53. package/dist/pixels/types.d.ts +18 -2
  54. package/dist/pixels/types.d.ts.map +1 -1
  55. package/dist/pixels/types.js +1 -0
  56. package/dist/pixels/types.js.map +1 -1
  57. package/dist/tagada-headless-commerce.min.js +2 -2
  58. package/dist/tagada-headless-commerce.min.js.map +3 -3
  59. package/dist/tagada-headless-react.min.js +2 -2
  60. package/dist/tagada-headless-react.min.js.map +4 -4
  61. package/dist/tagada-headless.js +191 -11
  62. package/dist/tagada-headless.min.js +2 -2
  63. package/dist/tagada-headless.min.js.map +4 -4
  64. package/dist/tagada-pixels.min.js +2 -2
  65. package/dist/tagada-pixels.min.js.map +4 -4
  66. package/dist/tgd/contract/envelope.d.ts +1 -1
  67. package/dist/tgd/contract/envelope.d.ts.map +1 -1
  68. package/dist/tgd/contract/registry.d.ts +10 -3
  69. package/dist/tgd/contract/registry.d.ts.map +1 -1
  70. package/dist/tgd/contract/registry.js +3 -2
  71. package/dist/tgd/contract/registry.js.map +1 -1
  72. package/dist/tgd/contract/unions.d.ts +1 -1
  73. package/dist/tgd/contract/unions.d.ts.map +1 -1
  74. package/dist/tgd/contract/unions.js +1 -1
  75. package/dist/tgd/contract/unions.js.map +1 -1
  76. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @tagadapay/headless-sdk v1.22.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.22.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.22.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) {
@@ -1002,7 +1162,13 @@ var TagadaHeadlessBundle = (() => {
1002
1162
  var _a;
1003
1163
  return engine == null ? void 0 : engine.track(
1004
1164
  event,
1005
- { value: input.amount, currency: input.currency, contents: input.items, num_items: (_a = input.items) == null ? void 0 : _a.length },
1165
+ {
1166
+ value: input.amount,
1167
+ currency: input.currency,
1168
+ contents: input.items,
1169
+ num_items: (_a = input.items) == null ? void 0 : _a.length,
1170
+ ...event === "Purchase" ? { transaction_id: id } : {}
1171
+ },
1006
1172
  { eventId: `${event}_${id}` }
1007
1173
  );
1008
1174
  }
@@ -1588,6 +1754,10 @@ var TagadaHeadlessBundle = (() => {
1588
1754
  }
1589
1755
  return import("../helpers/paymentsApi.js");
1590
1756
  }
1757
+ async function checkoutRiskBody() {
1758
+ const id = await checkoutRiskSessionId();
1759
+ return id ? { checkoutRiskSessionId: id } : {};
1760
+ }
1591
1761
  var FAILED_PAYMENT_STATUSES = /* @__PURE__ */ new Set(["failed", "declined", "rejected", "error"]);
1592
1762
  var oceanSlot = null;
1593
1763
  var oceanSlotTaken = () => !!oceanSlot && (!oceanSlot.attached || oceanSlot.element.isConnected);
@@ -1843,6 +2013,7 @@ var TagadaHeadlessBundle = (() => {
1843
2013
  * Also accepts `paymentInstrumentId` directly for pre-created instruments.
1844
2014
  */
1845
2015
  async pay(opts) {
2016
+ const risk = await checkoutRiskBody();
1846
2017
  if (opts.tagadaToken && !opts.paymentInstrumentId) {
1847
2018
  return this.rememberPaymentsApiStart(await this.http.post("/api/v1/payment/pay-with-token", {
1848
2019
  tagadaToken: opts.tagadaToken,
@@ -1852,7 +2023,8 @@ var TagadaHeadlessBundle = (() => {
1852
2023
  processorId: opts.processorId,
1853
2024
  paymentMethod: opts.paymentMethod,
1854
2025
  isExpress: opts.isExpress,
1855
- metadata: opts.metadata
2026
+ metadata: opts.metadata,
2027
+ ...risk
1856
2028
  }), opts);
1857
2029
  }
1858
2030
  return this.rememberPaymentsApiStart(await this.http.post("/api/public/v1/checkout/pay-v2", {
@@ -1865,7 +2037,8 @@ var TagadaHeadlessBundle = (() => {
1865
2037
  paymentMethod: opts.paymentMethod,
1866
2038
  isExpress: opts.isExpress,
1867
2039
  metadata: opts.metadata,
1868
- returnUrl: opts.returnUrl
2040
+ returnUrl: opts.returnUrl,
2041
+ ...risk
1869
2042
  }), opts);
1870
2043
  }
1871
2044
  /**
@@ -1873,6 +2046,7 @@ var TagadaHeadlessBundle = (() => {
1873
2046
  * where no instrument is needed (redirect-based methods).
1874
2047
  */
1875
2048
  async payDirect(opts) {
2049
+ const risk = await checkoutRiskBody();
1876
2050
  return this.rememberPaymentsApiStart(await this.http.post("/api/public/v1/checkout/pay-v2", {
1877
2051
  checkoutSessionId: opts.checkoutSessionId,
1878
2052
  paymentInstrumentId: opts.paymentInstrumentId ?? "",
@@ -1882,7 +2056,8 @@ var TagadaHeadlessBundle = (() => {
1882
2056
  paymentMethod: opts.paymentMethod,
1883
2057
  isExpress: opts.isExpress,
1884
2058
  threedsSessionId: opts.threedsSessionId,
1885
- returnUrl: opts.returnUrl
2059
+ returnUrl: opts.returnUrl,
2060
+ ...risk
1886
2061
  }), opts);
1887
2062
  }
1888
2063
  /**
@@ -2796,7 +2971,7 @@ var TagadaHeadlessBundle = (() => {
2796
2971
 
2797
2972
  // src/core/modules/lazyCommerce.ts
2798
2973
  var script = typeof document === "undefined" ? null : document.currentScript;
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";
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";
2800
2975
  var loading;
2801
2976
  function loadCommerce() {
2802
2977
  if (window.TagadaHeadlessCommerce)
@@ -3331,7 +3506,12 @@ var TagadaHeadlessBundle = (() => {
3331
3506
  (p) => this.track.notePaid(p),
3332
3507
  (v, d) => this.track.noteSignal("wallet_unavailable", v, d)
3333
3508
  );
3334
- 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
+ );
3335
3515
  this.customer = new CustomerModule(this.http, this.config.storeId);
3336
3516
  this.portal = new CustomerPortalModule(this.http, this.config.storeId, setToken);
3337
3517
  this.catalog = new CatalogModule(this.http, this.config.storeId);