@tagadapay/headless-sdk 1.14.0 → 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 +13 -11
- 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 +442 -26
- 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
|
/**
|
|
@@ -359,16 +365,9 @@ var TagadaHeadlessBundle = (() => {
|
|
|
359
365
|
* ```
|
|
360
366
|
*/
|
|
361
367
|
async createSessionUrl(opts) {
|
|
362
|
-
const
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
returnUrl: opts.returnUrl,
|
|
366
|
-
customerEmail: opts.customerEmail,
|
|
367
|
-
customerFirstName: opts.customerFirstName,
|
|
368
|
-
customerLastName: opts.customerLastName
|
|
369
|
-
});
|
|
370
|
-
const origin = opts.origin ?? (typeof window !== "undefined" ? window.location.origin : "");
|
|
371
|
-
const checkoutPath = opts.checkoutPath ?? "/checkout";
|
|
368
|
+
const { checkoutPath = "/checkout", origin: originOverride, ...sessionOpts } = opts;
|
|
369
|
+
const session = await this.createSession(sessionOpts);
|
|
370
|
+
const origin = originOverride ?? (typeof window !== "undefined" ? window.location.origin : "");
|
|
372
371
|
const params = new URLSearchParams({
|
|
373
372
|
checkoutToken: session.checkoutToken,
|
|
374
373
|
sessionToken: session.sessionToken
|
|
@@ -758,6 +757,358 @@ var TagadaHeadlessBundle = (() => {
|
|
|
758
757
|
return Boolean(((_a = address.line1) == null ? void 0 : _a.trim()) && ((_b = address.country) == null ? void 0 : _b.trim()));
|
|
759
758
|
}
|
|
760
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
|
+
|
|
761
1112
|
// src/core/modules/payment.ts
|
|
762
1113
|
var EXPRESS_METHOD_TYPES = /* @__PURE__ */ new Set(["apple_pay", "google_pay", "paypal", "klarna", "klarna_express", "link"]);
|
|
763
1114
|
function paymentMethodListEntryToConfig(entry) {
|
|
@@ -782,11 +1133,13 @@ var TagadaHeadlessBundle = (() => {
|
|
|
782
1133
|
};
|
|
783
1134
|
}
|
|
784
1135
|
var PaymentModule = class {
|
|
785
|
-
constructor(http, storeId, environment, checkout) {
|
|
1136
|
+
constructor(http, storeId, environment, checkout, onPaid, onSignal) {
|
|
786
1137
|
this.http = http;
|
|
787
1138
|
this.storeId = storeId;
|
|
788
1139
|
this.environment = environment;
|
|
789
1140
|
this.checkout = checkout;
|
|
1141
|
+
this.onPaid = onPaid;
|
|
1142
|
+
this.onSignal = onSignal;
|
|
790
1143
|
/**
|
|
791
1144
|
* Last payment setup seen by `getPaymentSetup` — lets `processApplePay`
|
|
792
1145
|
* resolve the domain's Apple Pay registration (BYOK / platform-integrator)
|
|
@@ -854,7 +1207,7 @@ var TagadaHeadlessBundle = (() => {
|
|
|
854
1207
|
* filtered to only those available in the current browser.
|
|
855
1208
|
*/
|
|
856
1209
|
async getExpressMethods(checkoutSessionId, opts) {
|
|
857
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1210
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
858
1211
|
const setup = await this.getPaymentSetup(checkoutSessionId, opts);
|
|
859
1212
|
const result = {};
|
|
860
1213
|
for (const [key, config] of Object.entries(setup)) {
|
|
@@ -872,12 +1225,15 @@ var TagadaHeadlessBundle = (() => {
|
|
|
872
1225
|
result.applePay = { ...base2, type: "apple_pay", available: !!hasApplePay };
|
|
873
1226
|
}
|
|
874
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
|
+
}
|
|
875
1231
|
result.googlePay = { ...base2, type: "google_pay" };
|
|
876
1232
|
}
|
|
877
|
-
if ((
|
|
1233
|
+
if ((_f = config.methods.link) == null ? void 0 : _f.enabled) {
|
|
878
1234
|
result.link = { ...base2, type: "link" };
|
|
879
1235
|
}
|
|
880
|
-
if ((
|
|
1236
|
+
if ((_g = config.methods.klarna_express) == null ? void 0 : _g.enabled) {
|
|
881
1237
|
result.klarna = { ...base2, type: "klarna_express" };
|
|
882
1238
|
}
|
|
883
1239
|
continue;
|
|
@@ -893,9 +1249,12 @@ var TagadaHeadlessBundle = (() => {
|
|
|
893
1249
|
metadata: config.metadata
|
|
894
1250
|
};
|
|
895
1251
|
if (method === "apple_pay" || config.type === "apple_pay") {
|
|
896
|
-
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));
|
|
897
1253
|
result.applePay = { ...base, available: !!hasApplePay };
|
|
898
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
|
+
}
|
|
899
1258
|
result.googlePay = base;
|
|
900
1259
|
} else if (method === "paypal") {
|
|
901
1260
|
result.paypal = base;
|
|
@@ -1294,14 +1653,15 @@ var TagadaHeadlessBundle = (() => {
|
|
|
1294
1653
|
* don't need to re-pay.
|
|
1295
1654
|
*/
|
|
1296
1655
|
async finalize(input, opts) {
|
|
1297
|
-
var _a, _b;
|
|
1656
|
+
var _a, _b, _c;
|
|
1298
1657
|
const payment = input.payment;
|
|
1299
1658
|
const returnUrl = (opts == null ? void 0 : opts.returnUrl) ?? (typeof window !== "undefined" ? window.location.href : void 0);
|
|
1300
1659
|
if (payment.status === "succeeded") {
|
|
1660
|
+
this.emitPaid((_a = input.order) == null ? void 0 : _a.id, payment);
|
|
1301
1661
|
return { status: "succeeded", payment, order: input.order };
|
|
1302
1662
|
}
|
|
1303
1663
|
if (payment.status === "failed" || payment.status === "declined") {
|
|
1304
|
-
const msg = ((
|
|
1664
|
+
const msg = ((_b = payment.requireActionData) == null ? void 0 : _b.message) || ((_c = payment.requireActionData) == null ? void 0 : _c.errorCode) || `Payment ${payment.status}`;
|
|
1305
1665
|
return { status: "failed", error: msg, payment };
|
|
1306
1666
|
}
|
|
1307
1667
|
if (payment.requireAction && payment.requireAction !== "none" && payment.requireActionData) {
|
|
@@ -1535,6 +1895,7 @@ var TagadaHeadlessBundle = (() => {
|
|
|
1535
1895
|
* Also handles new requireAction that may appear during polling.
|
|
1536
1896
|
*/
|
|
1537
1897
|
async pollUntilDone(paymentId, opts) {
|
|
1898
|
+
var _a;
|
|
1538
1899
|
const interval = (opts == null ? void 0 : opts.intervalMs) ?? 1500;
|
|
1539
1900
|
const timeout = (opts == null ? void 0 : opts.timeoutMs) ?? 6e4;
|
|
1540
1901
|
const start = Date.now();
|
|
@@ -1553,6 +1914,9 @@ var TagadaHeadlessBundle = (() => {
|
|
|
1553
1914
|
continue;
|
|
1554
1915
|
}
|
|
1555
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
|
+
}
|
|
1556
1920
|
return { status: "succeeded", payment: status, order: status.order };
|
|
1557
1921
|
}
|
|
1558
1922
|
if (status.status === "failed" || status.status === "declined") {
|
|
@@ -1588,14 +1952,32 @@ var TagadaHeadlessBundle = (() => {
|
|
|
1588
1952
|
return null;
|
|
1589
1953
|
}
|
|
1590
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
|
+
}
|
|
1591
1971
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1592
1972
|
async loadCoreJs() {
|
|
1593
1973
|
try {
|
|
1594
1974
|
return await import("@tagadapay/core-js");
|
|
1595
|
-
} catch {
|
|
1596
|
-
|
|
1975
|
+
} catch (cause) {
|
|
1976
|
+
const error = new Error(
|
|
1597
1977
|
"This method requires @tagadapay/core-js. Install it: npm install @tagadapay/core-js"
|
|
1598
1978
|
);
|
|
1979
|
+
error.cause = cause;
|
|
1980
|
+
throw error;
|
|
1599
1981
|
}
|
|
1600
1982
|
}
|
|
1601
1983
|
};
|
|
@@ -2029,8 +2411,24 @@ var TagadaHeadlessBundle = (() => {
|
|
|
2029
2411
|
|
|
2030
2412
|
// src/core/modules/rx.ts
|
|
2031
2413
|
var RxModule = class {
|
|
2032
|
-
constructor(http) {
|
|
2414
|
+
constructor(http, storeId) {
|
|
2033
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
|
+
});
|
|
2034
2432
|
}
|
|
2035
2433
|
/**
|
|
2036
2434
|
* Check whether a product requires an Rx case. Storefronts call this
|
|
@@ -2094,11 +2492,29 @@ var TagadaHeadlessBundle = (() => {
|
|
|
2094
2492
|
apiKey: config.apiKey,
|
|
2095
2493
|
getToken: () => this._sessionToken
|
|
2096
2494
|
});
|
|
2495
|
+
this.track = new TrackModule(baseUrl, this.config.storeId, this.config.funnel ?? "main");
|
|
2097
2496
|
const setToken = (token) => {
|
|
2098
2497
|
this._sessionToken = token;
|
|
2099
2498
|
};
|
|
2100
|
-
this.checkout = new CheckoutModule(
|
|
2101
|
-
|
|
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
|
+
);
|
|
2102
2518
|
this.offers = new OffersModule(this.http, this.config.storeId, this.payment);
|
|
2103
2519
|
this.customer = new CustomerModule(this.http, this.config.storeId);
|
|
2104
2520
|
this.catalog = new CatalogModule(this.http, this.config.storeId);
|
|
@@ -2108,7 +2524,7 @@ var TagadaHeadlessBundle = (() => {
|
|
|
2108
2524
|
this.checkout,
|
|
2109
2525
|
this.config.accountId
|
|
2110
2526
|
);
|
|
2111
|
-
this.rx = new RxModule(this.http);
|
|
2527
|
+
this.rx = new RxModule(this.http, this.config.storeId);
|
|
2112
2528
|
}
|
|
2113
2529
|
/** Manually set the session token (e.g. from URL params on page load). */
|
|
2114
2530
|
setSessionToken(token) {
|