@tagadapay/headless-sdk 1.14.1 → 1.16.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.
- package/dist/core/client.d.ts +7 -0
- package/dist/core/client.d.ts.map +1 -1
- package/dist/core/client.js +10 -3
- package/dist/core/client.js.map +1 -1
- package/dist/core/index.d.ts +3 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/modules/checkout.d.ts +5 -1
- package/dist/core/modules/checkout.d.ts.map +1 -1
- package/dist/core/modules/checkout.js +10 -1
- package/dist/core/modules/checkout.js.map +1 -1
- package/dist/core/modules/payment.d.ts +19 -1
- package/dist/core/modules/payment.d.ts.map +1 -1
- package/dist/core/modules/payment.js +42 -3
- package/dist/core/modules/payment.js.map +1 -1
- package/dist/core/modules/rx.d.ts +32 -1
- package/dist/core/modules/rx.d.ts.map +1 -1
- package/dist/core/modules/rx.js +17 -1
- package/dist/core/modules/rx.js.map +1 -1
- package/dist/core/modules/track.d.ts +127 -0
- package/dist/core/modules/track.d.ts.map +1 -0
- package/dist/core/modules/track.js +371 -0
- package/dist/core/modules/track.js.map +1 -0
- package/dist/core/types.d.ts +2 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/version.d.ts +4 -0
- package/dist/core/version.d.ts.map +1 -0
- package/dist/core/version.js +4 -0
- package/dist/core/version.js.map +1 -0
- package/dist/pixels/engine.d.ts +56 -0
- package/dist/pixels/engine.d.ts.map +1 -0
- package/dist/pixels/engine.js +263 -0
- package/dist/pixels/engine.js.map +1 -0
- package/dist/pixels/index.d.ts +10 -0
- package/dist/pixels/index.d.ts.map +1 -0
- package/dist/pixels/index.js +5 -0
- package/dist/pixels/index.js.map +1 -0
- package/dist/pixels/metaEventId.d.ts +15 -0
- package/dist/pixels/metaEventId.d.ts.map +1 -0
- package/dist/pixels/metaEventId.js +17 -0
- package/dist/pixels/metaEventId.js.map +1 -0
- package/dist/pixels/pixelIdentity.d.ts +34 -0
- package/dist/pixels/pixelIdentity.d.ts.map +1 -0
- package/dist/pixels/pixelIdentity.js +65 -0
- package/dist/pixels/pixelIdentity.js.map +1 -0
- package/dist/pixels/pixelMapping.d.ts +172 -0
- package/dist/pixels/pixelMapping.d.ts.map +1 -0
- package/dist/pixels/pixelMapping.js +574 -0
- package/dist/pixels/pixelMapping.js.map +1 -0
- package/dist/pixels/pixelTracker.d.ts +81 -0
- package/dist/pixels/pixelTracker.d.ts.map +1 -0
- package/dist/pixels/pixelTracker.js +795 -0
- package/dist/pixels/pixelTracker.js.map +1 -0
- package/dist/pixels/types.d.ts +103 -0
- package/dist/pixels/types.d.ts.map +1 -0
- package/dist/pixels/types.js +14 -0
- package/dist/pixels/types.js.map +1 -0
- package/dist/react/hooks/useStep.d.ts +7 -0
- package/dist/react/hooks/useStep.d.ts.map +1 -0
- package/dist/react/hooks/useStep.js +14 -0
- package/dist/react/hooks/useStep.js.map +1 -0
- package/dist/react/index.d.ts +1 -0
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +1 -0
- package/dist/react/index.js.map +1 -1
- package/dist/stripe/index.d.ts +3 -1
- package/dist/stripe/index.d.ts.map +1 -1
- package/dist/stripe/index.js +13 -6
- package/dist/stripe/index.js.map +1 -1
- package/dist/stripe/useStripeExpress.d.ts.map +1 -1
- package/dist/stripe/useStripeExpress.js +15 -1
- package/dist/stripe/useStripeExpress.js.map +1 -1
- package/dist/tagada-headless-react.min.js +2 -2
- package/dist/tagada-headless-react.min.js.map +4 -4
- package/dist/tagada-headless.js +439 -16
- package/dist/tagada-headless.min.js +2 -2
- package/dist/tagada-headless.min.js.map +4 -4
- package/dist/tagada-pixels.min.js +7 -0
- package/dist/tagada-pixels.min.js.map +7 -0
- package/package.json +8 -1
package/dist/tagada-headless.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @tagadapay/headless-sdk v1.
|
|
2
|
+
* @tagadapay/headless-sdk v1.16.0
|
|
3
3
|
* Headless checkout, payments, offers, and CRM
|
|
4
4
|
* @license MIT
|
|
5
5
|
*/
|
|
@@ -63,6 +63,7 @@ var TagadaHeadlessBundle = (() => {
|
|
|
63
63
|
TagadaPaymentError: () => TagadaPaymentError,
|
|
64
64
|
TagadaRateLimitError: () => TagadaRateLimitError,
|
|
65
65
|
TagadaValidationError: () => TagadaValidationError,
|
|
66
|
+
TrackModule: () => TrackModule,
|
|
66
67
|
createHeadlessClient: () => createHeadlessClient,
|
|
67
68
|
ensureGeoDataLoaded: () => ensureGeoDataLoaded,
|
|
68
69
|
formatMoney: () => formatMoney,
|
|
@@ -237,10 +238,11 @@ var TagadaHeadlessBundle = (() => {
|
|
|
237
238
|
|
|
238
239
|
// src/core/modules/checkout.ts
|
|
239
240
|
var CheckoutModule = class _CheckoutModule {
|
|
240
|
-
constructor(http, storeId, onTokenChange) {
|
|
241
|
+
constructor(http, storeId, onTokenChange, onSession) {
|
|
241
242
|
this.http = http;
|
|
242
243
|
this.storeId = storeId;
|
|
243
244
|
this.onTokenChange = onTokenChange;
|
|
245
|
+
this.onSession = onSession;
|
|
244
246
|
}
|
|
245
247
|
/**
|
|
246
248
|
* Returns the most recently loaded `CheckoutSession`, if any.
|
|
@@ -264,7 +266,7 @@ var TagadaHeadlessBundle = (() => {
|
|
|
264
266
|
* Example URL: `/checkout?checkoutToken=abc123&token=eyJ...`
|
|
265
267
|
*/
|
|
266
268
|
async loadSession(checkoutToken, sessionToken, opts) {
|
|
267
|
-
var _a;
|
|
269
|
+
var _a, _b;
|
|
268
270
|
if (sessionToken) {
|
|
269
271
|
this.sessionToken = sessionToken;
|
|
270
272
|
(_a = this.onTokenChange) == null ? void 0 : _a.call(this, sessionToken);
|
|
@@ -282,6 +284,10 @@ var TagadaHeadlessBundle = (() => {
|
|
|
282
284
|
);
|
|
283
285
|
const session = this.normalizeSession(raw);
|
|
284
286
|
this._currentSession = session;
|
|
287
|
+
try {
|
|
288
|
+
(_b = this.onSession) == null ? void 0 : _b.call(this, session);
|
|
289
|
+
} catch {
|
|
290
|
+
}
|
|
285
291
|
return session;
|
|
286
292
|
}
|
|
287
293
|
/**
|
|
@@ -751,6 +757,358 @@ var TagadaHeadlessBundle = (() => {
|
|
|
751
757
|
return Boolean(((_a = address.line1) == null ? void 0 : _a.trim()) && ((_b = address.country) == null ? void 0 : _b.trim()));
|
|
752
758
|
}
|
|
753
759
|
|
|
760
|
+
// src/core/version.ts
|
|
761
|
+
var SDK_NAME = "headless";
|
|
762
|
+
var SDK_VERSION = "1.16.0";
|
|
763
|
+
|
|
764
|
+
// src/core/modules/track.ts
|
|
765
|
+
var CDN_URL = false ? "" : "https://cdn.jsdelivr.net/npm/@tagadapay/headless-sdk@1.16.0/dist/tagada-pixels.min.js";
|
|
766
|
+
async function loadPixels() {
|
|
767
|
+
if (typeof window === "undefined")
|
|
768
|
+
return null;
|
|
769
|
+
if (CDN_URL) {
|
|
770
|
+
const w = window;
|
|
771
|
+
if (w.TagadaPixels)
|
|
772
|
+
return w.TagadaPixels;
|
|
773
|
+
await new Promise((resolve, reject) => {
|
|
774
|
+
const s = document.createElement("script");
|
|
775
|
+
s.src = CDN_URL;
|
|
776
|
+
s.async = true;
|
|
777
|
+
s.onload = () => resolve();
|
|
778
|
+
s.onerror = () => reject(new Error("pixel bundle failed to load"));
|
|
779
|
+
document.head.appendChild(s);
|
|
780
|
+
});
|
|
781
|
+
return w.TagadaPixels ?? null;
|
|
782
|
+
}
|
|
783
|
+
return await import("../../pixels/index.js");
|
|
784
|
+
}
|
|
785
|
+
var FLAG_KEY = "__tgd_track";
|
|
786
|
+
var ANON_KEY = "__tgd_aid";
|
|
787
|
+
var SESSION_KEY = "__tgd_sid";
|
|
788
|
+
var QUEUE_LIMIT = 50;
|
|
789
|
+
var FLUSH_MS = 2e3;
|
|
790
|
+
var DEDUP_MS = 1e3;
|
|
791
|
+
var STEP_MEMORY = 64;
|
|
792
|
+
function toContents(items) {
|
|
793
|
+
if (!Array.isArray(items) || items.length === 0)
|
|
794
|
+
return void 0;
|
|
795
|
+
return items.map((item) => ({ id: item.variantId, quantity: item.quantity, item_price: item.unitAmount }));
|
|
796
|
+
}
|
|
797
|
+
function scalars(data) {
|
|
798
|
+
if (!data)
|
|
799
|
+
return void 0;
|
|
800
|
+
const out = {};
|
|
801
|
+
for (const [key, value] of Object.entries(data)) {
|
|
802
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean")
|
|
803
|
+
out[key] = value;
|
|
804
|
+
}
|
|
805
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
806
|
+
}
|
|
807
|
+
var STANDARD_EVENTS = {
|
|
808
|
+
lead: "Lead",
|
|
809
|
+
product_viewed: "ViewContent",
|
|
810
|
+
added_to_cart: "AddToCart"
|
|
811
|
+
};
|
|
812
|
+
function uuid() {
|
|
813
|
+
try {
|
|
814
|
+
return crypto.randomUUID();
|
|
815
|
+
} catch {
|
|
816
|
+
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
function toPixelsConfig(pixels) {
|
|
820
|
+
const out = {};
|
|
821
|
+
for (const pixel of pixels) {
|
|
822
|
+
const { provider, id, idKey, ...rest } = pixel;
|
|
823
|
+
(out[provider] ?? (out[provider] = [])).push({ ...rest, enabled: true, [idKey]: id, events: pixel.events ?? {} });
|
|
824
|
+
}
|
|
825
|
+
return out;
|
|
826
|
+
}
|
|
827
|
+
var TrackModule = class {
|
|
828
|
+
constructor(baseUrl, storeId, funnelKey) {
|
|
829
|
+
this.baseUrl = baseUrl;
|
|
830
|
+
this.storeId = storeId;
|
|
831
|
+
this.funnelKey = funnelKey;
|
|
832
|
+
this.records = [];
|
|
833
|
+
this.lastStep = /* @__PURE__ */ new Map();
|
|
834
|
+
this.signals = [];
|
|
835
|
+
this.currentStepId = null;
|
|
836
|
+
this.manifestHash = null;
|
|
837
|
+
this.loadedProviders = [];
|
|
838
|
+
this.configPromise = null;
|
|
839
|
+
this.enginePromise = null;
|
|
840
|
+
this.flushTimer = null;
|
|
841
|
+
this.listening = false;
|
|
842
|
+
}
|
|
843
|
+
// -- opt-in flag ----------------------------------------------------------
|
|
844
|
+
/**
|
|
845
|
+
* The flag is `<storeId>:<funnelKey>`. Only the storeId half arms it; the funnel half is DATA,
|
|
846
|
+
* read back by `flagFunnelKey()` so automatic events report the funnel the last `step()` named.
|
|
847
|
+
* A funnel-key mismatch never disarms tracking; only another tenant's storeId reads as disabled.
|
|
848
|
+
*/
|
|
849
|
+
flag() {
|
|
850
|
+
try {
|
|
851
|
+
return (localStorage.getItem(FLAG_KEY) ?? "").split(":");
|
|
852
|
+
} catch {
|
|
853
|
+
return [];
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
enabled() {
|
|
857
|
+
return this.flag()[0] === this.storeId;
|
|
858
|
+
}
|
|
859
|
+
flagFunnelKey() {
|
|
860
|
+
return this.flag()[1] || this.funnelKey;
|
|
861
|
+
}
|
|
862
|
+
/** Every automatic path is off under SSR and off without the flag. */
|
|
863
|
+
off() {
|
|
864
|
+
return typeof window === "undefined" || !this.enabled();
|
|
865
|
+
}
|
|
866
|
+
arm() {
|
|
867
|
+
try {
|
|
868
|
+
localStorage.setItem(FLAG_KEY, `${this.storeId}:${this.funnelKey}`);
|
|
869
|
+
} catch {
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
// -- public API -----------------------------------------------------------
|
|
873
|
+
step(stepId, data) {
|
|
874
|
+
if (typeof window === "undefined")
|
|
875
|
+
return;
|
|
876
|
+
this.arm();
|
|
877
|
+
const path = (data == null ? void 0 : data.path) ?? window.location.pathname;
|
|
878
|
+
const key = `${stepId}|${path}`;
|
|
879
|
+
const at = Date.now();
|
|
880
|
+
const previous = this.lastStep.get(key);
|
|
881
|
+
if (previous !== void 0 && at - previous < DEDUP_MS)
|
|
882
|
+
return;
|
|
883
|
+
this.remember(key, at);
|
|
884
|
+
this.currentStepId = stepId;
|
|
885
|
+
this.listen();
|
|
886
|
+
this.push({ kind: "step", stepId, at, path });
|
|
887
|
+
void this.pixels().then((engine) => engine == null ? void 0 : engine.pageView(path, { stepId }));
|
|
888
|
+
}
|
|
889
|
+
event(name, data) {
|
|
890
|
+
if (this.off())
|
|
891
|
+
return;
|
|
892
|
+
const stepId = this.currentStepId;
|
|
893
|
+
if (stepId === null)
|
|
894
|
+
return;
|
|
895
|
+
const standard = STANDARD_EVENTS[name];
|
|
896
|
+
const eventId = `${standard ?? name}_${uuid()}`;
|
|
897
|
+
this.push({ kind: "event", stepId, name, at: Date.now(), eventId, props: scalars(data) });
|
|
898
|
+
void this.pixels().then(
|
|
899
|
+
(engine) => standard ? engine == null ? void 0 : engine.track(standard, data, { stepId, eventId }) : engine == null ? void 0 : engine.trackCustom(name, data, { stepId })
|
|
900
|
+
);
|
|
901
|
+
}
|
|
902
|
+
/** Keep the dedup map to entries still inside the window, and never past `STEP_MEMORY`. */
|
|
903
|
+
remember(key, at) {
|
|
904
|
+
for (const [seen, when] of this.lastStep) {
|
|
905
|
+
if (at - when >= DEDUP_MS)
|
|
906
|
+
this.lastStep.delete(seen);
|
|
907
|
+
}
|
|
908
|
+
while (this.lastStep.size >= STEP_MEMORY) {
|
|
909
|
+
const oldest = this.lastStep.keys().next();
|
|
910
|
+
if (oldest.done === true)
|
|
911
|
+
break;
|
|
912
|
+
this.lastStep.delete(oldest.value);
|
|
913
|
+
}
|
|
914
|
+
this.lastStep.set(key, at);
|
|
915
|
+
}
|
|
916
|
+
identify(who) {
|
|
917
|
+
if (this.off())
|
|
918
|
+
return;
|
|
919
|
+
void this.pixels().then(
|
|
920
|
+
(engine) => engine == null ? void 0 : engine.identify({ email: who.email, phone: who.phone, externalId: who.customerId })
|
|
921
|
+
);
|
|
922
|
+
}
|
|
923
|
+
consent(state) {
|
|
924
|
+
if (this.off())
|
|
925
|
+
return;
|
|
926
|
+
void this.pixels().then((engine) => engine == null ? void 0 : engine.consent(state));
|
|
927
|
+
}
|
|
928
|
+
async health() {
|
|
929
|
+
if (typeof window === "undefined")
|
|
930
|
+
return this.snapshot();
|
|
931
|
+
if (this.enabled())
|
|
932
|
+
await this.config();
|
|
933
|
+
return this.snapshot();
|
|
934
|
+
}
|
|
935
|
+
// -- internal hooks, called by the checkout and payment modules -----------
|
|
936
|
+
/** @internal */
|
|
937
|
+
noteCheckout(input) {
|
|
938
|
+
this.notePixel("InitiateCheckout", input.checkoutSessionId, input);
|
|
939
|
+
}
|
|
940
|
+
/** @internal */
|
|
941
|
+
notePaid(input) {
|
|
942
|
+
this.notePixel("Purchase", input.orderId, input);
|
|
943
|
+
}
|
|
944
|
+
/** The `eventId` formula is the server's `makeMetaEventId`, so Meta and TikTok dedup. */
|
|
945
|
+
notePixel(event, id, input) {
|
|
946
|
+
if (this.off())
|
|
947
|
+
return;
|
|
948
|
+
void this.pixels().then(
|
|
949
|
+
(engine) => {
|
|
950
|
+
var _a;
|
|
951
|
+
return engine == null ? void 0 : engine.track(
|
|
952
|
+
event,
|
|
953
|
+
{ value: input.amount, currency: input.currency, contents: input.items, num_items: (_a = input.items) == null ? void 0 : _a.length },
|
|
954
|
+
{ eventId: `${event}_${id}` }
|
|
955
|
+
);
|
|
956
|
+
}
|
|
957
|
+
);
|
|
958
|
+
}
|
|
959
|
+
/** @internal */
|
|
960
|
+
noteSignal(signal, value, detail) {
|
|
961
|
+
if (this.off())
|
|
962
|
+
return;
|
|
963
|
+
this.signals.push({ signal, value, detail });
|
|
964
|
+
this.listen();
|
|
965
|
+
this.push({ kind: "signal", signal, value, detail });
|
|
966
|
+
}
|
|
967
|
+
// -- config, engine -------------------------------------------------------
|
|
968
|
+
snapshot() {
|
|
969
|
+
return {
|
|
970
|
+
enabled: typeof window === "undefined" ? false : this.enabled(),
|
|
971
|
+
storeId: this.storeId,
|
|
972
|
+
funnelKey: this.flagFunnelKey(),
|
|
973
|
+
sdk: { name: SDK_NAME, version: SDK_VERSION },
|
|
974
|
+
manifestHash: this.manifestHash,
|
|
975
|
+
pixels: { loaded: this.loadedProviders.length > 0, providers: [...this.loadedProviders] },
|
|
976
|
+
signals: [...this.signals]
|
|
977
|
+
};
|
|
978
|
+
}
|
|
979
|
+
/**
|
|
980
|
+
* R4, once per page. Plain `fetch`, no header, no credentials — never `HttpClient`,
|
|
981
|
+
* which adds `Content-Type` and `x-cms-token` and so preflights against a fixed allow-list.
|
|
982
|
+
*/
|
|
983
|
+
config() {
|
|
984
|
+
if (this.configPromise !== null)
|
|
985
|
+
return this.configPromise;
|
|
986
|
+
const url = `${this.baseUrl}/api/public/v1/sdk/config?storeId=${encodeURIComponent(this.storeId)}&funnel=${encodeURIComponent(this.flagFunnelKey())}`;
|
|
987
|
+
this.configPromise = (async () => {
|
|
988
|
+
try {
|
|
989
|
+
const response = await fetch(url);
|
|
990
|
+
if (!response.ok)
|
|
991
|
+
return null;
|
|
992
|
+
const config = await response.json();
|
|
993
|
+
this.manifestHash = config.manifestHash || null;
|
|
994
|
+
return config;
|
|
995
|
+
} catch {
|
|
996
|
+
return null;
|
|
997
|
+
}
|
|
998
|
+
})();
|
|
999
|
+
return this.configPromise;
|
|
1000
|
+
}
|
|
1001
|
+
pixels() {
|
|
1002
|
+
if (!this.enabled())
|
|
1003
|
+
return Promise.resolve(null);
|
|
1004
|
+
this.enginePromise ?? (this.enginePromise = this.startEngine());
|
|
1005
|
+
return this.enginePromise;
|
|
1006
|
+
}
|
|
1007
|
+
async startEngine() {
|
|
1008
|
+
var _a;
|
|
1009
|
+
try {
|
|
1010
|
+
const config = await this.config();
|
|
1011
|
+
if (config === null)
|
|
1012
|
+
return null;
|
|
1013
|
+
const module = await loadPixels();
|
|
1014
|
+
if (module === null)
|
|
1015
|
+
return null;
|
|
1016
|
+
const engine = module.createPixelEngine({
|
|
1017
|
+
pixels: toPixelsConfig(config.pixels ?? []),
|
|
1018
|
+
steps: config.steps,
|
|
1019
|
+
checkout: config.checkout,
|
|
1020
|
+
requireConsent: ((_a = config.consent) == null ? void 0 : _a.required) === true,
|
|
1021
|
+
onSignal: (signal) => this.onPixelSignal(signal)
|
|
1022
|
+
});
|
|
1023
|
+
await engine.init();
|
|
1024
|
+
this.loadedProviders = [...new Set((config.pixels ?? []).map((pixel) => pixel.provider))];
|
|
1025
|
+
return engine;
|
|
1026
|
+
} catch {
|
|
1027
|
+
return null;
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
onPixelSignal(signal) {
|
|
1031
|
+
const detail = signal.detail ?? {};
|
|
1032
|
+
this.signals.push({ signal: signal.kind, value: signal.provider, detail });
|
|
1033
|
+
this.push({ kind: "signal", signal: signal.kind, value: signal.provider, detail });
|
|
1034
|
+
}
|
|
1035
|
+
// -- R5 queue -------------------------------------------------------------
|
|
1036
|
+
listen() {
|
|
1037
|
+
if (this.listening || typeof window === "undefined")
|
|
1038
|
+
return;
|
|
1039
|
+
this.listening = true;
|
|
1040
|
+
const onLeave = (event) => {
|
|
1041
|
+
if (event.type === "visibilitychange" && document.visibilityState !== "hidden")
|
|
1042
|
+
return;
|
|
1043
|
+
this.flush();
|
|
1044
|
+
};
|
|
1045
|
+
window.addEventListener("pagehide", onLeave);
|
|
1046
|
+
window.addEventListener("visibilitychange", onLeave);
|
|
1047
|
+
}
|
|
1048
|
+
push(record) {
|
|
1049
|
+
if (!this.enabled())
|
|
1050
|
+
return;
|
|
1051
|
+
this.records.push(record);
|
|
1052
|
+
if (this.records.length >= QUEUE_LIMIT) {
|
|
1053
|
+
this.flush();
|
|
1054
|
+
return;
|
|
1055
|
+
}
|
|
1056
|
+
if (this.flushTimer === null)
|
|
1057
|
+
this.flushTimer = setTimeout(() => this.flush(), FLUSH_MS);
|
|
1058
|
+
}
|
|
1059
|
+
/** `localStorage` is an undeclared identifier in Node, so it is read inside the try. */
|
|
1060
|
+
identifier(scope, key) {
|
|
1061
|
+
try {
|
|
1062
|
+
const store = scope === "local" ? localStorage : sessionStorage;
|
|
1063
|
+
const existing = store.getItem(key);
|
|
1064
|
+
if (existing)
|
|
1065
|
+
return existing;
|
|
1066
|
+
const fresh = uuid();
|
|
1067
|
+
store.setItem(key, fresh);
|
|
1068
|
+
return fresh;
|
|
1069
|
+
} catch {
|
|
1070
|
+
return uuid();
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
flush() {
|
|
1074
|
+
if (this.flushTimer !== null) {
|
|
1075
|
+
clearTimeout(this.flushTimer);
|
|
1076
|
+
this.flushTimer = null;
|
|
1077
|
+
}
|
|
1078
|
+
if (this.records.length === 0)
|
|
1079
|
+
return;
|
|
1080
|
+
const records = this.records.splice(0, QUEUE_LIMIT);
|
|
1081
|
+
const payload = {
|
|
1082
|
+
storeId: this.storeId,
|
|
1083
|
+
funnelKey: this.flagFunnelKey(),
|
|
1084
|
+
sdk: { name: SDK_NAME, version: SDK_VERSION },
|
|
1085
|
+
anonymousId: this.identifier("local", ANON_KEY),
|
|
1086
|
+
sessionId: this.identifier("session", SESSION_KEY),
|
|
1087
|
+
records
|
|
1088
|
+
};
|
|
1089
|
+
if (this.manifestHash !== null)
|
|
1090
|
+
payload.manifestHash = this.manifestHash;
|
|
1091
|
+
const body = JSON.stringify(payload);
|
|
1092
|
+
const url = `${this.baseUrl}/api/public/v1/sdk/events`;
|
|
1093
|
+
try {
|
|
1094
|
+
if (typeof navigator !== "undefined" && typeof navigator.sendBeacon === "function") {
|
|
1095
|
+
if (navigator.sendBeacon(url, new Blob([body], { type: "text/plain;charset=UTF-8" })))
|
|
1096
|
+
return;
|
|
1097
|
+
}
|
|
1098
|
+
} catch {
|
|
1099
|
+
}
|
|
1100
|
+
try {
|
|
1101
|
+
void fetch(url, {
|
|
1102
|
+
method: "POST",
|
|
1103
|
+
body,
|
|
1104
|
+
keepalive: true,
|
|
1105
|
+
headers: { "content-type": "text/plain;charset=UTF-8" }
|
|
1106
|
+
}).catch(() => void 0);
|
|
1107
|
+
} catch {
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
};
|
|
1111
|
+
|
|
754
1112
|
// src/core/modules/payment.ts
|
|
755
1113
|
var EXPRESS_METHOD_TYPES = /* @__PURE__ */ new Set(["apple_pay", "google_pay", "paypal", "klarna", "klarna_express", "link"]);
|
|
756
1114
|
function paymentMethodListEntryToConfig(entry) {
|
|
@@ -775,11 +1133,13 @@ var TagadaHeadlessBundle = (() => {
|
|
|
775
1133
|
};
|
|
776
1134
|
}
|
|
777
1135
|
var PaymentModule = class {
|
|
778
|
-
constructor(http, storeId, environment, checkout) {
|
|
1136
|
+
constructor(http, storeId, environment, checkout, onPaid, onSignal) {
|
|
779
1137
|
this.http = http;
|
|
780
1138
|
this.storeId = storeId;
|
|
781
1139
|
this.environment = environment;
|
|
782
1140
|
this.checkout = checkout;
|
|
1141
|
+
this.onPaid = onPaid;
|
|
1142
|
+
this.onSignal = onSignal;
|
|
783
1143
|
/**
|
|
784
1144
|
* Last payment setup seen by `getPaymentSetup` — lets `processApplePay`
|
|
785
1145
|
* resolve the domain's Apple Pay registration (BYOK / platform-integrator)
|
|
@@ -847,7 +1207,7 @@ var TagadaHeadlessBundle = (() => {
|
|
|
847
1207
|
* filtered to only those available in the current browser.
|
|
848
1208
|
*/
|
|
849
1209
|
async getExpressMethods(checkoutSessionId, opts) {
|
|
850
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1210
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
851
1211
|
const setup = await this.getPaymentSetup(checkoutSessionId, opts);
|
|
852
1212
|
const result = {};
|
|
853
1213
|
for (const [key, config] of Object.entries(setup)) {
|
|
@@ -865,12 +1225,15 @@ var TagadaHeadlessBundle = (() => {
|
|
|
865
1225
|
result.applePay = { ...base2, type: "apple_pay", available: !!hasApplePay };
|
|
866
1226
|
}
|
|
867
1227
|
if ((_d = config.methods.google_pay) == null ? void 0 : _d.enabled) {
|
|
1228
|
+
if (typeof window !== "undefined" && !("PaymentRequest" in window)) {
|
|
1229
|
+
(_e = this.onSignal) == null ? void 0 : _e.call(this, "googlePay", { reason: "no-payment-request-api" });
|
|
1230
|
+
}
|
|
868
1231
|
result.googlePay = { ...base2, type: "google_pay" };
|
|
869
1232
|
}
|
|
870
|
-
if ((
|
|
1233
|
+
if ((_f = config.methods.link) == null ? void 0 : _f.enabled) {
|
|
871
1234
|
result.link = { ...base2, type: "link" };
|
|
872
1235
|
}
|
|
873
|
-
if ((
|
|
1236
|
+
if ((_g = config.methods.klarna_express) == null ? void 0 : _g.enabled) {
|
|
874
1237
|
result.klarna = { ...base2, type: "klarna_express" };
|
|
875
1238
|
}
|
|
876
1239
|
continue;
|
|
@@ -886,9 +1249,12 @@ var TagadaHeadlessBundle = (() => {
|
|
|
886
1249
|
metadata: config.metadata
|
|
887
1250
|
};
|
|
888
1251
|
if (method === "apple_pay" || config.type === "apple_pay") {
|
|
889
|
-
const hasApplePay = typeof window !== "undefined" && "ApplePaySession" in window && ((
|
|
1252
|
+
const hasApplePay = typeof window !== "undefined" && "ApplePaySession" in window && ((_i = (_h = window.ApplePaySession) == null ? void 0 : _h.canMakePayments) == null ? void 0 : _i.call(_h));
|
|
890
1253
|
result.applePay = { ...base, available: !!hasApplePay };
|
|
891
1254
|
} else if (method === "google_pay" || config.type === "google_pay") {
|
|
1255
|
+
if (typeof window !== "undefined" && !("PaymentRequest" in window)) {
|
|
1256
|
+
(_j = this.onSignal) == null ? void 0 : _j.call(this, "googlePay", { reason: "no-payment-request-api" });
|
|
1257
|
+
}
|
|
892
1258
|
result.googlePay = base;
|
|
893
1259
|
} else if (method === "paypal") {
|
|
894
1260
|
result.paypal = base;
|
|
@@ -1287,14 +1653,15 @@ var TagadaHeadlessBundle = (() => {
|
|
|
1287
1653
|
* don't need to re-pay.
|
|
1288
1654
|
*/
|
|
1289
1655
|
async finalize(input, opts) {
|
|
1290
|
-
var _a, _b;
|
|
1656
|
+
var _a, _b, _c;
|
|
1291
1657
|
const payment = input.payment;
|
|
1292
1658
|
const returnUrl = (opts == null ? void 0 : opts.returnUrl) ?? (typeof window !== "undefined" ? window.location.href : void 0);
|
|
1293
1659
|
if (payment.status === "succeeded") {
|
|
1660
|
+
this.emitPaid((_a = input.order) == null ? void 0 : _a.id, payment);
|
|
1294
1661
|
return { status: "succeeded", payment, order: input.order };
|
|
1295
1662
|
}
|
|
1296
1663
|
if (payment.status === "failed" || payment.status === "declined") {
|
|
1297
|
-
const msg = ((
|
|
1664
|
+
const msg = ((_b = payment.requireActionData) == null ? void 0 : _b.message) || ((_c = payment.requireActionData) == null ? void 0 : _c.errorCode) || `Payment ${payment.status}`;
|
|
1298
1665
|
return { status: "failed", error: msg, payment };
|
|
1299
1666
|
}
|
|
1300
1667
|
if (payment.requireAction && payment.requireAction !== "none" && payment.requireActionData) {
|
|
@@ -1528,6 +1895,7 @@ var TagadaHeadlessBundle = (() => {
|
|
|
1528
1895
|
* Also handles new requireAction that may appear during polling.
|
|
1529
1896
|
*/
|
|
1530
1897
|
async pollUntilDone(paymentId, opts) {
|
|
1898
|
+
var _a;
|
|
1531
1899
|
const interval = (opts == null ? void 0 : opts.intervalMs) ?? 1500;
|
|
1532
1900
|
const timeout = (opts == null ? void 0 : opts.timeoutMs) ?? 6e4;
|
|
1533
1901
|
const start = Date.now();
|
|
@@ -1546,6 +1914,9 @@ var TagadaHeadlessBundle = (() => {
|
|
|
1546
1914
|
continue;
|
|
1547
1915
|
}
|
|
1548
1916
|
if (status.status === "succeeded" || status.status === "pending" && status.subStatus === "authorized") {
|
|
1917
|
+
if (status.status === "succeeded") {
|
|
1918
|
+
this.emitPaid((_a = status.order) == null ? void 0 : _a.id, status);
|
|
1919
|
+
}
|
|
1549
1920
|
return { status: "succeeded", payment: status, order: status.order };
|
|
1550
1921
|
}
|
|
1551
1922
|
if (status.status === "failed" || status.status === "declined") {
|
|
@@ -1581,14 +1952,32 @@ var TagadaHeadlessBundle = (() => {
|
|
|
1581
1952
|
return null;
|
|
1582
1953
|
}
|
|
1583
1954
|
}
|
|
1955
|
+
/** Tracking hook. Never throws, never awaits: a pixel must not be able to break a payment. */
|
|
1956
|
+
emitPaid(orderId, payment) {
|
|
1957
|
+
var _a;
|
|
1958
|
+
if (!orderId || !this.onPaid)
|
|
1959
|
+
return;
|
|
1960
|
+
try {
|
|
1961
|
+
const session = (_a = this.checkout) == null ? void 0 : _a.getCurrentSession();
|
|
1962
|
+
this.onPaid({
|
|
1963
|
+
orderId,
|
|
1964
|
+
amount: payment.amount,
|
|
1965
|
+
currency: payment.currency,
|
|
1966
|
+
items: toContents(session == null ? void 0 : session.items)
|
|
1967
|
+
});
|
|
1968
|
+
} catch {
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1584
1971
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1585
1972
|
async loadCoreJs() {
|
|
1586
1973
|
try {
|
|
1587
1974
|
return await import("@tagadapay/core-js");
|
|
1588
|
-
} catch {
|
|
1589
|
-
|
|
1975
|
+
} catch (cause) {
|
|
1976
|
+
const error = new Error(
|
|
1590
1977
|
"This method requires @tagadapay/core-js. Install it: npm install @tagadapay/core-js"
|
|
1591
1978
|
);
|
|
1979
|
+
error.cause = cause;
|
|
1980
|
+
throw error;
|
|
1592
1981
|
}
|
|
1593
1982
|
}
|
|
1594
1983
|
};
|
|
@@ -2022,8 +2411,24 @@ var TagadaHeadlessBundle = (() => {
|
|
|
2022
2411
|
|
|
2023
2412
|
// src/core/modules/rx.ts
|
|
2024
2413
|
var RxModule = class {
|
|
2025
|
-
constructor(http) {
|
|
2414
|
+
constructor(http, storeId) {
|
|
2026
2415
|
this.http = http;
|
|
2416
|
+
this.storeId = storeId;
|
|
2417
|
+
}
|
|
2418
|
+
/**
|
|
2419
|
+
* Activation status of the store: steps, missing items and whether Rx
|
|
2420
|
+
* payments are `setting_up` or `ready`. Storefronts use it to show
|
|
2421
|
+
* "Payments are being set up" instead of letting a checkout fail.
|
|
2422
|
+
*
|
|
2423
|
+
* Read-only / public. Defaults to the client's `storeId`.
|
|
2424
|
+
*/
|
|
2425
|
+
async getActivationStatus(storeId) {
|
|
2426
|
+
const id = storeId ?? this.storeId;
|
|
2427
|
+
if (!id)
|
|
2428
|
+
throw new Error("rx.getActivationStatus: storeId is required");
|
|
2429
|
+
return this.http.get("/api/public/v1/rx/activation-status", {
|
|
2430
|
+
params: { storeId: id }
|
|
2431
|
+
});
|
|
2027
2432
|
}
|
|
2028
2433
|
/**
|
|
2029
2434
|
* Check whether a product requires an Rx case. Storefronts call this
|
|
@@ -2087,11 +2492,29 @@ var TagadaHeadlessBundle = (() => {
|
|
|
2087
2492
|
apiKey: config.apiKey,
|
|
2088
2493
|
getToken: () => this._sessionToken
|
|
2089
2494
|
});
|
|
2495
|
+
this.track = new TrackModule(baseUrl, this.config.storeId, this.config.funnel ?? "main");
|
|
2090
2496
|
const setToken = (token) => {
|
|
2091
2497
|
this._sessionToken = token;
|
|
2092
2498
|
};
|
|
2093
|
-
this.checkout = new CheckoutModule(
|
|
2094
|
-
|
|
2499
|
+
this.checkout = new CheckoutModule(
|
|
2500
|
+
this.http,
|
|
2501
|
+
this.config.storeId,
|
|
2502
|
+
setToken,
|
|
2503
|
+
(s) => this.track.noteCheckout({
|
|
2504
|
+
checkoutSessionId: s.id,
|
|
2505
|
+
amount: s.totals.total,
|
|
2506
|
+
currency: s.totals.currency,
|
|
2507
|
+
items: toContents(s.items)
|
|
2508
|
+
})
|
|
2509
|
+
);
|
|
2510
|
+
this.payment = new PaymentModule(
|
|
2511
|
+
this.http,
|
|
2512
|
+
this.config.storeId,
|
|
2513
|
+
environment,
|
|
2514
|
+
this.checkout,
|
|
2515
|
+
(p) => this.track.notePaid(p),
|
|
2516
|
+
(v, d) => this.track.noteSignal("wallet_unavailable", v, d)
|
|
2517
|
+
);
|
|
2095
2518
|
this.offers = new OffersModule(this.http, this.config.storeId, this.payment);
|
|
2096
2519
|
this.customer = new CustomerModule(this.http, this.config.storeId);
|
|
2097
2520
|
this.catalog = new CatalogModule(this.http, this.config.storeId);
|
|
@@ -2101,7 +2524,7 @@ var TagadaHeadlessBundle = (() => {
|
|
|
2101
2524
|
this.checkout,
|
|
2102
2525
|
this.config.accountId
|
|
2103
2526
|
);
|
|
2104
|
-
this.rx = new RxModule(this.http);
|
|
2527
|
+
this.rx = new RxModule(this.http, this.config.storeId);
|
|
2105
2528
|
}
|
|
2106
2529
|
/** Manually set the session token (e.g. from URL params on page load). */
|
|
2107
2530
|
setSessionToken(token) {
|