@rift-finance/react 0.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/dist/rift-react.cjs +2 -0
- package/dist/rift-react.cjs.map +1 -0
- package/dist/rift-react.js +381 -0
- package/dist/rift-react.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const k=require("react/jsx-runtime"),r=require("react");let u=null,E=!1,S=[],h=null;const d=new Map;function H(){return`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,9)}`}function N(e){if(typeof document>"u")return Promise.reject(new Error("Cannot mount refresh iframe outside the browser"));if(u&&E)return Promise.resolve();if(h=new URL(e.widgetUrl).origin,!u){u=document.createElement("iframe"),u.setAttribute("aria-hidden","true"),u.setAttribute("tabindex","-1"),u.title="Rift session refresh",u.style.cssText="position:absolute;width:1px;height:1px;border:0;opacity:0;pointer-events:none;left:-9999px;top:-9999px;";const i=new URLSearchParams({key:e.apiKey,headless:"1"});u.src=`${e.widgetUrl.replace(/\/$/,"")}/?${i.toString()}`,document.body.appendChild(u),window.addEventListener("message",o=>{if(o.origin!==h)return;const t=o.data;if(!(!t||typeof t!="object"||typeof t.type!="string")&&t.type.startsWith("rift:")){if(t.type==="rift:ready"){E=!0,S.forEach(n=>n()),S=[];return}if(t.type==="rift:refresh-result"){const n=d.get(t.requestId);n&&(d.delete(t.requestId),n.resolve({accessToken:t.accessToken,expiresAt:t.expiresAt,expiresIn:t.expiresIn}));return}if(t.type==="rift:refresh-error"){const n=d.get(t.requestId);n&&(d.delete(t.requestId),n.reject(new Error(t.message||"Refresh failed")));return}if(t.type==="rift:logout-result"){const n=d.get(t.requestId);n&&(d.delete(t.requestId),n.resolve({accessToken:"",expiresAt:"",expiresIn:0}))}}})}return E?Promise.resolve():new Promise(i=>{S.push(i),setTimeout(()=>{if(!E){const o=S.shift();o&&o()}},8e3)})}async function F(e){if(await N(e),!u?.contentWindow||!h)throw new Error("Refresh iframe is not available");const i=H();return new Promise((o,t)=>{d.set(i,{resolve:o,reject:t}),u.contentWindow.postMessage({type:"rift:refresh-request",requestId:i},h),setTimeout(()=>{const n=d.get(i);n&&(d.delete(i),n.reject(new Error("Refresh timed out")))},1e4)})}async function X(e){try{if(await N(e),!u?.contentWindow||!h)return;const i=H();await new Promise(o=>{d.set(i,{resolve:()=>o(),reject:()=>o()}),u.contentWindow.postMessage({type:"rift:logout-request",requestId:i},h),setTimeout(()=>{d.delete(i),o()},5e3)})}catch{}}const Z="https://widget.riftfi.xyz",L="rift:identity",K=60,z=r.createContext(null);function Y(){const e=r.useContext(z);if(!e)throw new Error("[@rift/react] useRift() / <RiftAuth> must be used inside <RiftProvider>");return e}function ee(){if(typeof window>"u")return null;try{const e=localStorage.getItem(L);return e?JSON.parse(e):null}catch{return null}}function te(e){if(!(typeof window>"u"))try{e?localStorage.setItem(L,JSON.stringify(e)):localStorage.removeItem(L)}catch{}}function re({apiKey:e,widgetUrl:i,children:o,autoOpen:t=!1,persist:n=!0}){const a=i||Z,w=r.useMemo(()=>{try{return new URL(a).origin}catch{return a}},[a]),[g,A]=r.useState(null),[m,y]=r.useState(!1),[b,G]=r.useState("signin"),[j,I]=r.useState(!1),[C,O]=r.useState(null),[P,J]=r.useState(540),[U,B]=r.useState(0),T=r.useRef(null);T.current=g;const x=r.useRef(null),l=r.useCallback(s=>{A(s),n&&te(s?{user:s.user,address:s.address,btcAddress:s.btcAddress}:null)},[n]);r.useEffect(()=>{if(!n)return;const s=ee();if(!s)return;let f=!0;return(async()=>{try{const c=await F({apiKey:e,widgetUrl:a});if(!f)return;l({user:s.user,address:s.address,btcAddress:s.btcAddress,accessToken:c.accessToken,expiresAt:c.expiresAt})}catch{if(!f)return;l(null)}})(),()=>{f=!1}},[]);const v=r.useCallback(s=>{G(s?.mode||"signin"),O(null),I(!1),B(f=>f+1),y(!0)},[]),R=r.useCallback(()=>{y(!1),I(!1)},[]),q=r.useCallback(async()=>{await X({apiKey:e,widgetUrl:a}),l(null)},[e,a,l]),M=r.useCallback(async()=>{const s=T.current;if(!s)throw new Error("Not signed in");const f=s.expiresAt?new Date(s.expiresAt).getTime():null,c=Date.now();return!(!f||f-c<K*1e3)&&s.accessToken?s.accessToken:(x.current||(x.current=(async()=>{try{const p=await F({apiKey:e,widgetUrl:a}),D=T.current;if(!D)throw new Error("Signed out during refresh");const V={...D,accessToken:p.accessToken,expiresAt:p.expiresAt};return l(V),p.accessToken}catch(p){throw l(null),p instanceof Error?p:new Error(String(p))}finally{x.current=null}})()),x.current)},[e,a,l]);r.useEffect(()=>{if(typeof window>"u")return;const s=f=>{if(f.origin!==w)return;const c=f.data;if(!(!c||typeof c!="object"||typeof c.type!="string")&&c.type.startsWith("rift:"))switch(c.type){case"rift:ready":m&&I(!0);break;case"rift:close":R();break;case"rift:resize":J(Math.max(360,Math.min(820,c.height+8)));break;case"rift:signin-success":{const $={user:c.user,address:c.address,btcAddress:c.btcAddress,accessToken:c.accessToken,expiresAt:c.expiresAt};l($),y(!1);break}case"rift:signin-error":O(c.message);break}};return window.addEventListener("message",s),()=>window.removeEventListener("message",s)},[w,R,l,m]),r.useEffect(()=>{if(!(typeof document>"u")&&m){const s=document.documentElement.style.overflow;return document.documentElement.style.overflow="hidden",()=>{document.documentElement.style.overflow=s}}},[m]),r.useEffect(()=>{t&&!g&&v()},[]);const _=r.useMemo(()=>{const s=new URLSearchParams({key:e,mode:b,origin:typeof window<"u"?window.location.origin:"",t:String(U)});return`${a.replace(/\/$/,"")}/?${s.toString()}`},[e,b,U,a]),W=r.useCallback(()=>{},[]),Q=r.useMemo(()=>({apiKey:e,widgetUrl:a,user:g,isOpen:m,isReady:j,error:C,open:v,close:R,signOut:q,getAccessToken:M,_iframeSrc:_,_iframeHeight:P,_onIframeLoad:W}),[e,a,g,m,j,C,v,R,q,M,_,P,W]);return k.jsx(z.Provider,{value:Q,children:o})}function se({onSuccess:e,onError:i,onClose:o}){const{isOpen:t,isReady:n,error:a,close:w,user:g,_iframeSrc:A,_iframeHeight:m,_onIframeLoad:y}=Y();return r.useEffect(()=>{g&&e&&e(g)},[g,e]),r.useEffect(()=>{a&&i&&i(a)},[a,i]),r.useEffect(()=>{!t&&o&&o()},[t]),t?k.jsxs("div",{role:"dialog","aria-modal":"true","aria-label":"Sign in",onClick:b=>{b.target===b.currentTarget&&w()},style:{position:"fixed",inset:0,zIndex:2147483646,background:"rgba(15,15,20,0.55)",backdropFilter:"blur(6px)",WebkitBackdropFilter:"blur(6px)",display:"flex",alignItems:"center",justifyContent:"center",padding:16,animation:"rift-fade 180ms ease-out"},children:[k.jsx("style",{children:"@keyframes rift-fade { from { opacity: 0 } to { opacity: 1 } }"}),!n&&k.jsx("div",{"aria-hidden":!0,style:{position:"absolute",color:"rgba(255,255,255,0.75)",fontSize:13,fontFamily:"Inter, ui-sans-serif, system-ui, sans-serif"},children:"Loading sign-in…"}),k.jsx("iframe",{src:A,onLoad:y,title:"Rift sign-in",allow:"publickey-credentials-get; identity-credentials-get",style:{border:0,background:"transparent",colorScheme:"light",width:"100%",maxWidth:480,height:m,borderRadius:18,boxShadow:"0 24px 60px -12px rgba(0,0,0,0.35)",transition:"height 200ms ease",opacity:n?1:0}})]}):null}function ne(){const{user:e,isOpen:i,open:o,close:t,signOut:n,getAccessToken:a,error:w}=Y();return{user:e,isAuthenticated:!!e,isOpen:i,open:o,close:t,signOut:n,getAccessToken:a,error:w}}exports.RiftAuth=se;exports.RiftProvider=re;exports.useRift=ne;
|
|
2
|
+
//# sourceMappingURL=rift-react.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rift-react.cjs","sources":["../src/silentRefresh.ts","../src/RiftProvider.tsx","../src/RiftAuth.tsx","../src/useRift.ts"],"sourcesContent":["/**\n * Silent-refresh bridge.\n *\n * The v2 backend session sits behind an httpOnly refresh cookie scoped\n * to the widget origin (widget.riftfi.xyz → service.riftfi.xyz). The\n * cookie cannot be read or sent from the merchant's own JS — only\n * widget-origin code can use it. So to refresh, we mount a HIDDEN\n * widget iframe in `?headless=1` mode and ask it (via postMessage) to\n * call /auth/refresh on our behalf. It posts the new access token back.\n *\n * This module owns that iframe as a singleton: we lazily create it on\n * the first refresh request, keep it alive across the page's lifetime,\n * and use a requestId-based pending map so concurrent refresh calls\n * dedupe to one network round trip.\n */\n\nlet iframe: HTMLIFrameElement | null = null;\nlet ready = false;\nlet readyResolvers: Array<() => void> = [];\nlet widgetOrigin: string | null = null;\n\ninterface Pending {\n resolve: (value: RefreshSuccess) => void;\n reject: (err: Error) => void;\n}\nconst pending = new Map<string, Pending>();\n\nexport interface RefreshSuccess {\n accessToken: string;\n expiresAt: string;\n expiresIn: number;\n}\n\nfunction uuid(): string {\n // Lightweight ID — doesn't need crypto strength, just unique per page.\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 9)}`;\n}\n\nfunction ensureMounted(opts: { apiKey: string; widgetUrl: string }): Promise<void> {\n if (typeof document === \"undefined\") {\n return Promise.reject(new Error(\"Cannot mount refresh iframe outside the browser\"));\n }\n if (iframe && ready) return Promise.resolve();\n\n widgetOrigin = new URL(opts.widgetUrl).origin;\n\n if (!iframe) {\n iframe = document.createElement(\"iframe\");\n iframe.setAttribute(\"aria-hidden\", \"true\");\n iframe.setAttribute(\"tabindex\", \"-1\");\n iframe.title = \"Rift session refresh\";\n iframe.style.cssText =\n \"position:absolute;width:1px;height:1px;border:0;opacity:0;pointer-events:none;left:-9999px;top:-9999px;\";\n const params = new URLSearchParams({\n key: opts.apiKey,\n headless: \"1\",\n });\n iframe.src = `${opts.widgetUrl.replace(/\\/$/, \"\")}/?${params.toString()}`;\n document.body.appendChild(iframe);\n\n window.addEventListener(\"message\", (e) => {\n if (e.origin !== widgetOrigin) return;\n const data = e.data;\n if (!data || typeof data !== \"object\" || typeof data.type !== \"string\") return;\n if (!data.type.startsWith(\"rift:\")) return;\n\n if (data.type === \"rift:ready\") {\n ready = true;\n readyResolvers.forEach((r) => r());\n readyResolvers = [];\n return;\n }\n if (data.type === \"rift:refresh-result\") {\n const slot = pending.get(data.requestId);\n if (slot) {\n pending.delete(data.requestId);\n slot.resolve({\n accessToken: data.accessToken,\n expiresAt: data.expiresAt,\n expiresIn: data.expiresIn,\n });\n }\n return;\n }\n if (data.type === \"rift:refresh-error\") {\n const slot = pending.get(data.requestId);\n if (slot) {\n pending.delete(data.requestId);\n slot.reject(new Error(data.message || \"Refresh failed\"));\n }\n return;\n }\n if (data.type === \"rift:logout-result\") {\n const slot = pending.get(data.requestId);\n if (slot) {\n pending.delete(data.requestId);\n slot.resolve({ accessToken: \"\", expiresAt: \"\", expiresIn: 0 });\n }\n }\n });\n }\n\n if (ready) return Promise.resolve();\n return new Promise((resolve) => {\n readyResolvers.push(resolve);\n // Safety net: if the iframe somehow never posts ready (e.g. blocked\n // by browser privacy mode), reject after 8s so callers can surface\n // a useful error.\n setTimeout(() => {\n if (!ready) {\n const r = readyResolvers.shift();\n if (r) r();\n }\n }, 8000);\n });\n}\n\nexport async function silentRefresh(opts: {\n apiKey: string;\n widgetUrl: string;\n}): Promise<RefreshSuccess> {\n await ensureMounted(opts);\n if (!iframe?.contentWindow || !widgetOrigin) {\n throw new Error(\"Refresh iframe is not available\");\n }\n const requestId = uuid();\n return new Promise<RefreshSuccess>((resolve, reject) => {\n pending.set(requestId, { resolve, reject });\n iframe!.contentWindow!.postMessage(\n { type: \"rift:refresh-request\", requestId },\n widgetOrigin!\n );\n setTimeout(() => {\n const slot = pending.get(requestId);\n if (slot) {\n pending.delete(requestId);\n slot.reject(new Error(\"Refresh timed out\"));\n }\n }, 10000);\n });\n}\n\nexport async function silentLogout(opts: {\n apiKey: string;\n widgetUrl: string;\n}): Promise<void> {\n try {\n await ensureMounted(opts);\n if (!iframe?.contentWindow || !widgetOrigin) return;\n const requestId = uuid();\n await new Promise<void>((resolve) => {\n pending.set(requestId, {\n resolve: () => resolve(),\n reject: () => resolve(), // logout is idempotent — never reject\n });\n iframe!.contentWindow!.postMessage(\n { type: \"rift:logout-request\", requestId },\n widgetOrigin!\n );\n setTimeout(() => {\n pending.delete(requestId);\n resolve();\n }, 5000);\n });\n } catch {\n /* logout is best-effort */\n }\n}\n","import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from \"react\";\nimport type { RiftConfig, RiftEvent, RiftMode, RiftUser } from \"./types\";\nimport { silentLogout, silentRefresh } from \"./silentRefresh\";\n\nconst DEFAULT_WIDGET_URL = \"https://widget.riftfi.xyz\";\n\n// v2 session-mode policy: the access token lives in memory only. We\n// persist a small \"identity hint\" (user id, address, btcAddress) so the\n// UI can render an authenticated state on hard reload, but the actual\n// access JWT is re-issued via the refresh cookie. Refresh tokens live\n// in an httpOnly cookie scoped to the widget origin — totally invisible\n// to this code, which is the whole point.\nconst IDENTITY_STORAGE_KEY = \"rift:identity\";\n\ninterface PersistedIdentity {\n user: string;\n address: string;\n btcAddress?: string;\n}\n\n// Refresh proactively this many seconds before the access token expires.\n// Keeps API calls from racing the actual expiry.\nconst REFRESH_LEEWAY_SECONDS = 60;\n\ninterface RiftContextValue {\n apiKey: string;\n widgetUrl: string;\n user: RiftUser | null;\n isOpen: boolean;\n isReady: boolean;\n error: string | null;\n open: (opts?: { mode?: RiftMode }) => void;\n close: () => void;\n signOut: () => Promise<void>;\n /**\n * Returns a valid access token, refreshing silently if the current\n * one is missing or about to expire. Rejects if the user is signed\n * out or the refresh fails (in which case state is cleared and the\n * caller should prompt re-auth).\n */\n getAccessToken: () => Promise<string>;\n _iframeSrc: string;\n _iframeHeight: number;\n _onIframeLoad: () => void;\n}\n\nconst RiftContext = createContext<RiftContextValue | null>(null);\n\nexport function useRiftContext(): RiftContextValue {\n const ctx = useContext(RiftContext);\n if (!ctx) {\n throw new Error(\n \"[@rift/react] useRift() / <RiftAuth> must be used inside <RiftProvider>\"\n );\n }\n return ctx;\n}\n\ninterface RiftProviderProps extends RiftConfig {\n children: ReactNode;\n // Auto-open the modal on mount. Most apps will leave this false and call\n // open() in response to a user clicking \"Sign in\".\n autoOpen?: boolean;\n // Restore the persisted identity (just the user id / address — never\n // the access token) on mount, then silently refresh to mint a token.\n // Default: true.\n persist?: boolean;\n}\n\nfunction loadIdentity(): PersistedIdentity | null {\n if (typeof window === \"undefined\") return null;\n try {\n const raw = localStorage.getItem(IDENTITY_STORAGE_KEY);\n return raw ? (JSON.parse(raw) as PersistedIdentity) : null;\n } catch {\n return null;\n }\n}\n\nfunction saveIdentity(id: PersistedIdentity | null) {\n if (typeof window === \"undefined\") return;\n try {\n if (id) localStorage.setItem(IDENTITY_STORAGE_KEY, JSON.stringify(id));\n else localStorage.removeItem(IDENTITY_STORAGE_KEY);\n } catch {\n /* private mode / quota — non-fatal */\n }\n}\n\nexport function RiftProvider({\n apiKey,\n widgetUrl,\n children,\n autoOpen = false,\n persist = true,\n}: RiftProviderProps) {\n const resolvedWidgetUrl = widgetUrl || DEFAULT_WIDGET_URL;\n const widgetOrigin = useMemo(() => {\n try {\n return new URL(resolvedWidgetUrl).origin;\n } catch {\n return resolvedWidgetUrl;\n }\n }, [resolvedWidgetUrl]);\n\n const [user, setUser] = useState<RiftUser | null>(null);\n const [isOpen, setIsOpen] = useState(false);\n const [mode, setMode] = useState<RiftMode>(\"signin\");\n const [isReady, setIsReady] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [iframeHeight, setIframeHeight] = useState(540);\n const [openToken, setOpenToken] = useState(0);\n\n // Hot ref to the current user — getAccessToken() reads from this so\n // it never closes over a stale React state snapshot.\n const userRef = useRef<RiftUser | null>(null);\n userRef.current = user;\n\n // Dedupe in-flight refreshes: if multiple API calls hit\n // getAccessToken() simultaneously and the token is stale, we only\n // want one network call.\n const refreshInFlight = useRef<Promise<string> | null>(null);\n\n const setAndPersist = useCallback(\n (next: RiftUser | null) => {\n setUser(next);\n if (persist) {\n saveIdentity(\n next\n ? {\n user: next.user,\n address: next.address,\n btcAddress: next.btcAddress,\n }\n : null\n );\n }\n },\n [persist]\n );\n\n // On mount, if we have a persisted identity, try a silent refresh to\n // rehydrate the access token. If it fails, drop the identity — the\n // user will be prompted to sign in again on first action.\n useEffect(() => {\n if (!persist) return;\n const identity = loadIdentity();\n if (!identity) return;\n let alive = true;\n (async () => {\n try {\n const result = await silentRefresh({\n apiKey,\n widgetUrl: resolvedWidgetUrl,\n });\n if (!alive) return;\n setAndPersist({\n user: identity.user,\n address: identity.address,\n btcAddress: identity.btcAddress,\n accessToken: result.accessToken,\n expiresAt: result.expiresAt,\n });\n } catch {\n if (!alive) return;\n // Refresh failed — likely cookie expired or revoked. Clear the\n // identity hint so the UI shows the signed-out state.\n setAndPersist(null);\n }\n })();\n return () => {\n alive = false;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const open = useCallback((opts?: { mode?: RiftMode }) => {\n setMode(opts?.mode || \"signin\");\n setError(null);\n setIsReady(false);\n setOpenToken((t) => t + 1);\n setIsOpen(true);\n }, []);\n\n const close = useCallback(() => {\n setIsOpen(false);\n setIsReady(false);\n }, []);\n\n const signOut = useCallback(async () => {\n await silentLogout({ apiKey, widgetUrl: resolvedWidgetUrl });\n setAndPersist(null);\n }, [apiKey, resolvedWidgetUrl, setAndPersist]);\n\n const getAccessToken = useCallback(async (): Promise<string> => {\n const current = userRef.current;\n if (!current) throw new Error(\"Not signed in\");\n\n const expiresAt = current.expiresAt\n ? new Date(current.expiresAt).getTime()\n : null;\n const now = Date.now();\n const needsRefresh =\n !expiresAt || expiresAt - now < REFRESH_LEEWAY_SECONDS * 1000;\n\n if (!needsRefresh && current.accessToken) {\n return current.accessToken;\n }\n\n if (refreshInFlight.current) {\n return refreshInFlight.current;\n }\n\n refreshInFlight.current = (async () => {\n try {\n const result = await silentRefresh({\n apiKey,\n widgetUrl: resolvedWidgetUrl,\n });\n const latest = userRef.current;\n if (!latest) throw new Error(\"Signed out during refresh\");\n const next: RiftUser = {\n ...latest,\n accessToken: result.accessToken,\n expiresAt: result.expiresAt,\n };\n setAndPersist(next);\n return result.accessToken;\n } catch (err: any) {\n // Refresh failed — wipe state so the host UI can prompt re-auth.\n setAndPersist(null);\n throw err instanceof Error ? err : new Error(String(err));\n } finally {\n refreshInFlight.current = null;\n }\n })();\n return refreshInFlight.current;\n }, [apiKey, resolvedWidgetUrl, setAndPersist]);\n\n // Listen for messages from the VISIBLE login iframe (not the silent\n // refresh one — that one's events are handled inside silentRefresh.ts).\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const handler = (e: MessageEvent) => {\n if (e.origin !== widgetOrigin) return;\n const data = e.data as RiftEvent | undefined;\n if (!data || typeof data !== \"object\" || typeof data.type !== \"string\") return;\n if (!data.type.startsWith(\"rift:\")) return;\n\n switch (data.type) {\n case \"rift:ready\":\n // Only treat as \"modal ready\" while it's open — the silent\n // refresh iframe also emits ready, but we don't care here.\n if (isOpen) setIsReady(true);\n break;\n case \"rift:close\":\n close();\n break;\n case \"rift:resize\":\n setIframeHeight(Math.max(360, Math.min(820, data.height + 8)));\n break;\n case \"rift:signin-success\": {\n const next: RiftUser = {\n user: data.user,\n address: data.address,\n btcAddress: data.btcAddress,\n accessToken: data.accessToken,\n expiresAt: data.expiresAt,\n };\n setAndPersist(next);\n setIsOpen(false);\n break;\n }\n case \"rift:signin-error\":\n setError(data.message);\n break;\n // refresh / logout result events belong to silentRefresh.ts —\n // ignore them here.\n }\n };\n window.addEventListener(\"message\", handler);\n return () => window.removeEventListener(\"message\", handler);\n }, [widgetOrigin, close, setAndPersist, isOpen]);\n\n // Lock host page scroll while the modal is open.\n useEffect(() => {\n if (typeof document === \"undefined\") return;\n if (isOpen) {\n const prev = document.documentElement.style.overflow;\n document.documentElement.style.overflow = \"hidden\";\n return () => {\n document.documentElement.style.overflow = prev;\n };\n }\n }, [isOpen]);\n\n useEffect(() => {\n if (autoOpen && !user) open();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const iframeSrc = useMemo(() => {\n const params = new URLSearchParams({\n key: apiKey,\n mode,\n origin: typeof window !== \"undefined\" ? window.location.origin : \"\",\n t: String(openToken),\n });\n return `${resolvedWidgetUrl.replace(/\\/$/, \"\")}/?${params.toString()}`;\n }, [apiKey, mode, openToken, resolvedWidgetUrl]);\n\n const onIframeLoad = useCallback(() => {\n /* readiness is signalled via postMessage, not the load event */\n }, []);\n\n const value = useMemo<RiftContextValue>(\n () => ({\n apiKey,\n widgetUrl: resolvedWidgetUrl,\n user,\n isOpen,\n isReady,\n error,\n open,\n close,\n signOut,\n getAccessToken,\n _iframeSrc: iframeSrc,\n _iframeHeight: iframeHeight,\n _onIframeLoad: onIframeLoad,\n }),\n [\n apiKey,\n resolvedWidgetUrl,\n user,\n isOpen,\n isReady,\n error,\n open,\n close,\n signOut,\n getAccessToken,\n iframeSrc,\n iframeHeight,\n onIframeLoad,\n ]\n );\n\n return <RiftContext.Provider value={value}>{children}</RiftContext.Provider>;\n}\n","import { useEffect } from \"react\";\nimport { useRiftContext } from \"./RiftProvider\";\nimport type { RiftUser } from \"./types\";\n\ninterface RiftAuthProps {\n // Optional event hooks so callers don't have to compose useEffect by hand.\n onSuccess?: (user: RiftUser) => void;\n onError?: (message: string) => void;\n onClose?: () => void;\n}\n\n/**\n * Renders the modal backdrop + iframe whenever the provider's `isOpen` is\n * true. Place this once near the root of your app (typically just inside\n * <RiftProvider>); call `useRift().open()` to show it.\n */\nexport function RiftAuth({ onSuccess, onError, onClose }: RiftAuthProps) {\n const {\n isOpen,\n isReady,\n error,\n close,\n user,\n _iframeSrc,\n _iframeHeight,\n _onIframeLoad,\n } = useRiftContext();\n\n useEffect(() => {\n if (user && onSuccess) onSuccess(user);\n }, [user, onSuccess]);\n\n useEffect(() => {\n if (error && onError) onError(error);\n }, [error, onError]);\n\n useEffect(() => {\n if (!isOpen && onClose) onClose();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isOpen]);\n\n if (!isOpen) return null;\n\n return (\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Sign in\"\n onClick={(e) => {\n if (e.target === e.currentTarget) close();\n }}\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483646,\n background: \"rgba(15,15,20,0.55)\",\n backdropFilter: \"blur(6px)\",\n WebkitBackdropFilter: \"blur(6px)\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: 16,\n animation: \"rift-fade 180ms ease-out\",\n }}\n >\n <style>{`@keyframes rift-fade { from { opacity: 0 } to { opacity: 1 } }`}</style>\n {!isReady && (\n <div\n aria-hidden\n style={{\n position: \"absolute\",\n color: \"rgba(255,255,255,0.75)\",\n fontSize: 13,\n fontFamily:\n \"Inter, ui-sans-serif, system-ui, sans-serif\",\n }}\n >\n Loading sign-in…\n </div>\n )}\n <iframe\n src={_iframeSrc}\n onLoad={_onIframeLoad}\n title=\"Rift sign-in\"\n allow=\"publickey-credentials-get; identity-credentials-get\"\n style={{\n border: 0,\n background: \"transparent\",\n colorScheme: \"light\",\n width: \"100%\",\n maxWidth: 480,\n height: _iframeHeight,\n borderRadius: 18,\n boxShadow: \"0 24px 60px -12px rgba(0,0,0,0.35)\",\n transition: \"height 200ms ease\",\n opacity: isReady ? 1 : 0,\n }}\n />\n </div>\n );\n}\n","import { useRiftContext } from \"./RiftProvider\";\nimport type { RiftMode, RiftUser } from \"./types\";\n\ninterface UseRiftReturn {\n user: RiftUser | null;\n isAuthenticated: boolean;\n isOpen: boolean;\n open: (opts?: { mode?: RiftMode }) => void;\n close: () => void;\n signOut: () => Promise<void>;\n /**\n * Async getter for a valid access token. Use this when calling Rift /\n * your backend — it returns the current token if fresh, or silently\n * refreshes via a hidden iframe if near expiry. Rejects when the user\n * isn't signed in or the refresh fails (in which case auth state is\n * cleared and the host should prompt re-auth).\n */\n getAccessToken: () => Promise<string>;\n error: string | null;\n}\n\n/**\n * Read auth state and drive the widget from anywhere inside <RiftProvider>.\n *\n * const { user, isAuthenticated, open, signOut, getAccessToken } = useRift();\n * return isAuthenticated\n * ? <button onClick={signOut}>Sign out</button>\n * : <button onClick={() => open({ mode: 'signup' })}>Get started</button>;\n *\n * // When calling your backend with Rift's session JWT:\n * const token = await getAccessToken();\n * fetch('/api/my-thing', { headers: { Authorization: `Bearer ${token}` } });\n */\nexport function useRift(): UseRiftReturn {\n const { user, isOpen, open, close, signOut, getAccessToken, error } =\n useRiftContext();\n return {\n user,\n isAuthenticated: !!user,\n isOpen,\n open,\n close,\n signOut,\n getAccessToken,\n error,\n };\n}\n"],"names":["iframe","ready","readyResolvers","widgetOrigin","pending","uuid","ensureMounted","opts","params","e","data","r","slot","resolve","silentRefresh","requestId","reject","silentLogout","DEFAULT_WIDGET_URL","IDENTITY_STORAGE_KEY","REFRESH_LEEWAY_SECONDS","RiftContext","createContext","useRiftContext","ctx","useContext","loadIdentity","raw","saveIdentity","id","RiftProvider","apiKey","widgetUrl","children","autoOpen","persist","resolvedWidgetUrl","useMemo","user","setUser","useState","isOpen","setIsOpen","mode","setMode","isReady","setIsReady","error","setError","iframeHeight","setIframeHeight","openToken","setOpenToken","userRef","useRef","refreshInFlight","setAndPersist","useCallback","next","useEffect","identity","alive","result","open","t","close","signOut","getAccessToken","current","expiresAt","now","latest","err","handler","prev","iframeSrc","onIframeLoad","value","jsx","RiftAuth","onSuccess","onError","onClose","_iframeSrc","_iframeHeight","_onIframeLoad","jsxs","useRift"],"mappings":"wIAgBA,IAAIA,EAAmC,KACnCC,EAAQ,GACRC,EAAoC,CAAA,EACpCC,EAA8B,KAMlC,MAAMC,MAAc,IAQpB,SAASC,GAAe,CAEtB,MAAO,GAAG,KAAK,IAAA,EAAM,SAAS,EAAE,CAAC,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,MAAM,EAAG,CAAC,CAAC,EAC7E,CAEA,SAASC,EAAcC,EAA4D,CACjF,GAAI,OAAO,SAAa,IACtB,OAAO,QAAQ,OAAO,IAAI,MAAM,iDAAiD,CAAC,EAEpF,GAAIP,GAAUC,EAAO,OAAO,QAAQ,QAAA,EAIpC,GAFAE,EAAe,IAAI,IAAII,EAAK,SAAS,EAAE,OAEnC,CAACP,EAAQ,CACXA,EAAS,SAAS,cAAc,QAAQ,EACxCA,EAAO,aAAa,cAAe,MAAM,EACzCA,EAAO,aAAa,WAAY,IAAI,EACpCA,EAAO,MAAQ,uBACfA,EAAO,MAAM,QACX,0GACF,MAAMQ,EAAS,IAAI,gBAAgB,CACjC,IAAKD,EAAK,OACV,SAAU,GAAA,CACX,EACDP,EAAO,IAAM,GAAGO,EAAK,UAAU,QAAQ,MAAO,EAAE,CAAC,KAAKC,EAAO,SAAA,CAAU,GACvE,SAAS,KAAK,YAAYR,CAAM,EAEhC,OAAO,iBAAiB,UAAYS,GAAM,CACxC,GAAIA,EAAE,SAAWN,EAAc,OAC/B,MAAMO,EAAOD,EAAE,KACf,GAAI,GAACC,GAAQ,OAAOA,GAAS,UAAY,OAAOA,EAAK,MAAS,WACzDA,EAAK,KAAK,WAAW,OAAO,EAEjC,IAAIA,EAAK,OAAS,aAAc,CAC9BT,EAAQ,GACRC,EAAe,QAASS,GAAMA,EAAA,CAAG,EACjCT,EAAiB,CAAA,EACjB,MACF,CACA,GAAIQ,EAAK,OAAS,sBAAuB,CACvC,MAAME,EAAOR,EAAQ,IAAIM,EAAK,SAAS,EACnCE,IACFR,EAAQ,OAAOM,EAAK,SAAS,EAC7BE,EAAK,QAAQ,CACX,YAAaF,EAAK,YAClB,UAAWA,EAAK,UAChB,UAAWA,EAAK,SAAA,CACjB,GAEH,MACF,CACA,GAAIA,EAAK,OAAS,qBAAsB,CACtC,MAAME,EAAOR,EAAQ,IAAIM,EAAK,SAAS,EACnCE,IACFR,EAAQ,OAAOM,EAAK,SAAS,EAC7BE,EAAK,OAAO,IAAI,MAAMF,EAAK,SAAW,gBAAgB,CAAC,GAEzD,MACF,CACA,GAAIA,EAAK,OAAS,qBAAsB,CACtC,MAAME,EAAOR,EAAQ,IAAIM,EAAK,SAAS,EACnCE,IACFR,EAAQ,OAAOM,EAAK,SAAS,EAC7BE,EAAK,QAAQ,CAAE,YAAa,GAAI,UAAW,GAAI,UAAW,EAAG,EAEjE,EACF,CAAC,CACH,CAEA,OAAIX,EAAc,QAAQ,QAAA,EACnB,IAAI,QAASY,GAAY,CAC9BX,EAAe,KAAKW,CAAO,EAI3B,WAAW,IAAM,CACf,GAAI,CAACZ,EAAO,CACV,MAAMU,EAAIT,EAAe,MAAA,EACrBS,GAAGA,EAAA,CACT,CACF,EAAG,GAAI,CACT,CAAC,CACH,CAEA,eAAsBG,EAAcP,EAGR,CAE1B,GADA,MAAMD,EAAcC,CAAI,EACpB,CAACP,GAAQ,eAAiB,CAACG,EAC7B,MAAM,IAAI,MAAM,iCAAiC,EAEnD,MAAMY,EAAYV,EAAA,EAClB,OAAO,IAAI,QAAwB,CAACQ,EAASG,IAAW,CACtDZ,EAAQ,IAAIW,EAAW,CAAE,QAAAF,EAAS,OAAAG,EAAQ,EAC1ChB,EAAQ,cAAe,YACrB,CAAE,KAAM,uBAAwB,UAAAe,CAAA,EAChCZ,CAAA,EAEF,WAAW,IAAM,CACf,MAAMS,EAAOR,EAAQ,IAAIW,CAAS,EAC9BH,IACFR,EAAQ,OAAOW,CAAS,EACxBH,EAAK,OAAO,IAAI,MAAM,mBAAmB,CAAC,EAE9C,EAAG,GAAK,CACV,CAAC,CACH,CAEA,eAAsBK,EAAaV,EAGjB,CAChB,GAAI,CAEF,GADA,MAAMD,EAAcC,CAAI,EACpB,CAACP,GAAQ,eAAiB,CAACG,EAAc,OAC7C,MAAMY,EAAYV,EAAA,EAClB,MAAM,IAAI,QAAeQ,GAAY,CACnCT,EAAQ,IAAIW,EAAW,CACrB,QAAS,IAAMF,EAAA,EACf,OAAQ,IAAMA,EAAA,CAAQ,CACvB,EACDb,EAAQ,cAAe,YACrB,CAAE,KAAM,sBAAuB,UAAAe,CAAA,EAC/BZ,CAAA,EAEF,WAAW,IAAM,CACfC,EAAQ,OAAOW,CAAS,EACxBF,EAAA,CACF,EAAG,GAAI,CACT,CAAC,CACH,MAAQ,CAER,CACF,CC1JA,MAAMK,EAAqB,4BAQrBC,EAAuB,gBAUvBC,EAAyB,GAwBzBC,EAAcC,EAAAA,cAAuC,IAAI,EAExD,SAASC,GAAmC,CACjD,MAAMC,EAAMC,EAAAA,WAAWJ,CAAW,EAClC,GAAI,CAACG,EACH,MAAM,IAAI,MACR,yEAAA,EAGJ,OAAOA,CACT,CAaA,SAASE,IAAyC,CAChD,GAAI,OAAO,OAAW,IAAa,OAAO,KAC1C,GAAI,CACF,MAAMC,EAAM,aAAa,QAAQR,CAAoB,EACrD,OAAOQ,EAAO,KAAK,MAAMA,CAAG,EAA0B,IACxD,MAAQ,CACN,OAAO,IACT,CACF,CAEA,SAASC,GAAaC,EAA8B,CAClD,GAAI,SAAO,OAAW,KACtB,GAAI,CACEA,EAAI,aAAa,QAAQV,EAAsB,KAAK,UAAUU,CAAE,CAAC,EAChE,aAAa,WAAWV,CAAoB,CACnD,MAAQ,CAER,CACF,CAEO,SAASW,GAAa,CAC3B,OAAAC,EACA,UAAAC,EACA,SAAAC,EACA,SAAAC,EAAW,GACX,QAAAC,EAAU,EACZ,EAAsB,CACpB,MAAMC,EAAoBJ,GAAad,EACjCf,EAAekC,EAAAA,QAAQ,IAAM,CACjC,GAAI,CACF,OAAO,IAAI,IAAID,CAAiB,EAAE,MACpC,MAAQ,CACN,OAAOA,CACT,CACF,EAAG,CAACA,CAAiB,CAAC,EAEhB,CAACE,EAAMC,CAAO,EAAIC,EAAAA,SAA0B,IAAI,EAChD,CAACC,EAAQC,CAAS,EAAIF,EAAAA,SAAS,EAAK,EACpC,CAACG,EAAMC,CAAO,EAAIJ,EAAAA,SAAmB,QAAQ,EAC7C,CAACK,EAASC,CAAU,EAAIN,EAAAA,SAAS,EAAK,EACtC,CAACO,EAAOC,CAAQ,EAAIR,EAAAA,SAAwB,IAAI,EAChD,CAACS,EAAcC,CAAe,EAAIV,EAAAA,SAAS,GAAG,EAC9C,CAACW,EAAWC,CAAY,EAAIZ,EAAAA,SAAS,CAAC,EAItCa,EAAUC,EAAAA,OAAwB,IAAI,EAC5CD,EAAQ,QAAUf,EAKlB,MAAMiB,EAAkBD,EAAAA,OAA+B,IAAI,EAErDE,EAAgBC,EAAAA,YACnBC,GAA0B,CACzBnB,EAAQmB,CAAI,EACRvB,GACFP,GACE8B,EACI,CACE,KAAMA,EAAK,KACX,QAASA,EAAK,QACd,WAAYA,EAAK,UAAA,EAEnB,IAAA,CAGV,EACA,CAACvB,CAAO,CAAA,EAMVwB,EAAAA,UAAU,IAAM,CACd,GAAI,CAACxB,EAAS,OACd,MAAMyB,EAAWlC,GAAA,EACjB,GAAI,CAACkC,EAAU,OACf,IAAIC,EAAQ,GACZ,OAAC,SAAY,CACX,GAAI,CACF,MAAMC,EAAS,MAAMhD,EAAc,CACjC,OAAAiB,EACA,UAAWK,CAAA,CACZ,EACD,GAAI,CAACyB,EAAO,OACZL,EAAc,CACZ,KAAMI,EAAS,KACf,QAASA,EAAS,QAClB,WAAYA,EAAS,WACrB,YAAaE,EAAO,YACpB,UAAWA,EAAO,SAAA,CACnB,CACH,MAAQ,CACN,GAAI,CAACD,EAAO,OAGZL,EAAc,IAAI,CACpB,CACF,GAAA,EACO,IAAM,CACXK,EAAQ,EACV,CAEF,EAAG,CAAA,CAAE,EAEL,MAAME,EAAON,cAAalD,GAA+B,CACvDqC,EAAQrC,GAAM,MAAQ,QAAQ,EAC9ByC,EAAS,IAAI,EACbF,EAAW,EAAK,EAChBM,EAAcY,GAAMA,EAAI,CAAC,EACzBtB,EAAU,EAAI,CAChB,EAAG,CAAA,CAAE,EAECuB,EAAQR,EAAAA,YAAY,IAAM,CAC9Bf,EAAU,EAAK,EACfI,EAAW,EAAK,CAClB,EAAG,CAAA,CAAE,EAECoB,EAAUT,EAAAA,YAAY,SAAY,CACtC,MAAMxC,EAAa,CAAE,OAAAc,EAAQ,UAAWK,EAAmB,EAC3DoB,EAAc,IAAI,CACpB,EAAG,CAACzB,EAAQK,EAAmBoB,CAAa,CAAC,EAEvCW,EAAiBV,EAAAA,YAAY,SAA6B,CAC9D,MAAMW,EAAUf,EAAQ,QACxB,GAAI,CAACe,EAAS,MAAM,IAAI,MAAM,eAAe,EAE7C,MAAMC,EAAYD,EAAQ,UACtB,IAAI,KAAKA,EAAQ,SAAS,EAAE,QAAA,EAC5B,KACEE,EAAM,KAAK,IAAA,EAIjB,MAAI,EAFF,CAACD,GAAaA,EAAYC,EAAMlD,EAAyB,MAEtCgD,EAAQ,YACpBA,EAAQ,aAGbb,EAAgB,UAIpBA,EAAgB,SAAW,SAAY,CACrC,GAAI,CACF,MAAMO,EAAS,MAAMhD,EAAc,CACjC,OAAAiB,EACA,UAAWK,CAAA,CACZ,EACKmC,EAASlB,EAAQ,QACvB,GAAI,CAACkB,EAAQ,MAAM,IAAI,MAAM,2BAA2B,EACxD,MAAMb,EAAiB,CACrB,GAAGa,EACH,YAAaT,EAAO,YACpB,UAAWA,EAAO,SAAA,EAEpB,OAAAN,EAAcE,CAAI,EACXI,EAAO,WAChB,OAASU,EAAU,CAEjB,MAAAhB,EAAc,IAAI,EACZgB,aAAe,MAAQA,EAAM,IAAI,MAAM,OAAOA,CAAG,CAAC,CAC1D,QAAA,CACEjB,EAAgB,QAAU,IAC5B,CACF,GAAA,GACOA,EAAgB,QACzB,EAAG,CAACxB,EAAQK,EAAmBoB,CAAa,CAAC,EAI7CG,EAAAA,UAAU,IAAM,CACd,GAAI,OAAO,OAAW,IAAa,OACnC,MAAMc,EAAWhE,GAAoB,CACnC,GAAIA,EAAE,SAAWN,EAAc,OAC/B,MAAMO,EAAOD,EAAE,KACf,GAAI,GAACC,GAAQ,OAAOA,GAAS,UAAY,OAAOA,EAAK,MAAS,WACzDA,EAAK,KAAK,WAAW,OAAO,EAEjC,OAAQA,EAAK,KAAA,CACX,IAAK,aAGC+B,KAAmB,EAAI,EAC3B,MACF,IAAK,aACHwB,EAAA,EACA,MACF,IAAK,cACHf,EAAgB,KAAK,IAAI,IAAK,KAAK,IAAI,IAAKxC,EAAK,OAAS,CAAC,CAAC,CAAC,EAC7D,MACF,IAAK,sBAAuB,CAC1B,MAAMgD,EAAiB,CACrB,KAAMhD,EAAK,KACX,QAASA,EAAK,QACd,WAAYA,EAAK,WACjB,YAAaA,EAAK,YAClB,UAAWA,EAAK,SAAA,EAElB8C,EAAcE,CAAI,EAClBhB,EAAU,EAAK,EACf,KACF,CACA,IAAK,oBACHM,EAAStC,EAAK,OAAO,EACrB,KAAA,CAIN,EACA,cAAO,iBAAiB,UAAW+D,CAAO,EACnC,IAAM,OAAO,oBAAoB,UAAWA,CAAO,CAC5D,EAAG,CAACtE,EAAc8D,EAAOT,EAAef,CAAM,CAAC,EAG/CkB,EAAAA,UAAU,IAAM,CACd,GAAI,SAAO,SAAa,MACpBlB,EAAQ,CACV,MAAMiC,EAAO,SAAS,gBAAgB,MAAM,SAC5C,gBAAS,gBAAgB,MAAM,SAAW,SACnC,IAAM,CACX,SAAS,gBAAgB,MAAM,SAAWA,CAC5C,CACF,CACF,EAAG,CAACjC,CAAM,CAAC,EAEXkB,EAAAA,UAAU,IAAM,CACVzB,GAAY,CAACI,GAAMyB,EAAA,CAEzB,EAAG,CAAA,CAAE,EAEL,MAAMY,EAAYtC,EAAAA,QAAQ,IAAM,CAC9B,MAAM7B,EAAS,IAAI,gBAAgB,CACjC,IAAKuB,EACL,KAAAY,EACA,OAAQ,OAAO,OAAW,IAAc,OAAO,SAAS,OAAS,GACjE,EAAG,OAAOQ,CAAS,CAAA,CACpB,EACD,MAAO,GAAGf,EAAkB,QAAQ,MAAO,EAAE,CAAC,KAAK5B,EAAO,SAAA,CAAU,EACtE,EAAG,CAACuB,EAAQY,EAAMQ,EAAWf,CAAiB,CAAC,EAEzCwC,EAAenB,EAAAA,YAAY,IAAM,CAEvC,EAAG,CAAA,CAAE,EAECoB,EAAQxC,EAAAA,QACZ,KAAO,CACL,OAAAN,EACA,UAAWK,EACX,KAAAE,EACA,OAAAG,EACA,QAAAI,EACA,MAAAE,EACA,KAAAgB,EACA,MAAAE,EACA,QAAAC,EACA,eAAAC,EACA,WAAYQ,EACZ,cAAe1B,EACf,cAAe2B,CAAA,GAEjB,CACE7C,EACAK,EACAE,EACAG,EACAI,EACAE,EACAgB,EACAE,EACAC,EACAC,EACAQ,EACA1B,EACA2B,CAAA,CACF,EAGF,OAAOE,EAAAA,IAACzD,EAAY,SAAZ,CAAqB,MAAAwD,EAAe,SAAA5C,CAAA,CAAS,CACvD,CCtVO,SAAS8C,GAAS,CAAE,UAAAC,EAAW,QAAAC,EAAS,QAAAC,GAA0B,CACvE,KAAM,CACJ,OAAAzC,EACA,QAAAI,EACA,MAAAE,EACA,MAAAkB,EACA,KAAA3B,EACA,WAAA6C,EACA,cAAAC,EACA,cAAAC,CAAA,EACE9D,EAAA,EAeJ,OAbAoC,EAAAA,UAAU,IAAM,CACVrB,GAAQ0C,GAAWA,EAAU1C,CAAI,CACvC,EAAG,CAACA,EAAM0C,CAAS,CAAC,EAEpBrB,EAAAA,UAAU,IAAM,CACVZ,GAASkC,GAASA,EAAQlC,CAAK,CACrC,EAAG,CAACA,EAAOkC,CAAO,CAAC,EAEnBtB,EAAAA,UAAU,IAAM,CACV,CAAClB,GAAUyC,GAASA,EAAA,CAE1B,EAAG,CAACzC,CAAM,CAAC,EAENA,EAGH6C,EAAAA,KAAC,MAAA,CACC,KAAK,SACL,aAAW,OACX,aAAW,UACX,QAAU7E,GAAM,CACVA,EAAE,SAAWA,EAAE,eAAewD,EAAA,CACpC,EACA,MAAO,CACL,SAAU,QACV,MAAO,EACP,OAAQ,WACR,WAAY,sBACZ,eAAgB,YAChB,qBAAsB,YACtB,QAAS,OACT,WAAY,SACZ,eAAgB,SAChB,QAAS,GACT,UAAW,0BAAA,EAGb,SAAA,CAAAa,EAAAA,IAAC,SAAO,SAAA,gEAAA,CAAiE,EACxE,CAACjC,GACAiC,EAAAA,IAAC,MAAA,CACC,cAAW,GACX,MAAO,CACL,SAAU,WACV,MAAO,yBACP,SAAU,GACV,WACE,6CAAA,EAEL,SAAA,kBAAA,CAAA,EAIHA,EAAAA,IAAC,SAAA,CACC,IAAKK,EACL,OAAQE,EACR,MAAM,eACN,MAAM,sDACN,MAAO,CACL,OAAQ,EACR,WAAY,cACZ,YAAa,QACb,MAAO,OACP,SAAU,IACV,OAAQD,EACR,aAAc,GACd,UAAW,qCACX,WAAY,oBACZ,QAASvC,EAAU,EAAI,CAAA,CACzB,CAAA,CACF,CAAA,CAAA,EAxDgB,IA2DtB,CCnEO,SAAS0C,IAAyB,CACvC,KAAM,CAAE,KAAAjD,EAAM,OAAAG,EAAQ,KAAAsB,EAAM,MAAAE,EAAO,QAAAC,EAAS,eAAAC,EAAgB,MAAApB,CAAA,EAC1DxB,EAAA,EACF,MAAO,CACL,KAAAe,EACA,gBAAiB,CAAC,CAACA,EACnB,OAAAG,EACA,KAAAsB,EACA,MAAAE,EACA,QAAAC,EACA,eAAAC,EACA,MAAApB,CAAA,CAEJ"}
|
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
import { jsx as T, jsxs as te } from "react/jsx-runtime";
|
|
2
|
+
import { createContext as re, useMemo as O, useState as p, useRef as z, useCallback as y, useEffect as w, useContext as ne } from "react";
|
|
3
|
+
let c = null, I = !1, E = [], x = null;
|
|
4
|
+
const d = /* @__PURE__ */ new Map();
|
|
5
|
+
function G() {
|
|
6
|
+
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 9)}`;
|
|
7
|
+
}
|
|
8
|
+
function J(e) {
|
|
9
|
+
if (typeof document > "u")
|
|
10
|
+
return Promise.reject(new Error("Cannot mount refresh iframe outside the browser"));
|
|
11
|
+
if (c && I) return Promise.resolve();
|
|
12
|
+
if (x = new URL(e.widgetUrl).origin, !c) {
|
|
13
|
+
c = document.createElement("iframe"), c.setAttribute("aria-hidden", "true"), c.setAttribute("tabindex", "-1"), c.title = "Rift session refresh", c.style.cssText = "position:absolute;width:1px;height:1px;border:0;opacity:0;pointer-events:none;left:-9999px;top:-9999px;";
|
|
14
|
+
const s = new URLSearchParams({
|
|
15
|
+
key: e.apiKey,
|
|
16
|
+
headless: "1"
|
|
17
|
+
});
|
|
18
|
+
c.src = `${e.widgetUrl.replace(/\/$/, "")}/?${s.toString()}`, document.body.appendChild(c), window.addEventListener("message", (i) => {
|
|
19
|
+
if (i.origin !== x) return;
|
|
20
|
+
const t = i.data;
|
|
21
|
+
if (!(!t || typeof t != "object" || typeof t.type != "string") && t.type.startsWith("rift:")) {
|
|
22
|
+
if (t.type === "rift:ready") {
|
|
23
|
+
I = !0, E.forEach((n) => n()), E = [];
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (t.type === "rift:refresh-result") {
|
|
27
|
+
const n = d.get(t.requestId);
|
|
28
|
+
n && (d.delete(t.requestId), n.resolve({
|
|
29
|
+
accessToken: t.accessToken,
|
|
30
|
+
expiresAt: t.expiresAt,
|
|
31
|
+
expiresIn: t.expiresIn
|
|
32
|
+
}));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (t.type === "rift:refresh-error") {
|
|
36
|
+
const n = d.get(t.requestId);
|
|
37
|
+
n && (d.delete(t.requestId), n.reject(new Error(t.message || "Refresh failed")));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (t.type === "rift:logout-result") {
|
|
41
|
+
const n = d.get(t.requestId);
|
|
42
|
+
n && (d.delete(t.requestId), n.resolve({ accessToken: "", expiresAt: "", expiresIn: 0 }));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return I ? Promise.resolve() : new Promise((s) => {
|
|
48
|
+
E.push(s), setTimeout(() => {
|
|
49
|
+
if (!I) {
|
|
50
|
+
const i = E.shift();
|
|
51
|
+
i && i();
|
|
52
|
+
}
|
|
53
|
+
}, 8e3);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
async function Y(e) {
|
|
57
|
+
if (await J(e), !c?.contentWindow || !x)
|
|
58
|
+
throw new Error("Refresh iframe is not available");
|
|
59
|
+
const s = G();
|
|
60
|
+
return new Promise((i, t) => {
|
|
61
|
+
d.set(s, { resolve: i, reject: t }), c.contentWindow.postMessage(
|
|
62
|
+
{ type: "rift:refresh-request", requestId: s },
|
|
63
|
+
x
|
|
64
|
+
), setTimeout(() => {
|
|
65
|
+
const n = d.get(s);
|
|
66
|
+
n && (d.delete(s), n.reject(new Error("Refresh timed out")));
|
|
67
|
+
}, 1e4);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
async function se(e) {
|
|
71
|
+
try {
|
|
72
|
+
if (await J(e), !c?.contentWindow || !x) return;
|
|
73
|
+
const s = G();
|
|
74
|
+
await new Promise((i) => {
|
|
75
|
+
d.set(s, {
|
|
76
|
+
resolve: () => i(),
|
|
77
|
+
reject: () => i()
|
|
78
|
+
// logout is idempotent — never reject
|
|
79
|
+
}), c.contentWindow.postMessage(
|
|
80
|
+
{ type: "rift:logout-request", requestId: s },
|
|
81
|
+
x
|
|
82
|
+
), setTimeout(() => {
|
|
83
|
+
d.delete(s), i();
|
|
84
|
+
}, 5e3);
|
|
85
|
+
});
|
|
86
|
+
} catch {
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const ie = "https://widget.riftfi.xyz", P = "rift:identity", oe = 60, B = re(null);
|
|
90
|
+
function Q() {
|
|
91
|
+
const e = ne(B);
|
|
92
|
+
if (!e)
|
|
93
|
+
throw new Error(
|
|
94
|
+
"[@rift/react] useRift() / <RiftAuth> must be used inside <RiftProvider>"
|
|
95
|
+
);
|
|
96
|
+
return e;
|
|
97
|
+
}
|
|
98
|
+
function ae() {
|
|
99
|
+
if (typeof window > "u") return null;
|
|
100
|
+
try {
|
|
101
|
+
const e = localStorage.getItem(P);
|
|
102
|
+
return e ? JSON.parse(e) : null;
|
|
103
|
+
} catch {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function ce(e) {
|
|
108
|
+
if (!(typeof window > "u"))
|
|
109
|
+
try {
|
|
110
|
+
e ? localStorage.setItem(P, JSON.stringify(e)) : localStorage.removeItem(P);
|
|
111
|
+
} catch {
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function fe({
|
|
115
|
+
apiKey: e,
|
|
116
|
+
widgetUrl: s,
|
|
117
|
+
children: i,
|
|
118
|
+
autoOpen: t = !1,
|
|
119
|
+
persist: n = !0
|
|
120
|
+
}) {
|
|
121
|
+
const o = s || ie, h = O(() => {
|
|
122
|
+
try {
|
|
123
|
+
return new URL(o).origin;
|
|
124
|
+
} catch {
|
|
125
|
+
return o;
|
|
126
|
+
}
|
|
127
|
+
}, [o]), [l, v] = p(null), [g, b] = p(!1), [k, V] = p("signin"), [_, S] = p(!1), [W, q] = p(null), [j, X] = p(540), [C, Z] = p(0), L = z(null);
|
|
128
|
+
L.current = l;
|
|
129
|
+
const R = z(null), f = y(
|
|
130
|
+
(r) => {
|
|
131
|
+
v(r), n && ce(
|
|
132
|
+
r ? {
|
|
133
|
+
user: r.user,
|
|
134
|
+
address: r.address,
|
|
135
|
+
btcAddress: r.btcAddress
|
|
136
|
+
} : null
|
|
137
|
+
);
|
|
138
|
+
},
|
|
139
|
+
[n]
|
|
140
|
+
);
|
|
141
|
+
w(() => {
|
|
142
|
+
if (!n) return;
|
|
143
|
+
const r = ae();
|
|
144
|
+
if (!r) return;
|
|
145
|
+
let u = !0;
|
|
146
|
+
return (async () => {
|
|
147
|
+
try {
|
|
148
|
+
const a = await Y({
|
|
149
|
+
apiKey: e,
|
|
150
|
+
widgetUrl: o
|
|
151
|
+
});
|
|
152
|
+
if (!u) return;
|
|
153
|
+
f({
|
|
154
|
+
user: r.user,
|
|
155
|
+
address: r.address,
|
|
156
|
+
btcAddress: r.btcAddress,
|
|
157
|
+
accessToken: a.accessToken,
|
|
158
|
+
expiresAt: a.expiresAt
|
|
159
|
+
});
|
|
160
|
+
} catch {
|
|
161
|
+
if (!u) return;
|
|
162
|
+
f(null);
|
|
163
|
+
}
|
|
164
|
+
})(), () => {
|
|
165
|
+
u = !1;
|
|
166
|
+
};
|
|
167
|
+
}, []);
|
|
168
|
+
const U = y((r) => {
|
|
169
|
+
V(r?.mode || "signin"), q(null), S(!1), Z((u) => u + 1), b(!0);
|
|
170
|
+
}, []), A = y(() => {
|
|
171
|
+
b(!1), S(!1);
|
|
172
|
+
}, []), M = y(async () => {
|
|
173
|
+
await se({ apiKey: e, widgetUrl: o }), f(null);
|
|
174
|
+
}, [e, o, f]), $ = y(async () => {
|
|
175
|
+
const r = L.current;
|
|
176
|
+
if (!r) throw new Error("Not signed in");
|
|
177
|
+
const u = r.expiresAt ? new Date(r.expiresAt).getTime() : null, a = Date.now();
|
|
178
|
+
return !(!u || u - a < oe * 1e3) && r.accessToken ? r.accessToken : (R.current || (R.current = (async () => {
|
|
179
|
+
try {
|
|
180
|
+
const m = await Y({
|
|
181
|
+
apiKey: e,
|
|
182
|
+
widgetUrl: o
|
|
183
|
+
}), N = L.current;
|
|
184
|
+
if (!N) throw new Error("Signed out during refresh");
|
|
185
|
+
const ee = {
|
|
186
|
+
...N,
|
|
187
|
+
accessToken: m.accessToken,
|
|
188
|
+
expiresAt: m.expiresAt
|
|
189
|
+
};
|
|
190
|
+
return f(ee), m.accessToken;
|
|
191
|
+
} catch (m) {
|
|
192
|
+
throw f(null), m instanceof Error ? m : new Error(String(m));
|
|
193
|
+
} finally {
|
|
194
|
+
R.current = null;
|
|
195
|
+
}
|
|
196
|
+
})()), R.current);
|
|
197
|
+
}, [e, o, f]);
|
|
198
|
+
w(() => {
|
|
199
|
+
if (typeof window > "u") return;
|
|
200
|
+
const r = (u) => {
|
|
201
|
+
if (u.origin !== h) return;
|
|
202
|
+
const a = u.data;
|
|
203
|
+
if (!(!a || typeof a != "object" || typeof a.type != "string") && a.type.startsWith("rift:"))
|
|
204
|
+
switch (a.type) {
|
|
205
|
+
case "rift:ready":
|
|
206
|
+
g && S(!0);
|
|
207
|
+
break;
|
|
208
|
+
case "rift:close":
|
|
209
|
+
A();
|
|
210
|
+
break;
|
|
211
|
+
case "rift:resize":
|
|
212
|
+
X(Math.max(360, Math.min(820, a.height + 8)));
|
|
213
|
+
break;
|
|
214
|
+
case "rift:signin-success": {
|
|
215
|
+
const H = {
|
|
216
|
+
user: a.user,
|
|
217
|
+
address: a.address,
|
|
218
|
+
btcAddress: a.btcAddress,
|
|
219
|
+
accessToken: a.accessToken,
|
|
220
|
+
expiresAt: a.expiresAt
|
|
221
|
+
};
|
|
222
|
+
f(H), b(!1);
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
case "rift:signin-error":
|
|
226
|
+
q(a.message);
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
return window.addEventListener("message", r), () => window.removeEventListener("message", r);
|
|
231
|
+
}, [h, A, f, g]), w(() => {
|
|
232
|
+
if (!(typeof document > "u") && g) {
|
|
233
|
+
const r = document.documentElement.style.overflow;
|
|
234
|
+
return document.documentElement.style.overflow = "hidden", () => {
|
|
235
|
+
document.documentElement.style.overflow = r;
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
}, [g]), w(() => {
|
|
239
|
+
t && !l && U();
|
|
240
|
+
}, []);
|
|
241
|
+
const D = O(() => {
|
|
242
|
+
const r = new URLSearchParams({
|
|
243
|
+
key: e,
|
|
244
|
+
mode: k,
|
|
245
|
+
origin: typeof window < "u" ? window.location.origin : "",
|
|
246
|
+
t: String(C)
|
|
247
|
+
});
|
|
248
|
+
return `${o.replace(/\/$/, "")}/?${r.toString()}`;
|
|
249
|
+
}, [e, k, C, o]), F = y(() => {
|
|
250
|
+
}, []), K = O(
|
|
251
|
+
() => ({
|
|
252
|
+
apiKey: e,
|
|
253
|
+
widgetUrl: o,
|
|
254
|
+
user: l,
|
|
255
|
+
isOpen: g,
|
|
256
|
+
isReady: _,
|
|
257
|
+
error: W,
|
|
258
|
+
open: U,
|
|
259
|
+
close: A,
|
|
260
|
+
signOut: M,
|
|
261
|
+
getAccessToken: $,
|
|
262
|
+
_iframeSrc: D,
|
|
263
|
+
_iframeHeight: j,
|
|
264
|
+
_onIframeLoad: F
|
|
265
|
+
}),
|
|
266
|
+
[
|
|
267
|
+
e,
|
|
268
|
+
o,
|
|
269
|
+
l,
|
|
270
|
+
g,
|
|
271
|
+
_,
|
|
272
|
+
W,
|
|
273
|
+
U,
|
|
274
|
+
A,
|
|
275
|
+
M,
|
|
276
|
+
$,
|
|
277
|
+
D,
|
|
278
|
+
j,
|
|
279
|
+
F
|
|
280
|
+
]
|
|
281
|
+
);
|
|
282
|
+
return /* @__PURE__ */ T(B.Provider, { value: K, children: i });
|
|
283
|
+
}
|
|
284
|
+
function le({ onSuccess: e, onError: s, onClose: i }) {
|
|
285
|
+
const {
|
|
286
|
+
isOpen: t,
|
|
287
|
+
isReady: n,
|
|
288
|
+
error: o,
|
|
289
|
+
close: h,
|
|
290
|
+
user: l,
|
|
291
|
+
_iframeSrc: v,
|
|
292
|
+
_iframeHeight: g,
|
|
293
|
+
_onIframeLoad: b
|
|
294
|
+
} = Q();
|
|
295
|
+
return w(() => {
|
|
296
|
+
l && e && e(l);
|
|
297
|
+
}, [l, e]), w(() => {
|
|
298
|
+
o && s && s(o);
|
|
299
|
+
}, [o, s]), w(() => {
|
|
300
|
+
!t && i && i();
|
|
301
|
+
}, [t]), t ? /* @__PURE__ */ te(
|
|
302
|
+
"div",
|
|
303
|
+
{
|
|
304
|
+
role: "dialog",
|
|
305
|
+
"aria-modal": "true",
|
|
306
|
+
"aria-label": "Sign in",
|
|
307
|
+
onClick: (k) => {
|
|
308
|
+
k.target === k.currentTarget && h();
|
|
309
|
+
},
|
|
310
|
+
style: {
|
|
311
|
+
position: "fixed",
|
|
312
|
+
inset: 0,
|
|
313
|
+
zIndex: 2147483646,
|
|
314
|
+
background: "rgba(15,15,20,0.55)",
|
|
315
|
+
backdropFilter: "blur(6px)",
|
|
316
|
+
WebkitBackdropFilter: "blur(6px)",
|
|
317
|
+
display: "flex",
|
|
318
|
+
alignItems: "center",
|
|
319
|
+
justifyContent: "center",
|
|
320
|
+
padding: 16,
|
|
321
|
+
animation: "rift-fade 180ms ease-out"
|
|
322
|
+
},
|
|
323
|
+
children: [
|
|
324
|
+
/* @__PURE__ */ T("style", { children: "@keyframes rift-fade { from { opacity: 0 } to { opacity: 1 } }" }),
|
|
325
|
+
!n && /* @__PURE__ */ T(
|
|
326
|
+
"div",
|
|
327
|
+
{
|
|
328
|
+
"aria-hidden": !0,
|
|
329
|
+
style: {
|
|
330
|
+
position: "absolute",
|
|
331
|
+
color: "rgba(255,255,255,0.75)",
|
|
332
|
+
fontSize: 13,
|
|
333
|
+
fontFamily: "Inter, ui-sans-serif, system-ui, sans-serif"
|
|
334
|
+
},
|
|
335
|
+
children: "Loading sign-in…"
|
|
336
|
+
}
|
|
337
|
+
),
|
|
338
|
+
/* @__PURE__ */ T(
|
|
339
|
+
"iframe",
|
|
340
|
+
{
|
|
341
|
+
src: v,
|
|
342
|
+
onLoad: b,
|
|
343
|
+
title: "Rift sign-in",
|
|
344
|
+
allow: "publickey-credentials-get; identity-credentials-get",
|
|
345
|
+
style: {
|
|
346
|
+
border: 0,
|
|
347
|
+
background: "transparent",
|
|
348
|
+
colorScheme: "light",
|
|
349
|
+
width: "100%",
|
|
350
|
+
maxWidth: 480,
|
|
351
|
+
height: g,
|
|
352
|
+
borderRadius: 18,
|
|
353
|
+
boxShadow: "0 24px 60px -12px rgba(0,0,0,0.35)",
|
|
354
|
+
transition: "height 200ms ease",
|
|
355
|
+
opacity: n ? 1 : 0
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
)
|
|
359
|
+
]
|
|
360
|
+
}
|
|
361
|
+
) : null;
|
|
362
|
+
}
|
|
363
|
+
function ge() {
|
|
364
|
+
const { user: e, isOpen: s, open: i, close: t, signOut: n, getAccessToken: o, error: h } = Q();
|
|
365
|
+
return {
|
|
366
|
+
user: e,
|
|
367
|
+
isAuthenticated: !!e,
|
|
368
|
+
isOpen: s,
|
|
369
|
+
open: i,
|
|
370
|
+
close: t,
|
|
371
|
+
signOut: n,
|
|
372
|
+
getAccessToken: o,
|
|
373
|
+
error: h
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
export {
|
|
377
|
+
le as RiftAuth,
|
|
378
|
+
fe as RiftProvider,
|
|
379
|
+
ge as useRift
|
|
380
|
+
};
|
|
381
|
+
//# sourceMappingURL=rift-react.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rift-react.js","sources":["../src/silentRefresh.ts","../src/RiftProvider.tsx","../src/RiftAuth.tsx","../src/useRift.ts"],"sourcesContent":["/**\n * Silent-refresh bridge.\n *\n * The v2 backend session sits behind an httpOnly refresh cookie scoped\n * to the widget origin (widget.riftfi.xyz → service.riftfi.xyz). The\n * cookie cannot be read or sent from the merchant's own JS — only\n * widget-origin code can use it. So to refresh, we mount a HIDDEN\n * widget iframe in `?headless=1` mode and ask it (via postMessage) to\n * call /auth/refresh on our behalf. It posts the new access token back.\n *\n * This module owns that iframe as a singleton: we lazily create it on\n * the first refresh request, keep it alive across the page's lifetime,\n * and use a requestId-based pending map so concurrent refresh calls\n * dedupe to one network round trip.\n */\n\nlet iframe: HTMLIFrameElement | null = null;\nlet ready = false;\nlet readyResolvers: Array<() => void> = [];\nlet widgetOrigin: string | null = null;\n\ninterface Pending {\n resolve: (value: RefreshSuccess) => void;\n reject: (err: Error) => void;\n}\nconst pending = new Map<string, Pending>();\n\nexport interface RefreshSuccess {\n accessToken: string;\n expiresAt: string;\n expiresIn: number;\n}\n\nfunction uuid(): string {\n // Lightweight ID — doesn't need crypto strength, just unique per page.\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 9)}`;\n}\n\nfunction ensureMounted(opts: { apiKey: string; widgetUrl: string }): Promise<void> {\n if (typeof document === \"undefined\") {\n return Promise.reject(new Error(\"Cannot mount refresh iframe outside the browser\"));\n }\n if (iframe && ready) return Promise.resolve();\n\n widgetOrigin = new URL(opts.widgetUrl).origin;\n\n if (!iframe) {\n iframe = document.createElement(\"iframe\");\n iframe.setAttribute(\"aria-hidden\", \"true\");\n iframe.setAttribute(\"tabindex\", \"-1\");\n iframe.title = \"Rift session refresh\";\n iframe.style.cssText =\n \"position:absolute;width:1px;height:1px;border:0;opacity:0;pointer-events:none;left:-9999px;top:-9999px;\";\n const params = new URLSearchParams({\n key: opts.apiKey,\n headless: \"1\",\n });\n iframe.src = `${opts.widgetUrl.replace(/\\/$/, \"\")}/?${params.toString()}`;\n document.body.appendChild(iframe);\n\n window.addEventListener(\"message\", (e) => {\n if (e.origin !== widgetOrigin) return;\n const data = e.data;\n if (!data || typeof data !== \"object\" || typeof data.type !== \"string\") return;\n if (!data.type.startsWith(\"rift:\")) return;\n\n if (data.type === \"rift:ready\") {\n ready = true;\n readyResolvers.forEach((r) => r());\n readyResolvers = [];\n return;\n }\n if (data.type === \"rift:refresh-result\") {\n const slot = pending.get(data.requestId);\n if (slot) {\n pending.delete(data.requestId);\n slot.resolve({\n accessToken: data.accessToken,\n expiresAt: data.expiresAt,\n expiresIn: data.expiresIn,\n });\n }\n return;\n }\n if (data.type === \"rift:refresh-error\") {\n const slot = pending.get(data.requestId);\n if (slot) {\n pending.delete(data.requestId);\n slot.reject(new Error(data.message || \"Refresh failed\"));\n }\n return;\n }\n if (data.type === \"rift:logout-result\") {\n const slot = pending.get(data.requestId);\n if (slot) {\n pending.delete(data.requestId);\n slot.resolve({ accessToken: \"\", expiresAt: \"\", expiresIn: 0 });\n }\n }\n });\n }\n\n if (ready) return Promise.resolve();\n return new Promise((resolve) => {\n readyResolvers.push(resolve);\n // Safety net: if the iframe somehow never posts ready (e.g. blocked\n // by browser privacy mode), reject after 8s so callers can surface\n // a useful error.\n setTimeout(() => {\n if (!ready) {\n const r = readyResolvers.shift();\n if (r) r();\n }\n }, 8000);\n });\n}\n\nexport async function silentRefresh(opts: {\n apiKey: string;\n widgetUrl: string;\n}): Promise<RefreshSuccess> {\n await ensureMounted(opts);\n if (!iframe?.contentWindow || !widgetOrigin) {\n throw new Error(\"Refresh iframe is not available\");\n }\n const requestId = uuid();\n return new Promise<RefreshSuccess>((resolve, reject) => {\n pending.set(requestId, { resolve, reject });\n iframe!.contentWindow!.postMessage(\n { type: \"rift:refresh-request\", requestId },\n widgetOrigin!\n );\n setTimeout(() => {\n const slot = pending.get(requestId);\n if (slot) {\n pending.delete(requestId);\n slot.reject(new Error(\"Refresh timed out\"));\n }\n }, 10000);\n });\n}\n\nexport async function silentLogout(opts: {\n apiKey: string;\n widgetUrl: string;\n}): Promise<void> {\n try {\n await ensureMounted(opts);\n if (!iframe?.contentWindow || !widgetOrigin) return;\n const requestId = uuid();\n await new Promise<void>((resolve) => {\n pending.set(requestId, {\n resolve: () => resolve(),\n reject: () => resolve(), // logout is idempotent — never reject\n });\n iframe!.contentWindow!.postMessage(\n { type: \"rift:logout-request\", requestId },\n widgetOrigin!\n );\n setTimeout(() => {\n pending.delete(requestId);\n resolve();\n }, 5000);\n });\n } catch {\n /* logout is best-effort */\n }\n}\n","import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from \"react\";\nimport type { RiftConfig, RiftEvent, RiftMode, RiftUser } from \"./types\";\nimport { silentLogout, silentRefresh } from \"./silentRefresh\";\n\nconst DEFAULT_WIDGET_URL = \"https://widget.riftfi.xyz\";\n\n// v2 session-mode policy: the access token lives in memory only. We\n// persist a small \"identity hint\" (user id, address, btcAddress) so the\n// UI can render an authenticated state on hard reload, but the actual\n// access JWT is re-issued via the refresh cookie. Refresh tokens live\n// in an httpOnly cookie scoped to the widget origin — totally invisible\n// to this code, which is the whole point.\nconst IDENTITY_STORAGE_KEY = \"rift:identity\";\n\ninterface PersistedIdentity {\n user: string;\n address: string;\n btcAddress?: string;\n}\n\n// Refresh proactively this many seconds before the access token expires.\n// Keeps API calls from racing the actual expiry.\nconst REFRESH_LEEWAY_SECONDS = 60;\n\ninterface RiftContextValue {\n apiKey: string;\n widgetUrl: string;\n user: RiftUser | null;\n isOpen: boolean;\n isReady: boolean;\n error: string | null;\n open: (opts?: { mode?: RiftMode }) => void;\n close: () => void;\n signOut: () => Promise<void>;\n /**\n * Returns a valid access token, refreshing silently if the current\n * one is missing or about to expire. Rejects if the user is signed\n * out or the refresh fails (in which case state is cleared and the\n * caller should prompt re-auth).\n */\n getAccessToken: () => Promise<string>;\n _iframeSrc: string;\n _iframeHeight: number;\n _onIframeLoad: () => void;\n}\n\nconst RiftContext = createContext<RiftContextValue | null>(null);\n\nexport function useRiftContext(): RiftContextValue {\n const ctx = useContext(RiftContext);\n if (!ctx) {\n throw new Error(\n \"[@rift/react] useRift() / <RiftAuth> must be used inside <RiftProvider>\"\n );\n }\n return ctx;\n}\n\ninterface RiftProviderProps extends RiftConfig {\n children: ReactNode;\n // Auto-open the modal on mount. Most apps will leave this false and call\n // open() in response to a user clicking \"Sign in\".\n autoOpen?: boolean;\n // Restore the persisted identity (just the user id / address — never\n // the access token) on mount, then silently refresh to mint a token.\n // Default: true.\n persist?: boolean;\n}\n\nfunction loadIdentity(): PersistedIdentity | null {\n if (typeof window === \"undefined\") return null;\n try {\n const raw = localStorage.getItem(IDENTITY_STORAGE_KEY);\n return raw ? (JSON.parse(raw) as PersistedIdentity) : null;\n } catch {\n return null;\n }\n}\n\nfunction saveIdentity(id: PersistedIdentity | null) {\n if (typeof window === \"undefined\") return;\n try {\n if (id) localStorage.setItem(IDENTITY_STORAGE_KEY, JSON.stringify(id));\n else localStorage.removeItem(IDENTITY_STORAGE_KEY);\n } catch {\n /* private mode / quota — non-fatal */\n }\n}\n\nexport function RiftProvider({\n apiKey,\n widgetUrl,\n children,\n autoOpen = false,\n persist = true,\n}: RiftProviderProps) {\n const resolvedWidgetUrl = widgetUrl || DEFAULT_WIDGET_URL;\n const widgetOrigin = useMemo(() => {\n try {\n return new URL(resolvedWidgetUrl).origin;\n } catch {\n return resolvedWidgetUrl;\n }\n }, [resolvedWidgetUrl]);\n\n const [user, setUser] = useState<RiftUser | null>(null);\n const [isOpen, setIsOpen] = useState(false);\n const [mode, setMode] = useState<RiftMode>(\"signin\");\n const [isReady, setIsReady] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [iframeHeight, setIframeHeight] = useState(540);\n const [openToken, setOpenToken] = useState(0);\n\n // Hot ref to the current user — getAccessToken() reads from this so\n // it never closes over a stale React state snapshot.\n const userRef = useRef<RiftUser | null>(null);\n userRef.current = user;\n\n // Dedupe in-flight refreshes: if multiple API calls hit\n // getAccessToken() simultaneously and the token is stale, we only\n // want one network call.\n const refreshInFlight = useRef<Promise<string> | null>(null);\n\n const setAndPersist = useCallback(\n (next: RiftUser | null) => {\n setUser(next);\n if (persist) {\n saveIdentity(\n next\n ? {\n user: next.user,\n address: next.address,\n btcAddress: next.btcAddress,\n }\n : null\n );\n }\n },\n [persist]\n );\n\n // On mount, if we have a persisted identity, try a silent refresh to\n // rehydrate the access token. If it fails, drop the identity — the\n // user will be prompted to sign in again on first action.\n useEffect(() => {\n if (!persist) return;\n const identity = loadIdentity();\n if (!identity) return;\n let alive = true;\n (async () => {\n try {\n const result = await silentRefresh({\n apiKey,\n widgetUrl: resolvedWidgetUrl,\n });\n if (!alive) return;\n setAndPersist({\n user: identity.user,\n address: identity.address,\n btcAddress: identity.btcAddress,\n accessToken: result.accessToken,\n expiresAt: result.expiresAt,\n });\n } catch {\n if (!alive) return;\n // Refresh failed — likely cookie expired or revoked. Clear the\n // identity hint so the UI shows the signed-out state.\n setAndPersist(null);\n }\n })();\n return () => {\n alive = false;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const open = useCallback((opts?: { mode?: RiftMode }) => {\n setMode(opts?.mode || \"signin\");\n setError(null);\n setIsReady(false);\n setOpenToken((t) => t + 1);\n setIsOpen(true);\n }, []);\n\n const close = useCallback(() => {\n setIsOpen(false);\n setIsReady(false);\n }, []);\n\n const signOut = useCallback(async () => {\n await silentLogout({ apiKey, widgetUrl: resolvedWidgetUrl });\n setAndPersist(null);\n }, [apiKey, resolvedWidgetUrl, setAndPersist]);\n\n const getAccessToken = useCallback(async (): Promise<string> => {\n const current = userRef.current;\n if (!current) throw new Error(\"Not signed in\");\n\n const expiresAt = current.expiresAt\n ? new Date(current.expiresAt).getTime()\n : null;\n const now = Date.now();\n const needsRefresh =\n !expiresAt || expiresAt - now < REFRESH_LEEWAY_SECONDS * 1000;\n\n if (!needsRefresh && current.accessToken) {\n return current.accessToken;\n }\n\n if (refreshInFlight.current) {\n return refreshInFlight.current;\n }\n\n refreshInFlight.current = (async () => {\n try {\n const result = await silentRefresh({\n apiKey,\n widgetUrl: resolvedWidgetUrl,\n });\n const latest = userRef.current;\n if (!latest) throw new Error(\"Signed out during refresh\");\n const next: RiftUser = {\n ...latest,\n accessToken: result.accessToken,\n expiresAt: result.expiresAt,\n };\n setAndPersist(next);\n return result.accessToken;\n } catch (err: any) {\n // Refresh failed — wipe state so the host UI can prompt re-auth.\n setAndPersist(null);\n throw err instanceof Error ? err : new Error(String(err));\n } finally {\n refreshInFlight.current = null;\n }\n })();\n return refreshInFlight.current;\n }, [apiKey, resolvedWidgetUrl, setAndPersist]);\n\n // Listen for messages from the VISIBLE login iframe (not the silent\n // refresh one — that one's events are handled inside silentRefresh.ts).\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n const handler = (e: MessageEvent) => {\n if (e.origin !== widgetOrigin) return;\n const data = e.data as RiftEvent | undefined;\n if (!data || typeof data !== \"object\" || typeof data.type !== \"string\") return;\n if (!data.type.startsWith(\"rift:\")) return;\n\n switch (data.type) {\n case \"rift:ready\":\n // Only treat as \"modal ready\" while it's open — the silent\n // refresh iframe also emits ready, but we don't care here.\n if (isOpen) setIsReady(true);\n break;\n case \"rift:close\":\n close();\n break;\n case \"rift:resize\":\n setIframeHeight(Math.max(360, Math.min(820, data.height + 8)));\n break;\n case \"rift:signin-success\": {\n const next: RiftUser = {\n user: data.user,\n address: data.address,\n btcAddress: data.btcAddress,\n accessToken: data.accessToken,\n expiresAt: data.expiresAt,\n };\n setAndPersist(next);\n setIsOpen(false);\n break;\n }\n case \"rift:signin-error\":\n setError(data.message);\n break;\n // refresh / logout result events belong to silentRefresh.ts —\n // ignore them here.\n }\n };\n window.addEventListener(\"message\", handler);\n return () => window.removeEventListener(\"message\", handler);\n }, [widgetOrigin, close, setAndPersist, isOpen]);\n\n // Lock host page scroll while the modal is open.\n useEffect(() => {\n if (typeof document === \"undefined\") return;\n if (isOpen) {\n const prev = document.documentElement.style.overflow;\n document.documentElement.style.overflow = \"hidden\";\n return () => {\n document.documentElement.style.overflow = prev;\n };\n }\n }, [isOpen]);\n\n useEffect(() => {\n if (autoOpen && !user) open();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const iframeSrc = useMemo(() => {\n const params = new URLSearchParams({\n key: apiKey,\n mode,\n origin: typeof window !== \"undefined\" ? window.location.origin : \"\",\n t: String(openToken),\n });\n return `${resolvedWidgetUrl.replace(/\\/$/, \"\")}/?${params.toString()}`;\n }, [apiKey, mode, openToken, resolvedWidgetUrl]);\n\n const onIframeLoad = useCallback(() => {\n /* readiness is signalled via postMessage, not the load event */\n }, []);\n\n const value = useMemo<RiftContextValue>(\n () => ({\n apiKey,\n widgetUrl: resolvedWidgetUrl,\n user,\n isOpen,\n isReady,\n error,\n open,\n close,\n signOut,\n getAccessToken,\n _iframeSrc: iframeSrc,\n _iframeHeight: iframeHeight,\n _onIframeLoad: onIframeLoad,\n }),\n [\n apiKey,\n resolvedWidgetUrl,\n user,\n isOpen,\n isReady,\n error,\n open,\n close,\n signOut,\n getAccessToken,\n iframeSrc,\n iframeHeight,\n onIframeLoad,\n ]\n );\n\n return <RiftContext.Provider value={value}>{children}</RiftContext.Provider>;\n}\n","import { useEffect } from \"react\";\nimport { useRiftContext } from \"./RiftProvider\";\nimport type { RiftUser } from \"./types\";\n\ninterface RiftAuthProps {\n // Optional event hooks so callers don't have to compose useEffect by hand.\n onSuccess?: (user: RiftUser) => void;\n onError?: (message: string) => void;\n onClose?: () => void;\n}\n\n/**\n * Renders the modal backdrop + iframe whenever the provider's `isOpen` is\n * true. Place this once near the root of your app (typically just inside\n * <RiftProvider>); call `useRift().open()` to show it.\n */\nexport function RiftAuth({ onSuccess, onError, onClose }: RiftAuthProps) {\n const {\n isOpen,\n isReady,\n error,\n close,\n user,\n _iframeSrc,\n _iframeHeight,\n _onIframeLoad,\n } = useRiftContext();\n\n useEffect(() => {\n if (user && onSuccess) onSuccess(user);\n }, [user, onSuccess]);\n\n useEffect(() => {\n if (error && onError) onError(error);\n }, [error, onError]);\n\n useEffect(() => {\n if (!isOpen && onClose) onClose();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isOpen]);\n\n if (!isOpen) return null;\n\n return (\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Sign in\"\n onClick={(e) => {\n if (e.target === e.currentTarget) close();\n }}\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483646,\n background: \"rgba(15,15,20,0.55)\",\n backdropFilter: \"blur(6px)\",\n WebkitBackdropFilter: \"blur(6px)\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: 16,\n animation: \"rift-fade 180ms ease-out\",\n }}\n >\n <style>{`@keyframes rift-fade { from { opacity: 0 } to { opacity: 1 } }`}</style>\n {!isReady && (\n <div\n aria-hidden\n style={{\n position: \"absolute\",\n color: \"rgba(255,255,255,0.75)\",\n fontSize: 13,\n fontFamily:\n \"Inter, ui-sans-serif, system-ui, sans-serif\",\n }}\n >\n Loading sign-in…\n </div>\n )}\n <iframe\n src={_iframeSrc}\n onLoad={_onIframeLoad}\n title=\"Rift sign-in\"\n allow=\"publickey-credentials-get; identity-credentials-get\"\n style={{\n border: 0,\n background: \"transparent\",\n colorScheme: \"light\",\n width: \"100%\",\n maxWidth: 480,\n height: _iframeHeight,\n borderRadius: 18,\n boxShadow: \"0 24px 60px -12px rgba(0,0,0,0.35)\",\n transition: \"height 200ms ease\",\n opacity: isReady ? 1 : 0,\n }}\n />\n </div>\n );\n}\n","import { useRiftContext } from \"./RiftProvider\";\nimport type { RiftMode, RiftUser } from \"./types\";\n\ninterface UseRiftReturn {\n user: RiftUser | null;\n isAuthenticated: boolean;\n isOpen: boolean;\n open: (opts?: { mode?: RiftMode }) => void;\n close: () => void;\n signOut: () => Promise<void>;\n /**\n * Async getter for a valid access token. Use this when calling Rift /\n * your backend — it returns the current token if fresh, or silently\n * refreshes via a hidden iframe if near expiry. Rejects when the user\n * isn't signed in or the refresh fails (in which case auth state is\n * cleared and the host should prompt re-auth).\n */\n getAccessToken: () => Promise<string>;\n error: string | null;\n}\n\n/**\n * Read auth state and drive the widget from anywhere inside <RiftProvider>.\n *\n * const { user, isAuthenticated, open, signOut, getAccessToken } = useRift();\n * return isAuthenticated\n * ? <button onClick={signOut}>Sign out</button>\n * : <button onClick={() => open({ mode: 'signup' })}>Get started</button>;\n *\n * // When calling your backend with Rift's session JWT:\n * const token = await getAccessToken();\n * fetch('/api/my-thing', { headers: { Authorization: `Bearer ${token}` } });\n */\nexport function useRift(): UseRiftReturn {\n const { user, isOpen, open, close, signOut, getAccessToken, error } =\n useRiftContext();\n return {\n user,\n isAuthenticated: !!user,\n isOpen,\n open,\n close,\n signOut,\n getAccessToken,\n error,\n };\n}\n"],"names":["iframe","ready","readyResolvers","widgetOrigin","pending","uuid","ensureMounted","opts","params","e","data","r","slot","resolve","silentRefresh","requestId","reject","silentLogout","DEFAULT_WIDGET_URL","IDENTITY_STORAGE_KEY","REFRESH_LEEWAY_SECONDS","RiftContext","createContext","useRiftContext","ctx","useContext","loadIdentity","raw","saveIdentity","id","RiftProvider","apiKey","widgetUrl","children","autoOpen","persist","resolvedWidgetUrl","useMemo","user","setUser","useState","isOpen","setIsOpen","mode","setMode","isReady","setIsReady","error","setError","iframeHeight","setIframeHeight","openToken","setOpenToken","userRef","useRef","refreshInFlight","setAndPersist","useCallback","next","useEffect","identity","alive","result","open","t","close","signOut","getAccessToken","current","expiresAt","now","latest","err","handler","prev","iframeSrc","onIframeLoad","value","jsx","RiftAuth","onSuccess","onError","onClose","_iframeSrc","_iframeHeight","_onIframeLoad","jsxs","useRift"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rift-finance/react",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "React bindings for the Rift sign-in widget. Drop in <RiftProvider>, render <RiftAuth>, and read auth state with useRift().",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/Rift-FI/rift-react.git"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://riftfi.xyz",
|
|
10
|
+
"keywords": [
|
|
11
|
+
"rift",
|
|
12
|
+
"rift-finance",
|
|
13
|
+
"auth",
|
|
14
|
+
"wallet",
|
|
15
|
+
"embedded-wallet",
|
|
16
|
+
"react",
|
|
17
|
+
"oauth"
|
|
18
|
+
],
|
|
19
|
+
"type": "module",
|
|
20
|
+
"main": "./dist/rift-react.cjs",
|
|
21
|
+
"module": "./dist/rift-react.js",
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"import": "./dist/rift-react.js",
|
|
27
|
+
"require": "./dist/rift-react.cjs"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist"
|
|
32
|
+
],
|
|
33
|
+
"sideEffects": false,
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsc -b && vite build",
|
|
36
|
+
"dev": "vite build --watch"
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"react": ">=18",
|
|
40
|
+
"react-dom": ">=18"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/node": "^22.19.18",
|
|
44
|
+
"@types/react": "^19.1.2",
|
|
45
|
+
"@types/react-dom": "^19.1.2",
|
|
46
|
+
"@vitejs/plugin-react": "^4.4.1",
|
|
47
|
+
"react": "^19.1.0",
|
|
48
|
+
"react-dom": "^19.1.0",
|
|
49
|
+
"typescript": "~5.8.3",
|
|
50
|
+
"vite": "^6.3.5",
|
|
51
|
+
"vite-plugin-dts": "^4.5.4"
|
|
52
|
+
}
|
|
53
|
+
}
|