@appfunnel-dev/sdk 2.0.0-canary.4 → 2.0.0-canary.7
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/README.md +1 -1
- package/dist/{checkout-Dz8cGkB_.d.cts → checkout-CMEdxpgo.d.cts} +13 -13
- package/dist/{checkout-7Dy6IedP.d.ts → checkout-D1NUPv4p.d.ts} +13 -13
- package/dist/{chunk-AKO6XKXP.js → chunk-7YQLPPPG.js} +66 -91
- package/dist/chunk-7YQLPPPG.js.map +1 -0
- package/dist/{chunk-JSRKA375.cjs → chunk-BPOAWI4G.cjs} +68 -94
- package/dist/chunk-BPOAWI4G.cjs.map +1 -0
- package/dist/{chunk-M6U3FNRW.js → chunk-CFFMZYPE.js} +3 -3
- package/dist/{chunk-M6U3FNRW.js.map → chunk-CFFMZYPE.js.map} +1 -1
- package/dist/chunk-EMMSS5I5.cjs +37 -0
- package/dist/chunk-EMMSS5I5.cjs.map +1 -0
- package/dist/chunk-G3PMV62Z.js +33 -0
- package/dist/chunk-G3PMV62Z.js.map +1 -0
- package/dist/{chunk-LJYLGLFS.cjs → chunk-QMAZGLGV.cjs} +2 -35
- package/dist/chunk-QMAZGLGV.cjs.map +1 -0
- package/dist/{chunk-YY375F2B.js → chunk-TNLRQPVY.js} +3 -33
- package/dist/chunk-TNLRQPVY.js.map +1 -0
- package/dist/{chunk-CY4VBSMX.cjs → chunk-VAOR77NW.cjs} +7 -7
- package/dist/{chunk-CY4VBSMX.cjs.map → chunk-VAOR77NW.cjs.map} +1 -1
- package/dist/chunk-WYUDL4FI.cjs +8 -0
- package/dist/chunk-WYUDL4FI.cjs.map +1 -0
- package/dist/chunk-ZZJG4EYL.js +6 -0
- package/dist/chunk-ZZJG4EYL.js.map +1 -0
- package/dist/driver-paddle.cjs +23 -22
- package/dist/driver-paddle.cjs.map +1 -1
- package/dist/driver-paddle.d.cts +1 -1
- package/dist/driver-paddle.d.ts +1 -1
- package/dist/driver-paddle.js +3 -2
- package/dist/driver-paddle.js.map +1 -1
- package/dist/driver-stripe.cjs +277 -224
- package/dist/driver-stripe.cjs.map +1 -1
- package/dist/driver-stripe.d.cts +18 -2
- package/dist/driver-stripe.d.ts +18 -2
- package/dist/driver-stripe.js +244 -192
- package/dist/driver-stripe.js.map +1 -1
- package/dist/index.cjs +750 -150
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +151 -90
- package/dist/index.d.ts +151 -90
- package/dist/index.js +702 -98
- package/dist/index.js.map +1 -1
- package/dist/{manifest-Cr2y1op6.d.cts → manifest-CMe8yVkr.d.cts} +131 -88
- package/dist/{manifest-Cr2y1op6.d.ts → manifest-CMe8yVkr.d.ts} +131 -88
- package/dist/manifest-entry.cjs +62 -47
- package/dist/manifest-entry.cjs.map +1 -1
- package/dist/manifest-entry.d.cts +15 -15
- package/dist/manifest-entry.d.ts +15 -15
- package/dist/manifest-entry.js +25 -14
- package/dist/manifest-entry.js.map +1 -1
- package/dist/protocol.cjs +13 -0
- package/dist/protocol.cjs.map +1 -0
- package/dist/protocol.d.cts +182 -0
- package/dist/protocol.d.ts +182 -0
- package/dist/protocol.js +4 -0
- package/dist/protocol.js.map +1 -0
- package/package.json +14 -2
- package/dist/chunk-AKO6XKXP.js.map +0 -1
- package/dist/chunk-JSRKA375.cjs.map +0 -1
- package/dist/chunk-LJYLGLFS.cjs.map +0 -1
- package/dist/chunk-YY375F2B.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var chunkBPOAWI4G_cjs = require('./chunk-BPOAWI4G.cjs');
|
|
4
|
+
var chunkWYUDL4FI_cjs = require('./chunk-WYUDL4FI.cjs');
|
|
5
|
+
var chunkQMAZGLGV_cjs = require('./chunk-QMAZGLGV.cjs');
|
|
6
|
+
require('./chunk-EMMSS5I5.cjs');
|
|
5
7
|
var React = require('react');
|
|
6
8
|
var ReactDOM = require('react-dom');
|
|
7
9
|
var jsxRuntime = require('react/jsx-runtime');
|
|
@@ -385,7 +387,40 @@ function createBus(accessors, now2 = () => Date.now()) {
|
|
|
385
387
|
}
|
|
386
388
|
}
|
|
387
389
|
};
|
|
388
|
-
|
|
390
|
+
let nav = null;
|
|
391
|
+
let warnedNoNav = false;
|
|
392
|
+
const currentNav = () => {
|
|
393
|
+
if (!nav && !warnedNoNav) {
|
|
394
|
+
warnedNoNav = true;
|
|
395
|
+
console.warn(
|
|
396
|
+
"[appfunnel] window.appfunnel navigation called before the funnel flow mounted \u2014 ignored"
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
return nav;
|
|
400
|
+
};
|
|
401
|
+
const registerNavigation = (n) => {
|
|
402
|
+
nav = n;
|
|
403
|
+
warnedNoNav = false;
|
|
404
|
+
return () => {
|
|
405
|
+
if (nav === n) nav = null;
|
|
406
|
+
};
|
|
407
|
+
};
|
|
408
|
+
const goTo = (pageKey) => currentNav()?.goTo(pageKey) ?? false;
|
|
409
|
+
const goNext = () => currentNav()?.goNext();
|
|
410
|
+
const goPrevious = () => currentNav()?.goPrevious();
|
|
411
|
+
const navigation = () => nav?.snapshot() ?? null;
|
|
412
|
+
return {
|
|
413
|
+
on,
|
|
414
|
+
off,
|
|
415
|
+
events,
|
|
416
|
+
emit,
|
|
417
|
+
registerNavigation,
|
|
418
|
+
goTo,
|
|
419
|
+
goNext,
|
|
420
|
+
goPrevious,
|
|
421
|
+
navigation,
|
|
422
|
+
...accessors
|
|
423
|
+
};
|
|
389
424
|
}
|
|
390
425
|
function withBus(tracker, bus) {
|
|
391
426
|
return {
|
|
@@ -407,7 +442,19 @@ function withBus(tracker, bus) {
|
|
|
407
442
|
function attachBus(bus) {
|
|
408
443
|
if (typeof window === "undefined") return () => {
|
|
409
444
|
};
|
|
410
|
-
const {
|
|
445
|
+
const {
|
|
446
|
+
on,
|
|
447
|
+
off,
|
|
448
|
+
getVariable,
|
|
449
|
+
getVariables,
|
|
450
|
+
getCurrentPageId,
|
|
451
|
+
getCustomerId,
|
|
452
|
+
getVisitorId,
|
|
453
|
+
goTo,
|
|
454
|
+
goNext,
|
|
455
|
+
goPrevious,
|
|
456
|
+
navigation
|
|
457
|
+
} = bus;
|
|
411
458
|
const api = {
|
|
412
459
|
on,
|
|
413
460
|
off,
|
|
@@ -416,6 +463,11 @@ function attachBus(bus) {
|
|
|
416
463
|
getCurrentPageId,
|
|
417
464
|
getCustomerId,
|
|
418
465
|
getVisitorId,
|
|
466
|
+
// Flow control (bound closures over the bus's live nav registration).
|
|
467
|
+
goTo,
|
|
468
|
+
goNext,
|
|
469
|
+
goPrevious,
|
|
470
|
+
navigation,
|
|
419
471
|
get events() {
|
|
420
472
|
return bus.events;
|
|
421
473
|
}
|
|
@@ -452,9 +504,9 @@ function LocaleProvider({
|
|
|
452
504
|
override,
|
|
453
505
|
children
|
|
454
506
|
}) {
|
|
455
|
-
const [locale, setLocale] = React.useState(() =>
|
|
507
|
+
const [locale, setLocale] = React.useState(() => chunkBPOAWI4G_cjs.resolveLocale(config, detected, override));
|
|
456
508
|
React.useEffect(() => {
|
|
457
|
-
setLocale(
|
|
509
|
+
setLocale(chunkBPOAWI4G_cjs.resolveLocale(config, detected, override));
|
|
458
510
|
}, [config, detected, override]);
|
|
459
511
|
const value = React.useMemo(
|
|
460
512
|
() => ({ locale, setLocale, config, catalog }),
|
|
@@ -526,7 +578,7 @@ function useTranslation() {
|
|
|
526
578
|
fmt,
|
|
527
579
|
locale,
|
|
528
580
|
setLocale,
|
|
529
|
-
dir:
|
|
581
|
+
dir: chunkBPOAWI4G_cjs.isRtl(locale) ? "rtl" : "ltr",
|
|
530
582
|
locales: config?.supported ?? [locale]
|
|
531
583
|
};
|
|
532
584
|
}
|
|
@@ -543,20 +595,119 @@ function useCatalog() {
|
|
|
543
595
|
return React.useContext(CatalogContext) ?? EMPTY;
|
|
544
596
|
}
|
|
545
597
|
var EMPTY = /* @__PURE__ */ new Map();
|
|
546
|
-
function
|
|
598
|
+
function useOffering(id) {
|
|
547
599
|
const catalog = useCatalog();
|
|
548
600
|
const locale = useActiveLocale();
|
|
549
601
|
const resolved = id ? catalog.get(id) : void 0;
|
|
550
|
-
return React.useMemo(
|
|
602
|
+
return React.useMemo(
|
|
603
|
+
() => resolved ? chunkBPOAWI4G_cjs.formatOffering(resolved, locale) : void 0,
|
|
604
|
+
[resolved, locale]
|
|
605
|
+
);
|
|
551
606
|
}
|
|
552
|
-
function
|
|
607
|
+
function useOfferings() {
|
|
553
608
|
const catalog = useCatalog();
|
|
554
609
|
const locale = useActiveLocale();
|
|
555
610
|
return React.useMemo(
|
|
556
|
-
() => Array.from(catalog.values()).map((r) =>
|
|
611
|
+
() => Array.from(catalog.values()).map((r) => chunkBPOAWI4G_cjs.formatOffering(r, locale)),
|
|
557
612
|
[catalog, locale]
|
|
558
613
|
);
|
|
559
614
|
}
|
|
615
|
+
|
|
616
|
+
// src/flow/screenshot.ts
|
|
617
|
+
var MIME = { png: "image/png", jpeg: "image/jpeg", webp: "image/webp" };
|
|
618
|
+
var ScreenshotError = class extends Error {
|
|
619
|
+
constructor(code, message) {
|
|
620
|
+
super(message);
|
|
621
|
+
this.code = code;
|
|
622
|
+
}
|
|
623
|
+
};
|
|
624
|
+
function resolveTarget(t) {
|
|
625
|
+
if (!t || t.kind === "page") return document.getElementById("root") ?? document.body;
|
|
626
|
+
if (t.kind === "viewport") return document.body;
|
|
627
|
+
return document.querySelector(t.selector);
|
|
628
|
+
}
|
|
629
|
+
var delay = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
630
|
+
function hideAll(selectors) {
|
|
631
|
+
const touched = [];
|
|
632
|
+
for (const sel of selectors) {
|
|
633
|
+
document.querySelectorAll(sel).forEach((el) => {
|
|
634
|
+
touched.push([el, el.style.visibility]);
|
|
635
|
+
el.style.visibility = "hidden";
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
return () => touched.forEach(([el, v]) => el.style.visibility = v);
|
|
639
|
+
}
|
|
640
|
+
async function scrollThrough(el) {
|
|
641
|
+
const prev = el.scrollTop;
|
|
642
|
+
const step = el.clientHeight || window.innerHeight;
|
|
643
|
+
for (let y = 0; y < el.scrollHeight; y += step) {
|
|
644
|
+
el.scrollTop = y;
|
|
645
|
+
await delay(16);
|
|
646
|
+
}
|
|
647
|
+
el.scrollTop = prev;
|
|
648
|
+
await delay(16);
|
|
649
|
+
}
|
|
650
|
+
function blobToDataURL(blob) {
|
|
651
|
+
return new Promise((resolve, reject) => {
|
|
652
|
+
const fr = new FileReader();
|
|
653
|
+
fr.onload = () => resolve(String(fr.result));
|
|
654
|
+
fr.onerror = () => reject(fr.error);
|
|
655
|
+
fr.readAsDataURL(blob);
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
async function captureScreenshot(params = {}) {
|
|
659
|
+
const el = resolveTarget(params.target);
|
|
660
|
+
if (!el) throw new ScreenshotError("bad_params", "screenshot target not found");
|
|
661
|
+
const restore = params.hideSelectors?.length ? hideAll(params.hideSelectors) : null;
|
|
662
|
+
const scale = Math.min(params.scale ?? 2, params.maxScale ?? 3);
|
|
663
|
+
const format = params.format ?? "png";
|
|
664
|
+
const timeout = params.timeout ?? 1e4;
|
|
665
|
+
try {
|
|
666
|
+
if (params.waitForFonts !== false && document.fonts?.ready) {
|
|
667
|
+
await Promise.race([document.fonts.ready, delay(timeout)]);
|
|
668
|
+
}
|
|
669
|
+
if (params.triggerLazyLoad) await scrollThrough(el);
|
|
670
|
+
if (params.waitForImages !== false) {
|
|
671
|
+
await Promise.all(
|
|
672
|
+
Array.from(el.querySelectorAll("img")).map(
|
|
673
|
+
(img) => typeof img.decode === "function" ? img.decode().catch(() => {
|
|
674
|
+
}) : Promise.resolve()
|
|
675
|
+
)
|
|
676
|
+
);
|
|
677
|
+
}
|
|
678
|
+
const { domToBlob } = await import('modern-screenshot');
|
|
679
|
+
let blob;
|
|
680
|
+
try {
|
|
681
|
+
blob = await domToBlob(el, {
|
|
682
|
+
type: MIME[format],
|
|
683
|
+
quality: params.quality ?? 0.92,
|
|
684
|
+
scale,
|
|
685
|
+
width: params.width,
|
|
686
|
+
height: params.height,
|
|
687
|
+
// `null` = transparent (png/webp); only fall back to white when the caller omitted it. `??`
|
|
688
|
+
// would wrongly collapse an explicit `null` to white.
|
|
689
|
+
backgroundColor: params.backgroundColor === void 0 ? "#ffffff" : params.backgroundColor,
|
|
690
|
+
timeout
|
|
691
|
+
});
|
|
692
|
+
} catch (e) {
|
|
693
|
+
throw new ScreenshotError("failed", `capture failed (an image/font may be served without CORS '*'): ${String(e?.message || e)}`);
|
|
694
|
+
}
|
|
695
|
+
const result = {
|
|
696
|
+
mime: MIME[format],
|
|
697
|
+
width: Math.round((params.width ?? el.clientWidth) * scale),
|
|
698
|
+
height: Math.round((params.height ?? el.scrollHeight) * scale),
|
|
699
|
+
scale,
|
|
700
|
+
bytesApprox: blob.size
|
|
701
|
+
};
|
|
702
|
+
if ((params.encoding ?? "blob") === "dataURL") result.dataURL = await blobToDataURL(blob);
|
|
703
|
+
else result.blob = blob;
|
|
704
|
+
return result;
|
|
705
|
+
} finally {
|
|
706
|
+
restore?.();
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
// src/flow/flow.tsx
|
|
560
711
|
var NavContext = React.createContext(null);
|
|
561
712
|
var ExperimentContext = React.createContext({});
|
|
562
713
|
function useExperiment(id) {
|
|
@@ -609,6 +760,7 @@ function usePageExitTimer(tracker, currentKey) {
|
|
|
609
760
|
function FunnelView({
|
|
610
761
|
pages,
|
|
611
762
|
initialKey,
|
|
763
|
+
trustInitialKey = false,
|
|
612
764
|
layout,
|
|
613
765
|
fallback,
|
|
614
766
|
prefetch: prefetchMode = "auto",
|
|
@@ -634,10 +786,10 @@ function FunnelView({
|
|
|
634
786
|
[pages]
|
|
635
787
|
);
|
|
636
788
|
const seedRef = React.useRef(null);
|
|
637
|
-
if (seedRef.current === null) seedRef.current =
|
|
789
|
+
if (seedRef.current === null) seedRef.current = chunkBPOAWI4G_cjs.bucketingSeed(funnel.context);
|
|
638
790
|
const seed = seedRef.current;
|
|
639
791
|
const experiments = React.useMemo(
|
|
640
|
-
() =>
|
|
792
|
+
() => chunkBPOAWI4G_cjs.resolveExperiments(pages, funnel.experiments, seed),
|
|
641
793
|
[pages, funnel.experiments, seed]
|
|
642
794
|
);
|
|
643
795
|
const toSlot = React.useCallback((k) => experiments.slotOf[k] ?? k, [experiments]);
|
|
@@ -648,16 +800,21 @@ function FunnelView({
|
|
|
648
800
|
[experiments, pageByKey]
|
|
649
801
|
);
|
|
650
802
|
const flow = React.useMemo(
|
|
651
|
-
() => flowPages.map((p) =>
|
|
652
|
-
|
|
803
|
+
() => flowPages.map((p) => {
|
|
804
|
+
const servedVariant = experiments.render[p.key];
|
|
805
|
+
const variantNext = servedVariant ? pageByKey.get(servedVariant)?.meta?.next : void 0;
|
|
806
|
+
return variantNext ? { key: p.key, meta: { ...p.meta ?? {}, next: variantNext } } : { key: p.key, meta: p.meta };
|
|
807
|
+
}),
|
|
808
|
+
[flowPages, experiments, pageByKey]
|
|
653
809
|
);
|
|
654
810
|
const [history, setHistory] = React.useState(() => {
|
|
655
811
|
const start = flowPages[0]?.key;
|
|
656
812
|
if (!initialKey || initialKey === start) return start ? [start] : [];
|
|
657
813
|
const target = toSlot(initialKey);
|
|
658
814
|
const page2 = flowPages.find((p) => p.key === target);
|
|
659
|
-
|
|
660
|
-
const
|
|
815
|
+
if (trustInitialKey) return page2 ? [target] : start ? [start] : [];
|
|
816
|
+
const guard = chunkBPOAWI4G_cjs.entryGuard(page2?.meta);
|
|
817
|
+
const ok = page2 && (!guard || chunkBPOAWI4G_cjs.evaluateGate(guard, funnel.snapshot()));
|
|
661
818
|
const first = ok ? target : start;
|
|
662
819
|
return first ? [first] : [];
|
|
663
820
|
});
|
|
@@ -665,7 +822,7 @@ function FunnelView({
|
|
|
665
822
|
const index = history.length - 1;
|
|
666
823
|
const startKey = history[0];
|
|
667
824
|
const total = React.useMemo(
|
|
668
|
-
() =>
|
|
825
|
+
() => chunkBPOAWI4G_cjs.expectedPathLength(flow, startKey, funnel.snapshot()),
|
|
669
826
|
// currentKey in deps: re-trace as each step's answers settle the branch.
|
|
670
827
|
[flow, startKey, currentKey, funnel]
|
|
671
828
|
);
|
|
@@ -700,7 +857,7 @@ function FunnelView({
|
|
|
700
857
|
usePageExitTimer(tracker, currentKey);
|
|
701
858
|
const [isNavigating, startNav] = React.useTransition();
|
|
702
859
|
const next = React.useCallback(() => {
|
|
703
|
-
const target =
|
|
860
|
+
const target = chunkBPOAWI4G_cjs.nextPage(flow, currentKey, funnel.snapshot());
|
|
704
861
|
const resolved = target ? toSlot(target) : target;
|
|
705
862
|
if (resolved) startNav(() => setHistory((h) => [...h, resolved]));
|
|
706
863
|
}, [flow, currentKey, funnel, toSlot]);
|
|
@@ -724,7 +881,7 @@ function FunnelView({
|
|
|
724
881
|
[loaders, toRenderKey]
|
|
725
882
|
);
|
|
726
883
|
const nextCandidates = React.useMemo(
|
|
727
|
-
() => [...new Set(
|
|
884
|
+
() => [...new Set(chunkBPOAWI4G_cjs.outgoingKeys(flow, currentKey).map(toRenderKey))],
|
|
728
885
|
[flow, currentKey, toRenderKey]
|
|
729
886
|
);
|
|
730
887
|
React.useEffect(() => {
|
|
@@ -741,6 +898,44 @@ function FunnelView({
|
|
|
741
898
|
canGoBack: history.length > 1,
|
|
742
899
|
isNavigating
|
|
743
900
|
};
|
|
901
|
+
const bus = useBusInternal();
|
|
902
|
+
const navRef = React.useRef(value);
|
|
903
|
+
navRef.current = value;
|
|
904
|
+
React.useEffect(() => {
|
|
905
|
+
if (!bus) return;
|
|
906
|
+
const control = {
|
|
907
|
+
goTo: (key) => {
|
|
908
|
+
if (!components.has(toRenderKey(key))) return false;
|
|
909
|
+
navRef.current.go(key);
|
|
910
|
+
return true;
|
|
911
|
+
},
|
|
912
|
+
goNext: () => navRef.current.next(),
|
|
913
|
+
goPrevious: () => navRef.current.back(),
|
|
914
|
+
snapshot: () => {
|
|
915
|
+
const v = navRef.current;
|
|
916
|
+
return {
|
|
917
|
+
key: v.page.key,
|
|
918
|
+
index: v.page.index,
|
|
919
|
+
total: v.page.total,
|
|
920
|
+
progressPercentage: v.page.progressPercentage,
|
|
921
|
+
canGoBack: v.canGoBack,
|
|
922
|
+
nextCandidates: v.nextCandidates
|
|
923
|
+
};
|
|
924
|
+
}
|
|
925
|
+
};
|
|
926
|
+
return bus.registerNavigation(control);
|
|
927
|
+
}, [bus]);
|
|
928
|
+
React.useEffect(() => {
|
|
929
|
+
const v = navRef.current;
|
|
930
|
+
bus?.emit("navigation", {
|
|
931
|
+
key: v.page.key,
|
|
932
|
+
index: v.page.index,
|
|
933
|
+
total: v.page.total,
|
|
934
|
+
progressPercentage: v.page.progressPercentage,
|
|
935
|
+
canGoBack: v.canGoBack,
|
|
936
|
+
nextCandidates: v.nextCandidates
|
|
937
|
+
});
|
|
938
|
+
}, [bus, currentKey]);
|
|
744
939
|
const renderKey = toRenderKey(currentKey);
|
|
745
940
|
const Current = components.get(renderKey);
|
|
746
941
|
const pageEl = React.createElement(React.Suspense, { fallback: fallback ?? null }, Current ? React.createElement(Current) : null);
|
|
@@ -756,10 +951,85 @@ function useNavigation() {
|
|
|
756
951
|
if (!ctx) throw new Error("useNavigation must be used inside <FunnelView>");
|
|
757
952
|
return ctx;
|
|
758
953
|
}
|
|
954
|
+
var EMBED_CAPABILITIES = {
|
|
955
|
+
methods: ["nav.snapshot", "nav.goTo", "nav.goNext", "nav.goPrevious", "screenshot"],
|
|
956
|
+
events: ["navigation"]
|
|
957
|
+
};
|
|
958
|
+
function EmbedBridge() {
|
|
959
|
+
const bus = useBusInternal();
|
|
960
|
+
React.useEffect(() => {
|
|
961
|
+
if (!bus || typeof window === "undefined" || window.parent === window) return;
|
|
962
|
+
const parent = window.parent;
|
|
963
|
+
let disposed = false;
|
|
964
|
+
const send = (msg) => {
|
|
965
|
+
try {
|
|
966
|
+
parent.postMessage({ af: chunkWYUDL4FI_cjs.AF_PROTOCOL, source: "af-preview", ...msg }, "*");
|
|
967
|
+
} catch {
|
|
968
|
+
}
|
|
969
|
+
};
|
|
970
|
+
const hello = () => send({ kind: "hello", role: "funnel", protocol: chunkWYUDL4FI_cjs.AF_PROTOCOL, capabilities: EMBED_CAPABILITIES });
|
|
971
|
+
const sendSnapshot = () => {
|
|
972
|
+
const s = bus.navigation();
|
|
973
|
+
if (s) send({ kind: "event", event: "navigation", data: s });
|
|
974
|
+
};
|
|
975
|
+
async function invoke(method, params) {
|
|
976
|
+
switch (method) {
|
|
977
|
+
case "nav.snapshot":
|
|
978
|
+
return bus.navigation();
|
|
979
|
+
case "nav.goTo": {
|
|
980
|
+
const key = params?.key;
|
|
981
|
+
if (typeof key !== "string" || !bus.goTo(key)) throw { code: "bad_params", message: `unknown page key: ${String(key)}` };
|
|
982
|
+
return void 0;
|
|
983
|
+
}
|
|
984
|
+
case "nav.goNext":
|
|
985
|
+
bus.goNext();
|
|
986
|
+
return void 0;
|
|
987
|
+
case "nav.goPrevious":
|
|
988
|
+
bus.goPrevious();
|
|
989
|
+
return void 0;
|
|
990
|
+
case "screenshot":
|
|
991
|
+
return await captureScreenshot(params ?? {});
|
|
992
|
+
default:
|
|
993
|
+
throw { code: "unknown_method", message: `unknown method: ${method}` };
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
async function onMsg(e) {
|
|
997
|
+
if (e.source !== parent) return;
|
|
998
|
+
const d = e.data;
|
|
999
|
+
if (!d || typeof d !== "object" || d.af !== chunkWYUDL4FI_cjs.AF_PROTOCOL || d.source !== "af-host") return;
|
|
1000
|
+
if (d.kind === "hello") {
|
|
1001
|
+
hello();
|
|
1002
|
+
sendSnapshot();
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
1005
|
+
if (d.kind !== "request" || typeof d.id !== "string") return;
|
|
1006
|
+
try {
|
|
1007
|
+
const result = await invoke(d.method, d.params);
|
|
1008
|
+
if (!disposed) send({ kind: "response", id: d.id, ok: true, result });
|
|
1009
|
+
} catch (err) {
|
|
1010
|
+
const e2 = err;
|
|
1011
|
+
const error = e2 && typeof e2.code === "string" ? { code: e2.code, message: String(e2.message ?? e2.code) } : { code: "failed", message: String(e2?.message ?? err) };
|
|
1012
|
+
if (!disposed) send({ kind: "response", id: d.id, ok: false, error });
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
window.addEventListener("message", onMsg);
|
|
1016
|
+
const offNav = bus.on("navigation", (data) => {
|
|
1017
|
+
if (!disposed) send({ kind: "event", event: "navigation", data });
|
|
1018
|
+
});
|
|
1019
|
+
hello();
|
|
1020
|
+
sendSnapshot();
|
|
1021
|
+
return () => {
|
|
1022
|
+
disposed = true;
|
|
1023
|
+
offNav();
|
|
1024
|
+
window.removeEventListener("message", onMsg);
|
|
1025
|
+
};
|
|
1026
|
+
}, [bus]);
|
|
1027
|
+
return null;
|
|
1028
|
+
}
|
|
759
1029
|
function usePage() {
|
|
760
1030
|
return useNavigation().page;
|
|
761
1031
|
}
|
|
762
|
-
var symModalId = /* @__PURE__ */ Symbol("
|
|
1032
|
+
var symModalId = /* @__PURE__ */ Symbol("AppfunnelModalId");
|
|
763
1033
|
var initialState = {};
|
|
764
1034
|
var ModalStateContext = React.createContext(initialState);
|
|
765
1035
|
var ModalIdContext = React.createContext(null);
|
|
@@ -774,7 +1044,9 @@ var runtimeStack = [];
|
|
|
774
1044
|
var dispatch = (action) => {
|
|
775
1045
|
const top = runtimeStack[runtimeStack.length - 1];
|
|
776
1046
|
if (!top) {
|
|
777
|
-
throw new Error(
|
|
1047
|
+
throw new Error(
|
|
1048
|
+
"No modal dispatch \u2014 render inside <FunnelProvider> (which mounts the modal runtime)."
|
|
1049
|
+
);
|
|
778
1050
|
}
|
|
779
1051
|
top(action);
|
|
780
1052
|
};
|
|
@@ -873,26 +1145,42 @@ function useModal(modal, args) {
|
|
|
873
1145
|
const d = React.useContext(ModalDispatchContext) ?? dispatch;
|
|
874
1146
|
const isComponent = !!modal && typeof modal !== "string";
|
|
875
1147
|
const id = modal ? idOf(modal) : contextId;
|
|
876
|
-
if (!id)
|
|
1148
|
+
if (!id)
|
|
1149
|
+
throw new Error(
|
|
1150
|
+
"useModal: no modal id (call inside a defineModal component, or pass an id/component)."
|
|
1151
|
+
);
|
|
877
1152
|
React.useEffect(() => {
|
|
878
|
-
if (isComponent && !REGISTRY[id])
|
|
1153
|
+
if (isComponent && !REGISTRY[id])
|
|
1154
|
+
registerModal(id, modal, args);
|
|
879
1155
|
}, [isComponent, id, modal, args]);
|
|
880
1156
|
const info = modals[id];
|
|
881
|
-
const show = React.useCallback(
|
|
1157
|
+
const show = React.useCallback(
|
|
1158
|
+
(a) => showModalVia(d, id, a),
|
|
1159
|
+
[d, id]
|
|
1160
|
+
);
|
|
882
1161
|
const hide = React.useCallback(() => hideModalVia(d, id), [d, id]);
|
|
883
1162
|
const remove = React.useCallback(() => removeModalVia(d, id), [d, id]);
|
|
884
|
-
const resolve = React.useCallback(
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
1163
|
+
const resolve = React.useCallback(
|
|
1164
|
+
(v) => {
|
|
1165
|
+
modalCallbacks[id]?.resolve(v);
|
|
1166
|
+
delete modalCallbacks[id];
|
|
1167
|
+
},
|
|
1168
|
+
[id]
|
|
1169
|
+
);
|
|
1170
|
+
const reject = React.useCallback(
|
|
1171
|
+
(v) => {
|
|
1172
|
+
modalCallbacks[id]?.reject(v);
|
|
1173
|
+
delete modalCallbacks[id];
|
|
1174
|
+
},
|
|
1175
|
+
[id]
|
|
1176
|
+
);
|
|
1177
|
+
const resolveHide = React.useCallback(
|
|
1178
|
+
(v) => {
|
|
1179
|
+
hideCallbacks[id]?.resolve(v);
|
|
1180
|
+
delete hideCallbacks[id];
|
|
1181
|
+
},
|
|
1182
|
+
[id]
|
|
1183
|
+
);
|
|
896
1184
|
return React.useMemo(
|
|
897
1185
|
() => ({
|
|
898
1186
|
id,
|
|
@@ -906,11 +1194,27 @@ function useModal(modal, args) {
|
|
|
906
1194
|
reject,
|
|
907
1195
|
resolveHide
|
|
908
1196
|
}),
|
|
909
|
-
[
|
|
1197
|
+
[
|
|
1198
|
+
id,
|
|
1199
|
+
info?.args,
|
|
1200
|
+
info?.visible,
|
|
1201
|
+
info?.keepMounted,
|
|
1202
|
+
show,
|
|
1203
|
+
hide,
|
|
1204
|
+
remove,
|
|
1205
|
+
resolve,
|
|
1206
|
+
reject,
|
|
1207
|
+
resolveHide
|
|
1208
|
+
]
|
|
910
1209
|
);
|
|
911
1210
|
}
|
|
912
1211
|
function defineModal(Comp) {
|
|
913
|
-
return function Wrapped({
|
|
1212
|
+
return function Wrapped({
|
|
1213
|
+
id,
|
|
1214
|
+
defaultVisible,
|
|
1215
|
+
keepMounted,
|
|
1216
|
+
...props
|
|
1217
|
+
}) {
|
|
914
1218
|
const { args, show } = useModal(id);
|
|
915
1219
|
const modals = React.useContext(ModalStateContext);
|
|
916
1220
|
const d = React.useContext(ModalDispatchContext) ?? dispatch;
|
|
@@ -943,7 +1247,9 @@ function ModalRoot() {
|
|
|
943
1247
|
return React.createElement(
|
|
944
1248
|
"div",
|
|
945
1249
|
{ "data-appfunnel-modal-root": "" },
|
|
946
|
-
...toRender.map(
|
|
1250
|
+
...toRender.map(
|
|
1251
|
+
(t) => React.createElement(t.comp, { key: t.id, id: t.id, ...t.props })
|
|
1252
|
+
)
|
|
947
1253
|
);
|
|
948
1254
|
}
|
|
949
1255
|
function ModalRuntime({ children }) {
|
|
@@ -1071,12 +1377,20 @@ function Modal(props) {
|
|
|
1071
1377
|
|
|
1072
1378
|
// src/commerce/checkout.tsx
|
|
1073
1379
|
function createMockDriver(provider = "stripe", options = {}) {
|
|
1074
|
-
const success = options.result ?? {
|
|
1075
|
-
|
|
1380
|
+
const success = options.result ?? {
|
|
1381
|
+
ok: true,
|
|
1382
|
+
amountMinor: 0,
|
|
1383
|
+
currency: "USD"
|
|
1384
|
+
};
|
|
1385
|
+
const offError = typeof options.failOffSession === "object" ? options.failOffSession : chunkQMAZGLGV_cjs.checkoutError(
|
|
1386
|
+
"authentication_required",
|
|
1387
|
+
"off-session charge declined (mock)"
|
|
1388
|
+
);
|
|
1076
1389
|
return {
|
|
1077
1390
|
provider,
|
|
1078
1391
|
start: (req) => {
|
|
1079
|
-
if (options.failOffSession && !req.surface)
|
|
1392
|
+
if (options.failOffSession && !req.surface)
|
|
1393
|
+
return Promise.resolve({ ok: false, error: offError });
|
|
1080
1394
|
return Promise.resolve(success);
|
|
1081
1395
|
},
|
|
1082
1396
|
renderInline: (req, cb) => React.createElement(
|
|
@@ -1087,7 +1401,13 @@ function createMockDriver(provider = "stripe", options = {}) {
|
|
|
1087
1401
|
onClick: () => {
|
|
1088
1402
|
cb.onStart?.();
|
|
1089
1403
|
if (success.ok) cb.onSuccess(success);
|
|
1090
|
-
else
|
|
1404
|
+
else
|
|
1405
|
+
cb.onError(
|
|
1406
|
+
success.error ?? chunkQMAZGLGV_cjs.checkoutError(
|
|
1407
|
+
"processing_error",
|
|
1408
|
+
"failed (mock)"
|
|
1409
|
+
)
|
|
1410
|
+
);
|
|
1091
1411
|
}
|
|
1092
1412
|
},
|
|
1093
1413
|
`Pay (mock ${req.surface})`
|
|
@@ -1145,11 +1465,11 @@ function useCheckout(opts = {}) {
|
|
|
1145
1465
|
[catalog, kind]
|
|
1146
1466
|
);
|
|
1147
1467
|
const recovering = React.useRef(false);
|
|
1148
|
-
const failRef = React.useRef(
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
async () => ({ ok: false })
|
|
1468
|
+
const failRef = React.useRef(
|
|
1469
|
+
() => {
|
|
1470
|
+
}
|
|
1152
1471
|
);
|
|
1472
|
+
const attemptRef = React.useRef(async () => ({ ok: false }));
|
|
1153
1473
|
const succeed = React.useCallback(
|
|
1154
1474
|
(result, product) => {
|
|
1155
1475
|
setStatus("success");
|
|
@@ -1163,7 +1483,12 @@ function useCheckout(opts = {}) {
|
|
|
1163
1483
|
// server-minted (browser↔CAPI dedup); undefined if none
|
|
1164
1484
|
});
|
|
1165
1485
|
if (isSubscription) {
|
|
1166
|
-
tracker.track("subscription.created", {
|
|
1486
|
+
tracker.track("subscription.created", {
|
|
1487
|
+
amount,
|
|
1488
|
+
currency: result.currency,
|
|
1489
|
+
productId,
|
|
1490
|
+
eventId: result.eventId
|
|
1491
|
+
});
|
|
1167
1492
|
}
|
|
1168
1493
|
opts.onSuccess?.(result);
|
|
1169
1494
|
if (advance) nav.next();
|
|
@@ -1177,18 +1502,29 @@ function useCheckout(opts = {}) {
|
|
|
1177
1502
|
setStatus("loading");
|
|
1178
1503
|
setError(null);
|
|
1179
1504
|
const { productId, amount, currency } = productFacts(product);
|
|
1180
|
-
tracker.track("checkout.start", {
|
|
1505
|
+
tracker.track("checkout.start", {
|
|
1506
|
+
productId,
|
|
1507
|
+
amount,
|
|
1508
|
+
currency,
|
|
1509
|
+
surface,
|
|
1510
|
+
eventId: newEventId()
|
|
1511
|
+
});
|
|
1181
1512
|
},
|
|
1182
1513
|
[tracker, productFacts]
|
|
1183
1514
|
);
|
|
1184
1515
|
const paymentAdded = React.useCallback(
|
|
1185
1516
|
(product) => {
|
|
1186
1517
|
const { productId, amount, currency } = productFacts(product);
|
|
1187
|
-
tracker.track("checkout.payment_added", {
|
|
1518
|
+
tracker.track("checkout.payment_added", {
|
|
1519
|
+
productId,
|
|
1520
|
+
amount,
|
|
1521
|
+
currency,
|
|
1522
|
+
eventId: newEventId()
|
|
1523
|
+
});
|
|
1188
1524
|
},
|
|
1189
1525
|
[tracker, productFacts]
|
|
1190
1526
|
);
|
|
1191
|
-
const hostInSheet = (surface) => surface === "sheet" ||
|
|
1527
|
+
const hostInSheet = (surface) => surface === "sheet" || chunkQMAZGLGV_cjs.isInlineSurface(surface) && !!chunkQMAZGLGV_cjs.PROVIDER_PROFILES[driver.provider]?.surfaces.sheet;
|
|
1192
1528
|
const startRecovery = (product, surface) => {
|
|
1193
1529
|
recovering.current = true;
|
|
1194
1530
|
if (hostInSheet(surface)) {
|
|
@@ -1207,7 +1543,9 @@ function useCheckout(opts = {}) {
|
|
|
1207
1543
|
}
|
|
1208
1544
|
};
|
|
1209
1545
|
failRef.current = (err, product) => {
|
|
1210
|
-
setStatus(
|
|
1546
|
+
setStatus(
|
|
1547
|
+
err.category === "authentication_required" ? "requires_action" : "error"
|
|
1548
|
+
);
|
|
1211
1549
|
setError(err);
|
|
1212
1550
|
tracker.track("checkout.failed", {
|
|
1213
1551
|
category: err.category,
|
|
@@ -1238,35 +1576,59 @@ function useCheckout(opts = {}) {
|
|
|
1238
1576
|
if (!product) return;
|
|
1239
1577
|
recovering.current = true;
|
|
1240
1578
|
if (!surface) {
|
|
1241
|
-
if (intent === "upsell")
|
|
1242
|
-
|
|
1579
|
+
if (intent === "upsell")
|
|
1580
|
+
void attemptRef.current(product);
|
|
1581
|
+
else
|
|
1582
|
+
startRecovery(
|
|
1583
|
+
product,
|
|
1584
|
+
chunkQMAZGLGV_cjs.PROVIDER_PROFILES[driver.provider]?.surfaces.sheet ? "sheet" : "popup"
|
|
1585
|
+
);
|
|
1243
1586
|
return;
|
|
1244
1587
|
}
|
|
1245
1588
|
startRecovery(product, surface);
|
|
1246
1589
|
}
|
|
1247
1590
|
};
|
|
1248
|
-
void showModal(
|
|
1591
|
+
void showModal(
|
|
1592
|
+
route.modal,
|
|
1593
|
+
props
|
|
1594
|
+
);
|
|
1249
1595
|
} else if ("fallback" in route) {
|
|
1250
|
-
if (product && !recovering.current)
|
|
1596
|
+
if (product && !recovering.current)
|
|
1597
|
+
startRecovery(product, route.fallback);
|
|
1251
1598
|
}
|
|
1252
1599
|
};
|
|
1253
1600
|
attemptRef.current = async (product, surface) => {
|
|
1254
1601
|
begin(product, surface);
|
|
1255
1602
|
try {
|
|
1256
|
-
const result = await driver.start({
|
|
1603
|
+
const result = await driver.start({
|
|
1604
|
+
product,
|
|
1605
|
+
intent,
|
|
1606
|
+
surface,
|
|
1607
|
+
kind
|
|
1608
|
+
});
|
|
1257
1609
|
if (result.ok) succeedRef.current(result, product);
|
|
1258
|
-
else
|
|
1610
|
+
else
|
|
1611
|
+
failRef.current(
|
|
1612
|
+
result.error ?? chunkQMAZGLGV_cjs.checkoutError("unknown", "Checkout failed"),
|
|
1613
|
+
product
|
|
1614
|
+
);
|
|
1259
1615
|
return result;
|
|
1260
1616
|
} catch (e) {
|
|
1261
|
-
const err =
|
|
1617
|
+
const err = chunkQMAZGLGV_cjs.checkoutError(
|
|
1618
|
+
"processing_error",
|
|
1619
|
+
e instanceof Error ? e.message : "Checkout failed"
|
|
1620
|
+
);
|
|
1262
1621
|
failRef.current(err, product);
|
|
1263
1622
|
return { ok: false, error: err };
|
|
1264
1623
|
}
|
|
1265
1624
|
};
|
|
1266
|
-
const open = React.useCallback(
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1625
|
+
const open = React.useCallback(
|
|
1626
|
+
async (product, surface) => {
|
|
1627
|
+
recovering.current = false;
|
|
1628
|
+
return attemptRef.current(product, surface);
|
|
1629
|
+
},
|
|
1630
|
+
[]
|
|
1631
|
+
);
|
|
1270
1632
|
const callbacksFor = React.useCallback(
|
|
1271
1633
|
(product, surface) => ({
|
|
1272
1634
|
onStart: () => {
|
|
@@ -1284,7 +1646,14 @@ function useCheckout(opts = {}) {
|
|
|
1284
1646
|
setStatus("idle");
|
|
1285
1647
|
setError(null);
|
|
1286
1648
|
}, []);
|
|
1287
|
-
return {
|
|
1649
|
+
return {
|
|
1650
|
+
open,
|
|
1651
|
+
status,
|
|
1652
|
+
error,
|
|
1653
|
+
isLoading: status === "loading",
|
|
1654
|
+
reset,
|
|
1655
|
+
callbacksFor
|
|
1656
|
+
};
|
|
1288
1657
|
}
|
|
1289
1658
|
var CheckoutSheet = defineModal(({ product, surface, intent, kind, onSuccess, onError, onPaymentAdded }) => {
|
|
1290
1659
|
const driver = useDriver();
|
|
@@ -1297,7 +1666,10 @@ var CheckoutSheet = defineModal(({ product, surface, intent, kind, onSuccess, on
|
|
|
1297
1666
|
if (!hostable) {
|
|
1298
1667
|
resolved.current = true;
|
|
1299
1668
|
onErrorRef.current(
|
|
1300
|
-
|
|
1669
|
+
chunkQMAZGLGV_cjs.checkoutError(
|
|
1670
|
+
"processing_error",
|
|
1671
|
+
"This checkout driver has no inline surface to host in the sheet"
|
|
1672
|
+
)
|
|
1301
1673
|
);
|
|
1302
1674
|
void modal.hide();
|
|
1303
1675
|
modal.remove();
|
|
@@ -1305,7 +1677,12 @@ var CheckoutSheet = defineModal(({ product, surface, intent, kind, onSuccess, on
|
|
|
1305
1677
|
}
|
|
1306
1678
|
return () => {
|
|
1307
1679
|
if (!resolved.current) {
|
|
1308
|
-
onErrorRef.current(
|
|
1680
|
+
onErrorRef.current(
|
|
1681
|
+
chunkQMAZGLGV_cjs.checkoutError(
|
|
1682
|
+
"canceled",
|
|
1683
|
+
"Checkout was dismissed before completing"
|
|
1684
|
+
)
|
|
1685
|
+
);
|
|
1309
1686
|
}
|
|
1310
1687
|
};
|
|
1311
1688
|
}, []);
|
|
@@ -1332,29 +1709,42 @@ var CheckoutSheet = defineModal(({ product, surface, intent, kind, onSuccess, on
|
|
|
1332
1709
|
)
|
|
1333
1710
|
});
|
|
1334
1711
|
});
|
|
1335
|
-
function trigger(onClick, {
|
|
1712
|
+
function trigger(onClick, {
|
|
1713
|
+
asChild,
|
|
1714
|
+
children,
|
|
1715
|
+
className,
|
|
1716
|
+
disabled
|
|
1717
|
+
}) {
|
|
1336
1718
|
if (asChild && React.isValidElement(children)) {
|
|
1337
1719
|
const child = children;
|
|
1338
1720
|
return React.cloneElement(child, { onClick });
|
|
1339
1721
|
}
|
|
1340
|
-
return React.createElement(
|
|
1722
|
+
return React.createElement(
|
|
1723
|
+
"button",
|
|
1724
|
+
{ type: "button", className, disabled, onClick },
|
|
1725
|
+
children ?? "Continue"
|
|
1726
|
+
);
|
|
1341
1727
|
}
|
|
1342
1728
|
function Checkout({
|
|
1343
|
-
|
|
1729
|
+
offering,
|
|
1344
1730
|
surface,
|
|
1345
1731
|
asChild,
|
|
1346
1732
|
children,
|
|
1347
1733
|
className,
|
|
1348
1734
|
...options
|
|
1349
1735
|
}) {
|
|
1736
|
+
const product = offering;
|
|
1350
1737
|
const driver = useDriver();
|
|
1351
1738
|
const checkout = useCheckout(options);
|
|
1352
1739
|
const intent = options.intent ?? "purchase";
|
|
1353
|
-
if (
|
|
1740
|
+
if (chunkQMAZGLGV_cjs.isInlineSurface(surface)) {
|
|
1354
1741
|
return driver.renderInline ? React.createElement(
|
|
1355
1742
|
"div",
|
|
1356
1743
|
{ key: product, className },
|
|
1357
|
-
driver.renderInline(
|
|
1744
|
+
driver.renderInline(
|
|
1745
|
+
{ product, intent, surface },
|
|
1746
|
+
checkout.callbacksFor(product, surface)
|
|
1747
|
+
)
|
|
1358
1748
|
) : null;
|
|
1359
1749
|
}
|
|
1360
1750
|
if (surface === "sheet") {
|
|
@@ -1371,7 +1761,12 @@ function Checkout({
|
|
|
1371
1761
|
onPaymentAdded: cb.onPaymentAdded
|
|
1372
1762
|
});
|
|
1373
1763
|
};
|
|
1374
|
-
return trigger(open, {
|
|
1764
|
+
return trigger(open, {
|
|
1765
|
+
asChild,
|
|
1766
|
+
children,
|
|
1767
|
+
className,
|
|
1768
|
+
disabled: checkout.isLoading
|
|
1769
|
+
});
|
|
1375
1770
|
}
|
|
1376
1771
|
return trigger(() => checkout.open(product, surface), {
|
|
1377
1772
|
asChild,
|
|
@@ -1380,18 +1775,29 @@ function Checkout({
|
|
|
1380
1775
|
disabled: checkout.isLoading
|
|
1381
1776
|
});
|
|
1382
1777
|
}
|
|
1383
|
-
function Upsell({
|
|
1778
|
+
function Upsell({
|
|
1779
|
+
offering,
|
|
1780
|
+
fallback,
|
|
1781
|
+
asChild,
|
|
1782
|
+
children,
|
|
1783
|
+
className,
|
|
1784
|
+
...options
|
|
1785
|
+
}) {
|
|
1786
|
+
const product = offering;
|
|
1384
1787
|
const checkout = useCheckout({
|
|
1385
1788
|
...options,
|
|
1386
1789
|
intent: "upsell",
|
|
1387
1790
|
recoverySurface: fallback ?? options.recoverySurface
|
|
1388
1791
|
});
|
|
1389
|
-
return trigger(
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1792
|
+
return trigger(
|
|
1793
|
+
() => void checkout.open(product),
|
|
1794
|
+
{
|
|
1795
|
+
asChild,
|
|
1796
|
+
children: children ?? "Add to my plan",
|
|
1797
|
+
className,
|
|
1798
|
+
disabled: checkout.isLoading
|
|
1799
|
+
}
|
|
1800
|
+
);
|
|
1395
1801
|
}
|
|
1396
1802
|
var consumedResumes = /* @__PURE__ */ new Set();
|
|
1397
1803
|
function CheckoutResume(options = {}) {
|
|
@@ -1409,10 +1815,19 @@ function CheckoutResume(options = {}) {
|
|
|
1409
1815
|
const cb = callbacksRef.current();
|
|
1410
1816
|
if (result.ok) {
|
|
1411
1817
|
url.searchParams.delete("af_checkout");
|
|
1412
|
-
window.history.replaceState(
|
|
1818
|
+
window.history.replaceState(
|
|
1819
|
+
window.history.state,
|
|
1820
|
+
"",
|
|
1821
|
+
url.toString()
|
|
1822
|
+
);
|
|
1413
1823
|
cb.onSuccess(result);
|
|
1414
1824
|
} else {
|
|
1415
|
-
cb.onError(
|
|
1825
|
+
cb.onError(
|
|
1826
|
+
result.error ?? chunkQMAZGLGV_cjs.checkoutError(
|
|
1827
|
+
"unknown",
|
|
1828
|
+
"The checkout could not be verified"
|
|
1829
|
+
)
|
|
1830
|
+
);
|
|
1416
1831
|
}
|
|
1417
1832
|
});
|
|
1418
1833
|
}, []);
|
|
@@ -2527,7 +2942,8 @@ var Namespace = class {
|
|
|
2527
2942
|
const out = {};
|
|
2528
2943
|
const all = this.store.getState();
|
|
2529
2944
|
for (const key in all) {
|
|
2530
|
-
if (key.startsWith(this.dot))
|
|
2945
|
+
if (key.startsWith(this.dot))
|
|
2946
|
+
out[key.slice(this.dot.length)] = all[key];
|
|
2531
2947
|
}
|
|
2532
2948
|
return out;
|
|
2533
2949
|
}
|
|
@@ -2573,9 +2989,10 @@ var FunnelCtx = React.createContext(null);
|
|
|
2573
2989
|
function FunnelProvider({
|
|
2574
2990
|
config,
|
|
2575
2991
|
sessionValues,
|
|
2992
|
+
deferSessionValues = false,
|
|
2576
2993
|
tracker,
|
|
2577
2994
|
context: contextOpts,
|
|
2578
|
-
|
|
2995
|
+
offerings,
|
|
2579
2996
|
experiments,
|
|
2580
2997
|
checkout,
|
|
2581
2998
|
messages,
|
|
@@ -2588,7 +3005,12 @@ function FunnelProvider({
|
|
|
2588
3005
|
const [value] = React.useState(() => {
|
|
2589
3006
|
const s = store ?? createFunnelStore(
|
|
2590
3007
|
{ responses: config?.responses, data: config?.data },
|
|
2591
|
-
|
|
3008
|
+
// FLASH-FREE HYDRATION: with deferSessionValues the initial render is seeded with
|
|
3009
|
+
// DEFAULTS ONLY, so the client's first render is byte-identical to the build-time
|
|
3010
|
+
// DEFAULT-state prerender it hydrates against (clean match). The visitor's saved
|
|
3011
|
+
// answers arrive as a post-hydration setMany below. Without the flag, sessionValues
|
|
3012
|
+
// seed the store at construction (SSR + non-prerendered paths).
|
|
3013
|
+
deferSessionValues ? void 0 : sessionValues
|
|
2592
3014
|
);
|
|
2593
3015
|
const ctx = buildContext({
|
|
2594
3016
|
funnelId: config?.id,
|
|
@@ -2606,7 +3028,7 @@ function FunnelProvider({
|
|
|
2606
3028
|
const value2 = s.get("user.email");
|
|
2607
3029
|
return typeof value2 === "string" && /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test(value2) ? value2 : void 0;
|
|
2608
3030
|
};
|
|
2609
|
-
const catalog =
|
|
3031
|
+
const catalog = chunkBPOAWI4G_cjs.buildCatalog(offerings ?? []);
|
|
2610
3032
|
return {
|
|
2611
3033
|
funnel: createFunnel(s, ctx, busTracker, experiments ?? []),
|
|
2612
3034
|
store: s,
|
|
@@ -2614,12 +3036,25 @@ function FunnelProvider({
|
|
|
2614
3036
|
catalog,
|
|
2615
3037
|
// Slot → catalog-key resolution wraps the email-enriching driver, so the wire charges the real
|
|
2616
3038
|
// catalog key while pages + analytics keep the durable SLOT identity (req.product).
|
|
2617
|
-
driver: driverWithCatalog(
|
|
3039
|
+
driver: driverWithCatalog(
|
|
3040
|
+
driverWithEmail(
|
|
3041
|
+
checkout ?? createMockDriver(),
|
|
3042
|
+
emailForCheckout
|
|
3043
|
+
),
|
|
3044
|
+
catalog
|
|
3045
|
+
),
|
|
2618
3046
|
tracker: busTracker,
|
|
2619
3047
|
bus
|
|
2620
3048
|
};
|
|
2621
3049
|
});
|
|
2622
3050
|
React.useEffect(() => attachBus(value.bus), [value.bus]);
|
|
3051
|
+
React.useEffect(() => {
|
|
3052
|
+
if (!deferSessionValues || !sessionValues) return;
|
|
3053
|
+
const updates = {};
|
|
3054
|
+
for (const [key, v] of Object.entries(sessionValues))
|
|
3055
|
+
if (v !== void 0) updates[key] = v;
|
|
3056
|
+
if (Object.keys(updates).length > 0) value.store.setMany(updates);
|
|
3057
|
+
}, []);
|
|
2623
3058
|
React.useEffect(() => {
|
|
2624
3059
|
value.tracker.setAcquisition?.(buildAcquisition(value.context));
|
|
2625
3060
|
}, [value]);
|
|
@@ -2648,13 +3083,18 @@ var FALLBACK_TRACKER = createConsoleTracker({ silent: true });
|
|
|
2648
3083
|
function useFunnelCtx() {
|
|
2649
3084
|
const ctx = React.useContext(FunnelCtx);
|
|
2650
3085
|
if (!ctx) {
|
|
2651
|
-
throw new Error(
|
|
3086
|
+
throw new Error(
|
|
3087
|
+
"useFunnel/useResponse/\u2026 must be used inside <FunnelProvider>"
|
|
3088
|
+
);
|
|
2652
3089
|
}
|
|
2653
3090
|
return ctx;
|
|
2654
3091
|
}
|
|
2655
3092
|
function useFunnel() {
|
|
2656
3093
|
return useFunnelCtx().funnel;
|
|
2657
3094
|
}
|
|
3095
|
+
function useBusInternal() {
|
|
3096
|
+
return React.useContext(FunnelCtx)?.bus ?? null;
|
|
3097
|
+
}
|
|
2658
3098
|
function useStoreKey(store, key) {
|
|
2659
3099
|
const subscribe = React.useCallback(
|
|
2660
3100
|
(cb) => store.subscribe(cb, { keys: [key] }),
|
|
@@ -2683,7 +3123,9 @@ function useField(path) {
|
|
|
2683
3123
|
const key = path.slice(dot + 1);
|
|
2684
3124
|
const { funnel, store } = useFunnelCtx();
|
|
2685
3125
|
if (!(ns in NAMESPACE_PREFIX)) {
|
|
2686
|
-
throw new Error(
|
|
3126
|
+
throw new Error(
|
|
3127
|
+
`useField: "${path}" is not a writable namespace (user/responses/data)`
|
|
3128
|
+
);
|
|
2687
3129
|
}
|
|
2688
3130
|
const value = useStoreKey(store, `${NAMESPACE_PREFIX[ns]}.${key}`);
|
|
2689
3131
|
const set = React.useCallback(
|
|
@@ -2713,11 +3155,160 @@ function useSystem() {
|
|
|
2713
3155
|
function useContextValue(path) {
|
|
2714
3156
|
const ctx = useContextObject();
|
|
2715
3157
|
return React.useMemo(
|
|
2716
|
-
() => path.split(".").reduce(
|
|
3158
|
+
() => path.split(".").reduce(
|
|
3159
|
+
(acc, k) => acc?.[k],
|
|
3160
|
+
ctx
|
|
3161
|
+
),
|
|
2717
3162
|
[ctx, path]
|
|
2718
3163
|
);
|
|
2719
3164
|
}
|
|
2720
3165
|
|
|
3166
|
+
// src/tracking/snapshotPersistence.ts
|
|
3167
|
+
function createSnapshotPersistence(opts) {
|
|
3168
|
+
const baseDelay = opts.baseDelayMs ?? 1e3;
|
|
3169
|
+
const maxDelay = opts.maxDelayMs ?? 3e4;
|
|
3170
|
+
const setT = opts.timers?.setTimeout ?? ((fn, ms) => setTimeout(fn, ms));
|
|
3171
|
+
const clearT = opts.timers?.clearTimeout ?? ((h) => clearTimeout(h));
|
|
3172
|
+
const rand = opts.random ?? Math.random;
|
|
3173
|
+
let pending = null;
|
|
3174
|
+
let seq = 0;
|
|
3175
|
+
let pendingSeq = 0;
|
|
3176
|
+
let inFlight = false;
|
|
3177
|
+
let attempt = 0;
|
|
3178
|
+
let retryTimer = null;
|
|
3179
|
+
let disposed = false;
|
|
3180
|
+
let fatalSeq = -1;
|
|
3181
|
+
const clearRetry = () => {
|
|
3182
|
+
if (retryTimer !== null) {
|
|
3183
|
+
clearT(retryTimer);
|
|
3184
|
+
retryTimer = null;
|
|
3185
|
+
}
|
|
3186
|
+
};
|
|
3187
|
+
const buildBody = (snapshot, s) => JSON.stringify({ sessionId: opts.getSessionId(), userData: snapshot, seq: s });
|
|
3188
|
+
const trySend = () => {
|
|
3189
|
+
if (disposed || inFlight || pending === null) return;
|
|
3190
|
+
if (retryTimer !== null) return;
|
|
3191
|
+
const sessionId = opts.getSessionId();
|
|
3192
|
+
if (!sessionId) return;
|
|
3193
|
+
if (typeof navigator !== "undefined" && navigator.onLine === false) return;
|
|
3194
|
+
if (pendingSeq === fatalSeq) return;
|
|
3195
|
+
const snapshot = pending;
|
|
3196
|
+
const sentSeq = pendingSeq;
|
|
3197
|
+
const body = buildBody(snapshot, sentSeq);
|
|
3198
|
+
inFlight = true;
|
|
3199
|
+
void fetch(opts.url, {
|
|
3200
|
+
method: "POST",
|
|
3201
|
+
headers: { "content-type": "application/json" },
|
|
3202
|
+
body,
|
|
3203
|
+
keepalive: true
|
|
3204
|
+
}).then((res) => {
|
|
3205
|
+
inFlight = false;
|
|
3206
|
+
if (disposed) return;
|
|
3207
|
+
if (res.ok) {
|
|
3208
|
+
attempt = 0;
|
|
3209
|
+
if (pendingSeq === sentSeq) pending = null;
|
|
3210
|
+
else trySend();
|
|
3211
|
+
return;
|
|
3212
|
+
}
|
|
3213
|
+
if (res.status >= 400 && res.status < 500) {
|
|
3214
|
+
if (process.env.NODE_ENV !== "production") {
|
|
3215
|
+
console.warn(
|
|
3216
|
+
`[appfunnel] snapshot persist rejected ${res.status} (dropping snapshot; check session/payload)`
|
|
3217
|
+
);
|
|
3218
|
+
}
|
|
3219
|
+
fatalSeq = sentSeq;
|
|
3220
|
+
if (pendingSeq === sentSeq) pending = null;
|
|
3221
|
+
else trySend();
|
|
3222
|
+
return;
|
|
3223
|
+
}
|
|
3224
|
+
scheduleRetry();
|
|
3225
|
+
}).catch(() => {
|
|
3226
|
+
inFlight = false;
|
|
3227
|
+
if (disposed) return;
|
|
3228
|
+
scheduleRetry();
|
|
3229
|
+
});
|
|
3230
|
+
};
|
|
3231
|
+
const scheduleRetry = () => {
|
|
3232
|
+
if (disposed || pending === null) return;
|
|
3233
|
+
const exp = Math.min(maxDelay, baseDelay * 2 ** attempt);
|
|
3234
|
+
const delay2 = Math.round(exp * (0.5 + rand() * 0.5));
|
|
3235
|
+
attempt++;
|
|
3236
|
+
clearRetry();
|
|
3237
|
+
retryTimer = setT(() => {
|
|
3238
|
+
retryTimer = null;
|
|
3239
|
+
trySend();
|
|
3240
|
+
}, delay2);
|
|
3241
|
+
};
|
|
3242
|
+
const push = (snapshot) => {
|
|
3243
|
+
if (disposed) return;
|
|
3244
|
+
pending = snapshot;
|
|
3245
|
+
pendingSeq = ++seq;
|
|
3246
|
+
if (fatalSeq !== -1 && pendingSeq !== fatalSeq) fatalSeq = -1;
|
|
3247
|
+
if (retryTimer === null) trySend();
|
|
3248
|
+
};
|
|
3249
|
+
const flushBeacon = () => {
|
|
3250
|
+
if (disposed || pending === null) return;
|
|
3251
|
+
const sessionId = opts.getSessionId();
|
|
3252
|
+
if (!sessionId) return;
|
|
3253
|
+
const body = buildBody(pending, pendingSeq);
|
|
3254
|
+
let delivered = false;
|
|
3255
|
+
if (typeof navigator !== "undefined" && typeof navigator.sendBeacon === "function") {
|
|
3256
|
+
try {
|
|
3257
|
+
delivered = navigator.sendBeacon(
|
|
3258
|
+
opts.url,
|
|
3259
|
+
new Blob([body], { type: "application/json" })
|
|
3260
|
+
);
|
|
3261
|
+
} catch {
|
|
3262
|
+
delivered = false;
|
|
3263
|
+
}
|
|
3264
|
+
}
|
|
3265
|
+
if (!delivered) {
|
|
3266
|
+
try {
|
|
3267
|
+
void fetch(opts.url, {
|
|
3268
|
+
method: "POST",
|
|
3269
|
+
headers: { "content-type": "application/json" },
|
|
3270
|
+
body,
|
|
3271
|
+
keepalive: true
|
|
3272
|
+
}).catch(() => {
|
|
3273
|
+
});
|
|
3274
|
+
delivered = true;
|
|
3275
|
+
} catch {
|
|
3276
|
+
delivered = false;
|
|
3277
|
+
}
|
|
3278
|
+
}
|
|
3279
|
+
if (delivered) pending = null;
|
|
3280
|
+
};
|
|
3281
|
+
const onHidden = () => {
|
|
3282
|
+
if (typeof document !== "undefined" && document.visibilityState === "hidden") {
|
|
3283
|
+
flushBeacon();
|
|
3284
|
+
}
|
|
3285
|
+
};
|
|
3286
|
+
const onPageHide = () => flushBeacon();
|
|
3287
|
+
const onOnline = () => trySend();
|
|
3288
|
+
if (typeof window !== "undefined" && typeof window.addEventListener === "function") {
|
|
3289
|
+
try {
|
|
3290
|
+
document.addEventListener("visibilitychange", onHidden);
|
|
3291
|
+
window.addEventListener("pagehide", onPageHide);
|
|
3292
|
+
window.addEventListener("online", onOnline);
|
|
3293
|
+
} catch {
|
|
3294
|
+
}
|
|
3295
|
+
}
|
|
3296
|
+
const dispose = () => {
|
|
3297
|
+
disposed = true;
|
|
3298
|
+
clearRetry();
|
|
3299
|
+
pending = null;
|
|
3300
|
+
if (typeof window !== "undefined" && typeof window.removeEventListener === "function") {
|
|
3301
|
+
try {
|
|
3302
|
+
document.removeEventListener("visibilitychange", onHidden);
|
|
3303
|
+
window.removeEventListener("pagehide", onPageHide);
|
|
3304
|
+
window.removeEventListener("online", onOnline);
|
|
3305
|
+
} catch {
|
|
3306
|
+
}
|
|
3307
|
+
}
|
|
3308
|
+
};
|
|
3309
|
+
return { push, flushBeacon, dispose };
|
|
3310
|
+
}
|
|
3311
|
+
|
|
2721
3312
|
// src/tracking/platformTracker.ts
|
|
2722
3313
|
function validClickIds(acq) {
|
|
2723
3314
|
return Object.entries(acq.clickIds ?? {}).filter(
|
|
@@ -2823,32 +3414,35 @@ function createPlatformTracker(cfg) {
|
|
|
2823
3414
|
}
|
|
2824
3415
|
};
|
|
2825
3416
|
const VARS_DEBOUNCE_MS = 800;
|
|
3417
|
+
const dataUrl = `${base}/campaign/${encodeURIComponent(cfg.campaignId)}/event/session/data`;
|
|
2826
3418
|
let pendingVars = null;
|
|
2827
3419
|
let varsTimer = null;
|
|
3420
|
+
const persistence = createSnapshotPersistence({
|
|
3421
|
+
url: dataUrl,
|
|
3422
|
+
getSessionId: () => sessionId
|
|
3423
|
+
});
|
|
2828
3424
|
const flushVars = () => {
|
|
2829
3425
|
if (varsTimer) {
|
|
2830
3426
|
clearTimeout(varsTimer);
|
|
2831
3427
|
varsTimer = null;
|
|
2832
3428
|
}
|
|
2833
3429
|
if (!pendingVars) return;
|
|
2834
|
-
const
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
};
|
|
2847
|
-
if (sessionId) doPost();
|
|
2848
|
-
else chain = chain.then(doPost);
|
|
3430
|
+
const snapshot = pendingVars;
|
|
3431
|
+
pendingVars = null;
|
|
3432
|
+
persistence.push(snapshot);
|
|
3433
|
+
if (!sessionId) chain = chain.then(() => {
|
|
3434
|
+
persistence.push(snapshot);
|
|
3435
|
+
});
|
|
3436
|
+
};
|
|
3437
|
+
const drainOnExit = () => {
|
|
3438
|
+
if (pendingVars) {
|
|
3439
|
+
flushVars();
|
|
3440
|
+
persistence.flushBeacon();
|
|
3441
|
+
}
|
|
2849
3442
|
};
|
|
2850
3443
|
try {
|
|
2851
|
-
window.addEventListener("
|
|
3444
|
+
window.addEventListener("visibilitychange", drainOnExit);
|
|
3445
|
+
window.addEventListener("pagehide", drainOnExit);
|
|
2852
3446
|
} catch {
|
|
2853
3447
|
}
|
|
2854
3448
|
if (cfg.experiment?.id && cfg.experiment.variant) {
|
|
@@ -2891,6 +3485,7 @@ function createFunnelTree({
|
|
|
2891
3485
|
}) {
|
|
2892
3486
|
return function tree(opts) {
|
|
2893
3487
|
const mode = opts.mode ?? "live";
|
|
3488
|
+
const embedEnabled = opts.embed ?? false;
|
|
2894
3489
|
const tracker = opts.tracking ? createPlatformTracker({
|
|
2895
3490
|
...opts.tracking,
|
|
2896
3491
|
visitorId: opts.visitorId,
|
|
@@ -2912,6 +3507,7 @@ function createFunnelTree({
|
|
|
2912
3507
|
React.Fragment,
|
|
2913
3508
|
null,
|
|
2914
3509
|
React.createElement(CheckoutResume, null),
|
|
3510
|
+
embedEnabled ? React.createElement(EmbedBridge, null) : null,
|
|
2915
3511
|
layout ? React.createElement(layout, null, children) : children
|
|
2916
3512
|
);
|
|
2917
3513
|
};
|
|
@@ -2919,12 +3515,13 @@ function createFunnelTree({
|
|
|
2919
3515
|
assets: opts.assets,
|
|
2920
3516
|
children: React.createElement(FunnelProvider, {
|
|
2921
3517
|
config,
|
|
2922
|
-
|
|
3518
|
+
offerings: opts.offerings ?? [],
|
|
2923
3519
|
messages: opts.messages ?? messages,
|
|
2924
3520
|
locale: opts.locale,
|
|
2925
3521
|
tracker,
|
|
2926
3522
|
checkout,
|
|
2927
3523
|
sessionValues: opts.sessionValues,
|
|
3524
|
+
deferSessionValues: opts.deferSessionValues,
|
|
2928
3525
|
experiments: opts.experiments,
|
|
2929
3526
|
context: {
|
|
2930
3527
|
mode,
|
|
@@ -2936,6 +3533,13 @@ function createFunnelTree({
|
|
|
2936
3533
|
pages,
|
|
2937
3534
|
layout: layoutWithResume,
|
|
2938
3535
|
initialKey: opts.initialKey,
|
|
3536
|
+
// FLASH-FREE HYDRATION (Option B, FIX 1): trust the SERVER-resolved initialKey instead of
|
|
3537
|
+
// re-running the entry guard. The CLIENT sets this via deferSessionValues (its deferred
|
|
3538
|
+
// snapshot is empty, so re-running the guard would bounce a qualified deep-link and
|
|
3539
|
+
// mismatch the markup). The build-time PRERENDER sets `trustInitialKey` explicitly so a
|
|
3540
|
+
// guarded page prerenders its OWN default-state markup (the renderer picks target-vs-bounce
|
|
3541
|
+
// at serve time). Live SSR fallback leaves both off → the guard runs against real values.
|
|
3542
|
+
trustInitialKey: opts.trustInitialKey ?? opts.deferSessionValues,
|
|
2939
3543
|
prefetch: "off"
|
|
2940
3544
|
// renderer background-modulepreloads all chunks
|
|
2941
3545
|
})
|
|
@@ -3084,147 +3688,143 @@ function Script({
|
|
|
3084
3688
|
|
|
3085
3689
|
Object.defineProperty(exports, "assignVariant", {
|
|
3086
3690
|
enumerable: true,
|
|
3087
|
-
get: function () { return
|
|
3691
|
+
get: function () { return chunkBPOAWI4G_cjs.assignVariant; }
|
|
3088
3692
|
});
|
|
3089
3693
|
Object.defineProperty(exports, "bucketingSeed", {
|
|
3090
3694
|
enumerable: true,
|
|
3091
|
-
get: function () { return
|
|
3695
|
+
get: function () { return chunkBPOAWI4G_cjs.bucketingSeed; }
|
|
3092
3696
|
});
|
|
3093
3697
|
Object.defineProperty(exports, "buildCatalog", {
|
|
3094
3698
|
enumerable: true,
|
|
3095
|
-
get: function () { return
|
|
3699
|
+
get: function () { return chunkBPOAWI4G_cjs.buildCatalog; }
|
|
3096
3700
|
});
|
|
3097
3701
|
Object.defineProperty(exports, "compileManifest", {
|
|
3098
3702
|
enumerable: true,
|
|
3099
|
-
get: function () { return
|
|
3703
|
+
get: function () { return chunkBPOAWI4G_cjs.compileManifest; }
|
|
3100
3704
|
});
|
|
3101
3705
|
Object.defineProperty(exports, "currencyExponent", {
|
|
3102
3706
|
enumerable: true,
|
|
3103
|
-
get: function () { return
|
|
3707
|
+
get: function () { return chunkBPOAWI4G_cjs.currencyExponent; }
|
|
3104
3708
|
});
|
|
3105
3709
|
Object.defineProperty(exports, "defineFunnel", {
|
|
3106
3710
|
enumerable: true,
|
|
3107
|
-
get: function () { return
|
|
3711
|
+
get: function () { return chunkBPOAWI4G_cjs.defineFunnel; }
|
|
3108
3712
|
});
|
|
3109
3713
|
Object.defineProperty(exports, "definePage", {
|
|
3110
3714
|
enumerable: true,
|
|
3111
|
-
get: function () { return
|
|
3715
|
+
get: function () { return chunkBPOAWI4G_cjs.definePage; }
|
|
3112
3716
|
});
|
|
3113
3717
|
Object.defineProperty(exports, "entryGuard", {
|
|
3114
3718
|
enumerable: true,
|
|
3115
|
-
get: function () { return
|
|
3719
|
+
get: function () { return chunkBPOAWI4G_cjs.entryGuard; }
|
|
3116
3720
|
});
|
|
3117
3721
|
Object.defineProperty(exports, "evaluateCondition", {
|
|
3118
3722
|
enumerable: true,
|
|
3119
|
-
get: function () { return
|
|
3723
|
+
get: function () { return chunkBPOAWI4G_cjs.evaluateCondition; }
|
|
3120
3724
|
});
|
|
3121
3725
|
Object.defineProperty(exports, "evaluateGate", {
|
|
3122
3726
|
enumerable: true,
|
|
3123
|
-
get: function () { return
|
|
3727
|
+
get: function () { return chunkBPOAWI4G_cjs.evaluateGate; }
|
|
3124
3728
|
});
|
|
3125
3729
|
Object.defineProperty(exports, "expectedPathLength", {
|
|
3126
3730
|
enumerable: true,
|
|
3127
|
-
get: function () { return
|
|
3731
|
+
get: function () { return chunkBPOAWI4G_cjs.expectedPathLength; }
|
|
3128
3732
|
});
|
|
3129
3733
|
Object.defineProperty(exports, "fnv1a", {
|
|
3130
3734
|
enumerable: true,
|
|
3131
|
-
get: function () { return
|
|
3735
|
+
get: function () { return chunkBPOAWI4G_cjs.fnv1a; }
|
|
3132
3736
|
});
|
|
3133
3737
|
Object.defineProperty(exports, "formatMoney", {
|
|
3134
3738
|
enumerable: true,
|
|
3135
|
-
get: function () { return
|
|
3739
|
+
get: function () { return chunkBPOAWI4G_cjs.formatMoney; }
|
|
3136
3740
|
});
|
|
3137
|
-
Object.defineProperty(exports, "
|
|
3741
|
+
Object.defineProperty(exports, "formatOffering", {
|
|
3138
3742
|
enumerable: true,
|
|
3139
|
-
get: function () { return
|
|
3743
|
+
get: function () { return chunkBPOAWI4G_cjs.formatOffering; }
|
|
3140
3744
|
});
|
|
3141
3745
|
Object.defineProperty(exports, "hashToUnit", {
|
|
3142
3746
|
enumerable: true,
|
|
3143
|
-
get: function () { return
|
|
3747
|
+
get: function () { return chunkBPOAWI4G_cjs.hashToUnit; }
|
|
3144
3748
|
});
|
|
3145
3749
|
Object.defineProperty(exports, "isRtl", {
|
|
3146
3750
|
enumerable: true,
|
|
3147
|
-
get: function () { return
|
|
3751
|
+
get: function () { return chunkBPOAWI4G_cjs.isRtl; }
|
|
3148
3752
|
});
|
|
3149
3753
|
Object.defineProperty(exports, "isVariantKey", {
|
|
3150
3754
|
enumerable: true,
|
|
3151
|
-
get: function () { return
|
|
3755
|
+
get: function () { return chunkBPOAWI4G_cjs.isVariantKey; }
|
|
3152
3756
|
});
|
|
3153
3757
|
Object.defineProperty(exports, "nextPage", {
|
|
3154
3758
|
enumerable: true,
|
|
3155
|
-
get: function () { return
|
|
3759
|
+
get: function () { return chunkBPOAWI4G_cjs.nextPage; }
|
|
3156
3760
|
});
|
|
3157
3761
|
Object.defineProperty(exports, "outgoingKeys", {
|
|
3158
3762
|
enumerable: true,
|
|
3159
|
-
get: function () { return
|
|
3763
|
+
get: function () { return chunkBPOAWI4G_cjs.outgoingKeys; }
|
|
3160
3764
|
});
|
|
3161
3765
|
Object.defineProperty(exports, "pageMeta", {
|
|
3162
3766
|
enumerable: true,
|
|
3163
|
-
get: function () { return
|
|
3767
|
+
get: function () { return chunkBPOAWI4G_cjs.pageMeta; }
|
|
3164
3768
|
});
|
|
3165
3769
|
Object.defineProperty(exports, "parseSlotKey", {
|
|
3166
3770
|
enumerable: true,
|
|
3167
|
-
get: function () { return
|
|
3771
|
+
get: function () { return chunkBPOAWI4G_cjs.parseSlotKey; }
|
|
3168
3772
|
});
|
|
3169
3773
|
Object.defineProperty(exports, "pickByWeight", {
|
|
3170
3774
|
enumerable: true,
|
|
3171
|
-
get: function () { return
|
|
3775
|
+
get: function () { return chunkBPOAWI4G_cjs.pickByWeight; }
|
|
3172
3776
|
});
|
|
3173
3777
|
Object.defineProperty(exports, "resolveExperiments", {
|
|
3174
3778
|
enumerable: true,
|
|
3175
|
-
get: function () { return
|
|
3779
|
+
get: function () { return chunkBPOAWI4G_cjs.resolveExperiments; }
|
|
3176
3780
|
});
|
|
3177
3781
|
Object.defineProperty(exports, "resolveLocale", {
|
|
3178
3782
|
enumerable: true,
|
|
3179
|
-
get: function () { return
|
|
3783
|
+
get: function () { return chunkBPOAWI4G_cjs.resolveLocale; }
|
|
3180
3784
|
});
|
|
3181
|
-
Object.defineProperty(exports, "
|
|
3785
|
+
Object.defineProperty(exports, "resolveOffering", {
|
|
3182
3786
|
enumerable: true,
|
|
3183
|
-
get: function () { return
|
|
3787
|
+
get: function () { return chunkBPOAWI4G_cjs.resolveOffering; }
|
|
3184
3788
|
});
|
|
3185
3789
|
Object.defineProperty(exports, "resolveRoute", {
|
|
3186
3790
|
enumerable: true,
|
|
3187
|
-
get: function () { return
|
|
3188
|
-
});
|
|
3189
|
-
Object.defineProperty(exports, "validateExperiments", {
|
|
3190
|
-
enumerable: true,
|
|
3191
|
-
get: function () { return chunkJSRKA375_cjs.validateExperiments; }
|
|
3791
|
+
get: function () { return chunkBPOAWI4G_cjs.resolveRoute; }
|
|
3192
3792
|
});
|
|
3193
3793
|
Object.defineProperty(exports, "INLINE_SURFACES", {
|
|
3194
3794
|
enumerable: true,
|
|
3195
|
-
get: function () { return
|
|
3795
|
+
get: function () { return chunkQMAZGLGV_cjs.INLINE_SURFACES; }
|
|
3196
3796
|
});
|
|
3197
3797
|
Object.defineProperty(exports, "PROVIDER_PROFILES", {
|
|
3198
3798
|
enumerable: true,
|
|
3199
|
-
get: function () { return
|
|
3799
|
+
get: function () { return chunkQMAZGLGV_cjs.PROVIDER_PROFILES; }
|
|
3200
3800
|
});
|
|
3201
3801
|
Object.defineProperty(exports, "checkoutError", {
|
|
3202
3802
|
enumerable: true,
|
|
3203
|
-
get: function () { return
|
|
3803
|
+
get: function () { return chunkQMAZGLGV_cjs.checkoutError; }
|
|
3204
3804
|
});
|
|
3205
3805
|
Object.defineProperty(exports, "isInlineSurface", {
|
|
3206
3806
|
enumerable: true,
|
|
3207
|
-
get: function () { return
|
|
3807
|
+
get: function () { return chunkQMAZGLGV_cjs.isInlineSurface; }
|
|
3208
3808
|
});
|
|
3209
3809
|
Object.defineProperty(exports, "isMerchantOfRecord", {
|
|
3210
3810
|
enumerable: true,
|
|
3211
|
-
get: function () { return
|
|
3811
|
+
get: function () { return chunkQMAZGLGV_cjs.isMerchantOfRecord; }
|
|
3212
3812
|
});
|
|
3213
3813
|
Object.defineProperty(exports, "isOrchestrator", {
|
|
3214
3814
|
enumerable: true,
|
|
3215
|
-
get: function () { return
|
|
3815
|
+
get: function () { return chunkQMAZGLGV_cjs.isOrchestrator; }
|
|
3216
3816
|
});
|
|
3217
3817
|
Object.defineProperty(exports, "surfacesFor", {
|
|
3218
3818
|
enumerable: true,
|
|
3219
|
-
get: function () { return
|
|
3819
|
+
get: function () { return chunkQMAZGLGV_cjs.surfacesFor; }
|
|
3220
3820
|
});
|
|
3221
3821
|
Object.defineProperty(exports, "validateCheckout", {
|
|
3222
3822
|
enumerable: true,
|
|
3223
|
-
get: function () { return
|
|
3823
|
+
get: function () { return chunkQMAZGLGV_cjs.validateCheckout; }
|
|
3224
3824
|
});
|
|
3225
3825
|
Object.defineProperty(exports, "validateUpsell", {
|
|
3226
3826
|
enumerable: true,
|
|
3227
|
-
get: function () { return
|
|
3827
|
+
get: function () { return chunkQMAZGLGV_cjs.validateUpsell; }
|
|
3228
3828
|
});
|
|
3229
3829
|
exports.AssetsContext = AssetsContext;
|
|
3230
3830
|
exports.AssetsProvider = AssetsProvider;
|
|
@@ -3277,9 +3877,9 @@ exports.useFunnel = useFunnel;
|
|
|
3277
3877
|
exports.useLocale = useLocale;
|
|
3278
3878
|
exports.useModal = useModal;
|
|
3279
3879
|
exports.useNavigation = useNavigation;
|
|
3880
|
+
exports.useOffering = useOffering;
|
|
3881
|
+
exports.useOfferings = useOfferings;
|
|
3280
3882
|
exports.usePage = usePage;
|
|
3281
|
-
exports.useProduct = useProduct;
|
|
3282
|
-
exports.useProducts = useProducts;
|
|
3283
3883
|
exports.useResponse = useResponse;
|
|
3284
3884
|
exports.useSystem = useSystem;
|
|
3285
3885
|
exports.useTracker = useTracker;
|