@uninspired/auth-client 2.0.0 → 2.1.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/README.md +19 -0
- package/dist/cookie-banner.js +1 -1
- package/dist/cookie-banner.js.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -137,6 +137,25 @@ tracking?.trackPurchase({ eventId, value, currency, contentIds }); // Meta, mark
|
|
|
137
137
|
|
|
138
138
|
`useAuth()` also exposes `captureFeatureUsed`, `captureCheckoutStarted`, and `registerProduct`, which delegate to the tracking client.
|
|
139
139
|
|
|
140
|
+
### Feature flags
|
|
141
|
+
|
|
142
|
+
`TrackingProvider` wraps PostHog's React context around the same `posthog-js` instance it initializes. Do **not** mount a second `PostHogProvider` or call `posthog.init()` yourself.
|
|
143
|
+
|
|
144
|
+
```tsx
|
|
145
|
+
import {
|
|
146
|
+
useFeatureFlagVariantKey,
|
|
147
|
+
useTracking,
|
|
148
|
+
getPostHog,
|
|
149
|
+
} from "@uninspired/auth-client";
|
|
150
|
+
|
|
151
|
+
const variant = useFeatureFlagVariantKey("my-flag");
|
|
152
|
+
const tracking = useTracking();
|
|
153
|
+
const flag = tracking?.getFeatureFlag("my-flag");
|
|
154
|
+
const ph = getPostHog();
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Feature flags load in every consent mode (cookieless included). `identify` stays consent-gated, so person-based targeting applies only after analytics consent and login.
|
|
158
|
+
|
|
140
159
|
## Better Auth client (accounts login UI)
|
|
141
160
|
|
|
142
161
|
For apps that host the login UI (e.g. `apps/frontend`), use the shared Better Auth factory instead of duplicating plugin setup:
|
package/dist/cookie-banner.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{n as e,t}from"./purgeLegacyTracking-C4nrnU7N.js";import n,{useCallback as r,useEffect as i,useState as a}from"react";import{Fragment as o,jsx as s,jsxs as c}from"react/jsx-runtime";import{createPortal as l}from"react-dom";import*as u from"@subframe/core";import{FeatherChevronLeft as d,FeatherChevronRight as f,FeatherInfo as p,FeatherPlus as m,FeatherStar as h,FeatherX as g}from"@subframe/core";import{Close as _,Content as v,Overlay as y,Portal as b,Root as x,Title as S}from"@radix-ui/react-dialog";const C=u.createTwClassNames([`text-caption`,`text-caption-bold`,`text-body`,`text-body-bold`,`text-heading-3`,`text-heading-2`,`text-heading-1`,`text-monospace-body`,`text-heading-section`,`text-heading-subsection`]),w=n.forwardRef(function({disabled:e=!1,variant:t=`brand-primary`,size:n=`medium`,children:r,icon:i=null,iconRight:a=null,loading:o=!1,className:l,type:d=`button`,...f},p){return c(`button`,{className:C(`group/3b777358 flex h-8 cursor-pointer items-center justify-center gap-2 rounded-md border-none bg-brand-600 px-3 text-left hover:bg-brand-500 active:bg-brand-600 disabled:cursor-default disabled:bg-neutral-200 hover:disabled:cursor-default hover:disabled:bg-neutral-200 active:disabled:cursor-default active:disabled:bg-neutral-200`,{"h-6 gap-1 px-2":n===`small`,"h-10 px-4":n===`large`,"bg-transparent hover:bg-[#ffffff29] active:bg-[#ffffff3d]":t===`inverse`,"bg-transparent hover:bg-error-50 active:bg-error-100":t===`destructive-tertiary`,"bg-error-50 hover:bg-error-100 active:bg-error-50":t===`destructive-secondary`,"bg-error-600 hover:bg-error-500 active:bg-error-600":t===`destructive-primary`,"bg-transparent hover:bg-neutral-100 active:bg-neutral-200":t===`neutral-tertiary`,"border border-solid border-neutral-border bg-default-background hover:bg-neutral-50 active:bg-default-background":t===`neutral-secondary`,"bg-neutral-100 hover:bg-neutral-200 active:bg-neutral-100":t===`neutral-primary`,"bg-transparent hover:bg-brand-50 active:bg-brand-100":t===`brand-tertiary`,"bg-brand-50 hover:bg-brand-100 active:bg-brand-50":t===`brand-secondary`},l),ref:p,type:d,disabled:e,...f,children:[i?s(u.IconWrapper,{className:C(`text-body font-body text-white group-disabled/3b777358:text-neutral-400`,{hidden:o,"text-heading-3 font-heading-3":n===`large`,"text-error-700":t===`destructive-tertiary`||t===`destructive-secondary`,"text-neutral-700":t===`neutral-tertiary`||t===`neutral-secondary`||t===`neutral-primary`,"text-brand-700":t===`brand-tertiary`||t===`brand-secondary`}),children:i}):null,s(`div`,{className:C(`hidden h-4 w-4 flex-none items-center justify-center gap-2`,{flex:o,"h-3 w-3":n===`small`}),children:s(u.Loader,{className:C(`text-caption font-caption text-white group-disabled/3b777358:text-neutral-400`,{"leading-[20px]":o,"text-error-700":t===`destructive-tertiary`||t===`destructive-secondary`,"text-neutral-700":t===`neutral-tertiary`||t===`neutral-secondary`||t===`neutral-primary`,"text-brand-700":t===`brand-tertiary`||t===`brand-secondary`})})}),r?s(`span`,{className:C(`whitespace-nowrap text-heading-3 font-heading-3 text-white group-disabled/3b777358:text-neutral-400`,{hidden:o,"text-caption-bold font-caption-bold":n===`small`,"text-body-bold font-body-bold":n===`large`,"text-error-700":t===`destructive-tertiary`||t===`destructive-secondary`,"text-neutral-700":t===`neutral-tertiary`||t===`neutral-secondary`||t===`neutral-primary`,"text-brand-700":t===`brand-tertiary`||t===`brand-secondary`}),children:r}):null,a?s(u.IconWrapper,{className:C(`text-body font-body text-white group-disabled/3b777358:text-neutral-400`,{"text-heading-3 font-heading-3":n===`large`,"text-error-700":t===`destructive-tertiary`||t===`destructive-secondary`,"text-neutral-700":t===`neutral-tertiary`||t===`neutral-secondary`||t===`neutral-primary`,"text-brand-700":t===`brand-tertiary`||t===`brand-secondary`}),children:a}):null]})}),T=n.forwardRef(function({disabled:e=!1,variant:t=`neutral-tertiary`,size:n=`medium`,icon:r=s(m,{}),loading:i=!1,className:a,type:o=`button`,...l},d){return c(`button`,{className:C(`group/af9405b1 flex h-8 w-8 cursor-pointer items-center justify-center gap-2 rounded-md border-none bg-transparent text-left hover:bg-neutral-100 active:bg-neutral-50 disabled:cursor-default disabled:bg-neutral-100 hover:disabled:cursor-default active:disabled:cursor-default active:disabled:bg-neutral-100`,{"h-6 w-6":n===`small`,"h-10 w-10":n===`large`,"hover:bg-[#ffffff29] active:bg-[#ffffff3d]":t===`inverse`,"hover:bg-error-50 active:bg-error-100":t===`destructive-tertiary`,"bg-error-50 hover:bg-error-100 active:bg-error-50":t===`destructive-secondary`,"bg-error-600 hover:bg-error-500 active:bg-error-600":t===`destructive-primary`,"border border-solid border-neutral-border bg-white active:bg-white":t===`neutral-secondary`,"bg-neutral-100 hover:bg-neutral-200 active:bg-neutral-100":t===`neutral-primary`,"hover:bg-brand-50 active:bg-brand-100":t===`brand-tertiary`,"bg-brand-50 hover:bg-brand-100 active:bg-brand-50":t===`brand-secondary`,"bg-brand-600 hover:bg-brand-500 active:bg-brand-600":t===`brand-primary`},a),ref:d,type:o,disabled:e,...l,children:[r?s(u.IconWrapper,{className:C(`text-heading-3 font-heading-3 text-neutral-700 group-disabled/af9405b1:text-neutral-400`,{hidden:i,"text-body font-body":n===`small`,"text-white":t===`inverse`||t===`destructive-primary`||t===`brand-primary`,"text-error-700":t===`destructive-tertiary`||t===`destructive-secondary`,"text-brand-700":t===`brand-tertiary`||t===`brand-secondary`}),children:r}):null,s(u.Loader,{className:C(`hidden text-caption font-caption text-neutral-700 group-disabled/af9405b1:text-neutral-400`,{"inline-block":i,"text-white":t===`inverse`||t===`destructive-primary`||t===`brand-primary`,"text-error-700":t===`destructive-tertiary`||t===`destructive-secondary`,"text-brand-700":t===`brand-tertiary`||t===`brand-secondary`})})]})}),E=n.forwardRef(function({className:e,...t},n){return s(u.Switch.Thumb,{asChild:!0,...t,children:s(`div`,{className:C(`flex h-3.5 w-3.5 flex-col items-start gap-2 rounded-full bg-white shadow-sm`,e),ref:n})})}),D=n.forwardRef(function({checked:e=!1,className:t,...n},r){return s(u.Switch.Root,{checked:e,asChild:!0,...n,children:s(`div`,{className:C(`group/7a464794 flex h-5 w-8 cursor-pointer flex-col items-start justify-center gap-2 rounded-full border border-solid border-neutral-200 bg-neutral-200 px-0.5 py-0.5 aria-[checked=true]:border aria-[checked=true]:border-solid aria-[checked=true]:border-brand-600 aria-[checked=true]:bg-brand-600`,t),ref:r,children:s(E,{})})})}),O=Object.assign(D,{Thumb:E}),k=n.forwardRef(function({disabled:e=!1,children:t,icon:n=s(h,{}),className:r,...i},a){return s(u.ToggleGroup.Item,{asChild:!0,disabled:e,...i,children:c(`div`,{className:C(`group/56dea6ed flex h-7 w-full cursor-pointer items-center justify-center gap-2 rounded-md px-2 py-1 active:bg-neutral-100 aria-[checked=true]:bg-default-background aria-[checked=true]:shadow-sm active:aria-[checked=true]:bg-default-background`,{"active:bg-transparent":e},r),ref:a,children:[n?s(u.IconWrapper,{className:C(`text-body font-body text-subtext-color group-hover/56dea6ed:text-default-font group-aria-[checked=true]/56dea6ed:text-default-font`,{"text-neutral-400 group-hover/56dea6ed:text-neutral-400 group-active/56dea6ed:text-neutral-400":e}),children:n}):null,t?s(`span`,{className:C(`whitespace-nowrap text-caption-bold font-caption-bold text-subtext-color group-hover/56dea6ed:text-default-font group-aria-[checked=true]/56dea6ed:text-default-font`,{"text-neutral-400 group-hover/56dea6ed:text-neutral-400 group-active/56dea6ed:text-neutral-400":e}),children:t}):null]})})}),A=n.forwardRef(function({children:e,className:t,...n},r){return e?s(u.ToggleGroup.Root,{asChild:!0,...n,children:s(`div`,{className:C(`flex items-center gap-0.5 overflow-hidden rounded-md bg-neutral-100 px-0.5 py-0.5`,t),ref:r,children:e})}):null}),j=Object.assign(A,{Item:k}),M=n.forwardRef(function({children:e,className:t,...n},r){return s(`div`,{className:C(`flex flex-col items-start gap-2 rounded-md border border-solid border-neutral-900 bg-neutral-800 px-2 py-1 shadow-lg`,t),ref:r,...n,children:e?s(`span`,{className:`text-caption font-caption text-white`,children:e}):null})}),N=`strictly-necessary`,P=`marketing-and-analytics`,F={analytics:!0,marketing:!0};function I(e){if(!e.analytics&&!e.marketing)return N;if(e.analytics&&e.marketing)return P}function L(e){if(e===`strictly-necessary`)return{analytics:!1,marketing:!1};if(e===`marketing-and-analytics`)return{analytics:!0,marketing:!0}}const R={necessary:{title:`Necessary`,sections:[{heading:`Why do we need this?`,body:`These are how you stay signed in across Uninspired products, how checkout with Paddle can complete a payment, and how we remember that you already answered this banner so we don't ask on every page load.`},{heading:`What is being stored?`,body:`HttpOnly authentication session cookies, shared on uninspired.app so one login works across our apps. Paddle may set its own cookies while you pay. We also set uninspired_consent for 180 days with your analytics and marketing choice (yes or no) — nothing else.`},{heading:`Can I turn this off?`,body:`No — the site can't sign you in, take payment, or keep this preference without them. They are not used for ads, and they are not PostHog or Meta.`}]},analytics:{title:`Analytics`,sections:[{heading:`Why do we need this?`,body:`We use PostHog to see which features people actually use, where checkout starts, when something errors, and what to build next. Same events fire whether you allow cookies or not; this toggle only changes how identifying and persistent that data is.`},{heading:`What is being tracked?`,body:`Page views, clicks (autocapture), and product events such as feature used, checkout started, sign-up, and login. We never send your email. Visible text and element attributes are masked. Session recordings, surveys, and heatmaps are off. Query strings and magic-link paths are stripped before anything leaves the browser.`},{heading:`Where is my data sent?`,body:`PostHog, hosted in the EU. If you allow this, PostHog may set cookies (about 180 days) and browser storage, and we attach events to your account id after you sign in. If you decline (or haven't chosen yet), capture stays cookieless: no analytics cookies, no local storage, no account linking. Server-side events then use a salted hash of your user id instead of the id itself.`}]},marketing:{title:`Marketing`,sections:[{heading:`Why do we need this?`,body:`So we can tell whether Meta ads (Facebook / Instagram) actually lead to someone viewing a product, starting checkout, or buying. This is the only marketing tracker we load.`},{heading:`What is being tracked?`,body:`The Meta Pixel, and only after you allow it. We then load Meta's script and can send PageView, ViewContent, InitiateCheckout, and Purchase. Purchase may include a transaction id so Meta can ignore duplicates. We do not send your email through the pixel. If you later turn this off, we tell Meta to stop sending; leftover Meta cookies may remain until they expire.`},{heading:`Where is my data sent?`,body:`Meta (Facebook). The pixel script is not loaded if you decline, so no Meta cookies are set from us in that case. There is no separate server-side Conversions API path from this banner.`}]}};function z({category:e,onClose:t}){let n=e?R[e]:null;return s(x,{open:e!==null,onOpenChange:e=>!e&&t(),children:c(b,{children:[s(y,{className:`fixed inset-0 z-[10000] bg-[#00000099] data-[state=open]:animate-overlayShow`}),n?c(v,{className:`fixed left-1/2 top-1/2 z-[10000] flex max-h-[calc(100dvh-2rem)] w-[calc(100%-2rem)] max-w-none -translate-x-1/2 -translate-y-1/2 flex-col gap-4 overflow-y-auto rounded-md border border-solid border-neutral-border bg-default-background px-4 py-4 shadow-lg data-[state=open]:animate-contentShow focus:outline-none sm:max-w-[480px]`,children:[c(`div`,{className:`flex w-full items-start justify-between gap-4`,children:[s(S,{className:`text-heading-1 font-heading-1 text-default-font`,children:n.title}),s(T,{icon:s(g,{}),"aria-label":`Close`,onClick:t})]}),s(`div`,{className:`flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto`,children:n.sections.map(e=>c(`div`,{className:`flex max-w-[448px] flex-col items-start gap-0.5`,children:[s(`span`,{className:`text-heading-2 font-heading-2 text-default-font`,children:e.heading}),s(`span`,{className:`text-body font-body text-default-font`,children:e.body})]},e.heading))}),s(`div`,{className:`flex w-full items-center justify-end gap-2`,children:s(_,{asChild:!0,children:s(w,{variant:`neutral-primary`,onClick:t,children:`Close`})})})]}):null]})})}function B(e){return e??F}function V({privacyPolicyUrl:n=`https://legal.uninspired.studio/page/us-privacy-policy/`}){let{pending:u,consent:p,setConsent:m}=e(),[h,g]=a(!1),[_,v]=a(!1),[y,b]=a(F),[x,S]=a(null);i(()=>{g(!0)},[]),i(()=>{u&&t()},[u]),i(()=>{if(!u)return;let e=document.body.style.overflow;return document.body.style.overflow=`hidden`,()=>{document.body.style.overflow=e}},[u]),i(()=>{if(u){v(!0),b(F);return}v(!1),b(B(p))},[u,p]);let C=r(()=>{b(B(p)),v(!0)},[p]),E=r(()=>{v(!1),b(B(p))},[p]),D=r(()=>{m(y),v(!1)},[y,m]),O=I(y);if(!h)return null;let k=u||_;return l(c(o,{children:[u?s(`div`,{className:`fixed inset-0 z-[9998] bg-[#00000099]`,"aria-hidden":!0}):null,!u&&!_?s(`div`,{className:`fixed bottom-4 left-4 z-[9999]`,children:s(T,{icon:s(f,{}),"aria-label":`Open cookie preferences`,onClick:C})}):null,s(`div`,{className:`fixed bottom-4 left-4 z-[9999] flex w-[calc(100vw-2rem)] max-w-[512px] max-h-[calc(100dvh-2rem)] flex-col items-start transition-transform duration-300 ease-out ${k?`translate-x-0`:`-translate-x-[120%] pointer-events-none`}`,"aria-hidden":!k,children:c(`div`,{className:`relative w-full`,children:[u?null:s(`div`,{className:`absolute bottom-0 right-[-33px] z-10 flex h-[33px] w-[33px] flex-none flex-col items-start gap-2`,children:s(T,{icon:s(d,{}),"aria-label":`Close cookie preferences`,onClick:E})}),c(`div`,{className:`flex max-h-[calc(100dvh-2rem)] w-full flex-col items-start gap-5 overflow-y-auto rounded-lg border border-solid border-neutral-border bg-default-background px-4 py-4 shadow-lg`,children:[c(`div`,{className:`flex w-full flex-col items-start gap-1`,children:[s(`span`,{className:`text-heading-1 font-heading-1 text-default-font`,children:`We use cookies.`}),s(`span`,{className:`w-full text-caption font-caption text-subtext-color`,children:`We'd love not to, but a few of them are how this place actually works. Sign-in, checkout, and remembering this choice need cookies. Analytics and ads are optional — skip them if you'd rather. If you decline analytics we still look at product usage in a cookieless way, with nothing extra stored on your device.`}),c(`div`,{className:`flex flex-wrap items-start gap-1`,children:[s(`span`,{className:`text-caption font-caption text-subtext-color`,children:`For more information, please visit our`}),s(`a`,{href:n,target:`_blank`,rel:`noopener noreferrer`,className:`text-caption font-caption text-brand-700 underline-offset-2 hover:underline`,children:`Privacy Policy`})]})]}),c(`div`,{className:`flex w-full flex-col items-start rounded-lg border border-solid border-neutral-border`,children:[s(U,{title:`Necessary`,description:`Sign-in session, Paddle checkout, and this consent cookie.`,checked:!0,disabled:!0,onInfo:()=>S(`necessary`),tooltip:`Required for the site to work — this one stays on.`}),s(H,{}),s(U,{title:`Analytics`,description:`PostHog cookies and linking events to your account. Cookieless usage stats still run if you decline.`,checked:y.analytics,onCheckedChange:e=>b(t=>({...t,analytics:e})),onInfo:()=>S(`analytics`)}),s(H,{}),s(U,{title:`Marketing`,description:`Meta Pixel for ad measurement. The script is not loaded unless you allow it.`,checked:y.marketing,onCheckedChange:e=>b(t=>({...t,marketing:e})),onInfo:()=>S(`marketing`)})]}),c(`div`,{className:`flex w-full flex-col items-stretch justify-between gap-4 sm:flex-row sm:items-center sm:gap-8`,children:[c(j,{className:`w-full sm:w-auto`,value:O??``,onValueChange:e=>{let t=L(e);t&&b(t)},children:[s(j.Item,{icon:null,value:N,children:`Strictly Necessary`}),s(j.Item,{icon:null,value:P,children:`Marketing and Analytics`})]}),s(w,{className:`w-full shrink-0 sm:w-auto`,variant:`neutral-primary`,onClick:D,children:`Save`})]})]})]})}),s(z,{category:x,onClose:()=>S(null)})]}),document.body)}function H(){return s(`div`,{className:`flex h-px w-full flex-none flex-col items-center gap-2 bg-neutral-border`})}function U({title:e,description:t,checked:n,disabled:r=!1,onCheckedChange:i,onInfo:a,tooltip:o}){let l=s(O,{checked:n,disabled:r,onCheckedChange:i,className:r?`cursor-not-allowed aria-[checked=true]:border-neutral-400 aria-[checked=true]:bg-neutral-400`:void 0});return c(`div`,{className:`flex w-full items-center justify-between px-3 py-2`,children:[c(`div`,{className:`flex flex-col items-start`,children:[s(`span`,{className:`text-body-bold font-body-bold text-default-font`,children:e}),s(`span`,{className:`text-caption font-caption text-subtext-color`,children:t})]}),c(`div`,{className:`flex items-center justify-center gap-1`,children:[s(T,{icon:s(p,{}),"aria-label":`More information about ${e}`,onClick:a}),o?s(u.Tooltip.Provider,{children:c(u.Tooltip.Root,{children:[s(u.Tooltip.Trigger,{asChild:!0,children:l}),s(u.Tooltip.Portal,{children:s(u.Tooltip.Content,{side:`top`,align:`center`,sideOffset:4,asChild:!0,children:s(M,{className:`h-auto w-auto max-w-[208px] flex-none`,children:o})})})]})}):l]})]})}export{V as CookieBanner};
|
|
1
|
+
import{n as e,t}from"./purgeLegacyTracking-C4nrnU7N.js";import n,{useCallback as r,useEffect as i,useState as a}from"react";import{Fragment as o,jsx as s,jsxs as c}from"react/jsx-runtime";import{createPortal as l}from"react-dom";import*as u from"@subframe/core";import{FeatherChevronLeft as d,FeatherChevronRight as f,FeatherInfo as p,FeatherPlus as m,FeatherStar as h,FeatherX as g}from"@subframe/core";import{Close as _,Content as v,Overlay as y,Portal as b,Root as x,Title as S}from"@radix-ui/react-dialog";const C=u.createTwClassNames([`text-caption`,`text-caption-bold`,`text-body`,`text-body-bold`,`text-heading-3`,`text-heading-2`,`text-heading-1`,`text-monospace-body`,`text-heading-section`,`text-heading-subsection`]),w=n.forwardRef(function({disabled:e=!1,variant:t=`brand-primary`,size:n=`medium`,children:r,icon:i=null,iconRight:a=null,loading:o=!1,className:l,type:d=`button`,...f},p){return c(`button`,{className:C(`group/3b777358 flex h-8 cursor-pointer items-center justify-center gap-2 rounded-md border-none bg-brand-600 px-3 text-left hover:bg-brand-500 active:bg-brand-600 disabled:cursor-default disabled:bg-neutral-200 hover:disabled:cursor-default hover:disabled:bg-neutral-200 active:disabled:cursor-default active:disabled:bg-neutral-200`,{"h-6 gap-1 px-2":n===`small`,"h-10 px-4":n===`large`,"bg-transparent hover:bg-[#ffffff29] active:bg-[#ffffff3d]":t===`inverse`,"bg-transparent hover:bg-error-50 active:bg-error-100":t===`destructive-tertiary`,"bg-error-50 hover:bg-error-100 active:bg-error-50":t===`destructive-secondary`,"bg-error-600 hover:bg-error-500 active:bg-error-600":t===`destructive-primary`,"bg-transparent hover:bg-neutral-100 active:bg-neutral-200":t===`neutral-tertiary`,"border border-solid border-neutral-border bg-default-background hover:bg-neutral-50 active:bg-default-background":t===`neutral-secondary`,"bg-neutral-100 hover:bg-neutral-200 active:bg-neutral-100":t===`neutral-primary`,"bg-transparent hover:bg-brand-50 active:bg-brand-100":t===`brand-tertiary`,"bg-brand-50 hover:bg-brand-100 active:bg-brand-50":t===`brand-secondary`},l),ref:p,type:d,disabled:e,...f,children:[i?s(u.IconWrapper,{className:C(`text-body font-body text-white group-disabled/3b777358:text-neutral-400`,{hidden:o,"text-heading-3 font-heading-3":n===`large`,"text-error-700":t===`destructive-tertiary`||t===`destructive-secondary`,"text-neutral-700":t===`neutral-tertiary`||t===`neutral-secondary`||t===`neutral-primary`,"text-brand-700":t===`brand-tertiary`||t===`brand-secondary`}),children:i}):null,s(`div`,{className:C(`hidden h-4 w-4 flex-none items-center justify-center gap-2`,{flex:o,"h-3 w-3":n===`small`}),children:s(u.Loader,{className:C(`text-caption font-caption text-white group-disabled/3b777358:text-neutral-400`,{"leading-[20px]":o,"text-error-700":t===`destructive-tertiary`||t===`destructive-secondary`,"text-neutral-700":t===`neutral-tertiary`||t===`neutral-secondary`||t===`neutral-primary`,"text-brand-700":t===`brand-tertiary`||t===`brand-secondary`})})}),r?s(`span`,{className:C(`whitespace-nowrap text-heading-3 font-heading-3 text-white group-disabled/3b777358:text-neutral-400`,{hidden:o,"text-caption-bold font-caption-bold":n===`small`,"text-body-bold font-body-bold":n===`large`,"text-error-700":t===`destructive-tertiary`||t===`destructive-secondary`,"text-neutral-700":t===`neutral-tertiary`||t===`neutral-secondary`||t===`neutral-primary`,"text-brand-700":t===`brand-tertiary`||t===`brand-secondary`}),children:r}):null,a?s(u.IconWrapper,{className:C(`text-body font-body text-white group-disabled/3b777358:text-neutral-400`,{"text-heading-3 font-heading-3":n===`large`,"text-error-700":t===`destructive-tertiary`||t===`destructive-secondary`,"text-neutral-700":t===`neutral-tertiary`||t===`neutral-secondary`||t===`neutral-primary`,"text-brand-700":t===`brand-tertiary`||t===`brand-secondary`}),children:a}):null]})}),T=n.forwardRef(function({disabled:e=!1,variant:t=`neutral-tertiary`,size:n=`medium`,icon:r=s(m,{}),loading:i=!1,className:a,type:o=`button`,...l},d){return c(`button`,{className:C(`group/af9405b1 flex h-8 w-8 cursor-pointer items-center justify-center gap-2 rounded-md border-none bg-transparent text-left hover:bg-neutral-100 active:bg-neutral-50 disabled:cursor-default disabled:bg-neutral-100 hover:disabled:cursor-default active:disabled:cursor-default active:disabled:bg-neutral-100`,{"h-6 w-6":n===`small`,"h-10 w-10":n===`large`,"hover:bg-[#ffffff29] active:bg-[#ffffff3d]":t===`inverse`,"hover:bg-error-50 active:bg-error-100":t===`destructive-tertiary`,"bg-error-50 hover:bg-error-100 active:bg-error-50":t===`destructive-secondary`,"bg-error-600 hover:bg-error-500 active:bg-error-600":t===`destructive-primary`,"border border-solid border-neutral-border bg-white active:bg-white":t===`neutral-secondary`,"bg-neutral-100 hover:bg-neutral-200 active:bg-neutral-100":t===`neutral-primary`,"hover:bg-brand-50 active:bg-brand-100":t===`brand-tertiary`,"bg-brand-50 hover:bg-brand-100 active:bg-brand-50":t===`brand-secondary`,"bg-brand-600 hover:bg-brand-500 active:bg-brand-600":t===`brand-primary`},a),ref:d,type:o,disabled:e,...l,children:[r?s(u.IconWrapper,{className:C(`text-heading-3 font-heading-3 text-neutral-700 group-disabled/af9405b1:text-neutral-400`,{hidden:i,"text-body font-body":n===`small`,"text-white":t===`inverse`||t===`destructive-primary`||t===`brand-primary`,"text-error-700":t===`destructive-tertiary`||t===`destructive-secondary`,"text-brand-700":t===`brand-tertiary`||t===`brand-secondary`}),children:r}):null,s(u.Loader,{className:C(`hidden text-caption font-caption text-neutral-700 group-disabled/af9405b1:text-neutral-400`,{"inline-block":i,"text-white":t===`inverse`||t===`destructive-primary`||t===`brand-primary`,"text-error-700":t===`destructive-tertiary`||t===`destructive-secondary`,"text-brand-700":t===`brand-tertiary`||t===`brand-secondary`})})]})}),E=n.forwardRef(function({className:e,...t},n){return s(u.Switch.Thumb,{asChild:!0,...t,children:s(`div`,{className:C(`flex h-3.5 w-3.5 flex-col items-start gap-2 rounded-full bg-white shadow-sm`,e),ref:n})})}),D=n.forwardRef(function({checked:e=!1,className:t,...n},r){return s(u.Switch.Root,{checked:e,asChild:!0,...n,children:s(`div`,{className:C(`group/7a464794 flex h-5 w-8 cursor-pointer flex-col items-start justify-center gap-2 rounded-full border border-solid border-neutral-200 bg-neutral-200 px-0.5 py-0.5 aria-[checked=true]:border aria-[checked=true]:border-solid aria-[checked=true]:border-brand-600 aria-[checked=true]:bg-brand-600`,t),ref:r,children:s(E,{})})})}),O=Object.assign(D,{Thumb:E}),k=n.forwardRef(function({disabled:e=!1,children:t,icon:n=s(h,{}),className:r,...i},a){return s(u.ToggleGroup.Item,{asChild:!0,disabled:e,...i,children:c(`div`,{className:C(`group/56dea6ed flex h-7 w-full cursor-pointer items-center justify-center gap-2 rounded-md px-2 py-1 active:bg-neutral-100 aria-[checked=true]:bg-default-background aria-[checked=true]:shadow-sm active:aria-[checked=true]:bg-default-background`,{"active:bg-transparent":e},r),ref:a,children:[n?s(u.IconWrapper,{className:C(`text-body font-body text-subtext-color group-hover/56dea6ed:text-default-font group-aria-[checked=true]/56dea6ed:text-default-font`,{"text-neutral-400 group-hover/56dea6ed:text-neutral-400 group-active/56dea6ed:text-neutral-400":e}),children:n}):null,t?s(`span`,{className:C(`whitespace-nowrap text-caption-bold font-caption-bold text-subtext-color group-hover/56dea6ed:text-default-font group-aria-[checked=true]/56dea6ed:text-default-font`,{"text-neutral-400 group-hover/56dea6ed:text-neutral-400 group-active/56dea6ed:text-neutral-400":e}),children:t}):null]})})}),A=n.forwardRef(function({children:e,className:t,...n},r){return e?s(u.ToggleGroup.Root,{asChild:!0,...n,children:s(`div`,{className:C(`flex items-center gap-0.5 overflow-hidden rounded-md bg-neutral-100 px-0.5 py-0.5`,t),ref:r,children:e})}):null}),j=Object.assign(A,{Item:k}),M=n.forwardRef(function({children:e,className:t,...n},r){return s(`div`,{className:C(`flex flex-col items-start gap-2 rounded-md border border-solid border-neutral-900 bg-neutral-800 px-2 py-1 shadow-lg`,t),ref:r,...n,children:e?s(`span`,{className:`text-caption font-caption text-white`,children:e}):null})}),N=`strictly-necessary`,P=`marketing-and-analytics`,F={analytics:!0,marketing:!0};function I(e){if(!e.analytics&&!e.marketing)return N;if(e.analytics&&e.marketing)return P}function L(e){if(e===`strictly-necessary`)return{analytics:!1,marketing:!1};if(e===`marketing-and-analytics`)return{analytics:!0,marketing:!0}}const R={necessary:{title:`Necessary`,sections:[{heading:`Why do we need this?`,body:`These are how you stay signed in across Uninspired products, how checkout with Paddle can complete a payment, and how we remember that you already answered this banner so we don't ask on every page load.`},{heading:`What is being stored?`,body:`HttpOnly authentication session cookies, shared on uninspired.app so one login works across our apps. Paddle may set its own cookies while you pay. We also set uninspired_consent for 180 days with your analytics and marketing choice (yes or no) — nothing else.`},{heading:`Can I turn this off?`,body:`No — the site can't sign you in, take payment, or keep this preference without them. They are not used for ads, and they are not PostHog or Meta.`}]},analytics:{title:`Analytics`,sections:[{heading:`Why do we need this?`,body:`We use PostHog to see which features people actually use, where checkout starts, when something errors, and what to build next. Same events fire whether you allow cookies or not; this toggle only changes how identifying and persistent that data is.`},{heading:`What is being tracked?`,body:`Page views, clicks (autocapture), and product events such as feature used, checkout started, sign-up, and login. We never send your email. Visible text and element attributes are masked. Session recordings, surveys, and heatmaps are off. Query strings and magic-link paths are stripped before anything leaves the browser.`},{heading:`Where is my data sent?`,body:`PostHog, hosted in the EU. If you allow this, PostHog may set cookies (about 180 days) and browser storage, and we attach events to your account id after you sign in. If you decline (or haven't chosen yet), capture stays cookieless: no analytics cookies, no local storage, no account linking. Server-side events then use a salted hash of your user id instead of the id itself.`}]},marketing:{title:`Marketing`,sections:[{heading:`Why do we need this?`,body:`So we can tell whether Meta ads (Facebook / Instagram) actually lead to someone viewing a product, starting checkout, or buying. This is the only marketing tracker we load.`},{heading:`What is being tracked?`,body:`The Meta Pixel, and only after you allow it. We then load Meta's script and can send PageView, ViewContent, InitiateCheckout, and Purchase. Purchase may include a transaction id so Meta can ignore duplicates. We do not send your email through the pixel. If you later turn this off, we tell Meta to stop sending; leftover Meta cookies may remain until they expire.`},{heading:`Where is my data sent?`,body:`Meta (Facebook). The pixel script is not loaded if you decline, so no Meta cookies are set from us in that case. There is no separate server-side Conversions API path from this banner.`}]}};function z({category:e,onClose:t}){let n=e?R[e]:null;return s(x,{open:e!==null,onOpenChange:e=>!e&&t(),children:c(b,{children:[s(y,{className:`fixed inset-0 z-[10000] bg-[#00000099] data-[state=open]:animate-overlayShow`}),n?c(v,{className:`fixed left-1/2 top-1/2 z-[10000] flex max-h-[calc(100dvh-2rem)] w-[calc(100%-2rem)] max-w-none -translate-x-1/2 -translate-y-1/2 flex-col gap-4 overflow-y-auto rounded-md border border-solid border-neutral-border bg-default-background px-4 py-4 shadow-lg data-[state=open]:animate-contentShow focus:outline-none sm:max-w-[480px]`,children:[c(`div`,{className:`flex w-full items-start justify-between gap-4`,children:[s(S,{className:`text-heading-1 font-heading-1 text-default-font`,children:n.title}),s(T,{icon:s(g,{}),"aria-label":`Close`,onClick:t})]}),s(`div`,{className:`flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto`,children:n.sections.map(e=>c(`div`,{className:`flex max-w-[448px] flex-col items-start gap-0.5`,children:[s(`span`,{className:`text-heading-2 font-heading-2 text-default-font`,children:e.heading}),s(`span`,{className:`text-body font-body text-default-font`,children:e.body})]},e.heading))}),s(`div`,{className:`flex w-full items-center justify-end gap-2`,children:s(_,{asChild:!0,children:s(w,{variant:`neutral-primary`,onClick:t,children:`Close`})})})]}):null]})})}function B(e){return e??F}function V({privacyPolicyUrl:n=`https://legal.uninspired.studio/page/us-privacy-policy/`}){let{pending:u,consent:p,setConsent:m}=e(),[h,g]=a(!1),[_,v]=a(!1),[y,b]=a(F),[x,S]=a(null);i(()=>{g(!0)},[]),i(()=>{u&&t()},[u]),i(()=>{if(!u)return;let e=document.body.style.overflow;return document.body.style.overflow=`hidden`,()=>{document.body.style.overflow=e}},[u]),i(()=>{if(u){v(!0),b(F);return}v(!1),b(B(p))},[u,p]);let C=r(()=>{b(B(p)),v(!0)},[p]),E=r(()=>{v(!1),b(B(p))},[p]),D=r(()=>{m(y),v(!1)},[y,m]),O=I(y);if(!h)return null;let k=u||_;return l(c(o,{children:[u?s(`div`,{className:`fixed inset-0 z-[9998] bg-[#00000099]`,"aria-hidden":!0}):null,!u&&!_?s(`div`,{className:`fixed bottom-4 left-4 z-[9999]`,children:s(T,{icon:s(f,{}),"aria-label":`Open cookie preferences`,onClick:C})}):null,s(`div`,{className:`fixed bottom-4 left-4 z-[9999] flex w-[calc(100vw-2rem)] max-w-[512px] max-h-[calc(100dvh-2rem)] flex-col items-start transition-transform duration-300 ease-out ${k?`translate-x-0`:`-translate-x-[120%] pointer-events-none`}`,"aria-hidden":!k,children:c(`div`,{className:`relative w-full`,children:[u?null:s(`div`,{className:`absolute bottom-0 right-[-33px] z-10 flex h-[33px] w-[33px] flex-none flex-col items-start gap-2`,children:s(T,{icon:s(d,{}),"aria-label":`Close cookie preferences`,onClick:E})}),c(`div`,{className:`flex max-h-[calc(100dvh-2rem)] w-full flex-col items-start gap-5 overflow-y-auto rounded-lg border border-solid border-neutral-border bg-default-background px-4 py-4 shadow-lg`,children:[c(`div`,{className:`flex w-full flex-col items-start gap-1`,children:[s(`span`,{className:`text-heading-1 font-heading-1 text-default-font`,children:`We use cookies.`}),s(`span`,{className:`w-full text-caption font-caption text-subtext-color`,children:`We'd love not to, but they tend to be really useful. If you want to help us make better products, please enable some of them. It's cool if you don't though.`}),c(`div`,{className:`flex flex-wrap items-start gap-1`,children:[s(`span`,{className:`text-caption font-caption text-subtext-color`,children:`For more information, please visit our`}),s(`a`,{href:n,target:`_blank`,rel:`noopener noreferrer`,className:`text-caption font-caption text-brand-700 underline-offset-2 hover:underline`,children:`Privacy Policy`})]})]}),c(`div`,{className:`flex w-full flex-col items-start rounded-lg border border-solid border-neutral-border`,children:[s(U,{title:`Necessary`,description:`Sign-in session, Paddle checkout, and this consent cookie.`,checked:!0,disabled:!0,onInfo:()=>S(`necessary`),tooltip:`Required for the site to work — this one stays on.`}),s(H,{}),s(U,{title:`Analytics`,description:`PostHog cookies and linking events to your account. Cookieless usage stats still run if you decline.`,checked:y.analytics,onCheckedChange:e=>b(t=>({...t,analytics:e})),onInfo:()=>S(`analytics`)}),s(H,{}),s(U,{title:`Marketing`,description:`Meta Pixel for ad measurement. The script is not loaded unless you allow it.`,checked:y.marketing,onCheckedChange:e=>b(t=>({...t,marketing:e})),onInfo:()=>S(`marketing`)})]}),c(`div`,{className:`flex w-full flex-col items-stretch justify-between gap-4 sm:flex-row sm:items-center sm:gap-8`,children:[c(j,{className:`w-full sm:w-auto`,value:O??``,onValueChange:e=>{let t=L(e);t&&b(t)},children:[s(j.Item,{icon:null,value:N,children:`Strictly Necessary`}),s(j.Item,{icon:null,value:P,children:`Marketing and Analytics`})]}),s(w,{className:`w-full shrink-0 sm:w-auto`,variant:`neutral-primary`,onClick:D,children:`Save`})]})]})]})}),s(z,{category:x,onClose:()=>S(null)})]}),document.body)}function H(){return s(`div`,{className:`flex h-px w-full flex-none flex-col items-center gap-2 bg-neutral-border`})}function U({title:e,description:t,checked:n,disabled:r=!1,onCheckedChange:i,onInfo:a,tooltip:o}){let l=s(O,{checked:n,disabled:r,onCheckedChange:i,className:r?`cursor-not-allowed aria-[checked=true]:border-neutral-400 aria-[checked=true]:bg-neutral-400`:void 0});return c(`div`,{className:`flex w-full items-center justify-between px-3 py-2`,children:[c(`div`,{className:`flex flex-col items-start`,children:[s(`span`,{className:`text-body-bold font-body-bold text-default-font`,children:e}),s(`span`,{className:`text-caption font-caption text-subtext-color`,children:t})]}),c(`div`,{className:`flex items-center justify-center gap-1`,children:[s(T,{icon:s(p,{}),"aria-label":`More information about ${e}`,onClick:a}),o?s(u.Tooltip.Provider,{children:c(u.Tooltip.Root,{children:[s(u.Tooltip.Trigger,{asChild:!0,children:l}),s(u.Tooltip.Portal,{children:s(u.Tooltip.Content,{side:`top`,align:`center`,sideOffset:4,asChild:!0,children:s(M,{className:`h-auto w-auto max-w-[208px] flex-none`,children:o})})})]})}):l]})]})}export{V as CookieBanner};
|
|
2
2
|
//# sourceMappingURL=cookie-banner.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cookie-banner.js","names":["SubframeUtils.twClassNames","Button","ButtonComponent","SubframeUtils.twClassNames","IconButton","IconButtonComponent","SubframeUtils.twClassNames","Switch","SwitchComponent","SubframeUtils.twClassNames","ToggleGroup","ToggleGroupComponent","SubframeUtils.twClassNames","Tooltip","TooltipComponent"],"sources":["../../components/ui/utils.ts","../../components/ui/components/Button/Button.tsx","../../components/ui/components/Button/index.tsx","../../components/ui/components/IconButton/IconButton.tsx","../../components/ui/components/IconButton/index.tsx","../../components/ui/components/Switch/Switch.tsx","../../components/ui/components/Switch/index.tsx","../../components/ui/components/ToggleGroup/ToggleGroup.tsx","../../components/ui/components/ToggleGroup/index.tsx","../../components/ui/components/Tooltip/Tooltip.tsx","../../components/ui/components/Tooltip/index.tsx","../src/cookie-banner/consentPresets.ts","../src/cookie-banner/ConsentInfoDialog.tsx","../src/cookie-banner/CookieBanner.tsx"],"sourcesContent":["import * as SubframeCore from \"@subframe/core\";\n\nexport const twClassNames = SubframeCore.createTwClassNames([\n \"text-caption\",\n \"text-caption-bold\",\n \"text-body\",\n \"text-body-bold\",\n \"text-heading-3\",\n \"text-heading-2\",\n \"text-heading-1\",\n \"text-monospace-body\",\n \"text-heading-section\",\n \"text-heading-subsection\",\n]);\n","\"use client\";\n/*\n * Documentation:\n * Button — https://app.subframe.com/49eb78b484b2/library?component=Button_3b777358-b86b-40af-9327-891efc6826fe\n */\n\nimport React from \"react\";\nimport * as SubframeCore from \"@subframe/core\";\nimport * as SubframeUtils from \"../../utils\";\n\nexport interface ButtonRootProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n disabled?: boolean;\n variant?:\n | \"brand-primary\"\n | \"brand-secondary\"\n | \"brand-tertiary\"\n | \"neutral-primary\"\n | \"neutral-secondary\"\n | \"neutral-tertiary\"\n | \"destructive-primary\"\n | \"destructive-secondary\"\n | \"destructive-tertiary\"\n | \"inverse\";\n size?: \"large\" | \"medium\" | \"small\";\n children?: React.ReactNode;\n icon?: React.ReactNode;\n iconRight?: React.ReactNode;\n loading?: boolean;\n onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;\n className?: string;\n}\n\nconst ButtonRoot = React.forwardRef<HTMLButtonElement, ButtonRootProps>(\n function ButtonRoot(\n {\n disabled = false,\n variant = \"brand-primary\",\n size = \"medium\",\n children,\n icon = null,\n iconRight = null,\n loading = false,\n className,\n type = \"button\",\n ...otherProps\n }: ButtonRootProps,\n ref\n ) {\n return (\n <button\n className={SubframeUtils.twClassNames(\n \"group/3b777358 flex h-8 cursor-pointer items-center justify-center gap-2 rounded-md border-none bg-brand-600 px-3 text-left hover:bg-brand-500 active:bg-brand-600 disabled:cursor-default disabled:bg-neutral-200 hover:disabled:cursor-default hover:disabled:bg-neutral-200 active:disabled:cursor-default active:disabled:bg-neutral-200\",\n {\n \"h-6 gap-1 px-2\": size === \"small\",\n \"h-10 px-4\": size === \"large\",\n \"bg-transparent hover:bg-[#ffffff29] active:bg-[#ffffff3d]\":\n variant === \"inverse\",\n \"bg-transparent hover:bg-error-50 active:bg-error-100\":\n variant === \"destructive-tertiary\",\n \"bg-error-50 hover:bg-error-100 active:bg-error-50\":\n variant === \"destructive-secondary\",\n \"bg-error-600 hover:bg-error-500 active:bg-error-600\":\n variant === \"destructive-primary\",\n \"bg-transparent hover:bg-neutral-100 active:bg-neutral-200\":\n variant === \"neutral-tertiary\",\n \"border border-solid border-neutral-border bg-default-background hover:bg-neutral-50 active:bg-default-background\":\n variant === \"neutral-secondary\",\n \"bg-neutral-100 hover:bg-neutral-200 active:bg-neutral-100\":\n variant === \"neutral-primary\",\n \"bg-transparent hover:bg-brand-50 active:bg-brand-100\":\n variant === \"brand-tertiary\",\n \"bg-brand-50 hover:bg-brand-100 active:bg-brand-50\":\n variant === \"brand-secondary\",\n },\n className\n )}\n ref={ref}\n type={type}\n disabled={disabled}\n {...otherProps}\n >\n {icon ? (\n <SubframeCore.IconWrapper\n className={SubframeUtils.twClassNames(\n \"text-body font-body text-white group-disabled/3b777358:text-neutral-400\",\n {\n hidden: loading,\n \"text-heading-3 font-heading-3\": size === \"large\",\n \"text-error-700\":\n variant === \"destructive-tertiary\" ||\n variant === \"destructive-secondary\",\n \"text-neutral-700\":\n variant === \"neutral-tertiary\" ||\n variant === \"neutral-secondary\" ||\n variant === \"neutral-primary\",\n \"text-brand-700\":\n variant === \"brand-tertiary\" || variant === \"brand-secondary\",\n }\n )}\n >\n {icon}\n </SubframeCore.IconWrapper>\n ) : null}\n <div\n className={SubframeUtils.twClassNames(\n \"hidden h-4 w-4 flex-none items-center justify-center gap-2\",\n { flex: loading, \"h-3 w-3\": size === \"small\" }\n )}\n >\n <SubframeCore.Loader\n className={SubframeUtils.twClassNames(\n \"text-caption font-caption text-white group-disabled/3b777358:text-neutral-400\",\n {\n \"leading-[20px]\": loading,\n \"text-error-700\":\n variant === \"destructive-tertiary\" ||\n variant === \"destructive-secondary\",\n \"text-neutral-700\":\n variant === \"neutral-tertiary\" ||\n variant === \"neutral-secondary\" ||\n variant === \"neutral-primary\",\n \"text-brand-700\":\n variant === \"brand-tertiary\" || variant === \"brand-secondary\",\n }\n )}\n />\n </div>\n {children ? (\n <span\n className={SubframeUtils.twClassNames(\n \"whitespace-nowrap text-heading-3 font-heading-3 text-white group-disabled/3b777358:text-neutral-400\",\n {\n hidden: loading,\n \"text-caption-bold font-caption-bold\": size === \"small\",\n \"text-body-bold font-body-bold\": size === \"large\",\n \"text-error-700\":\n variant === \"destructive-tertiary\" ||\n variant === \"destructive-secondary\",\n \"text-neutral-700\":\n variant === \"neutral-tertiary\" ||\n variant === \"neutral-secondary\" ||\n variant === \"neutral-primary\",\n \"text-brand-700\":\n variant === \"brand-tertiary\" || variant === \"brand-secondary\",\n }\n )}\n >\n {children}\n </span>\n ) : null}\n {iconRight ? (\n <SubframeCore.IconWrapper\n className={SubframeUtils.twClassNames(\n \"text-body font-body text-white group-disabled/3b777358:text-neutral-400\",\n {\n \"text-heading-3 font-heading-3\": size === \"large\",\n \"text-error-700\":\n variant === \"destructive-tertiary\" ||\n variant === \"destructive-secondary\",\n \"text-neutral-700\":\n variant === \"neutral-tertiary\" ||\n variant === \"neutral-secondary\" ||\n variant === \"neutral-primary\",\n \"text-brand-700\":\n variant === \"brand-tertiary\" || variant === \"brand-secondary\",\n }\n )}\n >\n {iconRight}\n </SubframeCore.IconWrapper>\n ) : null}\n </button>\n );\n }\n);\n\nexport const Button = ButtonRoot;\n","\"use client\";\nimport { Button as ButtonComponent } from \"./Button\";\n\n/**\n * Add wrapper components and business logic here.\n * If you modify this file, disable Subframe sync for it to prevent overwrites.\n * Learn more: https://docs.subframe.com/concepts/syncing-components#wrapping-components\n */\n\nexport const Button = ButtonComponent;\n","\"use client\";\n/*\n * Documentation:\n * Icon Button — https://app.subframe.com/49eb78b484b2/library?component=Icon+Button_af9405b1-8c54-4e01-9786-5aad308224f6\n */\n\nimport React from \"react\";\nimport { FeatherPlus } from \"@subframe/core\";\nimport * as SubframeCore from \"@subframe/core\";\nimport * as SubframeUtils from \"../../utils\";\n\nexport interface IconButtonRootProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n disabled?: boolean;\n variant?:\n | \"brand-primary\"\n | \"brand-secondary\"\n | \"brand-tertiary\"\n | \"neutral-primary\"\n | \"neutral-secondary\"\n | \"neutral-tertiary\"\n | \"destructive-primary\"\n | \"destructive-secondary\"\n | \"destructive-tertiary\"\n | \"inverse\";\n size?: \"large\" | \"medium\" | \"small\";\n icon?: React.ReactNode;\n loading?: boolean;\n onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;\n className?: string;\n}\n\nconst IconButtonRoot = React.forwardRef<HTMLButtonElement, IconButtonRootProps>(\n function IconButtonRoot(\n {\n disabled = false,\n variant = \"neutral-tertiary\",\n size = \"medium\",\n icon = <FeatherPlus />,\n loading = false,\n className,\n type = \"button\",\n ...otherProps\n }: IconButtonRootProps,\n ref\n ) {\n return (\n <button\n className={SubframeUtils.twClassNames(\n \"group/af9405b1 flex h-8 w-8 cursor-pointer items-center justify-center gap-2 rounded-md border-none bg-transparent text-left hover:bg-neutral-100 active:bg-neutral-50 disabled:cursor-default disabled:bg-neutral-100 hover:disabled:cursor-default active:disabled:cursor-default active:disabled:bg-neutral-100\",\n {\n \"h-6 w-6\": size === \"small\",\n \"h-10 w-10\": size === \"large\",\n \"hover:bg-[#ffffff29] active:bg-[#ffffff3d]\": variant === \"inverse\",\n \"hover:bg-error-50 active:bg-error-100\":\n variant === \"destructive-tertiary\",\n \"bg-error-50 hover:bg-error-100 active:bg-error-50\":\n variant === \"destructive-secondary\",\n \"bg-error-600 hover:bg-error-500 active:bg-error-600\":\n variant === \"destructive-primary\",\n \"border border-solid border-neutral-border bg-white active:bg-white\":\n variant === \"neutral-secondary\",\n \"bg-neutral-100 hover:bg-neutral-200 active:bg-neutral-100\":\n variant === \"neutral-primary\",\n \"hover:bg-brand-50 active:bg-brand-100\":\n variant === \"brand-tertiary\",\n \"bg-brand-50 hover:bg-brand-100 active:bg-brand-50\":\n variant === \"brand-secondary\",\n \"bg-brand-600 hover:bg-brand-500 active:bg-brand-600\":\n variant === \"brand-primary\",\n },\n className\n )}\n ref={ref}\n type={type}\n disabled={disabled}\n {...otherProps}\n >\n {icon ? (\n <SubframeCore.IconWrapper\n className={SubframeUtils.twClassNames(\n \"text-heading-3 font-heading-3 text-neutral-700 group-disabled/af9405b1:text-neutral-400\",\n {\n hidden: loading,\n \"text-body font-body\": size === \"small\",\n \"text-white\":\n variant === \"inverse\" ||\n variant === \"destructive-primary\" ||\n variant === \"brand-primary\",\n \"text-error-700\":\n variant === \"destructive-tertiary\" ||\n variant === \"destructive-secondary\",\n \"text-brand-700\":\n variant === \"brand-tertiary\" || variant === \"brand-secondary\",\n }\n )}\n >\n {icon}\n </SubframeCore.IconWrapper>\n ) : null}\n <SubframeCore.Loader\n className={SubframeUtils.twClassNames(\n \"hidden text-caption font-caption text-neutral-700 group-disabled/af9405b1:text-neutral-400\",\n {\n \"inline-block\": loading,\n \"text-white\":\n variant === \"inverse\" ||\n variant === \"destructive-primary\" ||\n variant === \"brand-primary\",\n \"text-error-700\":\n variant === \"destructive-tertiary\" ||\n variant === \"destructive-secondary\",\n \"text-brand-700\":\n variant === \"brand-tertiary\" || variant === \"brand-secondary\",\n }\n )}\n />\n </button>\n );\n }\n);\n\nexport const IconButton = IconButtonRoot;\n","\"use client\";\nimport { IconButton as IconButtonComponent } from \"./IconButton\";\n\n/**\n * Add wrapper components and business logic here.\n * If you modify this file, disable Subframe sync for it to prevent overwrites.\n * Learn more: https://docs.subframe.com/concepts/syncing-components#wrapping-components\n */\n\nexport const IconButton = IconButtonComponent;\n","\"use client\";\n/*\n * Documentation:\n * Switch — https://app.subframe.com/49eb78b484b2/library?component=Switch_7a464794-9ea9-4040-b1de-5bfb2ce599d9\n */\n\nimport React from \"react\";\nimport * as SubframeCore from \"@subframe/core\";\nimport * as SubframeUtils from \"../../utils\";\n\nexport interface ThumbProps\n extends React.ComponentProps<typeof SubframeCore.Switch.Thumb> {\n className?: string;\n}\n\nconst Thumb = React.forwardRef<HTMLDivElement, ThumbProps>(function Thumb(\n { className, ...otherProps }: ThumbProps,\n ref\n) {\n return (\n <SubframeCore.Switch.Thumb asChild={true} {...otherProps}>\n <div\n className={SubframeUtils.twClassNames(\n \"flex h-3.5 w-3.5 flex-col items-start gap-2 rounded-full bg-white shadow-sm\",\n className\n )}\n ref={ref}\n />\n </SubframeCore.Switch.Thumb>\n );\n});\n\nexport interface SwitchRootProps\n extends React.ComponentProps<typeof SubframeCore.Switch.Root> {\n checked?: boolean;\n onCheckedChange?: (checked: boolean) => void;\n className?: string;\n}\n\nconst SwitchRoot = React.forwardRef<HTMLDivElement, SwitchRootProps>(\n function SwitchRoot(\n { checked = false, className, ...otherProps }: SwitchRootProps,\n ref\n ) {\n return (\n <SubframeCore.Switch.Root\n checked={checked}\n asChild={true}\n {...otherProps}\n >\n <div\n className={SubframeUtils.twClassNames(\n \"group/7a464794 flex h-5 w-8 cursor-pointer flex-col items-start justify-center gap-2 rounded-full border border-solid border-neutral-200 bg-neutral-200 px-0.5 py-0.5 aria-[checked=true]:border aria-[checked=true]:border-solid aria-[checked=true]:border-brand-600 aria-[checked=true]:bg-brand-600\",\n className\n )}\n ref={ref}\n >\n <Thumb />\n </div>\n </SubframeCore.Switch.Root>\n );\n }\n);\n\nexport const Switch = Object.assign(SwitchRoot, {\n Thumb,\n});\n","\"use client\";\nimport { Switch as SwitchComponent } from \"./Switch\";\n\n/**\n * Add wrapper components and business logic here.\n * If you modify this file, disable Subframe sync for it to prevent overwrites.\n * Learn more: https://docs.subframe.com/concepts/syncing-components#wrapping-components\n */\n\nexport const Switch = SwitchComponent;\n","\"use client\";\n/*\n * Documentation:\n * Toggle Group — https://app.subframe.com/49eb78b484b2/library?component=Toggle+Group_2026f10a-e3cc-4c89-80da-a7259acae3b7\n */\n\nimport React from \"react\";\nimport { FeatherStar } from \"@subframe/core\";\nimport * as SubframeCore from \"@subframe/core\";\nimport * as SubframeUtils from \"../../utils\";\n\nexport interface ItemProps\n extends React.ComponentProps<typeof SubframeCore.ToggleGroup.Item> {\n disabled?: boolean;\n children?: React.ReactNode;\n icon?: React.ReactNode;\n className?: string;\n}\n\nconst Item = React.forwardRef<HTMLDivElement, ItemProps>(function Item(\n {\n disabled = false,\n children,\n icon = <FeatherStar />,\n className,\n ...otherProps\n }: ItemProps,\n ref\n) {\n return (\n <SubframeCore.ToggleGroup.Item\n asChild={true}\n disabled={disabled}\n {...otherProps}\n >\n <div\n className={SubframeUtils.twClassNames(\n \"group/56dea6ed flex h-7 w-full cursor-pointer items-center justify-center gap-2 rounded-md px-2 py-1 active:bg-neutral-100 aria-[checked=true]:bg-default-background aria-[checked=true]:shadow-sm active:aria-[checked=true]:bg-default-background\",\n { \"active:bg-transparent\": disabled },\n className\n )}\n ref={ref}\n >\n {icon ? (\n <SubframeCore.IconWrapper\n className={SubframeUtils.twClassNames(\n \"text-body font-body text-subtext-color group-hover/56dea6ed:text-default-font group-aria-[checked=true]/56dea6ed:text-default-font\",\n {\n \"text-neutral-400 group-hover/56dea6ed:text-neutral-400 group-active/56dea6ed:text-neutral-400\":\n disabled,\n }\n )}\n >\n {icon}\n </SubframeCore.IconWrapper>\n ) : null}\n {children ? (\n <span\n className={SubframeUtils.twClassNames(\n \"whitespace-nowrap text-caption-bold font-caption-bold text-subtext-color group-hover/56dea6ed:text-default-font group-aria-[checked=true]/56dea6ed:text-default-font\",\n {\n \"text-neutral-400 group-hover/56dea6ed:text-neutral-400 group-active/56dea6ed:text-neutral-400\":\n disabled,\n }\n )}\n >\n {children}\n </span>\n ) : null}\n </div>\n </SubframeCore.ToggleGroup.Item>\n );\n});\n\nexport interface ToggleGroupRootProps\n extends React.ComponentProps<typeof SubframeCore.ToggleGroup.Root> {\n children?: React.ReactNode;\n value?: string;\n onValueChange?: (value: string) => void;\n className?: string;\n}\n\nconst ToggleGroupRoot = React.forwardRef<HTMLDivElement, ToggleGroupRootProps>(\n function ToggleGroupRoot(\n { children, className, ...otherProps }: ToggleGroupRootProps,\n ref\n ) {\n return children ? (\n <SubframeCore.ToggleGroup.Root asChild={true} {...otherProps}>\n <div\n className={SubframeUtils.twClassNames(\n \"flex items-center gap-0.5 overflow-hidden rounded-md bg-neutral-100 px-0.5 py-0.5\",\n className\n )}\n ref={ref}\n >\n {children}\n </div>\n </SubframeCore.ToggleGroup.Root>\n ) : null;\n }\n);\n\nexport const ToggleGroup = Object.assign(ToggleGroupRoot, {\n Item,\n});\n","\"use client\";\nimport { ToggleGroup as ToggleGroupComponent } from \"./ToggleGroup\";\n\n/**\n * Add wrapper components and business logic here.\n * If you modify this file, disable Subframe sync for it to prevent overwrites.\n * Learn more: https://docs.subframe.com/concepts/syncing-components#wrapping-components\n */\n\nexport const ToggleGroup = ToggleGroupComponent;\n","\"use client\";\n/*\n * Documentation:\n * Tooltip — https://app.subframe.com/49eb78b484b2/library?component=Tooltip_ccebd1e9-f6ac-4737-8376-0dfacd90c9f3\n */\n\nimport React from \"react\";\nimport * as SubframeUtils from \"../../utils\";\n\nexport interface TooltipRootProps extends React.HTMLAttributes<HTMLDivElement> {\n children?: React.ReactNode;\n className?: string;\n}\n\nconst TooltipRoot = React.forwardRef<HTMLDivElement, TooltipRootProps>(\n function TooltipRoot(\n { children, className, ...otherProps }: TooltipRootProps,\n ref\n ) {\n return (\n <div\n className={SubframeUtils.twClassNames(\n \"flex flex-col items-start gap-2 rounded-md border border-solid border-neutral-900 bg-neutral-800 px-2 py-1 shadow-lg\",\n className\n )}\n ref={ref}\n {...otherProps}\n >\n {children ? (\n <span className=\"text-caption font-caption text-white\">\n {children}\n </span>\n ) : null}\n </div>\n );\n }\n);\n\nexport const Tooltip = TooltipRoot;\n","\"use client\";\nimport { Tooltip as TooltipComponent } from \"./Tooltip\";\n\n/**\n * Add wrapper components and business logic here.\n * If you modify this file, disable Subframe sync for it to prevent overwrites.\n * Learn more: https://docs.subframe.com/concepts/syncing-components#wrapping-components\n */\n\nexport const Tooltip = TooltipComponent;\n","import type { TrackingConsent } from \"@us-auth/types\";\n\nexport const PRESET_STRICTLY_NECESSARY = \"strictly-necessary\";\nexport const PRESET_MARKETING_AND_ANALYTICS = \"marketing-and-analytics\";\n\nexport type ConsentPreset =\n | typeof PRESET_STRICTLY_NECESSARY\n | typeof PRESET_MARKETING_AND_ANALYTICS;\n\nexport const DEFAULT_DRAFT_CONSENT: TrackingConsent = {\n analytics: true,\n marketing: true,\n};\n\nexport function consentToPreset(\n consent: Pick<TrackingConsent, \"analytics\" | \"marketing\">,\n): ConsentPreset | undefined {\n if (!consent.analytics && !consent.marketing) {\n return PRESET_STRICTLY_NECESSARY;\n }\n if (consent.analytics && consent.marketing) {\n return PRESET_MARKETING_AND_ANALYTICS;\n }\n return undefined;\n}\n\nexport function presetToConsent(preset: string): TrackingConsent | undefined {\n if (preset === PRESET_STRICTLY_NECESSARY) {\n return { analytics: false, marketing: false };\n }\n if (preset === PRESET_MARKETING_AND_ANALYTICS) {\n return { analytics: true, marketing: true };\n }\n return undefined;\n}\n","\"use client\";\n\nimport {\n Close,\n Content,\n Overlay,\n Portal,\n Root,\n Title,\n} from \"@radix-ui/react-dialog\";\nimport { FeatherX } from \"@subframe/core\";\nimport { Button } from \"@us-auth/components/components/Button\";\nimport { IconButton } from \"@us-auth/components/components/IconButton\";\n\nexport type ConsentInfoCategory = \"necessary\" | \"analytics\" | \"marketing\";\n\nconst INFO_COPY: Record<\n ConsentInfoCategory,\n { title: string; sections: { heading: string; body: string }[] }\n> = {\n necessary: {\n title: \"Necessary\",\n sections: [\n {\n heading: \"Why do we need this?\",\n body:\n \"These are how you stay signed in across Uninspired products, how checkout with Paddle can complete a payment, and how we remember that you already answered this banner so we don't ask on every page load.\",\n },\n {\n heading: \"What is being stored?\",\n body:\n \"HttpOnly authentication session cookies, shared on uninspired.app so one login works across our apps. Paddle may set its own cookies while you pay. We also set uninspired_consent for 180 days with your analytics and marketing choice (yes or no) — nothing else.\",\n },\n {\n heading: \"Can I turn this off?\",\n body:\n \"No — the site can't sign you in, take payment, or keep this preference without them. They are not used for ads, and they are not PostHog or Meta.\",\n },\n ],\n },\n analytics: {\n title: \"Analytics\",\n sections: [\n {\n heading: \"Why do we need this?\",\n body:\n \"We use PostHog to see which features people actually use, where checkout starts, when something errors, and what to build next. Same events fire whether you allow cookies or not; this toggle only changes how identifying and persistent that data is.\",\n },\n {\n heading: \"What is being tracked?\",\n body:\n \"Page views, clicks (autocapture), and product events such as feature used, checkout started, sign-up, and login. We never send your email. Visible text and element attributes are masked. Session recordings, surveys, and heatmaps are off. Query strings and magic-link paths are stripped before anything leaves the browser.\",\n },\n {\n heading: \"Where is my data sent?\",\n body:\n \"PostHog, hosted in the EU. If you allow this, PostHog may set cookies (about 180 days) and browser storage, and we attach events to your account id after you sign in. If you decline (or haven't chosen yet), capture stays cookieless: no analytics cookies, no local storage, no account linking. Server-side events then use a salted hash of your user id instead of the id itself.\",\n },\n ],\n },\n marketing: {\n title: \"Marketing\",\n sections: [\n {\n heading: \"Why do we need this?\",\n body:\n \"So we can tell whether Meta ads (Facebook / Instagram) actually lead to someone viewing a product, starting checkout, or buying. This is the only marketing tracker we load.\",\n },\n {\n heading: \"What is being tracked?\",\n body:\n \"The Meta Pixel, and only after you allow it. We then load Meta's script and can send PageView, ViewContent, InitiateCheckout, and Purchase. Purchase may include a transaction id so Meta can ignore duplicates. We do not send your email through the pixel. If you later turn this off, we tell Meta to stop sending; leftover Meta cookies may remain until they expire.\",\n },\n {\n heading: \"Where is my data sent?\",\n body:\n \"Meta (Facebook). The pixel script is not loaded if you decline, so no Meta cookies are set from us in that case. There is no separate server-side Conversions API path from this banner.\",\n },\n ],\n },\n};\n\nexport interface ConsentInfoDialogProps {\n category: ConsentInfoCategory | null;\n onClose: () => void;\n}\n\nexport function ConsentInfoDialog({ category, onClose }: ConsentInfoDialogProps) {\n const copy = category ? INFO_COPY[category] : null;\n\n return (\n <Root open={category !== null} onOpenChange={(open) => !open && onClose()}>\n <Portal>\n <Overlay\n className=\"fixed inset-0 z-[10000] bg-[#00000099] data-[state=open]:animate-overlayShow\"\n />\n {copy ? (\n <Content\n className=\"fixed left-1/2 top-1/2 z-[10000] flex max-h-[calc(100dvh-2rem)] w-[calc(100%-2rem)] max-w-none -translate-x-1/2 -translate-y-1/2 flex-col gap-4 overflow-y-auto rounded-md border border-solid border-neutral-border bg-default-background px-4 py-4 shadow-lg data-[state=open]:animate-contentShow focus:outline-none sm:max-w-[480px]\"\n >\n <div className=\"flex w-full items-start justify-between gap-4\">\n <Title className=\"text-heading-1 font-heading-1 text-default-font\">\n {copy.title}\n </Title>\n <IconButton\n icon={<FeatherX />}\n aria-label=\"Close\"\n onClick={onClose}\n />\n </div>\n <div className=\"flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto\">\n {copy.sections.map((section) => (\n <div\n key={section.heading}\n className=\"flex max-w-[448px] flex-col items-start gap-0.5\"\n >\n <span className=\"text-heading-2 font-heading-2 text-default-font\">\n {section.heading}\n </span>\n <span className=\"text-body font-body text-default-font\">\n {section.body}\n </span>\n </div>\n ))}\n </div>\n <div className=\"flex w-full items-center justify-end gap-2\">\n <Close asChild>\n <Button variant=\"neutral-primary\" onClick={onClose}>\n Close\n </Button>\n </Close>\n </div>\n </Content>\n ) : null}\n </Portal>\n </Root>\n );\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { FeatherChevronLeft, FeatherChevronRight, FeatherInfo } from \"@subframe/core\";\nimport * as SubframeCore from \"@subframe/core\";\nimport { Button } from \"@us-auth/components/components/Button\";\nimport { IconButton } from \"@us-auth/components/components/IconButton\";\nimport { Switch } from \"@us-auth/components/components/Switch\";\nimport { ToggleGroup } from \"@us-auth/components/components/ToggleGroup\";\nimport { Tooltip } from \"@us-auth/components/components/Tooltip\";\nimport type { ConsentState, TrackingConsent } from \"@us-auth/types\";\nimport { purgeLegacyTracking } from \"../consent/purgeLegacyTracking\";\nimport { useTrackingConsent } from \"../consent/useTrackingConsent\";\nimport {\n consentToPreset,\n DEFAULT_DRAFT_CONSENT,\n PRESET_MARKETING_AND_ANALYTICS,\n PRESET_STRICTLY_NECESSARY,\n presetToConsent,\n} from \"./consentPresets\";\nimport {\n ConsentInfoDialog,\n type ConsentInfoCategory,\n} from \"./ConsentInfoDialog\";\n\nconst DEFAULT_PRIVACY_POLICY_URL =\n \"https://legal.uninspired.studio/page/us-privacy-policy/\";\n\nexport interface CookieBannerProps {\n privacyPolicyUrl?: string;\n}\n\nfunction draftFromConsent(consent: ConsentState): TrackingConsent {\n return consent ?? DEFAULT_DRAFT_CONSENT;\n}\n\nexport function CookieBanner({\n privacyPolicyUrl = DEFAULT_PRIVACY_POLICY_URL,\n}: CookieBannerProps) {\n const { pending, consent, setConsent } = useTrackingConsent();\n const [mounted, setMounted] = useState(false);\n const [panelOpen, setPanelOpen] = useState(false);\n const [draft, setDraft] = useState<TrackingConsent>(DEFAULT_DRAFT_CONSENT);\n const [infoCategory, setInfoCategory] = useState<ConsentInfoCategory | null>(\n null,\n );\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n useEffect(() => {\n if (!pending) return;\n purgeLegacyTracking();\n }, [pending]);\n\n useEffect(() => {\n if (!pending) return;\n const previousOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.body.style.overflow = previousOverflow;\n };\n }, [pending]);\n\n useEffect(() => {\n if (pending) {\n setPanelOpen(true);\n setDraft(DEFAULT_DRAFT_CONSENT);\n return;\n }\n setPanelOpen(false);\n setDraft(draftFromConsent(consent));\n }, [pending, consent]);\n\n const openPanel = useCallback(() => {\n setDraft(draftFromConsent(consent));\n setPanelOpen(true);\n }, [consent]);\n\n const closePanel = useCallback(() => {\n setPanelOpen(false);\n setDraft(draftFromConsent(consent));\n }, [consent]);\n\n const save = useCallback(() => {\n setConsent(draft);\n setPanelOpen(false);\n }, [draft, setConsent]);\n\n const presetValue = consentToPreset(draft);\n\n if (!mounted) return null;\n\n const effectivePanelOpen = pending || panelOpen;\n const showCollapsedTab = !pending && !panelOpen;\n\n return createPortal(\n <>\n {pending ? (\n <div\n className=\"fixed inset-0 z-[9998] bg-[#00000099]\"\n aria-hidden\n />\n ) : null}\n\n {showCollapsedTab ? (\n <div className=\"fixed bottom-4 left-4 z-[9999]\">\n <IconButton\n icon={<FeatherChevronRight />}\n aria-label=\"Open cookie preferences\"\n onClick={openPanel}\n />\n </div>\n ) : null}\n\n <div\n className={`fixed bottom-4 left-4 z-[9999] flex w-[calc(100vw-2rem)] max-w-[512px] max-h-[calc(100dvh-2rem)] flex-col items-start transition-transform duration-300 ease-out ${\n effectivePanelOpen\n ? \"translate-x-0\"\n : \"-translate-x-[120%] pointer-events-none\"\n }`}\n aria-hidden={!effectivePanelOpen}\n >\n <div className=\"relative w-full\">\n {!pending ? (\n <div className=\"absolute bottom-0 right-[-33px] z-10 flex h-[33px] w-[33px] flex-none flex-col items-start gap-2\">\n <IconButton\n icon={<FeatherChevronLeft />}\n aria-label=\"Close cookie preferences\"\n onClick={closePanel}\n />\n </div>\n ) : null}\n <div className=\"flex max-h-[calc(100dvh-2rem)] w-full flex-col items-start gap-5 overflow-y-auto rounded-lg border border-solid border-neutral-border bg-default-background px-4 py-4 shadow-lg\">\n\n <div className=\"flex w-full flex-col items-start gap-1\">\n <span className=\"text-heading-1 font-heading-1 text-default-font\">\n We use cookies.\n </span>\n <span className=\"w-full text-caption font-caption text-subtext-color\">\n We'd love not to, but a few of them are how this place\n actually works. Sign-in, checkout, and remembering this choice\n need cookies. Analytics and ads are optional — skip them if\n you'd rather. If you decline analytics we still look at\n product usage in a cookieless way, with nothing extra stored on\n your device.\n </span>\n <div className=\"flex flex-wrap items-start gap-1\">\n <span className=\"text-caption font-caption text-subtext-color\">\n For more information, please visit our\n </span>\n <a\n href={privacyPolicyUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-caption font-caption text-brand-700 underline-offset-2 hover:underline\"\n >\n Privacy Policy\n </a>\n </div>\n </div>\n\n <div className=\"flex w-full flex-col items-start rounded-lg border border-solid border-neutral-border\">\n <ConsentRow\n title=\"Necessary\"\n description=\"Sign-in session, Paddle checkout, and this consent cookie.\"\n checked={true}\n disabled\n onInfo={() => setInfoCategory(\"necessary\")}\n tooltip=\"Required for the site to work — this one stays on.\"\n />\n <RowDivider />\n <ConsentRow\n title=\"Analytics\"\n description=\"PostHog cookies and linking events to your account. Cookieless usage stats still run if you decline.\"\n checked={draft.analytics}\n onCheckedChange={(checked) =>\n setDraft((current) => ({ ...current, analytics: checked }))\n }\n onInfo={() => setInfoCategory(\"analytics\")}\n />\n <RowDivider />\n <ConsentRow\n title=\"Marketing\"\n description=\"Meta Pixel for ad measurement. The script is not loaded unless you allow it.\"\n checked={draft.marketing}\n onCheckedChange={(checked) =>\n setDraft((current) => ({ ...current, marketing: checked }))\n }\n onInfo={() => setInfoCategory(\"marketing\")}\n />\n </div>\n\n <div className=\"flex w-full flex-col items-stretch justify-between gap-4 sm:flex-row sm:items-center sm:gap-8\">\n <ToggleGroup\n className=\"w-full sm:w-auto\"\n value={presetValue ?? \"\"}\n onValueChange={(value: string) => {\n const next = presetToConsent(value);\n if (next) setDraft(next);\n }}\n >\n <ToggleGroup.Item icon={null} value={PRESET_STRICTLY_NECESSARY}>\n Strictly Necessary\n </ToggleGroup.Item>\n <ToggleGroup.Item\n icon={null}\n value={PRESET_MARKETING_AND_ANALYTICS}\n >\n Marketing and Analytics\n </ToggleGroup.Item>\n </ToggleGroup>\n <Button\n className=\"w-full shrink-0 sm:w-auto\"\n variant=\"neutral-primary\"\n onClick={save}\n >\n Save\n </Button>\n </div>\n </div>\n </div>\n </div>\n\n <ConsentInfoDialog\n category={infoCategory}\n onClose={() => setInfoCategory(null)}\n />\n </>,\n document.body,\n );\n}\n\nfunction RowDivider() {\n return (\n <div className=\"flex h-px w-full flex-none flex-col items-center gap-2 bg-neutral-border\" />\n );\n}\n\ninterface ConsentRowProps {\n title: string;\n description: string;\n checked: boolean;\n disabled?: boolean;\n onCheckedChange?: (checked: boolean) => void;\n onInfo: () => void;\n tooltip?: string;\n}\n\nfunction ConsentRow({\n title,\n description,\n checked,\n disabled = false,\n onCheckedChange,\n onInfo,\n tooltip,\n}: ConsentRowProps) {\n const switchControl = (\n <Switch\n checked={checked}\n disabled={disabled}\n onCheckedChange={onCheckedChange}\n className={\n disabled\n ? \"cursor-not-allowed aria-[checked=true]:border-neutral-400 aria-[checked=true]:bg-neutral-400\"\n : undefined\n }\n />\n );\n\n return (\n <div className=\"flex w-full items-center justify-between px-3 py-2\">\n <div className=\"flex flex-col items-start\">\n <span className=\"text-body-bold font-body-bold text-default-font\">\n {title}\n </span>\n <span className=\"text-caption font-caption text-subtext-color\">\n {description}\n </span>\n </div>\n <div className=\"flex items-center justify-center gap-1\">\n <IconButton\n icon={<FeatherInfo />}\n aria-label={`More information about ${title}`}\n onClick={onInfo}\n />\n {tooltip ? (\n <SubframeCore.Tooltip.Provider>\n <SubframeCore.Tooltip.Root>\n <SubframeCore.Tooltip.Trigger asChild={true}>\n {switchControl}\n </SubframeCore.Tooltip.Trigger>\n <SubframeCore.Tooltip.Portal>\n <SubframeCore.Tooltip.Content\n side=\"top\"\n align=\"center\"\n sideOffset={4}\n asChild={true}\n >\n <Tooltip className=\"h-auto w-auto max-w-[208px] flex-none\">\n {tooltip}\n </Tooltip>\n </SubframeCore.Tooltip.Content>\n </SubframeCore.Tooltip.Portal>\n </SubframeCore.Tooltip.Root>\n </SubframeCore.Tooltip.Provider>\n ) : (\n switchControl\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cookie-banner.js","names":["SubframeUtils.twClassNames","Button","ButtonComponent","SubframeUtils.twClassNames","IconButton","IconButtonComponent","SubframeUtils.twClassNames","Switch","SwitchComponent","SubframeUtils.twClassNames","ToggleGroup","ToggleGroupComponent","SubframeUtils.twClassNames","Tooltip","TooltipComponent"],"sources":["../../components/ui/utils.ts","../../components/ui/components/Button/Button.tsx","../../components/ui/components/Button/index.tsx","../../components/ui/components/IconButton/IconButton.tsx","../../components/ui/components/IconButton/index.tsx","../../components/ui/components/Switch/Switch.tsx","../../components/ui/components/Switch/index.tsx","../../components/ui/components/ToggleGroup/ToggleGroup.tsx","../../components/ui/components/ToggleGroup/index.tsx","../../components/ui/components/Tooltip/Tooltip.tsx","../../components/ui/components/Tooltip/index.tsx","../src/cookie-banner/consentPresets.ts","../src/cookie-banner/ConsentInfoDialog.tsx","../src/cookie-banner/CookieBanner.tsx"],"sourcesContent":["import * as SubframeCore from \"@subframe/core\";\n\nexport const twClassNames = SubframeCore.createTwClassNames([\n \"text-caption\",\n \"text-caption-bold\",\n \"text-body\",\n \"text-body-bold\",\n \"text-heading-3\",\n \"text-heading-2\",\n \"text-heading-1\",\n \"text-monospace-body\",\n \"text-heading-section\",\n \"text-heading-subsection\",\n]);\n","\"use client\";\n/*\n * Documentation:\n * Button — https://app.subframe.com/49eb78b484b2/library?component=Button_3b777358-b86b-40af-9327-891efc6826fe\n */\n\nimport React from \"react\";\nimport * as SubframeCore from \"@subframe/core\";\nimport * as SubframeUtils from \"../../utils\";\n\nexport interface ButtonRootProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n disabled?: boolean;\n variant?:\n | \"brand-primary\"\n | \"brand-secondary\"\n | \"brand-tertiary\"\n | \"neutral-primary\"\n | \"neutral-secondary\"\n | \"neutral-tertiary\"\n | \"destructive-primary\"\n | \"destructive-secondary\"\n | \"destructive-tertiary\"\n | \"inverse\";\n size?: \"large\" | \"medium\" | \"small\";\n children?: React.ReactNode;\n icon?: React.ReactNode;\n iconRight?: React.ReactNode;\n loading?: boolean;\n onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;\n className?: string;\n}\n\nconst ButtonRoot = React.forwardRef<HTMLButtonElement, ButtonRootProps>(\n function ButtonRoot(\n {\n disabled = false,\n variant = \"brand-primary\",\n size = \"medium\",\n children,\n icon = null,\n iconRight = null,\n loading = false,\n className,\n type = \"button\",\n ...otherProps\n }: ButtonRootProps,\n ref\n ) {\n return (\n <button\n className={SubframeUtils.twClassNames(\n \"group/3b777358 flex h-8 cursor-pointer items-center justify-center gap-2 rounded-md border-none bg-brand-600 px-3 text-left hover:bg-brand-500 active:bg-brand-600 disabled:cursor-default disabled:bg-neutral-200 hover:disabled:cursor-default hover:disabled:bg-neutral-200 active:disabled:cursor-default active:disabled:bg-neutral-200\",\n {\n \"h-6 gap-1 px-2\": size === \"small\",\n \"h-10 px-4\": size === \"large\",\n \"bg-transparent hover:bg-[#ffffff29] active:bg-[#ffffff3d]\":\n variant === \"inverse\",\n \"bg-transparent hover:bg-error-50 active:bg-error-100\":\n variant === \"destructive-tertiary\",\n \"bg-error-50 hover:bg-error-100 active:bg-error-50\":\n variant === \"destructive-secondary\",\n \"bg-error-600 hover:bg-error-500 active:bg-error-600\":\n variant === \"destructive-primary\",\n \"bg-transparent hover:bg-neutral-100 active:bg-neutral-200\":\n variant === \"neutral-tertiary\",\n \"border border-solid border-neutral-border bg-default-background hover:bg-neutral-50 active:bg-default-background\":\n variant === \"neutral-secondary\",\n \"bg-neutral-100 hover:bg-neutral-200 active:bg-neutral-100\":\n variant === \"neutral-primary\",\n \"bg-transparent hover:bg-brand-50 active:bg-brand-100\":\n variant === \"brand-tertiary\",\n \"bg-brand-50 hover:bg-brand-100 active:bg-brand-50\":\n variant === \"brand-secondary\",\n },\n className\n )}\n ref={ref}\n type={type}\n disabled={disabled}\n {...otherProps}\n >\n {icon ? (\n <SubframeCore.IconWrapper\n className={SubframeUtils.twClassNames(\n \"text-body font-body text-white group-disabled/3b777358:text-neutral-400\",\n {\n hidden: loading,\n \"text-heading-3 font-heading-3\": size === \"large\",\n \"text-error-700\":\n variant === \"destructive-tertiary\" ||\n variant === \"destructive-secondary\",\n \"text-neutral-700\":\n variant === \"neutral-tertiary\" ||\n variant === \"neutral-secondary\" ||\n variant === \"neutral-primary\",\n \"text-brand-700\":\n variant === \"brand-tertiary\" || variant === \"brand-secondary\",\n }\n )}\n >\n {icon}\n </SubframeCore.IconWrapper>\n ) : null}\n <div\n className={SubframeUtils.twClassNames(\n \"hidden h-4 w-4 flex-none items-center justify-center gap-2\",\n { flex: loading, \"h-3 w-3\": size === \"small\" }\n )}\n >\n <SubframeCore.Loader\n className={SubframeUtils.twClassNames(\n \"text-caption font-caption text-white group-disabled/3b777358:text-neutral-400\",\n {\n \"leading-[20px]\": loading,\n \"text-error-700\":\n variant === \"destructive-tertiary\" ||\n variant === \"destructive-secondary\",\n \"text-neutral-700\":\n variant === \"neutral-tertiary\" ||\n variant === \"neutral-secondary\" ||\n variant === \"neutral-primary\",\n \"text-brand-700\":\n variant === \"brand-tertiary\" || variant === \"brand-secondary\",\n }\n )}\n />\n </div>\n {children ? (\n <span\n className={SubframeUtils.twClassNames(\n \"whitespace-nowrap text-heading-3 font-heading-3 text-white group-disabled/3b777358:text-neutral-400\",\n {\n hidden: loading,\n \"text-caption-bold font-caption-bold\": size === \"small\",\n \"text-body-bold font-body-bold\": size === \"large\",\n \"text-error-700\":\n variant === \"destructive-tertiary\" ||\n variant === \"destructive-secondary\",\n \"text-neutral-700\":\n variant === \"neutral-tertiary\" ||\n variant === \"neutral-secondary\" ||\n variant === \"neutral-primary\",\n \"text-brand-700\":\n variant === \"brand-tertiary\" || variant === \"brand-secondary\",\n }\n )}\n >\n {children}\n </span>\n ) : null}\n {iconRight ? (\n <SubframeCore.IconWrapper\n className={SubframeUtils.twClassNames(\n \"text-body font-body text-white group-disabled/3b777358:text-neutral-400\",\n {\n \"text-heading-3 font-heading-3\": size === \"large\",\n \"text-error-700\":\n variant === \"destructive-tertiary\" ||\n variant === \"destructive-secondary\",\n \"text-neutral-700\":\n variant === \"neutral-tertiary\" ||\n variant === \"neutral-secondary\" ||\n variant === \"neutral-primary\",\n \"text-brand-700\":\n variant === \"brand-tertiary\" || variant === \"brand-secondary\",\n }\n )}\n >\n {iconRight}\n </SubframeCore.IconWrapper>\n ) : null}\n </button>\n );\n }\n);\n\nexport const Button = ButtonRoot;\n","\"use client\";\nimport { Button as ButtonComponent } from \"./Button\";\n\n/**\n * Add wrapper components and business logic here.\n * If you modify this file, disable Subframe sync for it to prevent overwrites.\n * Learn more: https://docs.subframe.com/concepts/syncing-components#wrapping-components\n */\n\nexport const Button = ButtonComponent;\n","\"use client\";\n/*\n * Documentation:\n * Icon Button — https://app.subframe.com/49eb78b484b2/library?component=Icon+Button_af9405b1-8c54-4e01-9786-5aad308224f6\n */\n\nimport React from \"react\";\nimport { FeatherPlus } from \"@subframe/core\";\nimport * as SubframeCore from \"@subframe/core\";\nimport * as SubframeUtils from \"../../utils\";\n\nexport interface IconButtonRootProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n disabled?: boolean;\n variant?:\n | \"brand-primary\"\n | \"brand-secondary\"\n | \"brand-tertiary\"\n | \"neutral-primary\"\n | \"neutral-secondary\"\n | \"neutral-tertiary\"\n | \"destructive-primary\"\n | \"destructive-secondary\"\n | \"destructive-tertiary\"\n | \"inverse\";\n size?: \"large\" | \"medium\" | \"small\";\n icon?: React.ReactNode;\n loading?: boolean;\n onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;\n className?: string;\n}\n\nconst IconButtonRoot = React.forwardRef<HTMLButtonElement, IconButtonRootProps>(\n function IconButtonRoot(\n {\n disabled = false,\n variant = \"neutral-tertiary\",\n size = \"medium\",\n icon = <FeatherPlus />,\n loading = false,\n className,\n type = \"button\",\n ...otherProps\n }: IconButtonRootProps,\n ref\n ) {\n return (\n <button\n className={SubframeUtils.twClassNames(\n \"group/af9405b1 flex h-8 w-8 cursor-pointer items-center justify-center gap-2 rounded-md border-none bg-transparent text-left hover:bg-neutral-100 active:bg-neutral-50 disabled:cursor-default disabled:bg-neutral-100 hover:disabled:cursor-default active:disabled:cursor-default active:disabled:bg-neutral-100\",\n {\n \"h-6 w-6\": size === \"small\",\n \"h-10 w-10\": size === \"large\",\n \"hover:bg-[#ffffff29] active:bg-[#ffffff3d]\": variant === \"inverse\",\n \"hover:bg-error-50 active:bg-error-100\":\n variant === \"destructive-tertiary\",\n \"bg-error-50 hover:bg-error-100 active:bg-error-50\":\n variant === \"destructive-secondary\",\n \"bg-error-600 hover:bg-error-500 active:bg-error-600\":\n variant === \"destructive-primary\",\n \"border border-solid border-neutral-border bg-white active:bg-white\":\n variant === \"neutral-secondary\",\n \"bg-neutral-100 hover:bg-neutral-200 active:bg-neutral-100\":\n variant === \"neutral-primary\",\n \"hover:bg-brand-50 active:bg-brand-100\":\n variant === \"brand-tertiary\",\n \"bg-brand-50 hover:bg-brand-100 active:bg-brand-50\":\n variant === \"brand-secondary\",\n \"bg-brand-600 hover:bg-brand-500 active:bg-brand-600\":\n variant === \"brand-primary\",\n },\n className\n )}\n ref={ref}\n type={type}\n disabled={disabled}\n {...otherProps}\n >\n {icon ? (\n <SubframeCore.IconWrapper\n className={SubframeUtils.twClassNames(\n \"text-heading-3 font-heading-3 text-neutral-700 group-disabled/af9405b1:text-neutral-400\",\n {\n hidden: loading,\n \"text-body font-body\": size === \"small\",\n \"text-white\":\n variant === \"inverse\" ||\n variant === \"destructive-primary\" ||\n variant === \"brand-primary\",\n \"text-error-700\":\n variant === \"destructive-tertiary\" ||\n variant === \"destructive-secondary\",\n \"text-brand-700\":\n variant === \"brand-tertiary\" || variant === \"brand-secondary\",\n }\n )}\n >\n {icon}\n </SubframeCore.IconWrapper>\n ) : null}\n <SubframeCore.Loader\n className={SubframeUtils.twClassNames(\n \"hidden text-caption font-caption text-neutral-700 group-disabled/af9405b1:text-neutral-400\",\n {\n \"inline-block\": loading,\n \"text-white\":\n variant === \"inverse\" ||\n variant === \"destructive-primary\" ||\n variant === \"brand-primary\",\n \"text-error-700\":\n variant === \"destructive-tertiary\" ||\n variant === \"destructive-secondary\",\n \"text-brand-700\":\n variant === \"brand-tertiary\" || variant === \"brand-secondary\",\n }\n )}\n />\n </button>\n );\n }\n);\n\nexport const IconButton = IconButtonRoot;\n","\"use client\";\nimport { IconButton as IconButtonComponent } from \"./IconButton\";\n\n/**\n * Add wrapper components and business logic here.\n * If you modify this file, disable Subframe sync for it to prevent overwrites.\n * Learn more: https://docs.subframe.com/concepts/syncing-components#wrapping-components\n */\n\nexport const IconButton = IconButtonComponent;\n","\"use client\";\n/*\n * Documentation:\n * Switch — https://app.subframe.com/49eb78b484b2/library?component=Switch_7a464794-9ea9-4040-b1de-5bfb2ce599d9\n */\n\nimport React from \"react\";\nimport * as SubframeCore from \"@subframe/core\";\nimport * as SubframeUtils from \"../../utils\";\n\nexport interface ThumbProps\n extends React.ComponentProps<typeof SubframeCore.Switch.Thumb> {\n className?: string;\n}\n\nconst Thumb = React.forwardRef<HTMLDivElement, ThumbProps>(function Thumb(\n { className, ...otherProps }: ThumbProps,\n ref\n) {\n return (\n <SubframeCore.Switch.Thumb asChild={true} {...otherProps}>\n <div\n className={SubframeUtils.twClassNames(\n \"flex h-3.5 w-3.5 flex-col items-start gap-2 rounded-full bg-white shadow-sm\",\n className\n )}\n ref={ref}\n />\n </SubframeCore.Switch.Thumb>\n );\n});\n\nexport interface SwitchRootProps\n extends React.ComponentProps<typeof SubframeCore.Switch.Root> {\n checked?: boolean;\n onCheckedChange?: (checked: boolean) => void;\n className?: string;\n}\n\nconst SwitchRoot = React.forwardRef<HTMLDivElement, SwitchRootProps>(\n function SwitchRoot(\n { checked = false, className, ...otherProps }: SwitchRootProps,\n ref\n ) {\n return (\n <SubframeCore.Switch.Root\n checked={checked}\n asChild={true}\n {...otherProps}\n >\n <div\n className={SubframeUtils.twClassNames(\n \"group/7a464794 flex h-5 w-8 cursor-pointer flex-col items-start justify-center gap-2 rounded-full border border-solid border-neutral-200 bg-neutral-200 px-0.5 py-0.5 aria-[checked=true]:border aria-[checked=true]:border-solid aria-[checked=true]:border-brand-600 aria-[checked=true]:bg-brand-600\",\n className\n )}\n ref={ref}\n >\n <Thumb />\n </div>\n </SubframeCore.Switch.Root>\n );\n }\n);\n\nexport const Switch = Object.assign(SwitchRoot, {\n Thumb,\n});\n","\"use client\";\nimport { Switch as SwitchComponent } from \"./Switch\";\n\n/**\n * Add wrapper components and business logic here.\n * If you modify this file, disable Subframe sync for it to prevent overwrites.\n * Learn more: https://docs.subframe.com/concepts/syncing-components#wrapping-components\n */\n\nexport const Switch = SwitchComponent;\n","\"use client\";\n/*\n * Documentation:\n * Toggle Group — https://app.subframe.com/49eb78b484b2/library?component=Toggle+Group_2026f10a-e3cc-4c89-80da-a7259acae3b7\n */\n\nimport React from \"react\";\nimport { FeatherStar } from \"@subframe/core\";\nimport * as SubframeCore from \"@subframe/core\";\nimport * as SubframeUtils from \"../../utils\";\n\nexport interface ItemProps\n extends React.ComponentProps<typeof SubframeCore.ToggleGroup.Item> {\n disabled?: boolean;\n children?: React.ReactNode;\n icon?: React.ReactNode;\n className?: string;\n}\n\nconst Item = React.forwardRef<HTMLDivElement, ItemProps>(function Item(\n {\n disabled = false,\n children,\n icon = <FeatherStar />,\n className,\n ...otherProps\n }: ItemProps,\n ref\n) {\n return (\n <SubframeCore.ToggleGroup.Item\n asChild={true}\n disabled={disabled}\n {...otherProps}\n >\n <div\n className={SubframeUtils.twClassNames(\n \"group/56dea6ed flex h-7 w-full cursor-pointer items-center justify-center gap-2 rounded-md px-2 py-1 active:bg-neutral-100 aria-[checked=true]:bg-default-background aria-[checked=true]:shadow-sm active:aria-[checked=true]:bg-default-background\",\n { \"active:bg-transparent\": disabled },\n className\n )}\n ref={ref}\n >\n {icon ? (\n <SubframeCore.IconWrapper\n className={SubframeUtils.twClassNames(\n \"text-body font-body text-subtext-color group-hover/56dea6ed:text-default-font group-aria-[checked=true]/56dea6ed:text-default-font\",\n {\n \"text-neutral-400 group-hover/56dea6ed:text-neutral-400 group-active/56dea6ed:text-neutral-400\":\n disabled,\n }\n )}\n >\n {icon}\n </SubframeCore.IconWrapper>\n ) : null}\n {children ? (\n <span\n className={SubframeUtils.twClassNames(\n \"whitespace-nowrap text-caption-bold font-caption-bold text-subtext-color group-hover/56dea6ed:text-default-font group-aria-[checked=true]/56dea6ed:text-default-font\",\n {\n \"text-neutral-400 group-hover/56dea6ed:text-neutral-400 group-active/56dea6ed:text-neutral-400\":\n disabled,\n }\n )}\n >\n {children}\n </span>\n ) : null}\n </div>\n </SubframeCore.ToggleGroup.Item>\n );\n});\n\nexport interface ToggleGroupRootProps\n extends React.ComponentProps<typeof SubframeCore.ToggleGroup.Root> {\n children?: React.ReactNode;\n value?: string;\n onValueChange?: (value: string) => void;\n className?: string;\n}\n\nconst ToggleGroupRoot = React.forwardRef<HTMLDivElement, ToggleGroupRootProps>(\n function ToggleGroupRoot(\n { children, className, ...otherProps }: ToggleGroupRootProps,\n ref\n ) {\n return children ? (\n <SubframeCore.ToggleGroup.Root asChild={true} {...otherProps}>\n <div\n className={SubframeUtils.twClassNames(\n \"flex items-center gap-0.5 overflow-hidden rounded-md bg-neutral-100 px-0.5 py-0.5\",\n className\n )}\n ref={ref}\n >\n {children}\n </div>\n </SubframeCore.ToggleGroup.Root>\n ) : null;\n }\n);\n\nexport const ToggleGroup = Object.assign(ToggleGroupRoot, {\n Item,\n});\n","\"use client\";\nimport { ToggleGroup as ToggleGroupComponent } from \"./ToggleGroup\";\n\n/**\n * Add wrapper components and business logic here.\n * If you modify this file, disable Subframe sync for it to prevent overwrites.\n * Learn more: https://docs.subframe.com/concepts/syncing-components#wrapping-components\n */\n\nexport const ToggleGroup = ToggleGroupComponent;\n","\"use client\";\n/*\n * Documentation:\n * Tooltip — https://app.subframe.com/49eb78b484b2/library?component=Tooltip_ccebd1e9-f6ac-4737-8376-0dfacd90c9f3\n */\n\nimport React from \"react\";\nimport * as SubframeUtils from \"../../utils\";\n\nexport interface TooltipRootProps extends React.HTMLAttributes<HTMLDivElement> {\n children?: React.ReactNode;\n className?: string;\n}\n\nconst TooltipRoot = React.forwardRef<HTMLDivElement, TooltipRootProps>(\n function TooltipRoot(\n { children, className, ...otherProps }: TooltipRootProps,\n ref\n ) {\n return (\n <div\n className={SubframeUtils.twClassNames(\n \"flex flex-col items-start gap-2 rounded-md border border-solid border-neutral-900 bg-neutral-800 px-2 py-1 shadow-lg\",\n className\n )}\n ref={ref}\n {...otherProps}\n >\n {children ? (\n <span className=\"text-caption font-caption text-white\">\n {children}\n </span>\n ) : null}\n </div>\n );\n }\n);\n\nexport const Tooltip = TooltipRoot;\n","\"use client\";\nimport { Tooltip as TooltipComponent } from \"./Tooltip\";\n\n/**\n * Add wrapper components and business logic here.\n * If you modify this file, disable Subframe sync for it to prevent overwrites.\n * Learn more: https://docs.subframe.com/concepts/syncing-components#wrapping-components\n */\n\nexport const Tooltip = TooltipComponent;\n","import type { TrackingConsent } from \"@us-auth/types\";\n\nexport const PRESET_STRICTLY_NECESSARY = \"strictly-necessary\";\nexport const PRESET_MARKETING_AND_ANALYTICS = \"marketing-and-analytics\";\n\nexport type ConsentPreset =\n | typeof PRESET_STRICTLY_NECESSARY\n | typeof PRESET_MARKETING_AND_ANALYTICS;\n\nexport const DEFAULT_DRAFT_CONSENT: TrackingConsent = {\n analytics: true,\n marketing: true,\n};\n\nexport function consentToPreset(\n consent: Pick<TrackingConsent, \"analytics\" | \"marketing\">,\n): ConsentPreset | undefined {\n if (!consent.analytics && !consent.marketing) {\n return PRESET_STRICTLY_NECESSARY;\n }\n if (consent.analytics && consent.marketing) {\n return PRESET_MARKETING_AND_ANALYTICS;\n }\n return undefined;\n}\n\nexport function presetToConsent(preset: string): TrackingConsent | undefined {\n if (preset === PRESET_STRICTLY_NECESSARY) {\n return { analytics: false, marketing: false };\n }\n if (preset === PRESET_MARKETING_AND_ANALYTICS) {\n return { analytics: true, marketing: true };\n }\n return undefined;\n}\n","\"use client\";\n\nimport {\n Close,\n Content,\n Overlay,\n Portal,\n Root,\n Title,\n} from \"@radix-ui/react-dialog\";\nimport { FeatherX } from \"@subframe/core\";\nimport { Button } from \"@us-auth/components/components/Button\";\nimport { IconButton } from \"@us-auth/components/components/IconButton\";\n\nexport type ConsentInfoCategory = \"necessary\" | \"analytics\" | \"marketing\";\n\nconst INFO_COPY: Record<\n ConsentInfoCategory,\n { title: string; sections: { heading: string; body: string }[] }\n> = {\n necessary: {\n title: \"Necessary\",\n sections: [\n {\n heading: \"Why do we need this?\",\n body:\n \"These are how you stay signed in across Uninspired products, how checkout with Paddle can complete a payment, and how we remember that you already answered this banner so we don't ask on every page load.\",\n },\n {\n heading: \"What is being stored?\",\n body:\n \"HttpOnly authentication session cookies, shared on uninspired.app so one login works across our apps. Paddle may set its own cookies while you pay. We also set uninspired_consent for 180 days with your analytics and marketing choice (yes or no) — nothing else.\",\n },\n {\n heading: \"Can I turn this off?\",\n body:\n \"No — the site can't sign you in, take payment, or keep this preference without them. They are not used for ads, and they are not PostHog or Meta.\",\n },\n ],\n },\n analytics: {\n title: \"Analytics\",\n sections: [\n {\n heading: \"Why do we need this?\",\n body:\n \"We use PostHog to see which features people actually use, where checkout starts, when something errors, and what to build next. Same events fire whether you allow cookies or not; this toggle only changes how identifying and persistent that data is.\",\n },\n {\n heading: \"What is being tracked?\",\n body:\n \"Page views, clicks (autocapture), and product events such as feature used, checkout started, sign-up, and login. We never send your email. Visible text and element attributes are masked. Session recordings, surveys, and heatmaps are off. Query strings and magic-link paths are stripped before anything leaves the browser.\",\n },\n {\n heading: \"Where is my data sent?\",\n body:\n \"PostHog, hosted in the EU. If you allow this, PostHog may set cookies (about 180 days) and browser storage, and we attach events to your account id after you sign in. If you decline (or haven't chosen yet), capture stays cookieless: no analytics cookies, no local storage, no account linking. Server-side events then use a salted hash of your user id instead of the id itself.\",\n },\n ],\n },\n marketing: {\n title: \"Marketing\",\n sections: [\n {\n heading: \"Why do we need this?\",\n body:\n \"So we can tell whether Meta ads (Facebook / Instagram) actually lead to someone viewing a product, starting checkout, or buying. This is the only marketing tracker we load.\",\n },\n {\n heading: \"What is being tracked?\",\n body:\n \"The Meta Pixel, and only after you allow it. We then load Meta's script and can send PageView, ViewContent, InitiateCheckout, and Purchase. Purchase may include a transaction id so Meta can ignore duplicates. We do not send your email through the pixel. If you later turn this off, we tell Meta to stop sending; leftover Meta cookies may remain until they expire.\",\n },\n {\n heading: \"Where is my data sent?\",\n body:\n \"Meta (Facebook). The pixel script is not loaded if you decline, so no Meta cookies are set from us in that case. There is no separate server-side Conversions API path from this banner.\",\n },\n ],\n },\n};\n\nexport interface ConsentInfoDialogProps {\n category: ConsentInfoCategory | null;\n onClose: () => void;\n}\n\nexport function ConsentInfoDialog({ category, onClose }: ConsentInfoDialogProps) {\n const copy = category ? INFO_COPY[category] : null;\n\n return (\n <Root open={category !== null} onOpenChange={(open) => !open && onClose()}>\n <Portal>\n <Overlay\n className=\"fixed inset-0 z-[10000] bg-[#00000099] data-[state=open]:animate-overlayShow\"\n />\n {copy ? (\n <Content\n className=\"fixed left-1/2 top-1/2 z-[10000] flex max-h-[calc(100dvh-2rem)] w-[calc(100%-2rem)] max-w-none -translate-x-1/2 -translate-y-1/2 flex-col gap-4 overflow-y-auto rounded-md border border-solid border-neutral-border bg-default-background px-4 py-4 shadow-lg data-[state=open]:animate-contentShow focus:outline-none sm:max-w-[480px]\"\n >\n <div className=\"flex w-full items-start justify-between gap-4\">\n <Title className=\"text-heading-1 font-heading-1 text-default-font\">\n {copy.title}\n </Title>\n <IconButton\n icon={<FeatherX />}\n aria-label=\"Close\"\n onClick={onClose}\n />\n </div>\n <div className=\"flex min-h-0 flex-1 flex-col gap-4 overflow-y-auto\">\n {copy.sections.map((section) => (\n <div\n key={section.heading}\n className=\"flex max-w-[448px] flex-col items-start gap-0.5\"\n >\n <span className=\"text-heading-2 font-heading-2 text-default-font\">\n {section.heading}\n </span>\n <span className=\"text-body font-body text-default-font\">\n {section.body}\n </span>\n </div>\n ))}\n </div>\n <div className=\"flex w-full items-center justify-end gap-2\">\n <Close asChild>\n <Button variant=\"neutral-primary\" onClick={onClose}>\n Close\n </Button>\n </Close>\n </div>\n </Content>\n ) : null}\n </Portal>\n </Root>\n );\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { FeatherChevronLeft, FeatherChevronRight, FeatherInfo } from \"@subframe/core\";\nimport * as SubframeCore from \"@subframe/core\";\nimport { Button } from \"@us-auth/components/components/Button\";\nimport { IconButton } from \"@us-auth/components/components/IconButton\";\nimport { Switch } from \"@us-auth/components/components/Switch\";\nimport { ToggleGroup } from \"@us-auth/components/components/ToggleGroup\";\nimport { Tooltip } from \"@us-auth/components/components/Tooltip\";\nimport type { ConsentState, TrackingConsent } from \"@us-auth/types\";\nimport { purgeLegacyTracking } from \"../consent/purgeLegacyTracking\";\nimport { useTrackingConsent } from \"../consent/useTrackingConsent\";\nimport {\n consentToPreset,\n DEFAULT_DRAFT_CONSENT,\n PRESET_MARKETING_AND_ANALYTICS,\n PRESET_STRICTLY_NECESSARY,\n presetToConsent,\n} from \"./consentPresets\";\nimport {\n ConsentInfoDialog,\n type ConsentInfoCategory,\n} from \"./ConsentInfoDialog\";\n\nconst DEFAULT_PRIVACY_POLICY_URL =\n \"https://legal.uninspired.studio/page/us-privacy-policy/\";\n\nexport interface CookieBannerProps {\n privacyPolicyUrl?: string;\n}\n\nfunction draftFromConsent(consent: ConsentState): TrackingConsent {\n return consent ?? DEFAULT_DRAFT_CONSENT;\n}\n\nexport function CookieBanner({\n privacyPolicyUrl = DEFAULT_PRIVACY_POLICY_URL,\n}: CookieBannerProps) {\n const { pending, consent, setConsent } = useTrackingConsent();\n const [mounted, setMounted] = useState(false);\n const [panelOpen, setPanelOpen] = useState(false);\n const [draft, setDraft] = useState<TrackingConsent>(DEFAULT_DRAFT_CONSENT);\n const [infoCategory, setInfoCategory] = useState<ConsentInfoCategory | null>(\n null,\n );\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n useEffect(() => {\n if (!pending) return;\n purgeLegacyTracking();\n }, [pending]);\n\n useEffect(() => {\n if (!pending) return;\n const previousOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.body.style.overflow = previousOverflow;\n };\n }, [pending]);\n\n useEffect(() => {\n if (pending) {\n setPanelOpen(true);\n setDraft(DEFAULT_DRAFT_CONSENT);\n return;\n }\n setPanelOpen(false);\n setDraft(draftFromConsent(consent));\n }, [pending, consent]);\n\n const openPanel = useCallback(() => {\n setDraft(draftFromConsent(consent));\n setPanelOpen(true);\n }, [consent]);\n\n const closePanel = useCallback(() => {\n setPanelOpen(false);\n setDraft(draftFromConsent(consent));\n }, [consent]);\n\n const save = useCallback(() => {\n setConsent(draft);\n setPanelOpen(false);\n }, [draft, setConsent]);\n\n const presetValue = consentToPreset(draft);\n\n if (!mounted) return null;\n\n const effectivePanelOpen = pending || panelOpen;\n const showCollapsedTab = !pending && !panelOpen;\n\n return createPortal(\n <>\n {pending ? (\n <div\n className=\"fixed inset-0 z-[9998] bg-[#00000099]\"\n aria-hidden\n />\n ) : null}\n\n {showCollapsedTab ? (\n <div className=\"fixed bottom-4 left-4 z-[9999]\">\n <IconButton\n icon={<FeatherChevronRight />}\n aria-label=\"Open cookie preferences\"\n onClick={openPanel}\n />\n </div>\n ) : null}\n\n <div\n className={`fixed bottom-4 left-4 z-[9999] flex w-[calc(100vw-2rem)] max-w-[512px] max-h-[calc(100dvh-2rem)] flex-col items-start transition-transform duration-300 ease-out ${\n effectivePanelOpen\n ? \"translate-x-0\"\n : \"-translate-x-[120%] pointer-events-none\"\n }`}\n aria-hidden={!effectivePanelOpen}\n >\n <div className=\"relative w-full\">\n {!pending ? (\n <div className=\"absolute bottom-0 right-[-33px] z-10 flex h-[33px] w-[33px] flex-none flex-col items-start gap-2\">\n <IconButton\n icon={<FeatherChevronLeft />}\n aria-label=\"Close cookie preferences\"\n onClick={closePanel}\n />\n </div>\n ) : null}\n <div className=\"flex max-h-[calc(100dvh-2rem)] w-full flex-col items-start gap-5 overflow-y-auto rounded-lg border border-solid border-neutral-border bg-default-background px-4 py-4 shadow-lg\">\n\n <div className=\"flex w-full flex-col items-start gap-1\">\n <span className=\"text-heading-1 font-heading-1 text-default-font\">\n We use cookies.\n </span>\n <span className=\"w-full text-caption font-caption text-subtext-color\">\n We'd love not to, but they tend to be really useful. If you\n want to help us make better products, please enable some of them.\n It's cool if you don't though.\n </span>\n <div className=\"flex flex-wrap items-start gap-1\">\n <span className=\"text-caption font-caption text-subtext-color\">\n For more information, please visit our\n </span>\n <a\n href={privacyPolicyUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"text-caption font-caption text-brand-700 underline-offset-2 hover:underline\"\n >\n Privacy Policy\n </a>\n </div>\n </div>\n\n <div className=\"flex w-full flex-col items-start rounded-lg border border-solid border-neutral-border\">\n <ConsentRow\n title=\"Necessary\"\n description=\"Sign-in session, Paddle checkout, and this consent cookie.\"\n checked={true}\n disabled\n onInfo={() => setInfoCategory(\"necessary\")}\n tooltip=\"Required for the site to work — this one stays on.\"\n />\n <RowDivider />\n <ConsentRow\n title=\"Analytics\"\n description=\"PostHog cookies and linking events to your account. Cookieless usage stats still run if you decline.\"\n checked={draft.analytics}\n onCheckedChange={(checked) =>\n setDraft((current) => ({ ...current, analytics: checked }))\n }\n onInfo={() => setInfoCategory(\"analytics\")}\n />\n <RowDivider />\n <ConsentRow\n title=\"Marketing\"\n description=\"Meta Pixel for ad measurement. The script is not loaded unless you allow it.\"\n checked={draft.marketing}\n onCheckedChange={(checked) =>\n setDraft((current) => ({ ...current, marketing: checked }))\n }\n onInfo={() => setInfoCategory(\"marketing\")}\n />\n </div>\n\n <div className=\"flex w-full flex-col items-stretch justify-between gap-4 sm:flex-row sm:items-center sm:gap-8\">\n <ToggleGroup\n className=\"w-full sm:w-auto\"\n value={presetValue ?? \"\"}\n onValueChange={(value: string) => {\n const next = presetToConsent(value);\n if (next) setDraft(next);\n }}\n >\n <ToggleGroup.Item icon={null} value={PRESET_STRICTLY_NECESSARY}>\n Strictly Necessary\n </ToggleGroup.Item>\n <ToggleGroup.Item\n icon={null}\n value={PRESET_MARKETING_AND_ANALYTICS}\n >\n Marketing and Analytics\n </ToggleGroup.Item>\n </ToggleGroup>\n <Button\n className=\"w-full shrink-0 sm:w-auto\"\n variant=\"neutral-primary\"\n onClick={save}\n >\n Save\n </Button>\n </div>\n </div>\n </div>\n </div>\n\n <ConsentInfoDialog\n category={infoCategory}\n onClose={() => setInfoCategory(null)}\n />\n </>,\n document.body,\n );\n}\n\nfunction RowDivider() {\n return (\n <div className=\"flex h-px w-full flex-none flex-col items-center gap-2 bg-neutral-border\" />\n );\n}\n\ninterface ConsentRowProps {\n title: string;\n description: string;\n checked: boolean;\n disabled?: boolean;\n onCheckedChange?: (checked: boolean) => void;\n onInfo: () => void;\n tooltip?: string;\n}\n\nfunction ConsentRow({\n title,\n description,\n checked,\n disabled = false,\n onCheckedChange,\n onInfo,\n tooltip,\n}: ConsentRowProps) {\n const switchControl = (\n <Switch\n checked={checked}\n disabled={disabled}\n onCheckedChange={onCheckedChange}\n className={\n disabled\n ? \"cursor-not-allowed aria-[checked=true]:border-neutral-400 aria-[checked=true]:bg-neutral-400\"\n : undefined\n }\n />\n );\n\n return (\n <div className=\"flex w-full items-center justify-between px-3 py-2\">\n <div className=\"flex flex-col items-start\">\n <span className=\"text-body-bold font-body-bold text-default-font\">\n {title}\n </span>\n <span className=\"text-caption font-caption text-subtext-color\">\n {description}\n </span>\n </div>\n <div className=\"flex items-center justify-center gap-1\">\n <IconButton\n icon={<FeatherInfo />}\n aria-label={`More information about ${title}`}\n onClick={onInfo}\n />\n {tooltip ? (\n <SubframeCore.Tooltip.Provider>\n <SubframeCore.Tooltip.Root>\n <SubframeCore.Tooltip.Trigger asChild={true}>\n {switchControl}\n </SubframeCore.Tooltip.Trigger>\n <SubframeCore.Tooltip.Portal>\n <SubframeCore.Tooltip.Content\n side=\"top\"\n align=\"center\"\n sideOffset={4}\n asChild={true}\n >\n <Tooltip className=\"h-auto w-auto max-w-[208px] flex-none\">\n {tooltip}\n </Tooltip>\n </SubframeCore.Tooltip.Content>\n </SubframeCore.Tooltip.Portal>\n </SubframeCore.Tooltip.Root>\n </SubframeCore.Tooltip.Provider>\n ) : (\n switchControl\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { z } from "zod";
|
|
|
6
6
|
import * as _$react from "react";
|
|
7
7
|
import { PropsWithChildren } from "react";
|
|
8
8
|
import { PostHog } from "posthog-js";
|
|
9
|
+
import { PostHogProvider, useFeatureFlagEnabled, useFeatureFlagVariantKey, usePostHog } from "posthog-js/react/dist/esm/slim/index.js";
|
|
9
10
|
import { QueryClient } from "@tanstack/react-query";
|
|
10
11
|
import * as _$better_auth0 from "better-auth";
|
|
11
12
|
import { Session as Session$1, User } from "better-auth";
|
|
@@ -1771,6 +1772,8 @@ interface PostHogConfigInput {
|
|
|
1771
1772
|
uiHost?: string;
|
|
1772
1773
|
}
|
|
1773
1774
|
declare function getOrInitPostHog(config: PostHogConfigInput): PostHog | null;
|
|
1775
|
+
/** Returns the PostHog singleton initialized by `TrackingProvider`, if any. */
|
|
1776
|
+
declare function getPostHog(): PostHog | null;
|
|
1774
1777
|
/**
|
|
1775
1778
|
* Mirrors the `uninspired_consent` decision into PostHog's own consent state.
|
|
1776
1779
|
*
|
|
@@ -1825,6 +1828,7 @@ declare class TrackingClient {
|
|
|
1825
1828
|
captureException(error: unknown, properties?: Record<string, unknown>): void;
|
|
1826
1829
|
identify(userId: string): void;
|
|
1827
1830
|
reset(): void;
|
|
1831
|
+
getFeatureFlag(key: string): boolean | string | undefined;
|
|
1828
1832
|
registerProduct(product: AnalyticsProduct): void;
|
|
1829
1833
|
captureFeatureUsed(featureName: string, extra?: Record<string, unknown>): void;
|
|
1830
1834
|
captureCheckoutStarted(options: {
|
|
@@ -2019,5 +2023,5 @@ declare const RESEND_COOLDOWN_SECONDS = 30;
|
|
|
2019
2023
|
declare function remainingCooldownSeconds(availableAt: number, now: number): number;
|
|
2020
2024
|
declare function resendButtonLabel(label: string, remainingSeconds: number): string;
|
|
2021
2025
|
//#endregion
|
|
2022
|
-
export { ANALYTICS_EVENTS, type AnalyticsProduct, AuthClient, AuthContext, AuthContextType, type AuthMethod, AuthProvider, AuthProviderProps, type BetterAuthClient, EmailOtpAuthClient, EmailOtpLoginFlowOptions, type InitiateCheckoutOptions, PostHogAnalyticsClient, type PostHogConfigInput, type PurchaseOptions, RESEND_COOLDOWN_SECONDS, type Session, TrackingClient, type TrackingClientOptions, type TrackingConsentApi, TrackingProvider, type TrackingProviderProps, type UserPurchases, type ViewContentOptions, captureCheckoutStarted, captureFeatureUsed, configureConsentDomain, createBetterAuthClient, getConsent, getOrInitPostHog, isAnalyticsProduct, isConsentPending, isMetaPixelLoaded, loadMetaPixel, posthogConsentAction, redactBeforeSend, refreshConsent, registerProduct, remainingCooldownSeconds, resendButtonLabel, resolveConsentCookieDomain, revokeMetaPixelConsent, setConsent, subscribeConsent, syncPostHogConsent, trackMetaPixel, useAuth, useEmailOtpLoginFlow, useTracking, useTrackingConsent };
|
|
2026
|
+
export { ANALYTICS_EVENTS, type AnalyticsProduct, AuthClient, AuthContext, AuthContextType, type AuthMethod, AuthProvider, AuthProviderProps, type BetterAuthClient, EmailOtpAuthClient, EmailOtpLoginFlowOptions, type InitiateCheckoutOptions, PostHogAnalyticsClient, type PostHogConfigInput, PostHogProvider, type PurchaseOptions, RESEND_COOLDOWN_SECONDS, type Session, TrackingClient, type TrackingClientOptions, type TrackingConsentApi, TrackingProvider, type TrackingProviderProps, type UserPurchases, type ViewContentOptions, captureCheckoutStarted, captureFeatureUsed, configureConsentDomain, createBetterAuthClient, getConsent, getOrInitPostHog, getPostHog, isAnalyticsProduct, isConsentPending, isMetaPixelLoaded, loadMetaPixel, posthogConsentAction, redactBeforeSend, refreshConsent, registerProduct, remainingCooldownSeconds, resendButtonLabel, resolveConsentCookieDomain, revokeMetaPixelConsent, setConsent, subscribeConsent, syncPostHogConsent, trackMetaPixel, useAuth, useEmailOtpLoginFlow, useFeatureFlagEnabled, useFeatureFlagVariantKey, usePostHog, useTracking, useTrackingConsent };
|
|
2023
2027
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as e,c as t,d as n,f as r,i,l as a,n as o,o as s,r as c,s as l,t as u,u as d}from"./purgeLegacyTracking-C4nrnU7N.js";import{anonymousClient as f,emailOTPClient as p,magicLinkClient as m}from"better-auth/client/plugins";import{passkeyClient as h}from"@better-auth/passkey/client";import{createAuthClient as g}from"better-auth/client";import{hc as _}from"hono/client";import{createAuthClient as v}from"better-auth/react";import y from"zod";import{createContext as b,useCallback as x,useContext as S,useEffect as C,useMemo as w,useRef as T,useState as E}from"react";import D from"posthog-js";import{jsx as O}from"react/jsx-runtime";import{QueryClient as k,useQuery as A}from"@tanstack/react-query";var j=class{#e;#t;#n;#r;constructor(e,t,n){this.#r=n,this.#e=t,this.#t=g({baseURL:e,plugins:[f(),m(),p(),h()]}),this.#n=_(new URL(`/api/app`,e).toString(),{fetch:(e,t)=>fetch(e,{...t,credentials:`include`})})}getSession=async()=>{let{data:e,error:t}=await this.#t.getSession({},{headers:this.#r?{Cookie:this.#r}:void 0});if(t)throw t;return e};signInAnonymously=async()=>{let{error:e}=await this.#t.signIn.anonymous();if(e)throw e;return this.getSession()};signOut=async e=>{let{error:t}=await this.#t.signOut({fetchOptions:{onSuccess:e}},{headers:this.#r?{Cookie:this.#r}:void 0});if(t)throw t};getPurchases=async()=>{let e=await this.#n.purchases.$get(void 0,{headers:this.#r?{Cookie:this.#r}:void 0});if(!e.ok)throw Error(`Failed to get purchases`,{cause:await e.text()});return await e.json()};#i=(e,t)=>JSON.stringify({type:`redirect`,redirectUrl:e,appName:t});getLoginUrl=e=>{let t=new URL(`/login`,this.#e);return e?.redirectUrl&&t.searchParams.set(`intent`,this.#i(e.redirectUrl,e.appName)),t.toString()};getCheckoutUrl=e=>{let t=new URL(`/auth/checkout`,this.#e);return t.searchParams.set(`priceId`,e.priceId),t.searchParams.set(`productId`,e.productId),e.discountCode&&t.searchParams.set(`discountCode`,e.discountCode),e.successUrl&&t.searchParams.set(`successUrl`,e.successUrl),t.searchParams.set(`quantity`,e.quantity?.toString()??`1`),t.toString()}};function M(e){return v({baseURL:e,plugins:[f(),m(),p(),h()]})}const N=n;function P(e,t){e?.register?.({product:t})}function F(e,t,n){e?.capture(N.FEATURE_USED,{feature_name:t,...n})}function I(e,{plan:t,product:n}){n&&P(e,n),e?.capture(N.CHECKOUT_STARTED,{plan:t,...n?{product:n}:{}})}let L=!1;function R(e){if(typeof window>`u`||L)return;let t=window;if(!t.fbq){let e=((...t)=>{e.callMethod?e.callMethod(...t):e.queue?.push(t)});e.queue=[],e.loaded=!0,e.version=`2.0`,t.fbq=e,t._fbq||=e;let n=document.createElement(`script`);n.async=!0,n.src=`https://connect.facebook.net/en_US/fbevents.js`,document.head.appendChild(n)}t.fbq(`init`,e),t.fbq(`track`,`PageView`),L=!0}function z(){return L}function B(){if(typeof window>`u`)return;let e=window.fbq;e?.(`consent`,`revoke`)}function V(e,t,n){if(typeof window>`u`)return;let r=window.fbq;r&&(n?r(`track`,e,t,{eventID:n}):r(`track`,e,t))}const H=[`$current_url`,`$initial_current_url`,`$referrer`,`$initial_referrer`],ee=[`$pathname`,`$initial_pathname`];function U(e){return e.replace(/^\/s\/[^/]+/,`/s/[redacted]`)}function te(e){if(typeof e!=`string`)return e;try{let t=new URL(e);return t.search=``,t.hash=``,t.pathname=U(t.pathname),t.toString()}catch{return e}}function ne(e){return typeof e==`string`?U(e):e}function W(e){if(!e||!e.properties)return e;let t=e.properties;for(let e of H)e in t&&(t[e]=te(t[e]));for(let e of ee)e in t&&(t[e]=ne(t[e]));return e}function G(e){return e?.analytics?`opt_in`:`opt_out`}const re={defaults:`2026-05-30`,person_profiles:`identified_only`,cookieless_mode:`on_reject`,opt_out_capturing_by_default:!0,consent_persistence_name:`uninspired_ph_consent`,cross_subdomain_cookie:!0,cookie_expiration:180,mask_all_text:!0,mask_all_element_attributes:!0,disable_session_recording:!0,disable_surveys:!0,capture_heatmaps:!1,capture_exceptions:!0,before_send:W};let K=null;function q(e){return typeof window>`u`?null:K||(K=D.init(e.apiKey,{...re,api_host:e.apiHost,...e.uiHost?{ui_host:e.uiHost}:{}}),K)}function J(e,t){e&&(G(t)===`opt_in`?e.opt_in_capturing():e.opt_out_capturing())}var Y=class{ph;product;#e;#t;#n=!1;constructor(e){this.product=e.product,this.#e=e.metaPixelId,c(e.consentCookieDomain),u(),this.ph=e.posthog?q(e.posthog):null,this.ph&&P(this.ph,this.product)}start(){this.#n||(this.#n=!0,this.#t=a(()=>this.#r(i())),this.#r(i()))}stop(){this.#t?.(),this.#t=void 0,this.#n=!1}#r(e){J(this.ph,e),e?.marketing&&this.#e?R(this.#e):z()&&B()}#i(){return i()?.marketing===!0}getConsent(){return i()}setConsent(e){t(e)}capture(e,t){this.ph?.capture(e,t)}captureException(e,t){this.ph?.captureException(e,t)}identify(e){i()?.analytics&&this.ph?.get_distinct_id()!==e&&this.ph?.identify(e)}reset(){this.ph?.reset()}registerProduct(e){P(this.ph,e)}captureFeatureUsed(e,t){F(this.ph,e,t)}captureCheckoutStarted(e){I(this.ph,e)}trackPageView(){this.#i()&&V(`PageView`)}trackViewContent({contentId:e,value:t,currency:n}){this.#i()&&V(`ViewContent`,{content_ids:[e],content_type:`product`,...t===void 0?{}:{value:t},...n?{currency:n}:{}})}trackInitiateCheckout({contentIds:e,value:t,currency:n}={}){this.#i()&&V(`InitiateCheckout`,{...e?.length?{content_ids:e,content_type:`product`}:{},...t===void 0?{}:{value:t},...n?{currency:n}:{}})}trackPurchase({value:e,currency:t,contentIds:n,eventId:r}={}){this.#i()&&V(`Purchase`,{...n?.length?{content_ids:n,content_type:`product`}:{},...e===void 0?{}:{value:e},...t?{currency:t}:{}},r)}};const X=b(null),ie=({children:e,...t})=>{let n=T(null);return n.current||=new Y(t),C(()=>{let e=n.current;return e?.start(),()=>e?.stop()},[]),O(X.Provider,{value:n.current,children:e})};function Z(){return S(X)}const Q=b(null),ae=({children:e,baseUrl:t,frontendUrl:n,product:r,initialSession:i,initialPurchases:a,authClient:s,queryClient:c})=>{let l=w(()=>s??new j(t,n),[t,n,s]),u=w(()=>c??new k,[c]),f=Z(),{consent:p}=o(),m=p?.analytics===!0,{data:h,isFetching:g,status:_,refetch:v}=A({queryKey:[`us-auth-session`],staleTime:0,initialData:i,queryFn:l.getSession},u),y=w(()=>!(!h||h.user.isAnonymous),[h]),b=T(!1),S=x(e=>{f?.registerProduct(e)},[f]),E=x((e,t)=>{f?.captureFeatureUsed(e,t)},[f]),D=x(e=>{f?.captureCheckoutStarted(e)},[f]);C(()=>{r&&f?.registerProduct(r)},[f,r]),C(()=>{!f||!h?.user||h.user.isAnonymous||m&&f.identify(h.user.id)},[f,h,m]),C(()=>{g||_===`success`&&h===null&&(b.current||(b.current=!0,l.signInAnonymously().then(e=>{u.setQueryData([`us-auth-session`],e)}).catch(e=>console.error(e))))},[l,g,u,h,_]);let{data:M,isFetching:N,refetch:P}=A({queryKey:[`us-auth-purchases`],staleTime:1e3*60,initialData:a,queryFn:l.getPurchases},u),F=w(()=>l.getLoginUrl,[l]),I=w(()=>l.getCheckoutUrl,[l]),L=x(e=>l.signOut(()=>{u.setQueryData([`us-auth-session`],null),u.removeQueries({queryKey:[`us-auth-purchases`]}),f?.reset(),e?.()}),[l,u,f]),R=x(e=>M?M.paddle.transactions.some(t=>t.items.some(t=>e.includes(t))&&!d(t.adjustments)):!1,[M]),z=x((e,t)=>{if(!M)return!1;let n=M.paddle.subscriptions.some(n=>n.items.some(n=>e.includes(n.priceId)||t===n.productId)&&n.status===`active`),r=M.stripe.some(t=>t.status===`active`&&t.items.some(t=>e.includes(t)));return n||r},[M]);return O(Q.Provider,{value:{session:h??null,isSessionFetching:g,refetchSession:async()=>{await v()},purchases:M??null,isPurchasesFetching:N,refetchPurchases:async()=>{await P()},signOut:L,getLoginUrl:F,getCheckoutUrl:I,captureFeatureUsed:E,captureCheckoutStarted:D,registerProduct:S,isSubscribed:z,isPurchased:R,isLoggedIn:y},children:e})};function oe(){let e=S(Q);if(!e)throw Error(`useAuth must be used within an AuthProvider`);return e}const se=30;function $(e,t){return Math.max(0,Math.ceil((e-t)/1e3))}function ce(e,t){return t>0?`${e} (${t}s)`:e}const le=y.email(),ue=y.string().min(6).max(6).refine(e=>e.match(/^[0-9]{6}$/));function de({authClient:e,onVerified:t,onSendSuccess:n,onSendError:r,onVerifyError:i,resendCooldownSeconds:a=30}){let[o,s]=E(`email`),[c,l]=E(``),[u,d]=E(``),[f,p]=E(!1),[m,h]=E(!1),[g,_]=E(!1),[v,y]=E(()=>Date.now()+a*1e3),[b,S]=E(()=>Date.now()),C=w(()=>le.safeParse(c).success,[c]),T=w(()=>ue.safeParse(u).success,[u]),D=$(v,b),O=D>0,k=x(()=>{let e=Date.now();S(e),y(e+a*1e3)},[a]),A=x(async()=>{let{error:t}=await e.emailOtp.sendVerificationOtp({email:c,type:`sign-in`});if(t)throw t},[e,c]);return{step:o,email:c,setEmail:l,otp:u,setOtp:d,emailValid:C,otpValid:T,submitting:f,verifying:m,resending:g,remainingSeconds:D,isCoolingDown:O,submitEmail:x(async()=>{if(C){p(!0);try{await A(),n?.(),s(`otp`)}catch(e){r?.(e)}finally{p(!1)}}},[C,A,n,r]),resendOtp:x(async()=>{if(!(g||O)){_(!0);try{await A(),k(),n?.()}catch(e){r?.(e)}finally{_(!1)}}},[g,O,A,k,n,r]),verifyOtp:x(async()=>{if(T){h(!0);try{let{error:n}=await e.signIn.emailOtp({email:c,otp:u});if(n)throw n;await t()}catch(e){i?.(e),h(!1)}}},[T,e,c,u,t,i]),backToEmail:x(()=>{s(`email`),d(``)},[]),setNow:S,availableAt:v}}export{N as ANALYTICS_EVENTS,j as AuthClient,Q as AuthContext,ae as AuthProvider,se as RESEND_COOLDOWN_SECONDS,Y as TrackingClient,ie as TrackingProvider,I as captureCheckoutStarted,F as captureFeatureUsed,c as configureConsentDomain,M as createBetterAuthClient,i as getConsent,q as getOrInitPostHog,r as isAnalyticsProduct,e as isConsentPending,z as isMetaPixelLoaded,R as loadMetaPixel,G as posthogConsentAction,W as redactBeforeSend,s as refreshConsent,P as registerProduct,$ as remainingCooldownSeconds,ce as resendButtonLabel,l as resolveConsentCookieDomain,B as revokeMetaPixelConsent,t as setConsent,a as subscribeConsent,J as syncPostHogConsent,V as trackMetaPixel,oe as useAuth,de as useEmailOtpLoginFlow,Z as useTracking,o as useTrackingConsent};
|
|
1
|
+
import{a as e,c as t,d as n,f as r,i,l as a,n as o,o as s,r as c,s as l,t as u,u as d}from"./purgeLegacyTracking-C4nrnU7N.js";import{anonymousClient as f,emailOTPClient as p,magicLinkClient as m}from"better-auth/client/plugins";import{passkeyClient as h}from"@better-auth/passkey/client";import{createAuthClient as g}from"better-auth/client";import{hc as _}from"hono/client";import{createAuthClient as v}from"better-auth/react";import y from"zod";import{createContext as b,useCallback as x,useContext as S,useEffect as C,useMemo as w,useRef as T,useState as E}from"react";import D from"posthog-js";import{PostHogProvider as O,useFeatureFlagEnabled as k,useFeatureFlagVariantKey as A,usePostHog as j}from"posthog-js/react/dist/esm/slim/index.js";import{jsx as M}from"react/jsx-runtime";import{QueryClient as ee,useQuery as N}from"@tanstack/react-query";var P=class{#e;#t;#n;#r;constructor(e,t,n){this.#r=n,this.#e=t,this.#t=g({baseURL:e,plugins:[f(),m(),p(),h()]}),this.#n=_(new URL(`/api/app`,e).toString(),{fetch:(e,t)=>fetch(e,{...t,credentials:`include`})})}getSession=async()=>{let{data:e,error:t}=await this.#t.getSession({},{headers:this.#r?{Cookie:this.#r}:void 0});if(t)throw t;return e};signInAnonymously=async()=>{let{error:e}=await this.#t.signIn.anonymous();if(e)throw e;return this.getSession()};signOut=async e=>{let{error:t}=await this.#t.signOut({fetchOptions:{onSuccess:e}},{headers:this.#r?{Cookie:this.#r}:void 0});if(t)throw t};getPurchases=async()=>{let e=await this.#n.purchases.$get(void 0,{headers:this.#r?{Cookie:this.#r}:void 0});if(!e.ok)throw Error(`Failed to get purchases`,{cause:await e.text()});return await e.json()};#i=(e,t)=>JSON.stringify({type:`redirect`,redirectUrl:e,appName:t});getLoginUrl=e=>{let t=new URL(`/login`,this.#e);return e?.redirectUrl&&t.searchParams.set(`intent`,this.#i(e.redirectUrl,e.appName)),t.toString()};getCheckoutUrl=e=>{let t=new URL(`/auth/checkout`,this.#e);return t.searchParams.set(`priceId`,e.priceId),t.searchParams.set(`productId`,e.productId),e.discountCode&&t.searchParams.set(`discountCode`,e.discountCode),e.successUrl&&t.searchParams.set(`successUrl`,e.successUrl),t.searchParams.set(`quantity`,e.quantity?.toString()??`1`),t.toString()}};function F(e){return v({baseURL:e,plugins:[f(),m(),p(),h()]})}const I=n;function L(e,t){e?.register?.({product:t})}function R(e,t,n){e?.capture(I.FEATURE_USED,{feature_name:t,...n})}function te(e,{plan:t,product:n}){n&&L(e,n),e?.capture(I.CHECKOUT_STARTED,{plan:t,...n?{product:n}:{}})}let z=!1;function B(e){if(typeof window>`u`||z)return;let t=window;if(!t.fbq){let e=((...t)=>{e.callMethod?e.callMethod(...t):e.queue?.push(t)});e.queue=[],e.loaded=!0,e.version=`2.0`,t.fbq=e,t._fbq||=e;let n=document.createElement(`script`);n.async=!0,n.src=`https://connect.facebook.net/en_US/fbevents.js`,document.head.appendChild(n)}t.fbq(`init`,e),t.fbq(`track`,`PageView`),z=!0}function V(){return z}function H(){if(typeof window>`u`)return;let e=window.fbq;e?.(`consent`,`revoke`)}function U(e,t,n){if(typeof window>`u`)return;let r=window.fbq;r&&(n?r(`track`,e,t,{eventID:n}):r(`track`,e,t))}const ne=[`$current_url`,`$initial_current_url`,`$referrer`,`$initial_referrer`],re=[`$pathname`,`$initial_pathname`];function W(e){return e.replace(/^\/s\/[^/]+/,`/s/[redacted]`)}function ie(e){if(typeof e!=`string`)return e;try{let t=new URL(e);return t.search=``,t.hash=``,t.pathname=W(t.pathname),t.toString()}catch{return e}}function ae(e){return typeof e==`string`?W(e):e}function G(e){if(!e||!e.properties)return e;let t=e.properties;for(let e of ne)e in t&&(t[e]=ie(t[e]));for(let e of re)e in t&&(t[e]=ae(t[e]));return e}function K(e){return e?.analytics?`opt_in`:`opt_out`}const oe={defaults:`2026-05-30`,person_profiles:`identified_only`,cookieless_mode:`on_reject`,opt_out_capturing_by_default:!0,consent_persistence_name:`uninspired_ph_consent`,cross_subdomain_cookie:!0,cookie_expiration:180,mask_all_text:!0,mask_all_element_attributes:!0,disable_session_recording:!0,disable_surveys:!0,capture_heatmaps:!1,capture_exceptions:!0,before_send:G};let q=null;function J(e){return typeof window>`u`?null:q||(q=D.init(e.apiKey,{...oe,api_host:e.apiHost,...e.uiHost?{ui_host:e.uiHost}:{}}),q)}function se(){return q}function Y(e,t){e&&(K(t)===`opt_in`?e.opt_in_capturing():e.opt_out_capturing())}var X=class{ph;product;#e;#t;#n=!1;constructor(e){this.product=e.product,this.#e=e.metaPixelId,c(e.consentCookieDomain),u(),this.ph=e.posthog?J(e.posthog):null,this.ph&&L(this.ph,this.product)}start(){this.#n||(this.#n=!0,this.#t=a(()=>this.#r(i())),this.#r(i()))}stop(){this.#t?.(),this.#t=void 0,this.#n=!1}#r(e){Y(this.ph,e),e?.marketing&&this.#e?B(this.#e):V()&&H()}#i(){return i()?.marketing===!0}getConsent(){return i()}setConsent(e){t(e)}capture(e,t){this.ph?.capture(e,t)}captureException(e,t){this.ph?.captureException(e,t)}identify(e){i()?.analytics&&this.ph?.get_distinct_id()!==e&&this.ph?.identify(e)}reset(){this.ph?.reset()}getFeatureFlag(e){return this.ph?.getFeatureFlag(e)}registerProduct(e){L(this.ph,e)}captureFeatureUsed(e,t){R(this.ph,e,t)}captureCheckoutStarted(e){te(this.ph,e)}trackPageView(){this.#i()&&U(`PageView`)}trackViewContent({contentId:e,value:t,currency:n}){this.#i()&&U(`ViewContent`,{content_ids:[e],content_type:`product`,...t===void 0?{}:{value:t},...n?{currency:n}:{}})}trackInitiateCheckout({contentIds:e,value:t,currency:n}={}){this.#i()&&U(`InitiateCheckout`,{...e?.length?{content_ids:e,content_type:`product`}:{},...t===void 0?{}:{value:t},...n?{currency:n}:{}})}trackPurchase({value:e,currency:t,contentIds:n,eventId:r}={}){this.#i()&&U(`Purchase`,{...n?.length?{content_ids:n,content_type:`product`}:{},...e===void 0?{}:{value:e},...t?{currency:t}:{}},r)}};const Z=b(null),ce=({children:e,...t})=>{let n=T(null);n.current||=new X(t),C(()=>{let e=n.current;return e?.start(),()=>e?.stop()},[]);let r=n.current,i=r.ph;return M(Z.Provider,{value:r,children:i?M(O,{client:i,children:e}):e})};function Q(){return S(Z)}const $=b(null),le=({children:e,baseUrl:t,frontendUrl:n,product:r,initialSession:i,initialPurchases:a,authClient:s,queryClient:c})=>{let l=w(()=>s??new P(t,n),[t,n,s]),u=w(()=>c??new ee,[c]),f=Q(),{consent:p}=o(),m=p?.analytics===!0,{data:h,isFetching:g,status:_,refetch:v}=N({queryKey:[`us-auth-session`],staleTime:0,initialData:i,queryFn:l.getSession},u),y=w(()=>!(!h||h.user.isAnonymous),[h]),b=T(!1),S=x(e=>{f?.registerProduct(e)},[f]),E=x((e,t)=>{f?.captureFeatureUsed(e,t)},[f]),D=x(e=>{f?.captureCheckoutStarted(e)},[f]);C(()=>{r&&f?.registerProduct(r)},[f,r]),C(()=>{!f||!h?.user||h.user.isAnonymous||m&&f.identify(h.user.id)},[f,h,m]),C(()=>{g||_===`success`&&h===null&&(b.current||(b.current=!0,l.signInAnonymously().then(e=>{u.setQueryData([`us-auth-session`],e)}).catch(e=>console.error(e))))},[l,g,u,h,_]);let{data:O,isFetching:k,refetch:A}=N({queryKey:[`us-auth-purchases`],staleTime:1e3*60,initialData:a,queryFn:l.getPurchases},u),j=w(()=>l.getLoginUrl,[l]),F=w(()=>l.getCheckoutUrl,[l]),I=x(e=>l.signOut(()=>{u.setQueryData([`us-auth-session`],null),u.removeQueries({queryKey:[`us-auth-purchases`]}),f?.reset(),e?.()}),[l,u,f]),L=x(e=>O?O.paddle.transactions.some(t=>t.items.some(t=>e.includes(t))&&!d(t.adjustments)):!1,[O]),R=x((e,t)=>{if(!O)return!1;let n=O.paddle.subscriptions.some(n=>n.items.some(n=>e.includes(n.priceId)||t===n.productId)&&n.status===`active`),r=O.stripe.some(t=>t.status===`active`&&t.items.some(t=>e.includes(t)));return n||r},[O]);return M($.Provider,{value:{session:h??null,isSessionFetching:g,refetchSession:async()=>{await v()},purchases:O??null,isPurchasesFetching:k,refetchPurchases:async()=>{await A()},signOut:I,getLoginUrl:j,getCheckoutUrl:F,captureFeatureUsed:E,captureCheckoutStarted:D,registerProduct:S,isSubscribed:R,isPurchased:L,isLoggedIn:y},children:e})};function ue(){let e=S($);if(!e)throw Error(`useAuth must be used within an AuthProvider`);return e}const de=30;function fe(e,t){return Math.max(0,Math.ceil((e-t)/1e3))}function pe(e,t){return t>0?`${e} (${t}s)`:e}const me=y.email(),he=y.string().min(6).max(6).refine(e=>e.match(/^[0-9]{6}$/));function ge({authClient:e,onVerified:t,onSendSuccess:n,onSendError:r,onVerifyError:i,resendCooldownSeconds:a=30}){let[o,s]=E(`email`),[c,l]=E(``),[u,d]=E(``),[f,p]=E(!1),[m,h]=E(!1),[g,_]=E(!1),[v,y]=E(()=>Date.now()+a*1e3),[b,S]=E(()=>Date.now()),C=w(()=>me.safeParse(c).success,[c]),T=w(()=>he.safeParse(u).success,[u]),D=fe(v,b),O=D>0,k=x(()=>{let e=Date.now();S(e),y(e+a*1e3)},[a]),A=x(async()=>{let{error:t}=await e.emailOtp.sendVerificationOtp({email:c,type:`sign-in`});if(t)throw t},[e,c]);return{step:o,email:c,setEmail:l,otp:u,setOtp:d,emailValid:C,otpValid:T,submitting:f,verifying:m,resending:g,remainingSeconds:D,isCoolingDown:O,submitEmail:x(async()=>{if(C){p(!0);try{await A(),n?.(),s(`otp`)}catch(e){r?.(e)}finally{p(!1)}}},[C,A,n,r]),resendOtp:x(async()=>{if(!(g||O)){_(!0);try{await A(),k(),n?.()}catch(e){r?.(e)}finally{_(!1)}}},[g,O,A,k,n,r]),verifyOtp:x(async()=>{if(T){h(!0);try{let{error:n}=await e.signIn.emailOtp({email:c,otp:u});if(n)throw n;await t()}catch(e){i?.(e),h(!1)}}},[T,e,c,u,t,i]),backToEmail:x(()=>{s(`email`),d(``)},[]),setNow:S,availableAt:v}}export{I as ANALYTICS_EVENTS,P as AuthClient,$ as AuthContext,le as AuthProvider,O as PostHogProvider,de as RESEND_COOLDOWN_SECONDS,X as TrackingClient,ce as TrackingProvider,te as captureCheckoutStarted,R as captureFeatureUsed,c as configureConsentDomain,F as createBetterAuthClient,i as getConsent,J as getOrInitPostHog,se as getPostHog,r as isAnalyticsProduct,e as isConsentPending,V as isMetaPixelLoaded,B as loadMetaPixel,K as posthogConsentAction,G as redactBeforeSend,s as refreshConsent,L as registerProduct,fe as remainingCooldownSeconds,pe as resendButtonLabel,l as resolveConsentCookieDomain,H as revokeMetaPixelConsent,t as setConsent,a as subscribeConsent,Y as syncPostHogConsent,U as trackMetaPixel,ue as useAuth,ge as useEmailOtpLoginFlow,k as useFeatureFlagEnabled,A as useFeatureFlagVariantKey,j as usePostHog,Q as useTracking,o as useTrackingConsent};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["#cookie","#frontendUrl","#authClient","#appClient","#getRedirectIntent","createAuthClient","SHARED_ANALYTICS_EVENTS","#metaPixelId","#started","#unsubscribe","#applyConsent","#marketingGranted","z"],"sources":["../src/AuthClient.ts","../src/betterAuthClient.ts","../src/analytics.ts","../src/tracking/metaPixel.ts","../src/tracking/redaction.ts","../src/tracking/consentAction.ts","../src/tracking/posthog.ts","../src/tracking/TrackingClient.ts","../src/tracking/TrackingContext.ts","../src/tracking/TrackingProvider.tsx","../src/tracking/useTracking.ts","../src/react/AuthContext.ts","../src/react/AuthProvider.tsx","../src/react/useAuth.ts","../src/react/resendCooldown.ts","../src/react/useEmailOtpLoginFlow.ts"],"sourcesContent":["import {\n magicLinkClient,\n emailOTPClient,\n anonymousClient,\n} from \"better-auth/client/plugins\";\nimport { passkeyClient } from \"@better-auth/passkey/client\";\nimport { createAuthClient } from \"better-auth/client\";\nimport { hc } from \"hono/client\";\nimport type { AppRouter } from \"@us-auth/api/routers\";\nimport type {\n UserPurchases,\n Session,\n RedirectIntent,\n} from \"@us-auth/types\";\n\nexport class AuthClient {\n #frontendUrl: string;\n #authClient;\n #appClient: ReturnType<typeof hc<AppRouter>>;\n #cookie: string | undefined;\n\n constructor(apiUrl: string, frontendUrl: string, cookie?: string) {\n this.#cookie = cookie;\n this.#frontendUrl = frontendUrl;\n this.#authClient = createAuthClient({\n baseURL: apiUrl,\n plugins: [\n anonymousClient(),\n magicLinkClient(),\n emailOTPClient(),\n passkeyClient(),\n ],\n });\n this.#appClient = hc<AppRouter>(new URL(\"/api/app\", apiUrl).toString(), {\n fetch: (url: RequestInfo | URL, init?: RequestInit) =>\n fetch(url, {\n ...init,\n credentials: \"include\",\n }),\n });\n }\n\n // Authentication\n getSession = async (): Promise<Session | null> => {\n const { data, error } = await this.#authClient.getSession(\n {},\n {\n headers: this.#cookie\n ? {\n Cookie: this.#cookie,\n }\n : undefined,\n },\n );\n if (error) throw error;\n return data;\n };\n\n signInAnonymously = async (): Promise<Session | null> => {\n const { error } = await this.#authClient.signIn.anonymous();\n if (error) throw error;\n return this.getSession();\n };\n\n signOut = async (onSuccess?: () => void): Promise<void> => {\n const { error } = await this.#authClient.signOut(\n {\n fetchOptions: { onSuccess },\n },\n {\n headers: this.#cookie ? { Cookie: this.#cookie } : undefined,\n },\n );\n if (error) throw error;\n return;\n };\n\n // Purchases\n getPurchases = async (): Promise<UserPurchases | null> => {\n const res = await this.#appClient.purchases.$get(undefined, {\n headers: this.#cookie ? { Cookie: this.#cookie } : undefined,\n });\n if (!res.ok) {\n throw new Error(\"Failed to get purchases\", {\n cause: await res.text(),\n });\n }\n const data = await res.json();\n return data as UserPurchases | null;\n };\n\n #getRedirectIntent = (redirectUrl: string, appName?: string) => {\n return JSON.stringify({\n type: \"redirect\",\n redirectUrl,\n appName,\n } satisfies RedirectIntent);\n };\n\n // Utils\n getLoginUrl = (options?: { redirectUrl?: string; appName?: string }) => {\n const url = new URL(\"/login\", this.#frontendUrl);\n if (options?.redirectUrl) {\n url.searchParams.set(\n \"intent\",\n this.#getRedirectIntent(options.redirectUrl, options.appName),\n );\n }\n return url.toString();\n };\n\n getCheckoutUrl = (options: {\n priceId: string;\n productId: string;\n discountCode?: string;\n successUrl?: string;\n quantity?: number;\n }) => {\n const url = new URL(\"/auth/checkout\", this.#frontendUrl);\n url.searchParams.set(\"priceId\", options.priceId);\n url.searchParams.set(\"productId\", options.productId);\n if (options.discountCode) {\n url.searchParams.set(\"discountCode\", options.discountCode);\n }\n if (options.successUrl) {\n url.searchParams.set(\"successUrl\", options.successUrl);\n }\n url.searchParams.set(\"quantity\", options.quantity?.toString() ?? \"1\");\n return url.toString();\n };\n}\n","import {\n magicLinkClient,\n emailOTPClient,\n anonymousClient,\n} from \"better-auth/client/plugins\";\nimport { passkeyClient } from \"@better-auth/passkey/client\";\nimport { createAuthClient } from \"better-auth/react\";\n\nexport function createBetterAuthClient(baseURL: string) {\n return createAuthClient({\n baseURL,\n plugins: [\n anonymousClient(),\n magicLinkClient(),\n emailOTPClient(),\n passkeyClient(),\n ],\n });\n}\n\nexport type BetterAuthClient = ReturnType<typeof createBetterAuthClient>;\n","import {\n ANALYTICS_EVENTS as SHARED_ANALYTICS_EVENTS,\n isAnalyticsProduct,\n type AnalyticsProduct,\n type AuthMethod,\n} from \"@us-auth/types\";\n\n/**\n * Re-exported as a local binding: re-exporting the const directly from the\n * bundled `@us-auth/types` package trips the declaration bundler.\n */\nexport const ANALYTICS_EVENTS = SHARED_ANALYTICS_EVENTS;\n\nexport interface PostHogAnalyticsClient {\n capture: (event: string, properties?: Record<string, unknown>) => void;\n register?: (properties: Record<string, unknown>) => void;\n}\n\nexport function registerProduct(\n ph: PostHogAnalyticsClient | null | undefined,\n product: AnalyticsProduct,\n) {\n ph?.register?.({ product });\n}\n\nexport function captureFeatureUsed(\n ph: PostHogAnalyticsClient | null | undefined,\n featureName: string,\n extra?: Record<string, unknown>,\n) {\n ph?.capture(ANALYTICS_EVENTS.FEATURE_USED, {\n feature_name: featureName,\n ...extra,\n });\n}\n\nexport function captureCheckoutStarted(\n ph: PostHogAnalyticsClient | null | undefined,\n {\n plan,\n product,\n }: {\n plan: string;\n product?: AnalyticsProduct;\n },\n) {\n if (product) {\n registerProduct(ph, product);\n }\n ph?.capture(ANALYTICS_EVENTS.CHECKOUT_STARTED, {\n plan,\n ...(product ? { product } : {}),\n });\n}\n\nexport { isAnalyticsProduct };\nexport type { AnalyticsProduct, AuthMethod };\n","type FbqFunction = ((...args: unknown[]) => void) & {\n callMethod?: (...args: unknown[]) => void;\n queue?: unknown[][];\n loaded?: boolean;\n version?: string;\n};\n\ntype MetaWindow = Window & { fbq?: FbqFunction; _fbq?: FbqFunction };\n\nlet pixelLoaded = false;\n\n/** Injects the Meta Pixel base code and fires an initial PageView. Idempotent. */\nexport function loadMetaPixel(pixelId: string): void {\n if (typeof window === \"undefined\" || pixelLoaded) return;\n\n const w = window as MetaWindow;\n if (!w.fbq) {\n const fbq = ((...args: unknown[]) => {\n if (fbq.callMethod) fbq.callMethod(...args);\n else fbq.queue?.push(args);\n }) as FbqFunction;\n fbq.queue = [];\n fbq.loaded = true;\n fbq.version = \"2.0\";\n w.fbq = fbq;\n if (!w._fbq) w._fbq = fbq;\n\n const script = document.createElement(\"script\");\n script.async = true;\n script.src = \"https://connect.facebook.net/en_US/fbevents.js\";\n document.head.appendChild(script);\n }\n\n w.fbq(\"init\", pixelId);\n w.fbq(\"track\", \"PageView\");\n pixelLoaded = true;\n}\n\nexport function isMetaPixelLoaded(): boolean {\n return pixelLoaded;\n}\n\n/**\n * Tells an already-loaded pixel to stop sending when marketing consent is\n * withdrawn. Does not unload the script or clear cookies.\n */\nexport function revokeMetaPixelConsent(): void {\n if (typeof window === \"undefined\") return;\n const fbq = (window as MetaWindow).fbq;\n fbq?.(\"consent\", \"revoke\");\n}\n\n/** Fires a standard pixel event; `eventId` lets Meta dedupe on reloads. */\nexport function trackMetaPixel(\n event: string,\n params?: Record<string, unknown>,\n eventId?: string,\n): void {\n if (typeof window === \"undefined\") return;\n const fbq = (window as MetaWindow).fbq;\n if (!fbq) return;\n if (eventId) fbq(\"track\", event, params, { eventID: eventId });\n else fbq(\"track\", event, params);\n}\n","type RedactableEvent = { properties?: Record<string, unknown> };\n\nconst URL_PROPERTIES = [\n \"$current_url\",\n \"$initial_current_url\",\n \"$referrer\",\n \"$initial_referrer\",\n];\n\nconst PATH_PROPERTIES = [\"$pathname\", \"$initial_pathname\"];\n\nfunction redactPassphrasePath(pathname: string): string {\n return pathname.replace(/^\\/s\\/[^/]+/, \"/s/[redacted]\");\n}\n\nfunction redactUrl(value: unknown): unknown {\n if (typeof value !== \"string\") return value;\n try {\n const url = new URL(value);\n url.search = \"\";\n url.hash = \"\";\n url.pathname = redactPassphrasePath(url.pathname);\n return url.toString();\n } catch {\n return value;\n }\n}\n\nfunction redactPath(value: unknown): unknown {\n if (typeof value !== \"string\") return value;\n return redactPassphrasePath(value);\n}\n\n/**\n * Strips URL query strings and short-link passphrases from every event before\n * it leaves the browser. Together with `mask_all_text` this keeps autocapture\n * and pageviews PII-free without disabling them.\n *\n * Applies in every consent mode: it is PII hygiene, not a consent mitigation.\n */\nexport function redactBeforeSend<T extends RedactableEvent | null>(event: T): T {\n if (!event || !event.properties) return event;\n\n const properties = event.properties;\n for (const key of URL_PROPERTIES) {\n if (key in properties) {\n properties[key] = redactUrl(properties[key]);\n }\n }\n for (const key of PATH_PROPERTIES) {\n if (key in properties) {\n properties[key] = redactPath(properties[key]);\n }\n }\n\n return event;\n}","import type { ConsentState } from \"@us-auth/types\";\n\n/**\n * Pure mapping from consent state to the PostHog consent action.\n * Kept separate from the PostHog import so it is trivially testable.\n */\nexport function posthogConsentAction(\n consent: ConsentState,\n): \"opt_in\" | \"opt_out\" {\n return consent?.analytics ? \"opt_in\" : \"opt_out\";\n}","import posthog, { type PostHog } from \"posthog-js\";\nimport type { AnalyticsProduct, ConsentState } from \"@us-auth/types\";\nimport { redactBeforeSend } from \"./redaction\";\nimport { registerProduct as registerProductEvent } from \"../analytics\";\nimport { posthogConsentAction } from \"./consentAction\";\n\nexport { posthogConsentAction };\n\nexport interface PostHogConfigInput {\n apiKey: string;\n apiHost: string;\n uiHost?: string;\n}\n\n/**\n * PostHog runs in `on_reject` mode so the SDK's consent API can move us\n * between cookieless and full persistence at runtime. Every PII-hygiene\n * option is permanent in both modes; only persistence and `identify` change.\n */\nconst BASE_OPTIONS = {\n defaults: \"2026-05-30\" as const,\n person_profiles: \"identified_only\" as const,\n cookieless_mode: \"on_reject\" as const,\n // Belt-and-braces: before the consent sync runs, pending behaves as\n // \"not granted\" → cookieless capture rather than a full freeze.\n opt_out_capturing_by_default: true,\n // Keep PostHog's own consent record separate from `uninspired_consent`\n // (different value encoding).\n consent_persistence_name: \"uninspired_ph_consent\",\n cross_subdomain_cookie: true,\n cookie_expiration: 180,\n // Permanent PII hygiene — identical in both consent modes.\n mask_all_text: true,\n mask_all_element_attributes: true,\n disable_session_recording: true,\n disable_surveys: true,\n capture_heatmaps: false,\n capture_exceptions: true,\n before_send: redactBeforeSend,\n};\n\nlet cachedPh: PostHog | null = null;\n\nexport function getOrInitPostHog(config: PostHogConfigInput): PostHog | null {\n if (typeof window === \"undefined\") return null;\n if (cachedPh) return cachedPh;\n\n cachedPh = posthog.init(config.apiKey, {\n ...BASE_OPTIONS,\n api_host: config.apiHost,\n ...(config.uiHost ? { ui_host: config.uiHost } : {}),\n });\n\n return cachedPh;\n}\n\n/**\n * Mirrors the `uninspired_consent` decision into PostHog's own consent state.\n *\n * - granted → `opt_in_capturing()` upgrades to cookies + identify live\n * - pending → `opt_out_capturing()` keeps capturing cookielessly\n * - denied → same as pending (cookieless capture continues)\n */\nexport function syncPostHogConsent(ph: PostHog | null, consent: ConsentState) {\n if (!ph) return;\n if (posthogConsentAction(consent) === \"opt_in\") ph.opt_in_capturing();\n else ph.opt_out_capturing();\n}\n\nexport function registerTrackingProduct(\n ph: PostHog | null,\n product: AnalyticsProduct,\n) {\n registerProductEvent(ph, product);\n}\n","import type { PostHog } from \"posthog-js\";\nimport type { AnalyticsProduct, ConsentState, TrackingConsent } from \"@us-auth/types\";\nimport {\n configureConsentDomain,\n getConsent,\n setConsent as setConsentStore,\n subscribeConsent,\n} from \"../consent\";\nimport { purgeLegacyTracking } from \"../consent/purgeLegacyTracking\";\nimport {\n captureCheckoutStarted as captureCheckoutStartedEvent,\n captureFeatureUsed as captureFeatureUsedEvent,\n registerProduct as registerProductEvent,\n} from \"../analytics\";\nimport {\n isMetaPixelLoaded,\n loadMetaPixel,\n revokeMetaPixelConsent,\n trackMetaPixel,\n} from \"./metaPixel\";\nimport {\n getOrInitPostHog,\n syncPostHogConsent,\n type PostHogConfigInput,\n} from \"./posthog\";\n\nexport interface TrackingClientOptions {\n product: AnalyticsProduct;\n /** `null` disables PostHog entirely (product apps without analytics config). */\n posthog: PostHogConfigInput | null;\n metaPixelId?: string;\n /** `undefined` derives the domain, `\"\"` forces a host-only cookie. */\n consentCookieDomain?: string;\n}\n\nexport interface ViewContentOptions {\n contentId: string;\n value?: number;\n currency?: string;\n}\n\nexport interface InitiateCheckoutOptions {\n contentIds?: string[];\n value?: number;\n currency?: string;\n}\n\nexport interface PurchaseOptions {\n value?: number;\n currency?: string;\n contentIds?: string[];\n /** Paddle transaction id — lets Meta dedupe repeated browser events. */\n eventId?: string;\n}\n\n/**\n * Owns PostHog initialization and the Meta Pixel lifecycle for an app.\n *\n * PostHog capture always works (cookieless while pending/denied, full when\n * granted); `identify` and every Meta call are consent-gated.\n */\nexport class TrackingClient {\n readonly ph: PostHog | null;\n readonly product: AnalyticsProduct;\n\n #metaPixelId?: string;\n #unsubscribe?: () => void;\n #started = false;\n\n constructor(options: TrackingClientOptions) {\n this.product = options.product;\n this.#metaPixelId = options.metaPixelId;\n configureConsentDomain(options.consentCookieDomain);\n purgeLegacyTracking();\n this.ph = options.posthog ? getOrInitPostHog(options.posthog) : null;\n if (this.ph) registerProductEvent(this.ph, this.product);\n }\n\n start(): void {\n if (this.#started) return;\n this.#started = true;\n this.#unsubscribe = subscribeConsent(() =>\n this.#applyConsent(getConsent()),\n );\n this.#applyConsent(getConsent());\n }\n\n stop(): void {\n this.#unsubscribe?.();\n this.#unsubscribe = undefined;\n this.#started = false;\n }\n\n #applyConsent(consent: ConsentState): void {\n syncPostHogConsent(this.ph, consent);\n if (consent?.marketing && this.#metaPixelId) {\n loadMetaPixel(this.#metaPixelId);\n } else if (isMetaPixelLoaded()) {\n // Withdrawn after being granted: stop sends.\n revokeMetaPixelConsent();\n }\n }\n\n #marketingGranted(): boolean {\n return getConsent()?.marketing === true;\n }\n\n getConsent(): ConsentState {\n return getConsent();\n }\n\n setConsent(consent: TrackingConsent): void {\n setConsentStore(consent);\n }\n\n // --- PostHog -------------------------------------------------------------\n\n capture(event: string, properties?: Record<string, unknown>): void {\n this.ph?.capture(event, properties);\n }\n\n captureException(\n error: unknown,\n properties?: Record<string, unknown>,\n ): void {\n this.ph?.captureException(error, properties);\n }\n\n identify(userId: string): void {\n if (!getConsent()?.analytics) return;\n if (this.ph?.get_distinct_id() === userId) return;\n this.ph?.identify(userId);\n }\n\n reset(): void {\n this.ph?.reset();\n }\n\n registerProduct(product: AnalyticsProduct): void {\n registerProductEvent(this.ph, product);\n }\n\n captureFeatureUsed(featureName: string, extra?: Record<string, unknown>): void {\n captureFeatureUsedEvent(this.ph, featureName, extra);\n }\n\n captureCheckoutStarted(options: {\n plan: string;\n product?: AnalyticsProduct;\n }): void {\n captureCheckoutStartedEvent(this.ph, options);\n }\n\n // --- Meta Pixel ----------------------------------------------------------\n\n trackPageView(): void {\n if (!this.#marketingGranted()) return;\n trackMetaPixel(\"PageView\");\n }\n\n trackViewContent({ contentId, value, currency }: ViewContentOptions): void {\n if (!this.#marketingGranted()) return;\n trackMetaPixel(\"ViewContent\", {\n content_ids: [contentId],\n content_type: \"product\",\n ...(value !== undefined ? { value } : {}),\n ...(currency ? { currency } : {}),\n });\n }\n\n trackInitiateCheckout({\n contentIds,\n value,\n currency,\n }: InitiateCheckoutOptions = {}): void {\n if (!this.#marketingGranted()) return;\n trackMetaPixel(\"InitiateCheckout\", {\n ...(contentIds?.length\n ? { content_ids: contentIds, content_type: \"product\" }\n : {}),\n ...(value !== undefined ? { value } : {}),\n ...(currency ? { currency } : {}),\n });\n }\n\n trackPurchase({\n value,\n currency,\n contentIds,\n eventId,\n }: PurchaseOptions = {}): void {\n if (!this.#marketingGranted()) return;\n trackMetaPixel(\n \"Purchase\",\n {\n ...(contentIds?.length\n ? { content_ids: contentIds, content_type: \"product\" }\n : {}),\n ...(value !== undefined ? { value } : {}),\n ...(currency ? { currency } : {}),\n },\n eventId,\n );\n }\n}\n","import { createContext } from \"react\";\nimport type { TrackingClient } from \"./TrackingClient\";\n\nexport const TrackingContext = createContext<TrackingClient | null>(null);","import {\n useEffect,\n useRef,\n type PropsWithChildren,\n} from \"react\";\nimport { TrackingContext } from \"./TrackingContext\";\nimport {\n TrackingClient,\n type TrackingClientOptions,\n} from \"./TrackingClient\";\n\nexport interface TrackingProviderProps\n extends TrackingClientOptions,\n PropsWithChildren {}\n\n/**\n * Mount once per app, above `AuthProvider`. Owns PostHog init and the Meta\n * Pixel lifecycle, both driven by the shared consent cookie.\n */\nexport const TrackingProvider = ({\n children,\n ...options\n}: TrackingProviderProps) => {\n const clientRef = useRef<TrackingClient | null>(null);\n if (!clientRef.current) {\n clientRef.current = new TrackingClient(options);\n }\n\n useEffect(() => {\n const client = clientRef.current;\n client?.start();\n return () => client?.stop();\n }, []);\n\n return (\n <TrackingContext.Provider value={clientRef.current}>\n {children}\n </TrackingContext.Provider>\n );\n};\n","import { useContext } from \"react\";\nimport { TrackingContext } from \"./TrackingContext\";\nimport type { TrackingClient } from \"./TrackingClient\";\n\n/**\n * Returns the app's `TrackingClient`, or `null` when no `TrackingProvider`\n * wraps the tree (in which case all analytics no-op).\n */\nexport function useTracking(): TrackingClient | null {\n return useContext(TrackingContext);\n}","import { createContext } from \"react\";\nimport type { UserPurchases, Session, AnalyticsProduct } from \"@us-auth/types\";\nimport type { AuthClient } from \"../AuthClient\";\n\nexport type AuthContextType = {\n session: Session | null;\n isSessionFetching: boolean;\n refetchSession: () => Promise<void>;\n purchases: UserPurchases | null;\n isPurchasesFetching: boolean;\n refetchPurchases: () => Promise<void>;\n signOut: AuthClient[\"signOut\"];\n getLoginUrl: AuthClient[\"getLoginUrl\"];\n getCheckoutUrl: AuthClient[\"getCheckoutUrl\"];\n captureFeatureUsed: (\n featureName: string,\n extra?: Record<string, unknown>,\n ) => void;\n captureCheckoutStarted: (options: {\n plan: string;\n product?: AnalyticsProduct;\n }) => void;\n registerProduct: (product: AnalyticsProduct) => void;\n isPurchased: (priceIds: string[]) => boolean;\n isSubscribed: (priceIds: string[], productId: string) => boolean;\n isLoggedIn: boolean;\n} | null;\n\nexport const AuthContext = createContext<AuthContextType>(null);","import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n type PropsWithChildren,\n} from \"react\";\nimport { AuthContext } from \"./AuthContext\";\nimport { AuthClient } from \"../AuthClient\";\nimport type { Session, UserPurchases, AnalyticsProduct } from \"@us-auth/types\";\nimport { isPaddleTransactionRevoked } from \"@us-auth/types\";\nimport { QueryClient, useQuery } from \"@tanstack/react-query\";\nimport { useTracking } from \"../tracking/useTracking\";\nimport { useTrackingConsent } from \"../consent/useTrackingConsent\";\n\nexport interface AuthProviderProps extends PropsWithChildren {\n authClient?: AuthClient;\n queryClient?: QueryClient;\n baseUrl: string;\n frontendUrl: string;\n product?: AnalyticsProduct;\n initialSession?: Session | null;\n initialPurchases?: UserPurchases | null;\n}\n\nexport const AuthProvider = ({\n children,\n baseUrl,\n frontendUrl,\n product,\n initialSession,\n initialPurchases,\n authClient: providedAuthClient,\n queryClient: providedQueryClient,\n}: AuthProviderProps) => {\n const authClient = useMemo(\n () =>\n providedAuthClient ?? new AuthClient(baseUrl, frontendUrl),\n [baseUrl, frontendUrl, providedAuthClient],\n );\n const queryClient = useMemo(\n () => providedQueryClient ?? new QueryClient(),\n [providedQueryClient],\n );\n const tracking = useTracking();\n const { consent } = useTrackingConsent();\n const analyticsGranted = consent?.analytics === true;\n\n const {\n data: session,\n isFetching: isSessionFetching,\n status: sessionStatus,\n refetch: refetchSession,\n } = useQuery(\n {\n queryKey: [\"us-auth-session\"],\n staleTime: 0,\n initialData: initialSession,\n queryFn: authClient.getSession,\n },\n queryClient,\n );\n\n const isLoggedIn = useMemo(() => {\n if (!session || session.user.isAnonymous) return false;\n return true;\n }, [session]);\n\n const anonymousSignInAttempted = useRef(false);\n\n // Analytics delegates to the tracking client. PostHog capture works in every\n // consent mode (cookieless while pending/denied), so these stay callable;\n // the client itself gates identify and Meta.\n const registerProduct = useCallback(\n (nextProduct: AnalyticsProduct) => {\n tracking?.registerProduct(nextProduct);\n },\n [tracking],\n );\n\n const captureFeatureUsed = useCallback(\n (featureName: string, extra?: Record<string, unknown>) => {\n tracking?.captureFeatureUsed(featureName, extra);\n },\n [tracking],\n );\n\n const captureCheckoutStarted = useCallback(\n (options: { plan: string; product?: AnalyticsProduct }) => {\n tracking?.captureCheckoutStarted(options);\n },\n [tracking],\n );\n\n useEffect(() => {\n if (product) tracking?.registerProduct(product);\n }, [tracking, product]);\n\n // Identify only when analytics consent is granted, and re-run when consent\n // is granted mid-session. No email is ever sent — user id only.\n useEffect(() => {\n if (!tracking || !session?.user || session.user.isAnonymous) return;\n if (!analyticsGranted) return;\n tracking.identify(session.user.id);\n }, [tracking, session, analyticsGranted]);\n\n // Log unauthenticated users in anonymously automatically\n useEffect(() => {\n if (isSessionFetching) return;\n // Only treat the session as absent when the fetch actually SUCCEEDED and\n // returned null — a failed fetch keeps `data` at the initialData value\n // (null), and anonymous sign-in would overwrite a real session cookie.\n if (sessionStatus !== \"success\") return;\n if (session !== null) return;\n if (anonymousSignInAttempted.current) return;\n\n anonymousSignInAttempted.current = true;\n authClient\n .signInAnonymously()\n .then((newSession) => {\n queryClient.setQueryData([\"us-auth-session\"], newSession);\n })\n .catch((e) => console.error(e));\n }, [authClient, isSessionFetching, queryClient, session, sessionStatus]);\n\n const {\n data: purchases,\n isFetching: isPurchasesFetching,\n refetch: refetchPurchases,\n } = useQuery(\n {\n queryKey: [\"us-auth-purchases\"],\n staleTime: 1000 * 60,\n initialData: initialPurchases,\n queryFn: authClient.getPurchases,\n },\n queryClient,\n );\n\n const getLoginUrl = useMemo(() => authClient.getLoginUrl, [authClient]);\n const getCheckoutUrl = useMemo(() => authClient.getCheckoutUrl, [authClient]);\n const signOut = useCallback(\n (onSuccess?: () => void) =>\n authClient.signOut(() => {\n // Clear cached session/purchases so isLoggedIn, isPurchased and\n // isSubscribed stop serving the signed-out user immediately.\n queryClient.setQueryData([\"us-auth-session\"], null);\n queryClient.removeQueries({ queryKey: [\"us-auth-purchases\"] });\n // Drop the identified PostHog person so the next user starts fresh.\n tracking?.reset();\n onSuccess?.();\n }),\n [authClient, queryClient, tracking],\n );\n\n const isPurchased = useCallback(\n (priceIds: string[]): boolean => {\n if (!purchases) return false;\n return purchases.paddle.transactions.some(\n (tra) =>\n tra.items.some((item) => priceIds.includes(item)) &&\n !isPaddleTransactionRevoked(tra.adjustments),\n );\n },\n [purchases],\n );\n\n const isSubscribed = useCallback(\n (priceIds: string[], productId: string): boolean => {\n if (!purchases) return false;\n\n const paddleSubscriptions = purchases.paddle.subscriptions.some(\n (sub) =>\n sub.items.some(\n (item) =>\n priceIds.includes(item.priceId) || productId === item.productId,\n ) && sub.status === \"active\",\n );\n\n const stripeSubscriptions = purchases.stripe.some(\n (sub) =>\n sub.status === \"active\" &&\n sub.items.some((item) => priceIds.includes(item)),\n );\n\n return paddleSubscriptions || stripeSubscriptions;\n },\n [purchases],\n );\n\n return (\n <AuthContext.Provider\n value={{\n session: session ?? null,\n isSessionFetching,\n refetchSession: async () => {\n await refetchSession();\n },\n purchases: purchases ?? null,\n isPurchasesFetching,\n refetchPurchases: async () => {\n await refetchPurchases();\n },\n signOut,\n getLoginUrl,\n getCheckoutUrl,\n captureFeatureUsed,\n captureCheckoutStarted,\n registerProduct,\n isSubscribed,\n isPurchased,\n isLoggedIn,\n }}\n >\n {children}\n </AuthContext.Provider>\n );\n};\n","import { useContext } from \"react\";\nimport { AuthContext } from \"./AuthContext\";\n\nexport function useAuth() {\n const ctx = useContext(AuthContext);\n if (!ctx) {\n throw new Error(\"useAuth must be used within an AuthProvider\");\n }\n return ctx;\n}\n","export const RESEND_COOLDOWN_SECONDS = 30;\n\nexport function remainingCooldownSeconds(\n availableAt: number,\n now: number,\n): number {\n return Math.max(0, Math.ceil((availableAt - now) / 1000));\n}\n\nexport function resendButtonLabel(label: string, remainingSeconds: number) {\n return remainingSeconds > 0 ? `${label} (${remainingSeconds}s)` : label;\n}\n","import { useCallback, useMemo, useState } from \"react\";\nimport z from \"zod\";\nexport type EmailOtpAuthClient = {\n emailOtp: {\n sendVerificationOtp: (input: {\n email: string;\n type: \"sign-in\";\n }) => Promise<{ error?: unknown }>;\n };\n signIn: {\n emailOtp: (input: {\n email: string;\n otp: string;\n }) => Promise<{ error?: unknown }>;\n };\n};\nimport {\n remainingCooldownSeconds,\n RESEND_COOLDOWN_SECONDS,\n} from \"./resendCooldown\";\n\nconst emailSchema = z.email();\nconst otpSchema = z\n .string()\n .min(6)\n .max(6)\n .refine((otp) => otp.match(/^[0-9]{6}$/));\n\nexport type EmailOtpLoginFlowOptions = {\n authClient: EmailOtpAuthClient;\n onVerified: () => void | Promise<void>;\n onSendSuccess?: () => void;\n onSendError?: (error: unknown) => void;\n onVerifyError?: (error: unknown) => void;\n resendCooldownSeconds?: number;\n};\n\nexport function useEmailOtpLoginFlow({\n authClient,\n onVerified,\n onSendSuccess,\n onSendError,\n onVerifyError,\n resendCooldownSeconds = RESEND_COOLDOWN_SECONDS,\n}: EmailOtpLoginFlowOptions) {\n const [step, setStep] = useState<\"email\" | \"otp\">(\"email\");\n const [email, setEmail] = useState(\"\");\n const [otp, setOtp] = useState(\"\");\n const [submitting, setSubmitting] = useState(false);\n const [verifying, setVerifying] = useState(false);\n const [resending, setResending] = useState(false);\n const [availableAt, setAvailableAt] = useState(\n () => Date.now() + resendCooldownSeconds * 1000,\n );\n const [now, setNow] = useState(() => Date.now());\n\n const emailValid = useMemo(\n () => emailSchema.safeParse(email).success,\n [email],\n );\n const otpValid = useMemo(() => otpSchema.safeParse(otp).success, [otp]);\n const remainingSeconds = remainingCooldownSeconds(availableAt, now);\n const isCoolingDown = remainingSeconds > 0;\n\n const restartResendCooldown = useCallback(() => {\n const timestamp = Date.now();\n setNow(timestamp);\n setAvailableAt(timestamp + resendCooldownSeconds * 1000);\n }, [resendCooldownSeconds]);\n\n const sendOtp = useCallback(async () => {\n const { error } = await authClient.emailOtp.sendVerificationOtp({\n email,\n type: \"sign-in\",\n });\n if (error) throw error;\n }, [authClient, email]);\n\n const submitEmail = useCallback(async () => {\n if (!emailValid) return;\n setSubmitting(true);\n try {\n await sendOtp();\n onSendSuccess?.();\n setStep(\"otp\");\n } catch (error) {\n onSendError?.(error);\n } finally {\n setSubmitting(false);\n }\n }, [emailValid, sendOtp, onSendSuccess, onSendError]);\n\n const resendOtp = useCallback(async () => {\n if (resending || isCoolingDown) return;\n setResending(true);\n try {\n await sendOtp();\n restartResendCooldown();\n onSendSuccess?.();\n } catch (error) {\n onSendError?.(error);\n } finally {\n setResending(false);\n }\n }, [\n resending,\n isCoolingDown,\n sendOtp,\n restartResendCooldown,\n onSendSuccess,\n onSendError,\n ]);\n\n const verifyOtp = useCallback(async () => {\n if (!otpValid) return;\n setVerifying(true);\n try {\n const { error } = await authClient.signIn.emailOtp({ email, otp });\n if (error) throw error;\n await onVerified();\n } catch (error) {\n onVerifyError?.(error);\n setVerifying(false);\n }\n }, [otpValid, authClient, email, otp, onVerified, onVerifyError]);\n\n const backToEmail = useCallback(() => {\n setStep(\"email\");\n setOtp(\"\");\n }, []);\n\n return {\n step,\n email,\n setEmail,\n otp,\n setOtp,\n emailValid,\n otpValid,\n submitting,\n verifying,\n resending,\n remainingSeconds,\n isCoolingDown,\n submitEmail,\n resendOtp,\n verifyOtp,\n backToEmail,\n setNow,\n availableAt,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["#cookie","#frontendUrl","#authClient","#appClient","#getRedirectIntent","createAuthClient","SHARED_ANALYTICS_EVENTS","#metaPixelId","#started","#unsubscribe","#applyConsent","#marketingGranted","z"],"sources":["../src/AuthClient.ts","../src/betterAuthClient.ts","../src/analytics.ts","../src/tracking/metaPixel.ts","../src/tracking/redaction.ts","../src/tracking/consentAction.ts","../src/tracking/posthog.ts","../src/tracking/TrackingClient.ts","../src/tracking/TrackingContext.ts","../src/tracking/TrackingProvider.tsx","../src/tracking/useTracking.ts","../src/react/AuthContext.ts","../src/react/AuthProvider.tsx","../src/react/useAuth.ts","../src/react/resendCooldown.ts","../src/react/useEmailOtpLoginFlow.ts"],"sourcesContent":["import {\n magicLinkClient,\n emailOTPClient,\n anonymousClient,\n} from \"better-auth/client/plugins\";\nimport { passkeyClient } from \"@better-auth/passkey/client\";\nimport { createAuthClient } from \"better-auth/client\";\nimport { hc } from \"hono/client\";\nimport type { AppRouter } from \"@us-auth/api/routers\";\nimport type {\n UserPurchases,\n Session,\n RedirectIntent,\n} from \"@us-auth/types\";\n\nexport class AuthClient {\n #frontendUrl: string;\n #authClient;\n #appClient: ReturnType<typeof hc<AppRouter>>;\n #cookie: string | undefined;\n\n constructor(apiUrl: string, frontendUrl: string, cookie?: string) {\n this.#cookie = cookie;\n this.#frontendUrl = frontendUrl;\n this.#authClient = createAuthClient({\n baseURL: apiUrl,\n plugins: [\n anonymousClient(),\n magicLinkClient(),\n emailOTPClient(),\n passkeyClient(),\n ],\n });\n this.#appClient = hc<AppRouter>(new URL(\"/api/app\", apiUrl).toString(), {\n fetch: (url: RequestInfo | URL, init?: RequestInit) =>\n fetch(url, {\n ...init,\n credentials: \"include\",\n }),\n });\n }\n\n // Authentication\n getSession = async (): Promise<Session | null> => {\n const { data, error } = await this.#authClient.getSession(\n {},\n {\n headers: this.#cookie\n ? {\n Cookie: this.#cookie,\n }\n : undefined,\n },\n );\n if (error) throw error;\n return data;\n };\n\n signInAnonymously = async (): Promise<Session | null> => {\n const { error } = await this.#authClient.signIn.anonymous();\n if (error) throw error;\n return this.getSession();\n };\n\n signOut = async (onSuccess?: () => void): Promise<void> => {\n const { error } = await this.#authClient.signOut(\n {\n fetchOptions: { onSuccess },\n },\n {\n headers: this.#cookie ? { Cookie: this.#cookie } : undefined,\n },\n );\n if (error) throw error;\n return;\n };\n\n // Purchases\n getPurchases = async (): Promise<UserPurchases | null> => {\n const res = await this.#appClient.purchases.$get(undefined, {\n headers: this.#cookie ? { Cookie: this.#cookie } : undefined,\n });\n if (!res.ok) {\n throw new Error(\"Failed to get purchases\", {\n cause: await res.text(),\n });\n }\n const data = await res.json();\n return data as UserPurchases | null;\n };\n\n #getRedirectIntent = (redirectUrl: string, appName?: string) => {\n return JSON.stringify({\n type: \"redirect\",\n redirectUrl,\n appName,\n } satisfies RedirectIntent);\n };\n\n // Utils\n getLoginUrl = (options?: { redirectUrl?: string; appName?: string }) => {\n const url = new URL(\"/login\", this.#frontendUrl);\n if (options?.redirectUrl) {\n url.searchParams.set(\n \"intent\",\n this.#getRedirectIntent(options.redirectUrl, options.appName),\n );\n }\n return url.toString();\n };\n\n getCheckoutUrl = (options: {\n priceId: string;\n productId: string;\n discountCode?: string;\n successUrl?: string;\n quantity?: number;\n }) => {\n const url = new URL(\"/auth/checkout\", this.#frontendUrl);\n url.searchParams.set(\"priceId\", options.priceId);\n url.searchParams.set(\"productId\", options.productId);\n if (options.discountCode) {\n url.searchParams.set(\"discountCode\", options.discountCode);\n }\n if (options.successUrl) {\n url.searchParams.set(\"successUrl\", options.successUrl);\n }\n url.searchParams.set(\"quantity\", options.quantity?.toString() ?? \"1\");\n return url.toString();\n };\n}\n","import {\n magicLinkClient,\n emailOTPClient,\n anonymousClient,\n} from \"better-auth/client/plugins\";\nimport { passkeyClient } from \"@better-auth/passkey/client\";\nimport { createAuthClient } from \"better-auth/react\";\n\nexport function createBetterAuthClient(baseURL: string) {\n return createAuthClient({\n baseURL,\n plugins: [\n anonymousClient(),\n magicLinkClient(),\n emailOTPClient(),\n passkeyClient(),\n ],\n });\n}\n\nexport type BetterAuthClient = ReturnType<typeof createBetterAuthClient>;\n","import {\n ANALYTICS_EVENTS as SHARED_ANALYTICS_EVENTS,\n isAnalyticsProduct,\n type AnalyticsProduct,\n type AuthMethod,\n} from \"@us-auth/types\";\n\n/**\n * Re-exported as a local binding: re-exporting the const directly from the\n * bundled `@us-auth/types` package trips the declaration bundler.\n */\nexport const ANALYTICS_EVENTS = SHARED_ANALYTICS_EVENTS;\n\nexport interface PostHogAnalyticsClient {\n capture: (event: string, properties?: Record<string, unknown>) => void;\n register?: (properties: Record<string, unknown>) => void;\n}\n\nexport function registerProduct(\n ph: PostHogAnalyticsClient | null | undefined,\n product: AnalyticsProduct,\n) {\n ph?.register?.({ product });\n}\n\nexport function captureFeatureUsed(\n ph: PostHogAnalyticsClient | null | undefined,\n featureName: string,\n extra?: Record<string, unknown>,\n) {\n ph?.capture(ANALYTICS_EVENTS.FEATURE_USED, {\n feature_name: featureName,\n ...extra,\n });\n}\n\nexport function captureCheckoutStarted(\n ph: PostHogAnalyticsClient | null | undefined,\n {\n plan,\n product,\n }: {\n plan: string;\n product?: AnalyticsProduct;\n },\n) {\n if (product) {\n registerProduct(ph, product);\n }\n ph?.capture(ANALYTICS_EVENTS.CHECKOUT_STARTED, {\n plan,\n ...(product ? { product } : {}),\n });\n}\n\nexport { isAnalyticsProduct };\nexport type { AnalyticsProduct, AuthMethod };\n","type FbqFunction = ((...args: unknown[]) => void) & {\n callMethod?: (...args: unknown[]) => void;\n queue?: unknown[][];\n loaded?: boolean;\n version?: string;\n};\n\ntype MetaWindow = Window & { fbq?: FbqFunction; _fbq?: FbqFunction };\n\nlet pixelLoaded = false;\n\n/** Injects the Meta Pixel base code and fires an initial PageView. Idempotent. */\nexport function loadMetaPixel(pixelId: string): void {\n if (typeof window === \"undefined\" || pixelLoaded) return;\n\n const w = window as MetaWindow;\n if (!w.fbq) {\n const fbq = ((...args: unknown[]) => {\n if (fbq.callMethod) fbq.callMethod(...args);\n else fbq.queue?.push(args);\n }) as FbqFunction;\n fbq.queue = [];\n fbq.loaded = true;\n fbq.version = \"2.0\";\n w.fbq = fbq;\n if (!w._fbq) w._fbq = fbq;\n\n const script = document.createElement(\"script\");\n script.async = true;\n script.src = \"https://connect.facebook.net/en_US/fbevents.js\";\n document.head.appendChild(script);\n }\n\n w.fbq(\"init\", pixelId);\n w.fbq(\"track\", \"PageView\");\n pixelLoaded = true;\n}\n\nexport function isMetaPixelLoaded(): boolean {\n return pixelLoaded;\n}\n\n/**\n * Tells an already-loaded pixel to stop sending when marketing consent is\n * withdrawn. Does not unload the script or clear cookies.\n */\nexport function revokeMetaPixelConsent(): void {\n if (typeof window === \"undefined\") return;\n const fbq = (window as MetaWindow).fbq;\n fbq?.(\"consent\", \"revoke\");\n}\n\n/** Fires a standard pixel event; `eventId` lets Meta dedupe on reloads. */\nexport function trackMetaPixel(\n event: string,\n params?: Record<string, unknown>,\n eventId?: string,\n): void {\n if (typeof window === \"undefined\") return;\n const fbq = (window as MetaWindow).fbq;\n if (!fbq) return;\n if (eventId) fbq(\"track\", event, params, { eventID: eventId });\n else fbq(\"track\", event, params);\n}\n","type RedactableEvent = { properties?: Record<string, unknown> };\n\nconst URL_PROPERTIES = [\n \"$current_url\",\n \"$initial_current_url\",\n \"$referrer\",\n \"$initial_referrer\",\n];\n\nconst PATH_PROPERTIES = [\"$pathname\", \"$initial_pathname\"];\n\nfunction redactPassphrasePath(pathname: string): string {\n return pathname.replace(/^\\/s\\/[^/]+/, \"/s/[redacted]\");\n}\n\nfunction redactUrl(value: unknown): unknown {\n if (typeof value !== \"string\") return value;\n try {\n const url = new URL(value);\n url.search = \"\";\n url.hash = \"\";\n url.pathname = redactPassphrasePath(url.pathname);\n return url.toString();\n } catch {\n return value;\n }\n}\n\nfunction redactPath(value: unknown): unknown {\n if (typeof value !== \"string\") return value;\n return redactPassphrasePath(value);\n}\n\n/**\n * Strips URL query strings and short-link passphrases from every event before\n * it leaves the browser. Together with `mask_all_text` this keeps autocapture\n * and pageviews PII-free without disabling them.\n *\n * Applies in every consent mode: it is PII hygiene, not a consent mitigation.\n */\nexport function redactBeforeSend<T extends RedactableEvent | null>(event: T): T {\n if (!event || !event.properties) return event;\n\n const properties = event.properties;\n for (const key of URL_PROPERTIES) {\n if (key in properties) {\n properties[key] = redactUrl(properties[key]);\n }\n }\n for (const key of PATH_PROPERTIES) {\n if (key in properties) {\n properties[key] = redactPath(properties[key]);\n }\n }\n\n return event;\n}","import type { ConsentState } from \"@us-auth/types\";\n\n/**\n * Pure mapping from consent state to the PostHog consent action.\n * Kept separate from the PostHog import so it is trivially testable.\n */\nexport function posthogConsentAction(\n consent: ConsentState,\n): \"opt_in\" | \"opt_out\" {\n return consent?.analytics ? \"opt_in\" : \"opt_out\";\n}","import posthog, { type PostHog } from \"posthog-js\";\nimport type { AnalyticsProduct, ConsentState } from \"@us-auth/types\";\nimport { redactBeforeSend } from \"./redaction\";\nimport { registerProduct as registerProductEvent } from \"../analytics\";\nimport { posthogConsentAction } from \"./consentAction\";\n\nexport { posthogConsentAction };\n\nexport interface PostHogConfigInput {\n apiKey: string;\n apiHost: string;\n uiHost?: string;\n}\n\n/**\n * PostHog runs in `on_reject` mode so the SDK's consent API can move us\n * between cookieless and full persistence at runtime. Every PII-hygiene\n * option is permanent in both modes; only persistence and `identify` change.\n */\nconst BASE_OPTIONS = {\n defaults: \"2026-05-30\" as const,\n person_profiles: \"identified_only\" as const,\n cookieless_mode: \"on_reject\" as const,\n // Belt-and-braces: before the consent sync runs, pending behaves as\n // \"not granted\" → cookieless capture rather than a full freeze.\n opt_out_capturing_by_default: true,\n // Keep PostHog's own consent record separate from `uninspired_consent`\n // (different value encoding).\n consent_persistence_name: \"uninspired_ph_consent\",\n cross_subdomain_cookie: true,\n cookie_expiration: 180,\n // Permanent PII hygiene — identical in both consent modes.\n mask_all_text: true,\n mask_all_element_attributes: true,\n disable_session_recording: true,\n disable_surveys: true,\n capture_heatmaps: false,\n capture_exceptions: true,\n before_send: redactBeforeSend,\n};\n\nlet cachedPh: PostHog | null = null;\n\nexport function getOrInitPostHog(config: PostHogConfigInput): PostHog | null {\n if (typeof window === \"undefined\") return null;\n if (cachedPh) return cachedPh;\n\n cachedPh = posthog.init(config.apiKey, {\n ...BASE_OPTIONS,\n api_host: config.apiHost,\n ...(config.uiHost ? { ui_host: config.uiHost } : {}),\n });\n\n return cachedPh;\n}\n\n/** Returns the PostHog singleton initialized by `TrackingProvider`, if any. */\nexport function getPostHog(): PostHog | null {\n return cachedPh;\n}\n\n/**\n * Mirrors the `uninspired_consent` decision into PostHog's own consent state.\n *\n * - granted → `opt_in_capturing()` upgrades to cookies + identify live\n * - pending → `opt_out_capturing()` keeps capturing cookielessly\n * - denied → same as pending (cookieless capture continues)\n */\nexport function syncPostHogConsent(ph: PostHog | null, consent: ConsentState) {\n if (!ph) return;\n if (posthogConsentAction(consent) === \"opt_in\") ph.opt_in_capturing();\n else ph.opt_out_capturing();\n}\n\nexport function registerTrackingProduct(\n ph: PostHog | null,\n product: AnalyticsProduct,\n) {\n registerProductEvent(ph, product);\n}\n","import type { PostHog } from \"posthog-js\";\nimport type { AnalyticsProduct, ConsentState, TrackingConsent } from \"@us-auth/types\";\nimport {\n configureConsentDomain,\n getConsent,\n setConsent as setConsentStore,\n subscribeConsent,\n} from \"../consent\";\nimport { purgeLegacyTracking } from \"../consent/purgeLegacyTracking\";\nimport {\n captureCheckoutStarted as captureCheckoutStartedEvent,\n captureFeatureUsed as captureFeatureUsedEvent,\n registerProduct as registerProductEvent,\n} from \"../analytics\";\nimport {\n isMetaPixelLoaded,\n loadMetaPixel,\n revokeMetaPixelConsent,\n trackMetaPixel,\n} from \"./metaPixel\";\nimport {\n getOrInitPostHog,\n syncPostHogConsent,\n type PostHogConfigInput,\n} from \"./posthog\";\n\nexport interface TrackingClientOptions {\n product: AnalyticsProduct;\n /** `null` disables PostHog entirely (product apps without analytics config). */\n posthog: PostHogConfigInput | null;\n metaPixelId?: string;\n /** `undefined` derives the domain, `\"\"` forces a host-only cookie. */\n consentCookieDomain?: string;\n}\n\nexport interface ViewContentOptions {\n contentId: string;\n value?: number;\n currency?: string;\n}\n\nexport interface InitiateCheckoutOptions {\n contentIds?: string[];\n value?: number;\n currency?: string;\n}\n\nexport interface PurchaseOptions {\n value?: number;\n currency?: string;\n contentIds?: string[];\n /** Paddle transaction id — lets Meta dedupe repeated browser events. */\n eventId?: string;\n}\n\n/**\n * Owns PostHog initialization and the Meta Pixel lifecycle for an app.\n *\n * PostHog capture always works (cookieless while pending/denied, full when\n * granted); `identify` and every Meta call are consent-gated.\n */\nexport class TrackingClient {\n readonly ph: PostHog | null;\n readonly product: AnalyticsProduct;\n\n #metaPixelId?: string;\n #unsubscribe?: () => void;\n #started = false;\n\n constructor(options: TrackingClientOptions) {\n this.product = options.product;\n this.#metaPixelId = options.metaPixelId;\n configureConsentDomain(options.consentCookieDomain);\n purgeLegacyTracking();\n this.ph = options.posthog ? getOrInitPostHog(options.posthog) : null;\n if (this.ph) registerProductEvent(this.ph, this.product);\n }\n\n start(): void {\n if (this.#started) return;\n this.#started = true;\n this.#unsubscribe = subscribeConsent(() =>\n this.#applyConsent(getConsent()),\n );\n this.#applyConsent(getConsent());\n }\n\n stop(): void {\n this.#unsubscribe?.();\n this.#unsubscribe = undefined;\n this.#started = false;\n }\n\n #applyConsent(consent: ConsentState): void {\n syncPostHogConsent(this.ph, consent);\n if (consent?.marketing && this.#metaPixelId) {\n loadMetaPixel(this.#metaPixelId);\n } else if (isMetaPixelLoaded()) {\n // Withdrawn after being granted: stop sends.\n revokeMetaPixelConsent();\n }\n }\n\n #marketingGranted(): boolean {\n return getConsent()?.marketing === true;\n }\n\n getConsent(): ConsentState {\n return getConsent();\n }\n\n setConsent(consent: TrackingConsent): void {\n setConsentStore(consent);\n }\n\n // --- PostHog -------------------------------------------------------------\n\n capture(event: string, properties?: Record<string, unknown>): void {\n this.ph?.capture(event, properties);\n }\n\n captureException(\n error: unknown,\n properties?: Record<string, unknown>,\n ): void {\n this.ph?.captureException(error, properties);\n }\n\n identify(userId: string): void {\n if (!getConsent()?.analytics) return;\n if (this.ph?.get_distinct_id() === userId) return;\n this.ph?.identify(userId);\n }\n\n reset(): void {\n this.ph?.reset();\n }\n\n getFeatureFlag(key: string): boolean | string | undefined {\n return this.ph?.getFeatureFlag(key);\n }\n\n registerProduct(product: AnalyticsProduct): void {\n registerProductEvent(this.ph, product);\n }\n\n captureFeatureUsed(featureName: string, extra?: Record<string, unknown>): void {\n captureFeatureUsedEvent(this.ph, featureName, extra);\n }\n\n captureCheckoutStarted(options: {\n plan: string;\n product?: AnalyticsProduct;\n }): void {\n captureCheckoutStartedEvent(this.ph, options);\n }\n\n // --- Meta Pixel ----------------------------------------------------------\n\n trackPageView(): void {\n if (!this.#marketingGranted()) return;\n trackMetaPixel(\"PageView\");\n }\n\n trackViewContent({ contentId, value, currency }: ViewContentOptions): void {\n if (!this.#marketingGranted()) return;\n trackMetaPixel(\"ViewContent\", {\n content_ids: [contentId],\n content_type: \"product\",\n ...(value !== undefined ? { value } : {}),\n ...(currency ? { currency } : {}),\n });\n }\n\n trackInitiateCheckout({\n contentIds,\n value,\n currency,\n }: InitiateCheckoutOptions = {}): void {\n if (!this.#marketingGranted()) return;\n trackMetaPixel(\"InitiateCheckout\", {\n ...(contentIds?.length\n ? { content_ids: contentIds, content_type: \"product\" }\n : {}),\n ...(value !== undefined ? { value } : {}),\n ...(currency ? { currency } : {}),\n });\n }\n\n trackPurchase({\n value,\n currency,\n contentIds,\n eventId,\n }: PurchaseOptions = {}): void {\n if (!this.#marketingGranted()) return;\n trackMetaPixel(\n \"Purchase\",\n {\n ...(contentIds?.length\n ? { content_ids: contentIds, content_type: \"product\" }\n : {}),\n ...(value !== undefined ? { value } : {}),\n ...(currency ? { currency } : {}),\n },\n eventId,\n );\n }\n}\n","import { createContext } from \"react\";\nimport type { TrackingClient } from \"./TrackingClient\";\n\nexport const TrackingContext = createContext<TrackingClient | null>(null);","import {\n useEffect,\n useRef,\n type PropsWithChildren,\n} from \"react\";\nimport { TrackingContext } from \"./TrackingContext\";\nimport {\n TrackingClient,\n type TrackingClientOptions,\n} from \"./TrackingClient\";\nimport { PostHogProvider } from \"./posthogReact\";\n\nexport interface TrackingProviderProps\n extends TrackingClientOptions,\n PropsWithChildren {}\n\n/**\n * Mount once per app, above `AuthProvider`. Owns PostHog init and the Meta\n * Pixel lifecycle, both driven by the shared consent cookie.\n */\nexport const TrackingProvider = ({\n children,\n ...options\n}: TrackingProviderProps) => {\n const clientRef = useRef<TrackingClient | null>(null);\n if (!clientRef.current) {\n clientRef.current = new TrackingClient(options);\n }\n\n useEffect(() => {\n const client = clientRef.current;\n client?.start();\n return () => client?.stop();\n }, []);\n\n const client = clientRef.current;\n const ph = client.ph;\n\n return (\n <TrackingContext.Provider value={client}>\n {ph ? <PostHogProvider client={ph}>{children}</PostHogProvider> : children}\n </TrackingContext.Provider>\n );\n};\n","import { useContext } from \"react\";\nimport { TrackingContext } from \"./TrackingContext\";\nimport type { TrackingClient } from \"./TrackingClient\";\n\n/**\n * Returns the app's `TrackingClient`, or `null` when no `TrackingProvider`\n * wraps the tree (in which case all analytics no-op).\n */\nexport function useTracking(): TrackingClient | null {\n return useContext(TrackingContext);\n}","import { createContext } from \"react\";\nimport type { UserPurchases, Session, AnalyticsProduct } from \"@us-auth/types\";\nimport type { AuthClient } from \"../AuthClient\";\n\nexport type AuthContextType = {\n session: Session | null;\n isSessionFetching: boolean;\n refetchSession: () => Promise<void>;\n purchases: UserPurchases | null;\n isPurchasesFetching: boolean;\n refetchPurchases: () => Promise<void>;\n signOut: AuthClient[\"signOut\"];\n getLoginUrl: AuthClient[\"getLoginUrl\"];\n getCheckoutUrl: AuthClient[\"getCheckoutUrl\"];\n captureFeatureUsed: (\n featureName: string,\n extra?: Record<string, unknown>,\n ) => void;\n captureCheckoutStarted: (options: {\n plan: string;\n product?: AnalyticsProduct;\n }) => void;\n registerProduct: (product: AnalyticsProduct) => void;\n isPurchased: (priceIds: string[]) => boolean;\n isSubscribed: (priceIds: string[], productId: string) => boolean;\n isLoggedIn: boolean;\n} | null;\n\nexport const AuthContext = createContext<AuthContextType>(null);","import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n type PropsWithChildren,\n} from \"react\";\nimport { AuthContext } from \"./AuthContext\";\nimport { AuthClient } from \"../AuthClient\";\nimport type { Session, UserPurchases, AnalyticsProduct } from \"@us-auth/types\";\nimport { isPaddleTransactionRevoked } from \"@us-auth/types\";\nimport { QueryClient, useQuery } from \"@tanstack/react-query\";\nimport { useTracking } from \"../tracking/useTracking\";\nimport { useTrackingConsent } from \"../consent/useTrackingConsent\";\n\nexport interface AuthProviderProps extends PropsWithChildren {\n authClient?: AuthClient;\n queryClient?: QueryClient;\n baseUrl: string;\n frontendUrl: string;\n product?: AnalyticsProduct;\n initialSession?: Session | null;\n initialPurchases?: UserPurchases | null;\n}\n\nexport const AuthProvider = ({\n children,\n baseUrl,\n frontendUrl,\n product,\n initialSession,\n initialPurchases,\n authClient: providedAuthClient,\n queryClient: providedQueryClient,\n}: AuthProviderProps) => {\n const authClient = useMemo(\n () =>\n providedAuthClient ?? new AuthClient(baseUrl, frontendUrl),\n [baseUrl, frontendUrl, providedAuthClient],\n );\n const queryClient = useMemo(\n () => providedQueryClient ?? new QueryClient(),\n [providedQueryClient],\n );\n const tracking = useTracking();\n const { consent } = useTrackingConsent();\n const analyticsGranted = consent?.analytics === true;\n\n const {\n data: session,\n isFetching: isSessionFetching,\n status: sessionStatus,\n refetch: refetchSession,\n } = useQuery(\n {\n queryKey: [\"us-auth-session\"],\n staleTime: 0,\n initialData: initialSession,\n queryFn: authClient.getSession,\n },\n queryClient,\n );\n\n const isLoggedIn = useMemo(() => {\n if (!session || session.user.isAnonymous) return false;\n return true;\n }, [session]);\n\n const anonymousSignInAttempted = useRef(false);\n\n // Analytics delegates to the tracking client. PostHog capture works in every\n // consent mode (cookieless while pending/denied), so these stay callable;\n // the client itself gates identify and Meta.\n const registerProduct = useCallback(\n (nextProduct: AnalyticsProduct) => {\n tracking?.registerProduct(nextProduct);\n },\n [tracking],\n );\n\n const captureFeatureUsed = useCallback(\n (featureName: string, extra?: Record<string, unknown>) => {\n tracking?.captureFeatureUsed(featureName, extra);\n },\n [tracking],\n );\n\n const captureCheckoutStarted = useCallback(\n (options: { plan: string; product?: AnalyticsProduct }) => {\n tracking?.captureCheckoutStarted(options);\n },\n [tracking],\n );\n\n useEffect(() => {\n if (product) tracking?.registerProduct(product);\n }, [tracking, product]);\n\n // Identify only when analytics consent is granted, and re-run when consent\n // is granted mid-session. No email is ever sent — user id only.\n useEffect(() => {\n if (!tracking || !session?.user || session.user.isAnonymous) return;\n if (!analyticsGranted) return;\n tracking.identify(session.user.id);\n }, [tracking, session, analyticsGranted]);\n\n // Log unauthenticated users in anonymously automatically\n useEffect(() => {\n if (isSessionFetching) return;\n // Only treat the session as absent when the fetch actually SUCCEEDED and\n // returned null — a failed fetch keeps `data` at the initialData value\n // (null), and anonymous sign-in would overwrite a real session cookie.\n if (sessionStatus !== \"success\") return;\n if (session !== null) return;\n if (anonymousSignInAttempted.current) return;\n\n anonymousSignInAttempted.current = true;\n authClient\n .signInAnonymously()\n .then((newSession) => {\n queryClient.setQueryData([\"us-auth-session\"], newSession);\n })\n .catch((e) => console.error(e));\n }, [authClient, isSessionFetching, queryClient, session, sessionStatus]);\n\n const {\n data: purchases,\n isFetching: isPurchasesFetching,\n refetch: refetchPurchases,\n } = useQuery(\n {\n queryKey: [\"us-auth-purchases\"],\n staleTime: 1000 * 60,\n initialData: initialPurchases,\n queryFn: authClient.getPurchases,\n },\n queryClient,\n );\n\n const getLoginUrl = useMemo(() => authClient.getLoginUrl, [authClient]);\n const getCheckoutUrl = useMemo(() => authClient.getCheckoutUrl, [authClient]);\n const signOut = useCallback(\n (onSuccess?: () => void) =>\n authClient.signOut(() => {\n // Clear cached session/purchases so isLoggedIn, isPurchased and\n // isSubscribed stop serving the signed-out user immediately.\n queryClient.setQueryData([\"us-auth-session\"], null);\n queryClient.removeQueries({ queryKey: [\"us-auth-purchases\"] });\n // Drop the identified PostHog person so the next user starts fresh.\n tracking?.reset();\n onSuccess?.();\n }),\n [authClient, queryClient, tracking],\n );\n\n const isPurchased = useCallback(\n (priceIds: string[]): boolean => {\n if (!purchases) return false;\n return purchases.paddle.transactions.some(\n (tra) =>\n tra.items.some((item) => priceIds.includes(item)) &&\n !isPaddleTransactionRevoked(tra.adjustments),\n );\n },\n [purchases],\n );\n\n const isSubscribed = useCallback(\n (priceIds: string[], productId: string): boolean => {\n if (!purchases) return false;\n\n const paddleSubscriptions = purchases.paddle.subscriptions.some(\n (sub) =>\n sub.items.some(\n (item) =>\n priceIds.includes(item.priceId) || productId === item.productId,\n ) && sub.status === \"active\",\n );\n\n const stripeSubscriptions = purchases.stripe.some(\n (sub) =>\n sub.status === \"active\" &&\n sub.items.some((item) => priceIds.includes(item)),\n );\n\n return paddleSubscriptions || stripeSubscriptions;\n },\n [purchases],\n );\n\n return (\n <AuthContext.Provider\n value={{\n session: session ?? null,\n isSessionFetching,\n refetchSession: async () => {\n await refetchSession();\n },\n purchases: purchases ?? null,\n isPurchasesFetching,\n refetchPurchases: async () => {\n await refetchPurchases();\n },\n signOut,\n getLoginUrl,\n getCheckoutUrl,\n captureFeatureUsed,\n captureCheckoutStarted,\n registerProduct,\n isSubscribed,\n isPurchased,\n isLoggedIn,\n }}\n >\n {children}\n </AuthContext.Provider>\n );\n};\n","import { useContext } from \"react\";\nimport { AuthContext } from \"./AuthContext\";\n\nexport function useAuth() {\n const ctx = useContext(AuthContext);\n if (!ctx) {\n throw new Error(\"useAuth must be used within an AuthProvider\");\n }\n return ctx;\n}\n","export const RESEND_COOLDOWN_SECONDS = 30;\n\nexport function remainingCooldownSeconds(\n availableAt: number,\n now: number,\n): number {\n return Math.max(0, Math.ceil((availableAt - now) / 1000));\n}\n\nexport function resendButtonLabel(label: string, remainingSeconds: number) {\n return remainingSeconds > 0 ? `${label} (${remainingSeconds}s)` : label;\n}\n","import { useCallback, useMemo, useState } from \"react\";\nimport z from \"zod\";\nexport type EmailOtpAuthClient = {\n emailOtp: {\n sendVerificationOtp: (input: {\n email: string;\n type: \"sign-in\";\n }) => Promise<{ error?: unknown }>;\n };\n signIn: {\n emailOtp: (input: {\n email: string;\n otp: string;\n }) => Promise<{ error?: unknown }>;\n };\n};\nimport {\n remainingCooldownSeconds,\n RESEND_COOLDOWN_SECONDS,\n} from \"./resendCooldown\";\n\nconst emailSchema = z.email();\nconst otpSchema = z\n .string()\n .min(6)\n .max(6)\n .refine((otp) => otp.match(/^[0-9]{6}$/));\n\nexport type EmailOtpLoginFlowOptions = {\n authClient: EmailOtpAuthClient;\n onVerified: () => void | Promise<void>;\n onSendSuccess?: () => void;\n onSendError?: (error: unknown) => void;\n onVerifyError?: (error: unknown) => void;\n resendCooldownSeconds?: number;\n};\n\nexport function useEmailOtpLoginFlow({\n authClient,\n onVerified,\n onSendSuccess,\n onSendError,\n onVerifyError,\n resendCooldownSeconds = RESEND_COOLDOWN_SECONDS,\n}: EmailOtpLoginFlowOptions) {\n const [step, setStep] = useState<\"email\" | \"otp\">(\"email\");\n const [email, setEmail] = useState(\"\");\n const [otp, setOtp] = useState(\"\");\n const [submitting, setSubmitting] = useState(false);\n const [verifying, setVerifying] = useState(false);\n const [resending, setResending] = useState(false);\n const [availableAt, setAvailableAt] = useState(\n () => Date.now() + resendCooldownSeconds * 1000,\n );\n const [now, setNow] = useState(() => Date.now());\n\n const emailValid = useMemo(\n () => emailSchema.safeParse(email).success,\n [email],\n );\n const otpValid = useMemo(() => otpSchema.safeParse(otp).success, [otp]);\n const remainingSeconds = remainingCooldownSeconds(availableAt, now);\n const isCoolingDown = remainingSeconds > 0;\n\n const restartResendCooldown = useCallback(() => {\n const timestamp = Date.now();\n setNow(timestamp);\n setAvailableAt(timestamp + resendCooldownSeconds * 1000);\n }, [resendCooldownSeconds]);\n\n const sendOtp = useCallback(async () => {\n const { error } = await authClient.emailOtp.sendVerificationOtp({\n email,\n type: \"sign-in\",\n });\n if (error) throw error;\n }, [authClient, email]);\n\n const submitEmail = useCallback(async () => {\n if (!emailValid) return;\n setSubmitting(true);\n try {\n await sendOtp();\n onSendSuccess?.();\n setStep(\"otp\");\n } catch (error) {\n onSendError?.(error);\n } finally {\n setSubmitting(false);\n }\n }, [emailValid, sendOtp, onSendSuccess, onSendError]);\n\n const resendOtp = useCallback(async () => {\n if (resending || isCoolingDown) return;\n setResending(true);\n try {\n await sendOtp();\n restartResendCooldown();\n onSendSuccess?.();\n } catch (error) {\n onSendError?.(error);\n } finally {\n setResending(false);\n }\n }, [\n resending,\n isCoolingDown,\n sendOtp,\n restartResendCooldown,\n onSendSuccess,\n onSendError,\n ]);\n\n const verifyOtp = useCallback(async () => {\n if (!otpValid) return;\n setVerifying(true);\n try {\n const { error } = await authClient.signIn.emailOtp({ email, otp });\n if (error) throw error;\n await onVerified();\n } catch (error) {\n onVerifyError?.(error);\n setVerifying(false);\n }\n }, [otpValid, authClient, email, otp, onVerified, onVerifyError]);\n\n const backToEmail = useCallback(() => {\n setStep(\"email\");\n setOtp(\"\");\n }, []);\n\n return {\n step,\n email,\n setEmail,\n otp,\n setOtp,\n emailValid,\n otpValid,\n submitting,\n verifying,\n resending,\n remainingSeconds,\n isCoolingDown,\n submitEmail,\n resendOtp,\n verifyOtp,\n backToEmail,\n setNow,\n availableAt,\n };\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uninspired/auth-client",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Auth client for Uninspired Studio Products",
|
|
5
5
|
"author": "Chris Kolb <chris@uninspired.studio>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"check": "tsc --noEmit",
|
|
46
46
|
"lint": "eslint .",
|
|
47
47
|
"test": "bun test",
|
|
48
|
-
"prepack": "
|
|
48
|
+
"prepack": "node ../../scripts/apply-publish-config.mjs apply",
|
|
49
49
|
"postpack": "node ../../scripts/apply-publish-config.mjs restore"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|