@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
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this package. It follows semantic versioning; before 1.0 a minor version may change an API.
|
|
4
4
|
|
|
5
|
+
## 0.14.0 (not published yet)
|
|
6
|
+
|
|
7
|
+
- **Paywalls with pages:** a paywall from MRRocket › Conversion › Paywalls can have several pages (benefits, customer quotes, plans), served as the config's new `paywalls` per placement. `usePaywall().open(placement, { onPurchase, plans, onClose })` (Next.js and React Native, drawn by the provider), `mrrocket.paywall.open(…)` (script tag) show them one after another with Back and dots; the last page hands the chosen plan to `onPurchase`, where the app buys it (StoreKit/Play through RevenueCat or Adapty, Stripe Checkout). MRRocket never takes a payment; only after `onPurchase` resolves is the purchase recorded (`false`: the store sheet was cancelled, the paywall stays). Resolves with `{ outcome: "purchased" | "chosen" | "closed", plan, variant, index }`.
|
|
8
|
+
- **Tests per page:** a running paywall test gives each person their variant's pages (`assign`) and records `$exposure` when the paywall opens. New event `$paywall {paywall, placement, variant, page, index, action: "page" | "purchased" | "closed"}`: each page once per opening, so MRRocket shows drop-off between pages; a `purchased` counts as a test's purchase conversion.
|
|
9
|
+
- New module `paywall` with `createPaywallHost`, `paywallPages`, `PAYWALL_EVENT` and the types `PaywallConfig`, `PaywallPage`, `PaywallPlan`, `PaywallOptions`, `PaywallResult`; React Native `client.openPaywall`, `client.paywall`, `MRRocketFlows` takes `paywall`. The web dialog (`mountPaywall`) lives in `flows-ui` / `sdk-flows.js`; `sdk.js` stays within its 14.5 KB budget.
|
|
10
|
+
- Version reported in event batches: `0.14.0`.
|
|
11
|
+
|
|
12
|
+
## 0.13.0
|
|
13
|
+
|
|
14
|
+
- **Attack reports, from your server only** (`@mrrocket/sdk/next/server`, `watchRequest` and `reportSuspiciousRequest` also in `@mrrocket/sdk/next/proxy`): `reportFailedLogin({ userId, account, ip, reason })`, `reportAuthDenied({ status, path, ip, userId })`, `reportSuspiciousRequest({ path, query, ip, reason })` and `watchRequest(request)` for `proxy.ts`, which reads the path and query and reports only what looks like SQL injection, XSS, path traversal or a scanner's path (`/.env`, `/.git`, `/wp-admin`, `/phpmyadmin` …); an ordinary request sends nothing. They send `$login_failed`, `$auth_denied` and `$suspicious_request` with the product's server key (`MRROCKET_SERVER_KEY`); MRRocket hashes the IP and the account name on arrival (a daily hash) and its Build agent puts a possible attack into Needs you as Important. Every helper resolves to `true`/`false` and never throws. `attackIn(path, query)` and `ipOf(headers)` are exported too.
|
|
15
|
+
- Nothing changes in the browser: the script tag and the client bundle stay as they were.
|
|
16
|
+
- Version reported in event batches: `0.13.0`.
|
|
17
|
+
|
|
5
18
|
## 0.12.0 (not published yet)
|
|
6
19
|
|
|
7
20
|
- **Form leads:** a submitted form marked `data-mrrocket-form="<name>"` becomes a contact in MRRocket (`POST /api/sdk/forms`, sent with `sendBeacon`). It sends the email, the name and the other fields a person typed, plus the form's name, page, referrer, UTM and the state of a checkbox marked `data-mrrocket-consent`; never passwords, card, hidden or file fields, fields whose name looks sensitive (`SENSITIVE`) or anything inside `data-mrrocket-ignore`. With analytics consent the lead carries the visitor id and the SDK calls `identify(email)` when your code has not identified the person yet, so their history carries over. Opt-in auto-detection captures any form with an email field and no password field.
|
package/README.md
CHANGED
|
@@ -519,6 +519,66 @@ A form on your site becomes a contact in MRRocket when someone submits it. Mark
|
|
|
519
519
|
- **Script tag:** marked forms work as they are; the capture code (`sdk-forms.js`, about 2 KB gzip) loads only on pages with one. `data-forms="auto"` on the script tag captures any email form.
|
|
520
520
|
- **Not your form?** Typeform, Tally, Cal.com, Calendly, Webflow and Framer post to the product's lead webhook instead (MRRocket › Settings › Integrations › Leads and API).
|
|
521
521
|
|
|
522
|
+
## 20. Attack reports (0.13.0)
|
|
523
|
+
|
|
524
|
+
From your app's **server** only, with the product's server key in `MRROCKET_SERVER_KEY` (MRRocket › Settings › Products › Sign-in). MRRocket's Build agent watches the reports and puts a possible attack into Needs you as Important: many failed sign-ins on one account or from one address, a wave over many accounts, SQL injection / XSS / path traversal in requests, a scanner probing `/.env` or `/wp-admin`, a spike of 401/403 answers.
|
|
525
|
+
|
|
526
|
+
```ts
|
|
527
|
+
// proxy.ts: reports only requests that look like an attack, ordinary ones send nothing
|
|
528
|
+
import { watchRequest } from "@mrrocket/sdk/next/proxy";
|
|
529
|
+
|
|
530
|
+
export function proxy(request: NextRequest, event: NextFetchEvent) {
|
|
531
|
+
const report = watchRequest(request);
|
|
532
|
+
if (report) event.waitUntil(report);
|
|
533
|
+
return NextResponse.next();
|
|
534
|
+
}
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
```ts
|
|
538
|
+
import { ipOf, reportAuthDenied, reportFailedLogin } from "@mrrocket/sdk/next/server";
|
|
539
|
+
|
|
540
|
+
// where a sign-in fails (userId when the account exists, account = what was typed in)
|
|
541
|
+
await reportFailedLogin({ userId: user?.id, account: email, ip: ipOf(request.headers), reason: "wrong_password" });
|
|
542
|
+
// where your API refuses a request
|
|
543
|
+
await reportAuthDenied({ status: 403, path: url.pathname, ip: ipOf(request.headers), userId: session?.userId });
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
They send `$login_failed`, `$auth_denied` and `$suspicious_request` to `/api/sdk/events` with `server: true`. MRRocket hashes the IP and the account name on arrival (a hash that changes every day) and never stores them as sent. Every helper resolves to `true` or `false` and never throws. Using WorkOS or Auth0 webhooks for sign-in? Their failed sign-ins (WorkOS `authentication.*_failed`, Auth0 log types `f`, `fp`, `fu`, `limit_wc`, `limit_mu`) are read without any code; subscribe the webhook to those events.
|
|
547
|
+
|
|
548
|
+
## 21. Paywalls with pages (0.14.0)
|
|
549
|
+
|
|
550
|
+
A paywall built in MRRocket › Conversion › Paywalls can have several pages, for example **1** what you get, **2** what customers say, **3** the plans. The SDK shows them one after another; the last page's button hands the chosen plan to your `onPurchase`, where your code buys it. **MRRocket never takes a payment**: in apps you buy through StoreKit or Google Play (RevenueCat, Adapty), on the web through Stripe Checkout.
|
|
551
|
+
|
|
552
|
+
```tsx
|
|
553
|
+
// React Native / Expo: the provider draws it
|
|
554
|
+
const paywall = usePaywall();
|
|
555
|
+
const result = await paywall.open("onboarding_end", {
|
|
556
|
+
plans: storePlans, // optional: [{ id: "annual", name: "Annual", price: "$49.99" }] with your store's local prices
|
|
557
|
+
onPurchase: async (plan) => {
|
|
558
|
+
const { customerInfo } = await Purchases.purchasePackage(packages[plan.id]);
|
|
559
|
+
return !!customerInfo.entitlements.active.pro; // false: the person cancelled the store sheet, the paywall stays
|
|
560
|
+
},
|
|
561
|
+
});
|
|
562
|
+
// result.outcome: "purchased" | "chosen" (no onPurchase: buy result.plan yourself) | "closed"
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
```tsx
|
|
566
|
+
// Next.js / React
|
|
567
|
+
const paywall = usePaywall();
|
|
568
|
+
<button onClick={() => paywall.open("feature_gate", { onPurchase: (plan) => startCheckout(plan.id) })}>Upgrade</button>
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
```js
|
|
572
|
+
// Script tag
|
|
573
|
+
mrrocket.paywall.open("pricing_page", { onPurchase: (plan) => fetch("/checkout", { method: "POST", body: plan.id }) });
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
- **Plans:** each plan's `id` is what you buy (the store product id or the Stripe price), as set on the plan in MRRocket. Throwing in `onPurchase` keeps the paywall open with "The purchase did not go through".
|
|
577
|
+
- **Tests:** a running paywall test gives each person their variant's pages (the same stable split as every test) and records `$exposure` when the paywall opens. A purchase through the paywall counts as the test's conversion, and so does a store purchase RevenueCat or Adapty report for the same user id.
|
|
578
|
+
- **Drop-off:** each page records `$paywall {action: "page", page, index}` the first time it shows, `purchased` and `closed` too, so MRRocket shows how many reach page 2 and 3.
|
|
579
|
+
- **Without pages** a paywall keeps working as texts your own paywall marks (`paywall.<placement>.headline`, `.body`, `.cta`).
|
|
580
|
+
- The script tag loads the paywall dialog from `sdk-flows.js` on the first `open`; `sdk.js` stays within its budget.
|
|
581
|
+
|
|
522
582
|
## Privacy and consent
|
|
523
583
|
|
|
524
584
|
```tsx
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
(function(){'use strict';var
|
|
1
|
+
(function(){'use strict';var _=(n,e)=>Math.round(n*(1-e/100)*100)/100,M=(n,e)=>{try{return new Intl.NumberFormat(void 0,{style:"currency",currency:e}).format(n)}catch(a){return `${n.toFixed(2)} ${e}`}},T=n=>n.kind==="contact"?"Send to the team":n.kind==="pause"?"Pause instead":n.kind==="downgrade"?"Switch plan":"Accept offer";var L="ckf-styles",q=`
|
|
2
2
|
.ckf-root{--ckf-accent:#3f76ff;--ckf-accent-ink:#fff;--ckf-bg:#fff;--ckf-fg:#1c1d20;--ckf-muted:#5d6068;--ckf-soft:#f4f5f7;--ckf-line:#e4e5e8;--ckf-danger:#d92d20;--ckf-radius:14px;--ckf-font:inherit;--ckf-shadow:0 16px 40px -12px rgba(16,18,24,.28),0 0 0 1px rgba(16,18,24,.07)}
|
|
3
3
|
.ckf-root[data-theme=dark]{--ckf-bg:#17181b;--ckf-fg:#f1f2f4;--ckf-muted:#a9acb3;--ckf-soft:#232428;--ckf-line:#2e2f35;--ckf-shadow:0 16px 40px -12px rgba(0,0,0,.6),0 0 0 1px rgba(255,255,255,.08)}
|
|
4
4
|
@media (prefers-color-scheme:dark){.ckf-root[data-theme=auto]{--ckf-bg:#17181b;--ckf-fg:#f1f2f4;--ckf-muted:#a9acb3;--ckf-soft:#232428;--ckf-line:#2e2f35;--ckf-shadow:0 16px 40px -12px rgba(0,0,0,.6),0 0 0 1px rgba(255,255,255,.08)}}
|
|
@@ -56,9 +56,18 @@
|
|
|
56
56
|
.ckf-banner{position:fixed;z-index:2147483001;left:50%;top:12px;transform:translateX(-50%);width:min(640px,calc(100vw - 24px));background:var(--ckf-bg);border-radius:12px;box-shadow:var(--ckf-shadow);padding:10px 10px 10px 16px;display:flex;align-items:center;gap:12px;animation:ckf-in .18s ease-out}
|
|
57
57
|
.ckf-banner>span{flex:1;min-width:0;display:flex;flex-direction:column}
|
|
58
58
|
.ckf-banner .ckf-btn{height:32px}
|
|
59
|
+
.ckf-pw{max-width:420px;gap:14px}
|
|
60
|
+
.ckf-root[data-still] :is(.ckf-scrim,.ckf-card){animation:none}
|
|
61
|
+
.ckf-li{display:flex;gap:10px;align-items:flex-start;margin:0}
|
|
62
|
+
.ckf-li::before{content:"\u2713";flex:none;width:20px;height:20px;border-radius:50%;background:color-mix(in srgb,var(--ckf-accent) 14%,var(--ckf-bg));color:var(--ckf-accent);font-size:12px;font-weight:700;display:inline-flex;align-items:center;justify-content:center}
|
|
63
|
+
.ckf-quote{margin:0;padding:12px 14px;border-radius:12px;background:var(--ckf-soft)}
|
|
64
|
+
.ckf-quote cite{display:block;margin-top:6px;font-style:normal;font-size:12px;color:var(--ckf-muted)}
|
|
65
|
+
.ckf-plan{justify-content:space-between;min-height:52px}
|
|
66
|
+
.ckf-plan span:nth-child(2){display:flex;flex-direction:column;margin-right:auto}
|
|
67
|
+
.ckf-plan b{font-variant-numeric:tabular-nums}
|
|
59
68
|
@keyframes ckf-fade{from{opacity:0}}
|
|
60
69
|
@keyframes ckf-in{from{opacity:0;transform:translateY(6px)}}
|
|
61
70
|
.ckf-banner{animation-name:ckf-fade}
|
|
62
71
|
@media (max-width:520px){.ckf-scrim{align-items:flex-end;padding:0}.ckf-scrim .ckf-card{max-width:none;border-radius:var(--ckf-radius) var(--ckf-radius) 0 0;max-height:92dvh}.ckf-float{right:12px;bottom:12px}}
|
|
63
72
|
@media (prefers-reduced-motion:reduce){.ckf-root *{animation:none!important;transition:none!important}}
|
|
64
|
-
`,e=(o,a={},...u)=>{let d=document.createElement(o);for(let[f,c]of Object.entries(a))c===void 0||c===false||(typeof c=="function"?d.addEventListener(f.slice(2).toLowerCase(),c):f==="className"?d.className=String(c):d.setAttribute(f,c===true?"":c));for(let f of u)(f||f==="")&&d.append(typeof f=="string"?document.createTextNode(f):f);return d},b=(o,a,u,d={})=>e("button",{type:"button",className:`ckf-btn${a==="secondary"?"":` ckf-${a}`}`,disabled:!!d.disabled,"data-ckf-id":d.id,onClick:()=>u()},o),w=(o,a)=>e("button",{type:"button",className:"ckf-x","aria-label":o,"data-ckf-id":"x",onClick:()=>a()},"\xD7"),H=(o,a)=>a>1?e("span",{className:"ckf-dots",role:"img","aria-label":`Step ${o} of ${a}`},...Array.from({length:a},(u,d)=>e("span",{className:"ckf-dot","data-on":d<o}))):e("span"),z=o=>o.type==="cancel"?`c:${o.screen}`:o.type==="step"?`s:${o.step.id}`:o.type==="checklist"?`l:${o.flow.id}`:`m:${o.message.id}`,M=(o,a={})=>{var F;if(typeof document=="undefined")return ()=>{};if(!document.getElementById(S)){let n=document.createElement("style");n.id=S,n.textContent=j,document.head.appendChild(n);}let u=e("div",{className:`ckf-root${a.className?` ${a.className}`:""}`,"data-theme":(F=a.theme)!=null?F:"auto"});a.accent&&u.style.setProperty("--ckf-accent",a.accent),document.body.appendChild(u);let d="",f=null,c="",h=null,L=n=>{var l,p;let t="ckf-title",s=n.busy,i=[];if(n.screen==="survey")i.push(e("h2",{className:"ckf-h",id:t},n.flow.question||"Why are you leaving?"),e("div",{className:"ckf-opts",role:"radiogroup","aria-labelledby":t},...n.flow.reasons.map(r=>e("button",{type:"button",role:"radio",className:"ckf-opt","aria-checked":String(n.reason===r.id),"data-ckf-id":`r:${r.id}`,onClick:()=>o.cancel.pick(r.id)},e("span",{className:"ckf-radio"}),r.label))),e("div",{className:"ckf-btns"},b("Continue","primary",o.cancel.next,{disabled:!n.reason,id:"go"}),b("Never mind, keep my plan","quiet",o.cancel.close)));else if(n.screen==="offer"&&n.offer){let r=n.offer,g=(l=n.flow.reasons.find(y=>y.id===n.reason))==null?void 0:l.label,m=false;r.kind==="discount"&&r.percent&&(m=n.price?e("div",{className:"ckf-box"},e("span",{className:"ckf-big"},v($(n.price.amount,r.percent),n.price.currency)),e("span",{className:"ckf-strike"},v(n.price.amount,n.price.currency)),e("span",{className:"ckf-small"},`/${(p=n.price.interval)!=null?p:"month"}${r.months?` for ${r.months} ${r.months===1?"month":"months"}`:""}`)):e("div",{className:"ckf-box"},e("span",{className:"ckf-big"},`${r.percent}% off`),r.months?e("span",{className:"ckf-small"},`for ${r.months} ${r.months===1?"month":"months"}`):false)),r.kind==="pause"&&r.months&&(m=e("div",{className:"ckf-box"},e("span",{},`Pause for up to ${r.months} ${r.months===1?"month":"months"}. Your data stays.`))),r.kind==="downgrade"&&r.planName&&(m=e("div",{className:"ckf-box"},e("b",{},r.planName)));let k=r.kind==="contact"?e("textarea",{className:"ckf-text",placeholder:"What would make you stay?","aria-label":"Your message",maxlength:"500","data-ckf-id":"comment",onInput:y=>c=y.target.value}):null;k&&(k.value=c),i.push(g?e("p",{className:"ckf-small"},`You said: ${g}`):false,e("h2",{className:"ckf-h",id:t},r.headline),m,k!=null?k:false,e("div",{className:"ckf-btns"},b(s?"One moment\u2026":E(r),"primary",()=>o.cancel.accept(c),{disabled:s,id:"go"}),b("No thanks, continue cancelling","quiet",o.cancel.decline,{disabled:s})));}else {let g=n.steps===1?null:e("textarea",{className:"ckf-text",placeholder:"Anything else we should know? (optional)","aria-label":"Anything else we should know? (optional)",maxlength:"500","data-ckf-id":"comment",onInput:m=>c=m.target.value});g&&(g.value=c),i.push(e("h2",{className:"ckf-h",id:t},n.flow.confirm.title),n.flow.confirm.body?e("p",{className:"ckf-p"},n.flow.confirm.body):false,g!=null?g:false,e("div",{className:"ckf-btns"},b(s?"One moment\u2026":n.flow.confirm.button,"danger",()=>o.cancel.confirm(c),{disabled:s,id:"go"}),b("Keep my plan","secondary",o.cancel.close,{disabled:s})));}return e("div",{className:"ckf-scrim",onClick:r=>r.target===r.currentTarget&&!s&&o.cancel.close()},e("div",{className:"ckf-card",role:"dialog","aria-modal":"true","aria-labelledby":t},e("div",{className:"ckf-top"},H(n.step,n.steps),w("Close",o.cancel.close)),...i,n.error?e("p",{className:"ckf-err",role:"alert"},n.error):false))},T=n=>{let t=n.step,s=e("div",{className:"ckf-card",role:"dialog","aria-modal":t.kind==="modal"?"true":void 0,"aria-labelledby":"ckf-title"},e("div",{className:"ckf-top"},n.total>1?e("p",{className:"ckf-small"},`Step ${n.index+1} of ${n.total}`):e("span"),w("Close the tour",o.onboarding.dismiss)),e("h2",{className:"ckf-h",id:"ckf-title"},t.title),t.body?e("p",{className:"ckf-p"},t.body):false,e("div",{className:"ckf-row"},b(t.button||(n.last?"Done":"Next"),"primary",o.onboarding.next,{id:"go"})));if(t.kind==="modal")return e("div",{className:"ckf-scrim"},s);let i=t.target?I(t.target):null,l=e("div",{className:"ckf-float"},s);if(i){let p=e("div",{className:"ckf-ring","aria-hidden":"true"});return h={float:l,ring:p,target:i},N(l,p,i),e("div",{},p,l)}return l},I=n=>{var s;let t=()=>document.querySelector(`[data-ck-target="${CSS.escape(n)}"]`);return /^[#.[]|[\s>:=]/.test(n)&&(s=R(n))!=null?s:t()},R=n=>{try{return document.querySelector(n)}catch(t){return null}},N=(n,t,s)=>{let i=s.getBoundingClientRect();Object.assign(t.style,{left:`${i.left-4}px`,top:`${i.top-4}px`,width:`${i.width+8}px`,height:`${i.height+8}px`});let l=Math.min(340,window.innerWidth-24),p=Math.max(12,Math.min(i.left,window.innerWidth-l-12)),r=i.bottom+12;Object.assign(n.style,{left:`${p}px`,right:"auto",width:`${l}px`}),r+200<window.innerHeight?Object.assign(n.style,{top:`${r}px`,bottom:"auto"}):Object.assign(n.style,{top:"auto",bottom:`${Math.max(12,window.innerHeight-i.top+12)}px`});},A=n=>{let t=n.items.filter(s=>s.done).length;return e("div",{className:"ckf-float"},e("div",{className:"ckf-card",role:"region","aria-labelledby":"ckf-title"},e("div",{className:"ckf-top"},e("h2",{className:"ckf-h",id:"ckf-title"},n.flow.name),w("Hide the checklist",o.onboarding.dismiss)),e("p",{className:"ckf-small"},`${t} of ${n.items.length} done`),e("div",{className:"ckf-bar",role:"progressbar","aria-valuemin":"0","aria-valuemax":String(n.items.length),"aria-valuenow":String(t)},e("i",{style:`width:${t/n.items.length*100}%`})),e("div",{className:"ckf-opts"},...n.items.map(({step:s,done:i})=>{let l=[e("span",{className:"ckf-tick","aria-hidden":"true"},i?"\u2713":""),e("span",{},e("b",{},s.title),s.body?e("span",{className:"ckf-small"},s.body):false)];return i||s.event?e("div",{className:"ckf-check","data-done":i,role:"listitem"},...l):e("button",{type:"button",className:"ckf-check","aria-label":`Mark \u201C${s.title}\u201D done`,"data-ckf-id":`i:${s.id}`,onClick:()=>o.onboarding.check(s.id)},...l)}))))},_=n=>{let t=n.message,s=t.button?b(t.button,"primary",o.message.click,{id:"go"}):false;return t.style==="banner"?e("div",{className:"ckf-banner",role:"status"},e("span",{},e("b",{},t.title),t.body?e("span",{className:"ckf-small"},t.body):false),s,w("Dismiss",o.message.dismiss)):e("div",{className:"ckf-scrim",onClick:i=>i.target===i.currentTarget&&o.message.dismiss()},e("div",{className:"ckf-card",role:"dialog","aria-modal":"true","aria-labelledby":"ckf-title"},e("div",{className:"ckf-top"},e("span"),w("Dismiss",o.message.dismiss)),e("h2",{className:"ckf-h",id:"ckf-title"},t.title),t.body?e("p",{className:"ckf-p"},t.body):false,s?e("div",{className:"ckf-row"},s):false))},C=()=>{var i,l,p,r,g;let n=o.view(),t=n?z(n):"",s=(l=(i=document.activeElement)==null?void 0:i.closest)!=null&&l.call(i,".ckf-root")?(p=document.activeElement)==null?void 0:p.getAttribute("data-ckf-id"):null;if(t&&!d&&document.activeElement instanceof HTMLElement&&!document.activeElement.closest(".ckf-root")&&(f=document.activeElement),t!==d&&!t.startsWith("c:")&&(c=""),t||(c=""),h=null,u.replaceChildren(...n?[n.type==="cancel"?L(n):n.type==="step"?T(n):n.type==="checklist"?A(n):_(n)]:[]),t!==d){let m=u.querySelector("[aria-modal=true]"),k=(r=m==null?void 0:m.querySelector("[role=radio], [data-ckf-id=go], textarea"))!=null?r:null;k==null||k.focus(),!t&&f&&(f.focus(),f=null);}else s&&((g=u.querySelector(`[data-ckf-id="${CSS.escape(s)}"]`))==null||g.focus());d=t;},O=n=>{if(n.key!=="Escape")return;let t=o.view();(t==null?void 0:t.type)==="cancel"?o.cancel.close():(t==null?void 0:t.type)==="message"?o.message.dismiss():(t==null?void 0:t.type)==="step"&&t.step.kind==="modal"&&o.onboarding.dismiss();},x=()=>{h&&N(h.float,h.ring,h.target);};document.addEventListener("keydown",O),window.addEventListener("resize",x),window.addEventListener("scroll",x,{passive:true,capture:true});let P=o.subscribe(C);return C(),()=>{P(),document.removeEventListener("keydown",O),window.removeEventListener("resize",x),window.removeEventListener("scroll",x,{capture:true}),u.remove();}};window.__mrrocketFlows={mountFlows:M};})();
|
|
73
|
+
`,t=(n,e={},...a)=>{let s=document.createElement(n);for(let[g,p]of Object.entries(e))p===void 0||p===false||(typeof p=="function"?s.addEventListener(g.slice(2).toLowerCase(),p):g==="className"?s.className=String(p):s.setAttribute(g,p===true?"":p));for(let g of a)(g||g==="")&&s.append(typeof g=="string"?document.createTextNode(g):g);return s},P=(n,e,a,s={})=>t("button",{type:"button",className:`ckf-btn${e==="secondary"?"":` ckf-${e}`}`,disabled:!!s.disabled,"data-ckf-id":s.id,onClick:()=>a()},n),R=(n,e)=>t("button",{type:"button",className:"ckf-x","aria-label":n,"data-ckf-id":"x",onClick:()=>e()},"\xD7"),A=(n,e)=>e>1?t("span",{className:"ckf-dots",role:"img","aria-label":`Step ${n} of ${e}`},...Array.from({length:e},(a,s)=>t("span",{className:"ckf-dot","data-on":s<n}))):t("span"),z=n=>n.type==="cancel"?`c:${n.screen}`:n.type==="step"?`s:${n.step.id}`:n.type==="checklist"?`l:${n.flow.id}`:`m:${n.message.id}`,V=n=>{var a;if(!document.getElementById(L)){let s=document.createElement("style");s.id=L,s.textContent=q,document.head.appendChild(s);}let e=t("div",{className:`ckf-root${n.className?` ${n.className}`:""}`,"data-theme":(a=n.theme)!=null?a:"auto"});return n.accent&&e.style.setProperty("--ckf-accent",n.accent),document.body.appendChild(e),e},H=(n,e={})=>{if(typeof document=="undefined")return ()=>{};let a=V(e),s="",g=null,p="",h=null,y=r=>{var m,x;let o="ckf-title",c=r.busy,f=[];if(r.screen==="survey")f.push(t("h2",{className:"ckf-h",id:o},r.flow.question||"Why are you leaving?"),t("div",{className:"ckf-opts",role:"radiogroup","aria-labelledby":o},...r.flow.reasons.map(l=>t("button",{type:"button",role:"radio",className:"ckf-opt","aria-checked":String(r.reason===l.id),"data-ckf-id":`r:${l.id}`,onClick:()=>n.cancel.pick(l.id)},t("span",{className:"ckf-radio"}),l.label))),t("div",{className:"ckf-btns"},P("Continue","primary",n.cancel.next,{disabled:!r.reason,id:"go"}),P("Never mind, keep my plan","quiet",n.cancel.close)));else if(r.screen==="offer"&&r.offer){let l=r.offer,C=(m=r.flow.reasons.find(S=>S.id===r.reason))==null?void 0:m.label,N=false;l.kind==="discount"&&l.percent&&(N=r.price?t("div",{className:"ckf-box"},t("span",{className:"ckf-big"},M(_(r.price.amount,l.percent),r.price.currency)),t("span",{className:"ckf-strike"},M(r.price.amount,r.price.currency)),t("span",{className:"ckf-small"},`/${(x=r.price.interval)!=null?x:"month"}${l.months?` for ${l.months} ${l.months===1?"month":"months"}`:""}`)):t("div",{className:"ckf-box"},t("span",{className:"ckf-big"},`${l.percent}% off`),l.months?t("span",{className:"ckf-small"},`for ${l.months} ${l.months===1?"month":"months"}`):false)),l.kind==="pause"&&l.months&&(N=t("div",{className:"ckf-box"},t("span",{},`Pause for up to ${l.months} ${l.months===1?"month":"months"}. Your data stays.`))),l.kind==="downgrade"&&l.planName&&(N=t("div",{className:"ckf-box"},t("b",{},l.planName)));let E=l.kind==="contact"?t("textarea",{className:"ckf-text",placeholder:"What would make you stay?","aria-label":"Your message",maxlength:"500","data-ckf-id":"comment",onInput:S=>p=S.target.value}):null;E&&(E.value=p),f.push(C?t("p",{className:"ckf-small"},`You said: ${C}`):false,t("h2",{className:"ckf-h",id:o},l.headline),N,E!=null?E:false,t("div",{className:"ckf-btns"},P(c?"One moment\u2026":T(l),"primary",()=>n.cancel.accept(p),{disabled:c,id:"go"}),P("No thanks, continue cancelling","quiet",n.cancel.decline,{disabled:c})));}else {let C=r.steps===1?null:t("textarea",{className:"ckf-text",placeholder:"Anything else we should know? (optional)","aria-label":"Anything else we should know? (optional)",maxlength:"500","data-ckf-id":"comment",onInput:N=>p=N.target.value});C&&(C.value=p),f.push(t("h2",{className:"ckf-h",id:o},r.flow.confirm.title),r.flow.confirm.body?t("p",{className:"ckf-p"},r.flow.confirm.body):false,C!=null?C:false,t("div",{className:"ckf-btns"},P(c?"One moment\u2026":r.flow.confirm.button,"danger",()=>n.cancel.confirm(p),{disabled:c,id:"go"}),P("Keep my plan","secondary",n.cancel.close,{disabled:c})));}return t("div",{className:"ckf-scrim",onClick:l=>l.target===l.currentTarget&&!c&&n.cancel.close()},t("div",{className:"ckf-card",role:"dialog","aria-modal":"true","aria-labelledby":o},t("div",{className:"ckf-top"},A(r.step,r.steps),R("Close",n.cancel.close)),...f,r.error?t("p",{className:"ckf-err",role:"alert"},r.error):false))},u=r=>{let o=r.step,c=t("div",{className:"ckf-card",role:"dialog","aria-modal":o.kind==="modal"?"true":void 0,"aria-labelledby":"ckf-title"},t("div",{className:"ckf-top"},r.total>1?t("p",{className:"ckf-small"},`Step ${r.index+1} of ${r.total}`):t("span"),R("Close the tour",n.onboarding.dismiss)),t("h2",{className:"ckf-h",id:"ckf-title"},o.title),o.body?t("p",{className:"ckf-p"},o.body):false,t("div",{className:"ckf-row"},P(o.button||(r.last?"Done":"Next"),"primary",n.onboarding.next,{id:"go"})));if(o.kind==="modal")return t("div",{className:"ckf-scrim"},c);let f=o.target?i(o.target):null,m=t("div",{className:"ckf-float"},c);if(f){let x=t("div",{className:"ckf-ring","aria-hidden":"true"});return h={float:m,ring:x,target:f},b(m,x,f),t("div",{},x,m)}return m},i=r=>{var c;let o=()=>document.querySelector(`[data-ck-target="${CSS.escape(r)}"]`);return /^[#.[]|[\s>:=]/.test(r)&&(c=d(r))!=null?c:o()},d=r=>{try{return document.querySelector(r)}catch(o){return null}},b=(r,o,c)=>{let f=c.getBoundingClientRect();Object.assign(o.style,{left:`${f.left-4}px`,top:`${f.top-4}px`,width:`${f.width+8}px`,height:`${f.height+8}px`});let m=Math.min(340,window.innerWidth-24),x=Math.max(12,Math.min(f.left,window.innerWidth-m-12)),l=f.bottom+12;Object.assign(r.style,{left:`${x}px`,right:"auto",width:`${m}px`}),l+200<window.innerHeight?Object.assign(r.style,{top:`${l}px`,bottom:"auto"}):Object.assign(r.style,{top:"auto",bottom:`${Math.max(12,window.innerHeight-f.top+12)}px`});},w=r=>{let o=r.items.filter(c=>c.done).length;return t("div",{className:"ckf-float"},t("div",{className:"ckf-card",role:"region","aria-labelledby":"ckf-title"},t("div",{className:"ckf-top"},t("h2",{className:"ckf-h",id:"ckf-title"},r.flow.name),R("Hide the checklist",n.onboarding.dismiss)),t("p",{className:"ckf-small"},`${o} of ${r.items.length} done`),t("div",{className:"ckf-bar",role:"progressbar","aria-valuemin":"0","aria-valuemax":String(r.items.length),"aria-valuenow":String(o)},t("i",{style:`width:${o/r.items.length*100}%`})),t("div",{className:"ckf-opts"},...r.items.map(({step:c,done:f})=>{let m=[t("span",{className:"ckf-tick","aria-hidden":"true"},f?"\u2713":""),t("span",{},t("b",{},c.title),c.body?t("span",{className:"ckf-small"},c.body):false)];return f||c.event?t("div",{className:"ckf-check","data-done":f,role:"listitem"},...m):t("button",{type:"button",className:"ckf-check","aria-label":`Mark \u201C${c.title}\u201D done`,"data-ckf-id":`i:${c.id}`,onClick:()=>n.onboarding.check(c.id)},...m)}))))},v=r=>{let o=r.message,c=o.button?P(o.button,"primary",n.message.click,{id:"go"}):false;return o.style==="banner"?t("div",{className:"ckf-banner",role:"status"},t("span",{},t("b",{},o.title),o.body?t("span",{className:"ckf-small"},o.body):false),c,R("Dismiss",n.message.dismiss)):t("div",{className:"ckf-scrim",onClick:f=>f.target===f.currentTarget&&n.message.dismiss()},t("div",{className:"ckf-card",role:"dialog","aria-modal":"true","aria-labelledby":"ckf-title"},t("div",{className:"ckf-top"},t("span"),R("Dismiss",n.message.dismiss)),t("h2",{className:"ckf-h",id:"ckf-title"},o.title),o.body?t("p",{className:"ckf-p"},o.body):false,c?t("div",{className:"ckf-row"},c):false))},F=()=>{var f,m,x,l,C;let r=n.view(),o=r?z(r):"",c=(m=(f=document.activeElement)==null?void 0:f.closest)!=null&&m.call(f,".ckf-root")?(x=document.activeElement)==null?void 0:x.getAttribute("data-ckf-id"):null;if(o&&!s&&document.activeElement instanceof HTMLElement&&!document.activeElement.closest(".ckf-root")&&(g=document.activeElement),o!==s&&!o.startsWith("c:")&&(p=""),o||(p=""),h=null,a.replaceChildren(...r?[r.type==="cancel"?y(r):r.type==="step"?u(r):r.type==="checklist"?w(r):v(r)]:[]),o!==s){let N=a.querySelector("[aria-modal=true]"),E=(l=N==null?void 0:N.querySelector("[role=radio], [data-ckf-id=go], textarea"))!=null?l:null;E==null||E.focus(),!o&&g&&(g.focus(),g=null);}else c&&((C=a.querySelector(`[data-ckf-id="${CSS.escape(c)}"]`))==null||C.focus());s=o;},k=r=>{if(r.key!=="Escape")return;let o=n.view();(o==null?void 0:o.type)==="cancel"?n.cancel.close():(o==null?void 0:o.type)==="message"?n.message.dismiss():(o==null?void 0:o.type)==="step"&&o.step.kind==="modal"&&n.onboarding.dismiss();},O=()=>{h&&b(h.float,h.ring,h.target);};document.addEventListener("keydown",k),window.addEventListener("resize",O),window.addEventListener("scroll",O,{passive:true,capture:true});let $=n.subscribe(F);return F(),()=>{$(),document.removeEventListener("keydown",k),window.removeEventListener("resize",O),window.removeEventListener("scroll",O,{capture:true}),a.remove();}},j=(n,e={})=>{if(typeof document=="undefined")return ()=>{};let a=V(e),s="",g=null,p=()=>{var w,v,F;let u=n.view(),i=u?`${u.paywall.id}:${u.index}`:"";if(i&&!s&&document.activeElement instanceof HTMLElement&&(g=document.activeElement),!u){a.replaceChildren(),a.removeAttribute("data-still"),s&&(g==null||g.focus()),s="";return}s&&a.setAttribute("data-still","");let d=u.page,b=d.kind==="plans"?t("div",{className:"ckf-opts",role:"radiogroup","aria-label":"Plans"},...u.plans.map(k=>t("button",{type:"button",role:"radio",className:"ckf-opt ckf-plan","aria-checked":String(u.plan===k.id),"data-ckf-id":`p:${k.id}`,onClick:()=>n.pick(k.id)},t("span",{className:"ckf-radio"}),t("span",{},k.name,k.note?t("span",{className:"ckf-small"},k.note):false),t("b",{},k.price)))):false;a.replaceChildren(t("div",{className:"ckf-scrim",onClick:k=>k.target===k.currentTarget&&n.close()},t("div",{className:"ckf-card ckf-pw",role:"dialog","aria-modal":"true","aria-labelledby":"ckf-title"},t("div",{className:"ckf-top"},A(u.index+1,u.total),R("Close",n.close)),t("h2",{className:"ckf-h",id:"ckf-title"},d.title),d.body?t("p",{className:"ckf-p"},d.body):false,d.kind==="benefits"&&((w=d.items)!=null&&w.length)?t("div",{className:"ckf-opts"},...d.items.map(k=>t("p",{className:"ckf-li"},k))):false,d.kind==="proof"&&((v=d.quotes)!=null&&v.length)?t("div",{className:"ckf-opts"},...d.quotes.map(k=>t("blockquote",{className:"ckf-quote"},k.text,k.by?t("cite",{},k.by):false))):false,b,u.error?t("p",{className:"ckf-err",role:"alert"},u.error):false,t("div",{className:"ckf-btns"},P(u.busy?"One moment\u2026":d.button||"Continue","primary",n.next,{disabled:u.busy||d.kind==="plans"&&!u.plan,id:"go"}),u.index?P("Back","quiet",n.back,{disabled:u.busy}):false)))),i!==s&&((F=a.querySelector("[data-ckf-id=go]"))==null||F.focus()),s=i;},h=u=>{n.view()&&u.key==="Escape"&&n.close();};document.addEventListener("keydown",h);let y=n.subscribe(p);return p(),()=>{y(),document.removeEventListener("keydown",h),a.remove();}};var D=n=>{let e=2166136261;for(let a=0;a<n.length;a++)e^=n.charCodeAt(a),e=Math.imul(e,16777619);return (e>>>0)/4294967296};var U=(n,e)=>{var p,h,y,u;let a=(h=(p=n.variants[0])==null?void 0:p.id)!=null?h:"control";if(n.winner)return n.winner;if(n.status!=="running")return a;let s=D(`${n.key}:${e}`),g=0;for(let i of n.variants)if(g+=i.weight,s<g)return i.id;return (u=(y=n.variants[n.variants.length-1])==null?void 0:y.id)!=null?u:a};var I="$paywall",W=(n,e,a)=>{var h,y;let s=e.experiment?n==null?void 0:n.experiments.find(u=>u.key===e.experiment):void 0,g=s?U(s,a):(h=e.variants[0])==null?void 0:h.id,p=(y=e.variants.find(u=>u.id===g))!=null?y:e.variants[0];return p?{variant:p.id,pages:p.pages,test:(s==null?void 0:s.status)==="running"&&!s.winner?s.key:void 0}:null},K=n=>{let e=null,a=new Set,s=()=>{for(let i of [...a])try{i();}catch(d){}},g=()=>e?{paywall:e.w.id,placement:e.w.placement,variant:e.variant}:{},p=()=>{e&&!e.seen.has(e.index)&&(e.seen.add(e.index),n.track(I,{...g(),page:e.pages[e.index].id,index:e.index,action:"page"})),s();},h=i=>{var b,w;let d=e;d&&(e=null,i.outcome==="closed"&&((w=(b=d.options).onClose)==null||w.call(b,i)),d.resolve(i),s());},y=i=>{var d;return {outcome:i,index:(d=e==null?void 0:e.index)!=null?d:0,...e?{paywall:e.w.id,variant:e.variant}:{},...i!=="closed"&&e?{plan:e.plans.find(b=>b.id===e.plan)}:{}}},u=()=>{let i=e,d=i==null?void 0:i.plans.find(b=>b.id===i.plan);if(!(!i||!d||i.busy)){if(!i.options.onPurchase)return h(y("chosen"));i.busy=true,i.error=void 0,s(),Promise.resolve().then(()=>{var b,w;return (w=(b=i.options).onPurchase)==null?void 0:w.call(b,d)}).then(b=>{if(i.busy=false,e===i){if(b===false)return s();n.track(I,{...g(),page:i.pages[i.index].id,index:i.index,plan:d.id,action:"purchased"}),h(y("purchased"));}},()=>{i.busy=false,i.error="The purchase did not go through. Please try again.",s();});}};return {open:(i,d={})=>{var o,c,f;if(e)return e.promise;let b=n.config(),w=(o=b==null?void 0:b.paywalls)==null?void 0:o.find(m=>m.placement===i),v=w?W(b,w,n.distinctId()):null;if(!w||!(v!=null&&v.pages.length))return Promise.resolve({outcome:"closed",index:0});let F=new Map(((c=d.plans)!=null?c:[]).map(m=>[m.id,m])),k=w.plans.map(m=>{var x;return (x=F.get(m.id))!=null?x:m}),O=()=>{},$=new Promise(m=>O=m),r=k.some(m=>m.id===w.highlight)?w.highlight:(f=k[0])==null?void 0:f.id;return e={w,variant:v.variant,pages:v.pages,plans:k,index:0,plan:r,busy:false,seen:new Set,options:d,resolve:O,promise:$},v.test&&n.track("$exposure",{experiment:v.test,variant:v.variant}),p(),$},view:()=>e?{paywall:e.w,variant:e.variant,page:e.pages[e.index],index:e.index,total:e.pages.length,last:e.index===e.pages.length-1,plans:e.plans,plan:e.plan,busy:e.busy,error:e.error}:null,subscribe:i=>(a.add(i),()=>a.delete(i)),next:()=>{if(!(!e||e.busy)){if(e.pages[e.index].kind==="plans"||e.index===e.pages.length-1)return u();e.index++,e.error=void 0,p();}},back:()=>{!e||e.busy||!e.index||(e.index--,e.error=void 0,s());},pick:i=>{!e||e.busy||!e.plans.some(d=>d.id===i)||(e.plan=i,e.error=void 0,s());},close:()=>{!e||e.busy||(n.track(I,{...g(),index:e.index,action:"closed"}),h(y("closed")));}}};var B=(n,e)=>{let a=K(n);return j(a,e),a};window.__mrrocketFlows={mountFlows:H,paywallHost:B};})();
|