@mrrocket/sdk 0.12.0 → 0.14.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/CHANGELOG.md +13 -0
- package/README.md +60 -0
- package/dist/browser/mrrocket-flows.js +11 -2
- package/dist/browser/mrrocket-messenger.js +143 -65
- package/dist/browser/mrrocket.js +1 -1
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +2 -1
- package/dist/browser.js.map +1 -1
- package/dist/client.d.ts +12 -0
- package/dist/client.js +22 -0
- package/dist/client.js.map +1 -1
- package/dist/context.d.ts +3 -0
- package/dist/context.js.map +1 -1
- package/dist/core.d.ts +4 -1
- package/dist/core.js +1 -1
- package/dist/core.js.map +1 -1
- package/dist/flows-ui.d.ts +6 -4
- package/dist/flows-ui.js +99 -4
- package/dist/flows-ui.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/messenger-ui.d.ts +22 -0
- package/dist/messenger-ui.js +313 -79
- package/dist/messenger-ui.js.map +1 -1
- package/dist/paywall.d.ts +123 -0
- package/dist/paywall.js +131 -0
- package/dist/paywall.js.map +1 -0
- package/dist/proxy.d.ts +1 -0
- package/dist/proxy.js +3 -0
- package/dist/proxy.js.map +1 -1
- package/dist/react-native/index.d.cts +134 -3
- package/dist/react-native/index.d.ts +134 -3
- package/dist/react-native/index.js +204 -4
- package/dist/react-native/index.js.map +1 -1
- package/dist/security.d.ts +71 -0
- package/dist/security.js +73 -0
- package/dist/security.js.map +1 -0
- package/dist/server.d.ts +1 -0
- package/dist/server.js +8 -1
- package/dist/server.js.map +1 -1
- package/dist/styles-css.d.ts +1 -1
- package/dist/styles-css.js +141 -63
- package/dist/styles-css.js.map +1 -1
- package/package.json +1 -1
|
@@ -41,6 +41,7 @@ __export(native_exports, {
|
|
|
41
41
|
useMessenger: () => useMessenger,
|
|
42
42
|
useNavigationTracking: () => useNavigationTracking,
|
|
43
43
|
useOnboarding: () => useOnboarding,
|
|
44
|
+
usePaywall: () => usePaywall,
|
|
44
45
|
usePush: () => usePush,
|
|
45
46
|
useText: () => useText,
|
|
46
47
|
useVariant: () => useVariant
|
|
@@ -49,7 +50,7 @@ module.exports = __toCommonJS(native_exports);
|
|
|
49
50
|
var import_react3 = require("react");
|
|
50
51
|
|
|
51
52
|
// src/core.ts
|
|
52
|
-
var SDK_VERSION = "0.
|
|
53
|
+
var SDK_VERSION = "0.14.0";
|
|
53
54
|
var propOf = (person, name) => {
|
|
54
55
|
const want = name.trim().toLowerCase();
|
|
55
56
|
for (const [k, v] of Object.entries(person)) if (k.toLowerCase() === want) return v;
|
|
@@ -805,6 +806,131 @@ var createFlows = (env) => {
|
|
|
805
806
|
return controller;
|
|
806
807
|
};
|
|
807
808
|
|
|
809
|
+
// src/paywall.ts
|
|
810
|
+
var PAYWALL_EVENT = "$paywall";
|
|
811
|
+
var paywallPages = (config, w, distinctId) => {
|
|
812
|
+
const e = w.experiment ? config?.experiments.find((x) => x.key === w.experiment) : void 0;
|
|
813
|
+
const id = e ? assign(e, distinctId) : w.variants[0]?.id;
|
|
814
|
+
const v = w.variants.find((x) => x.id === id) ?? w.variants[0];
|
|
815
|
+
return v ? { variant: v.id, pages: v.pages, test: e?.status === "running" && !e.winner ? e.key : void 0 } : null;
|
|
816
|
+
};
|
|
817
|
+
var createPaywallHost = (env) => {
|
|
818
|
+
let run = null;
|
|
819
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
820
|
+
const emit = () => {
|
|
821
|
+
for (const l of [...listeners]) {
|
|
822
|
+
try {
|
|
823
|
+
l();
|
|
824
|
+
} catch {
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
};
|
|
828
|
+
const base = () => run ? { paywall: run.w.id, placement: run.w.placement, variant: run.variant } : {};
|
|
829
|
+
const show = () => {
|
|
830
|
+
if (run && !run.seen.has(run.index)) {
|
|
831
|
+
run.seen.add(run.index);
|
|
832
|
+
env.track(PAYWALL_EVENT, { ...base(), page: run.pages[run.index].id, index: run.index, action: "page" });
|
|
833
|
+
}
|
|
834
|
+
emit();
|
|
835
|
+
};
|
|
836
|
+
const end = (r) => {
|
|
837
|
+
const c = run;
|
|
838
|
+
if (!c) return;
|
|
839
|
+
run = null;
|
|
840
|
+
if (r.outcome === "closed") c.options.onClose?.(r);
|
|
841
|
+
c.resolve(r);
|
|
842
|
+
emit();
|
|
843
|
+
};
|
|
844
|
+
const result = (outcome) => ({
|
|
845
|
+
outcome,
|
|
846
|
+
index: run?.index ?? 0,
|
|
847
|
+
...run ? { paywall: run.w.id, variant: run.variant } : {},
|
|
848
|
+
...outcome !== "closed" && run ? { plan: run.plans.find((p) => p.id === run.plan) } : {}
|
|
849
|
+
});
|
|
850
|
+
const buy = () => {
|
|
851
|
+
const c = run;
|
|
852
|
+
const plan = c?.plans.find((p) => p.id === c.plan);
|
|
853
|
+
if (!c || !plan || c.busy) return;
|
|
854
|
+
if (!c.options.onPurchase) return end(result("chosen"));
|
|
855
|
+
c.busy = true;
|
|
856
|
+
c.error = void 0;
|
|
857
|
+
emit();
|
|
858
|
+
Promise.resolve().then(() => c.options.onPurchase?.(plan)).then(
|
|
859
|
+
(ok) => {
|
|
860
|
+
c.busy = false;
|
|
861
|
+
if (run !== c) return;
|
|
862
|
+
if (ok === false) return emit();
|
|
863
|
+
env.track(PAYWALL_EVENT, { ...base(), page: c.pages[c.index].id, index: c.index, plan: plan.id, action: "purchased" });
|
|
864
|
+
end(result("purchased"));
|
|
865
|
+
},
|
|
866
|
+
() => {
|
|
867
|
+
c.busy = false;
|
|
868
|
+
c.error = "The purchase did not go through. Please try again.";
|
|
869
|
+
emit();
|
|
870
|
+
}
|
|
871
|
+
);
|
|
872
|
+
};
|
|
873
|
+
return {
|
|
874
|
+
open: (placement, options = {}) => {
|
|
875
|
+
if (run) return run.promise;
|
|
876
|
+
const config = env.config();
|
|
877
|
+
const w = config?.paywalls?.find((x) => x.placement === placement);
|
|
878
|
+
const picked = w ? paywallPages(config, w, env.distinctId()) : null;
|
|
879
|
+
if (!w || !picked?.pages.length) return Promise.resolve({ outcome: "closed", index: 0 });
|
|
880
|
+
const own = new Map((options.plans ?? []).map((p) => [p.id, p]));
|
|
881
|
+
const plans = w.plans.map((p) => own.get(p.id) ?? p);
|
|
882
|
+
let resolve = () => {
|
|
883
|
+
};
|
|
884
|
+
const promise = new Promise((r) => resolve = r);
|
|
885
|
+
const plan = plans.some((p) => p.id === w.highlight) ? w.highlight : plans[0]?.id;
|
|
886
|
+
run = { w, variant: picked.variant, pages: picked.pages, plans, index: 0, plan, busy: false, seen: /* @__PURE__ */ new Set(), options, resolve, promise };
|
|
887
|
+
if (picked.test) env.track("$exposure", { experiment: picked.test, variant: picked.variant });
|
|
888
|
+
show();
|
|
889
|
+
return promise;
|
|
890
|
+
},
|
|
891
|
+
view: () => run ? {
|
|
892
|
+
paywall: run.w,
|
|
893
|
+
variant: run.variant,
|
|
894
|
+
page: run.pages[run.index],
|
|
895
|
+
index: run.index,
|
|
896
|
+
total: run.pages.length,
|
|
897
|
+
last: run.index === run.pages.length - 1,
|
|
898
|
+
plans: run.plans,
|
|
899
|
+
plan: run.plan,
|
|
900
|
+
busy: run.busy,
|
|
901
|
+
error: run.error
|
|
902
|
+
} : null,
|
|
903
|
+
subscribe: (l) => {
|
|
904
|
+
listeners.add(l);
|
|
905
|
+
return () => listeners.delete(l);
|
|
906
|
+
},
|
|
907
|
+
next: () => {
|
|
908
|
+
if (!run || run.busy) return;
|
|
909
|
+
if (run.pages[run.index].kind === "plans" || run.index === run.pages.length - 1) return buy();
|
|
910
|
+
run.index++;
|
|
911
|
+
run.error = void 0;
|
|
912
|
+
show();
|
|
913
|
+
},
|
|
914
|
+
back: () => {
|
|
915
|
+
if (!run || run.busy || !run.index) return;
|
|
916
|
+
run.index--;
|
|
917
|
+
run.error = void 0;
|
|
918
|
+
emit();
|
|
919
|
+
},
|
|
920
|
+
pick: (id) => {
|
|
921
|
+
if (!run || run.busy || !run.plans.some((p) => p.id === id)) return;
|
|
922
|
+
run.plan = id;
|
|
923
|
+
run.error = void 0;
|
|
924
|
+
emit();
|
|
925
|
+
},
|
|
926
|
+
close: () => {
|
|
927
|
+
if (!run || run.busy) return;
|
|
928
|
+
env.track(PAYWALL_EVENT, { ...base(), index: run.index, action: "closed" });
|
|
929
|
+
end(result("closed"));
|
|
930
|
+
}
|
|
931
|
+
};
|
|
932
|
+
};
|
|
933
|
+
|
|
808
934
|
// src/rage.ts
|
|
809
935
|
var RageDetector = class {
|
|
810
936
|
constructor(windowMs = 1e3, radius = 30, count = 3) {
|
|
@@ -1072,6 +1198,7 @@ var createClient = (options, deps) => {
|
|
|
1072
1198
|
const errorQueue = [];
|
|
1073
1199
|
const errorsSeen = /* @__PURE__ */ new Set();
|
|
1074
1200
|
let errorsSent = 0;
|
|
1201
|
+
const paywall = createPaywallHost({ config: () => config, distinctId: () => distinctId(), track: (event, props) => record(event, props) });
|
|
1075
1202
|
const flows = createFlows({
|
|
1076
1203
|
track: (event, props) => record(event, props),
|
|
1077
1204
|
personId: () => consent !== "off" ? identified : void 0,
|
|
@@ -1632,6 +1759,8 @@ var createClient = (options, deps) => {
|
|
|
1632
1759
|
},
|
|
1633
1760
|
openCancelFlow: (o) => flows.openCancelFlow(o),
|
|
1634
1761
|
startOnboarding: (id) => flows.startOnboarding(id),
|
|
1762
|
+
openPaywall: (placement, o) => paywall.open(placement, o),
|
|
1763
|
+
paywall,
|
|
1635
1764
|
registerForPush,
|
|
1636
1765
|
unregisterForPush,
|
|
1637
1766
|
flows,
|
|
@@ -1697,19 +1826,21 @@ var RN = require("react-native");
|
|
|
1697
1826
|
var LIGHT = { bg: "#ffffff", fg: "#1c1d20", muted: "#5d6068", soft: "#f4f5f7", line: "#e4e5e8" };
|
|
1698
1827
|
var DARK = { bg: "#17181b", fg: "#f1f2f4", muted: "#a9acb3", soft: "#232428", line: "#2e2f35" };
|
|
1699
1828
|
var months = (n) => `${n} ${n === 1 ? "month" : "months"}`;
|
|
1700
|
-
var MRRocketFlows = ({ flows, appearance = {} }) => {
|
|
1829
|
+
var MRRocketFlows = ({ flows, paywall, appearance = {} }) => {
|
|
1701
1830
|
const scheme = RN.useColorScheme?.();
|
|
1702
1831
|
const dark = appearance.theme === "dark" || (appearance.theme ?? "auto") === "auto" && scheme === "dark";
|
|
1703
1832
|
const p = { ...dark ? DARK : LIGHT, accent: appearance.accent ?? "#3f76ff", danger: "#d92d20" };
|
|
1704
1833
|
const [, setTick] = (0, import_react.useState)(0);
|
|
1705
1834
|
(0, import_react.useEffect)(() => flows.subscribe(() => setTick((t) => t + 1)), [flows]);
|
|
1835
|
+
(0, import_react.useEffect)(() => paywall?.subscribe(() => setTick((t) => t + 1)), [paywall]);
|
|
1836
|
+
const pw = paywall?.view() ?? null;
|
|
1706
1837
|
const v = flows.view();
|
|
1707
1838
|
const [comment, setComment] = (0, import_react.useState)("");
|
|
1708
1839
|
const screen = v?.type === "cancel" ? v.screen : null;
|
|
1709
1840
|
(0, import_react.useEffect)(() => {
|
|
1710
1841
|
if (!screen) setComment("");
|
|
1711
1842
|
}, [screen]);
|
|
1712
|
-
if (!v) return null;
|
|
1843
|
+
if (!v && !pw) return null;
|
|
1713
1844
|
const text2 = (children, style = {}) => (0, import_react.createElement)(RN.Text, { style: { color: p.fg, fontSize: 15, ...style } }, children);
|
|
1714
1845
|
const muted = (children, style = {}) => text2(children, { color: p.muted, fontSize: 13, ...style });
|
|
1715
1846
|
const title = (children) => (0, import_react.createElement)(RN.Text, { accessibilityRole: "header", style: { color: p.fg, fontSize: 18, fontWeight: "700" } }, children);
|
|
@@ -1778,6 +1909,71 @@ var MRRocketFlows = ({ flows, appearance = {} }) => {
|
|
|
1778
1909
|
accessibilityLabel: placeholder,
|
|
1779
1910
|
style: { minHeight: 72, borderWidth: 1, borderColor: p.line, borderRadius: 10, padding: 10, color: p.fg, textAlignVertical: "top" }
|
|
1780
1911
|
});
|
|
1912
|
+
const paywallSheet = (w) => {
|
|
1913
|
+
const pg = w.page;
|
|
1914
|
+
const host = paywall;
|
|
1915
|
+
return sheet(
|
|
1916
|
+
[
|
|
1917
|
+
(0, import_react.createElement)(
|
|
1918
|
+
RN.View,
|
|
1919
|
+
{ key: "top", style: { flexDirection: "row", alignItems: "center", gap: 4 } },
|
|
1920
|
+
...w.total > 1 ? Array.from(
|
|
1921
|
+
{ length: w.total },
|
|
1922
|
+
(_, i) => (0, import_react.createElement)(RN.View, { key: i, style: { width: 16, height: 4, borderRadius: 4, backgroundColor: i <= w.index ? p.accent : p.line } })
|
|
1923
|
+
) : [],
|
|
1924
|
+
close("Close", host.close)
|
|
1925
|
+
),
|
|
1926
|
+
title(pg.title),
|
|
1927
|
+
pg.body ? muted(pg.body, { fontSize: 15 }) : null,
|
|
1928
|
+
...pg.kind === "benefits" ? (pg.items ?? []).map(
|
|
1929
|
+
(item, i) => (0, import_react.createElement)(
|
|
1930
|
+
RN.View,
|
|
1931
|
+
{ key: `b${i}`, style: { flexDirection: "row", gap: 10, alignItems: "flex-start" } },
|
|
1932
|
+
text2("\u2713", { color: p.accent, fontWeight: "700" }),
|
|
1933
|
+
text2(item, { flex: 1 })
|
|
1934
|
+
)
|
|
1935
|
+
) : [],
|
|
1936
|
+
...pg.kind === "proof" ? (pg.quotes ?? []).map(
|
|
1937
|
+
(q, i) => (0, import_react.createElement)(RN.View, { key: `q${i}`, style: { backgroundColor: p.soft, borderRadius: 12, padding: 12, gap: 6 } }, text2(q.text), q.by ? muted(q.by) : null)
|
|
1938
|
+
) : [],
|
|
1939
|
+
pg.kind === "plans" ? (0, import_react.createElement)(
|
|
1940
|
+
RN.View,
|
|
1941
|
+
{ key: "plans", accessibilityRole: "radiogroup", style: { gap: 6 } },
|
|
1942
|
+
...w.plans.map(
|
|
1943
|
+
(plan) => (0, import_react.createElement)(
|
|
1944
|
+
RN.Pressable,
|
|
1945
|
+
{
|
|
1946
|
+
key: plan.id,
|
|
1947
|
+
onPress: () => host.pick(plan.id),
|
|
1948
|
+
accessibilityRole: "radio",
|
|
1949
|
+
accessibilityLabel: `${plan.name}, ${plan.price}`,
|
|
1950
|
+
accessibilityState: { checked: w.plan === plan.id },
|
|
1951
|
+
style: {
|
|
1952
|
+
minHeight: 52,
|
|
1953
|
+
paddingHorizontal: 12,
|
|
1954
|
+
borderRadius: 10,
|
|
1955
|
+
borderWidth: 1,
|
|
1956
|
+
borderColor: w.plan === plan.id ? p.accent : p.line,
|
|
1957
|
+
backgroundColor: w.plan === plan.id ? p.soft : p.bg,
|
|
1958
|
+
flexDirection: "row",
|
|
1959
|
+
alignItems: "center",
|
|
1960
|
+
gap: 10
|
|
1961
|
+
}
|
|
1962
|
+
},
|
|
1963
|
+
(0, import_react.createElement)(RN.View, { style: { flex: 1 } }, text2(plan.name, { fontWeight: "600" }), plan.note ? muted(plan.note) : null),
|
|
1964
|
+
text2(plan.price, { fontWeight: "700" })
|
|
1965
|
+
)
|
|
1966
|
+
)
|
|
1967
|
+
) : null,
|
|
1968
|
+
w.error ? text2(w.error, { color: p.danger, fontSize: 13 }) : null,
|
|
1969
|
+
btn(w.busy ? "One moment\u2026" : pg.button || "Continue", "primary", host.next, w.busy || pg.kind === "plans" && !w.plan),
|
|
1970
|
+
w.index ? btn("Back", "quiet", host.back, w.busy) : null
|
|
1971
|
+
],
|
|
1972
|
+
host.close
|
|
1973
|
+
);
|
|
1974
|
+
};
|
|
1975
|
+
if (pw) return paywallSheet(pw);
|
|
1976
|
+
if (!v) return null;
|
|
1781
1977
|
if (v.type === "cancel") {
|
|
1782
1978
|
const top = (0, import_react.createElement)(
|
|
1783
1979
|
RN.View,
|
|
@@ -3067,7 +3263,7 @@ var MRRocketProvider = ({ client: given, children, consent, flows = true, appear
|
|
|
3067
3263
|
Ctx.Provider,
|
|
3068
3264
|
{ value: client },
|
|
3069
3265
|
heatmaps ? (0, import_react3.createElement)(RN4.View, { style: { flex: 1 }, onTouchStartCapture: (e) => touch(e, false), onTouchEndCapture: (e) => touch(e, true) }, children) : children,
|
|
3070
|
-
flows ? (0, import_react3.createElement)(MRRocketFlows, { flows: client.flows, appearance }) : null,
|
|
3266
|
+
flows ? (0, import_react3.createElement)(MRRocketFlows, { flows: client.flows, paywall: client.paywall, appearance }) : null,
|
|
3071
3267
|
surveys ? (0, import_react3.createElement)(MRRocketSurveys, { client, appearance }) : null,
|
|
3072
3268
|
feedback ? (0, import_react3.createElement)(MRRocketFeedback, { client, appearance, options: feedback }) : null,
|
|
3073
3269
|
messenger ? (0, import_react3.createElement)(MRRocketMessenger, { client, appearance, options: messenger }) : null
|
|
@@ -3104,6 +3300,10 @@ var usePush = () => {
|
|
|
3104
3300
|
const client = useClient();
|
|
3105
3301
|
return { register: client.registerForPush, unregister: client.unregisterForPush };
|
|
3106
3302
|
};
|
|
3303
|
+
var usePaywall = () => {
|
|
3304
|
+
const client = useClient();
|
|
3305
|
+
return { open: client.openPaywall };
|
|
3306
|
+
};
|
|
3107
3307
|
var useOnboarding = () => {
|
|
3108
3308
|
const client = useClient();
|
|
3109
3309
|
return { start: client.startOnboarding };
|