sparkle-react 0.0.12 → 0.0.13

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/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import b,{useContext as ze,useEffect as Y,useState as q,createContext as Pe}from"react";import*as g from"react";import{motion as L}from"framer-motion";import{Loader2 as ee}from"lucide-react";function A({authenticate:t,loading:e}){return g.createElement("div",{className:"absolute inset-0 bg-black/60 backdrop-blur-xl"},g.createElement("div",{className:"absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 z-50 space-y-3 flex flex-col items-center max-w-xs w-full"},g.createElement("h3",{className:"font-semibold tracking-tight text-2xl"},"Counter Manager"),g.createElement(L.button,{layout:!0,className:"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground shadow hover:bg-primary/90 h-9 px-4 py-2 overflow-hidden",onClick:t,disabled:e},g.createElement(L.div,{layout:!0,key:e?"loading":"loaded",initial:{opacity:0},animate:{opacity:1},exit:{opacity:0}},e?g.createElement(ee,{className:"animate-spin"}):g.createElement("span",null,"Login with Twitch"))),g.createElement("span",{className:"text-xs"},"Powered by Sparkle")))}import m,{useContext as he}from"react";import{Loader2 as fe}from"lucide-react";import{motion as me}from"framer-motion";import*as B from"react";import{createContext as le,useCallback as F,useEffect as M,useState as O}from"react";import{decode as T}from"jsonwebtoken";var U=async(t,e)=>fetch("http://localhost:4005/auth/oat",{method:"POST",headers:{"Content-Type":"application/json","Api-Key":t.apiKey,"Project-Id":t.projectId},body:JSON.stringify({oat:e})});import{useCallback as J,useState as te,useRef as oe,useLayoutEffect as re}from"react";var E=()=>{};function k(t,...e){t&&t.addEventListener&&t.addEventListener(...e)}function S(t,...e){t&&t.removeEventListener&&t.removeEventListener(...e)}var C=typeof window<"u";var ne=(t,e,o)=>{if(!C)return[e,E,E];if(!t)throw new Error("useLocalStorage key may not be falsy");let r=o?o.raw?s=>s:o.deserializer:JSON.parse,i=oe(s=>{try{let c=o?o.raw?String:o.serializer:JSON.stringify,p=localStorage.getItem(s);return p!==null?r(p):(e&&localStorage.setItem(s,c(e)),e)}catch{return e}}),[l,n]=te(()=>i.current(t));re(()=>n(i.current(t)),[t]);let a=J(s=>{try{let c=typeof s=="function"?s(l):s;if(typeof c>"u")return;let p;o?o.raw?typeof c=="string"?p=c:p=JSON.stringify(c):o.serializer?p=o.serializer(c):p=JSON.stringify(c):p=JSON.stringify(c),localStorage.setItem(t,p),n(r(p))}catch{}},[t,n]),d=J(()=>{try{localStorage.removeItem(t),n(void 0)}catch{}},[t,n]);return[l,a,d]},N=ne;import{useEffect as ie,useState as ae}from"react";var W=(t,e)=>new URLSearchParams(t).get(e),se=t=>{let e=window.location,[o,r]=ae(()=>W(e.search,t));return ie(()=>{let i=()=>{r(W(e.search,t))};return k(window,"popstate",i),k(window,"pushstate",i),k(window,"replacestate",i),()=>{S(window,"popstate",i),S(window,"pushstate",i),S(window,"replacestate",i)}},[]),o},ce=()=>null,R=C?se:ce;var de="u9lt242tz2pn5hl5x444ls2xllnvip",pe="twitch_access_token",ue=[],h=le({account:null,token:null,loading:!0,authenticationMethod:"JWT",authenticate:()=>{},logout:()=>{}}),D=({children:t,config:e})=>{let[o,r]=N(pe,null),[i,l]=N("twitch"),n=e.oat||R("oat"),[a,d]=O(null),[s,c]=O(!1),[p,P]=O("JWT");M(()=>{if(o){let u=T(o);if(console.log(u),u.exp*1e3<Date.now()){r(null),d(null);return}d(u)}},[]),M(()=>{n&&(c(!0),U(e,n).then(u=>u.json()).then(u=>{r(u.accessToken);let w=T(u.accessToken);d(w)}).finally(()=>{c(!1),P("OAT")}))},[n]);let V=F(()=>{r(null),d(null)},[]);M(()=>{let u=new URLSearchParams(window.location.hash).get("#access_token");u&&(l(u),c(!0),fetch("http://localhost:4005/auth",{method:"POST",headers:{"Content-Type":"application/json","Api-Key":e.apiKey,"Project-Id":e.projectId},body:JSON.stringify({oat:u})}).then(w=>w.json()).then(w=>{r(w.accessToken);let v=T(w.accessToken);d(v)}).finally(()=>{c(!1),window.history.replaceState({},document.title,"/")}))},[]);let Z=F(async()=>{let u="http://localhost:3000",w=ue.join(" ");c(!0);try{if(!o)window.location.replace(`https://id.twitch.tv/oauth2/authorize?client_id=${de}&redirect_uri=${u}&response_type=token&scope=${w}&force_verify=true`);else{let v=T(o);d(v)}}catch(v){console.error("Erreur lors de l'authentification :",v)}finally{}},[o]);return B.createElement(h.Provider,{value:{authenticationMethod:p,account:a,token:o,loading:s,authenticate:Z,logout:V}},t)};function j({user:t,loading:e,logout:o}){let{authenticationMethod:r}=he(h);return r==="OAT"?null:m.createElement(me.div,{className:"bg-popover flex items-start fixed right-3 bottom-3 rounded-md ring-1 ring-white/10 flex-col p-3 gap-3 cursor-pointer shadow-md bg-black text-white",layout:!0},e||!t?m.createElement("div",{className:"flex flex-row text-muted-foreground items-center gap-2"},m.createElement("div",{className:"text-sm"},"Authenticating with Twitch..."),m.createElement(fe,{className:"animate-spin",size:16})):m.createElement("div",{className:"flex w-full flex-row items-center gap-3"},m.createElement("div",{className:"flex h-[34px] w-[34px] flex-shrink-0 items-center justify-center overflow-hidden rounded-lg bg-[#313131] text-sm"},m.createElement("img",{src:t?.profilePictureUrl||"",alt:t?.displayName+"'s profile picture",width:34,height:34})),m.createElement("div",{className:"flex w-full flex-col justify-center min-w-[124px]"},m.createElement("div",{className:"space-x-2"},m.createElement("span",{className:"text-primary text-sm font-medium capitalize"},t?.displayName)),m.createElement("span",{className:"text-muted-foreground text-xs font-normal"},"Broadcaster")),m.createElement("button",{className:"bg-red-500 rounded-md p-2 text-xs whitespace-nowrap",onClick:o},"Log Out")))}import ye,{useCallback as ve,useContext as xe,useRef as ke}from"react";import{createContext as Se,useEffect as H,useState as Ce}from"react";import f from"zod";import ge from"events";var we=f.object({type:f.literal("subscribe"),channels:f.array(f.string()),scope:f.string()}),be=f.object({type:f.literal("unsubscribe"),channels:f.string()}),ht=f.object({scope:f.enum(["__key__","__hook__"]),type:f.string(),payload:f.string()}),ft=f.union([we,be]),z=class extends ge{constructor(o){super();this.socket=null;this.queue=[];this.subscriptions=[];this.isAuthenticating=!1;this.jwt=null;this.url=o}send(o){this.socket?.readyState===WebSocket.OPEN?this.socket?.send(JSON.stringify(o)):this.queue.push(o)}authenticate(o){this.isAuthenticating||(this.isAuthenticating=!0,this.jwt=o,this.connect())}connect(){let o=this.url+"?jwt="+this.jwt;this.socket=new WebSocket(o),this.socket.onopen=()=>{this.queue.forEach(r=>this.send(r)),this.queue=[]},this.socket.onmessage=r=>{let i=JSON.parse(r.data);this.emit("message",i)},this.socket.onclose=()=>{this.reconnect()}}reconnect(){setTimeout(()=>{this.queue=[{type:"subscribe",channels:this.subscriptions,scope:"key"}],console.log("try reconnecting"),this.connect()},5e3)}subscribe(o,r="key"){let i=o.filter(l=>!this.subscriptions.includes(l));i.length&&(this.subscriptions=[...this.subscriptions,...i],console.log("subscribe",r,o),this.send({type:"subscribe",channels:o,scope:r}))}unsubscribe(o){this.send({type:"unsubscribe",channels:o})}disconnect(){this.socket&&(this.socket.onclose=()=>{},this.socket.close())}};import Te from"events";var x=Se({subscribe:()=>{},values:{},on:()=>{},off:()=>{}}),_=new Te,$=({children:t})=>{let[e,o]=Ce({}),r=ke(),{token:i}=xe(h),l=(d,s)=>{_.on(d,s)},n=(d,s)=>{_.off(d,s)};H(()=>(r.current=new z("ws://localhost:8000"),r.current.on("message",d=>{let{scope:s,payload:c,type:p}=d;if(s==="__hook__"){_.emit(p,JSON.parse(c));return}s==="__key__"&&o(P=>({...P,[p]:JSON.parse(c)}))}),()=>{r.current?.disconnect()}),[]),H(()=>{!r.current||!i||r.current.authenticate(i)},[i]);let a=ve((d,s)=>{r.current?.subscribe(d,s)},[r]);return ye.createElement(x.Provider,{value:{subscribe:a,values:e,on:l,off:n}},t)};var K=t=>({set:async(e,o)=>t.httpCall({action:"set",key:e,value:o}),get:async e=>t.httpCall({action:"get",key:e}),incr:async(e,o)=>t.httpCall({action:"incr",key:e,value:o}),decr:async(e,o)=>t.httpCall({action:"decr",key:e,value:o}),del:async e=>t.httpCall({action:"del",key:e})});var y=class{constructor(e){this.config=e,this.token=""}setToken(e){this.token=e}get database(){return K(this)}get twitch(){return null}get hook(){return null}async httpCall(e){return await fetch("http://localhost:4005/actions",{method:"POST",body:JSON.stringify(e),headers:{Authorization:`Bearer ${this.token}`,"Content-Type":"application/json"}})}},zt=new y({apiKey:"123",projectId:"123"});var Ae=({children:t})=>{let[e,o]=q(!1),{authenticate:r,logout:i,token:l,account:n,loading:a}=ze(h);return Y(()=>{o(!0)},[]),e?l?b.createElement(b.Fragment,null,b.createElement(j,{user:n,logout:i,loading:a}),n&&t):b.createElement(A,{authenticate:r,loading:a}):null},I=Pe({sparkle:void 0}),_t=({children:t,config:e})=>{let[o,r]=q();return Y(()=>{e&&r(new y(e))},[e]),b.createElement(I.Provider,{value:{sparkle:o}},b.createElement(D,{config:e},b.createElement($,{config:e},b.createElement(Ae,null,t))))};import{useContext as Ee,useEffect as Ne,useMemo as Me}from"react";function Jt(...t){let e=Ee(x),o=Me(()=>t,[t.join(",")]);if(!e)throw new Error("You must use useRealtime inside a SparkleProvider");return Ne(()=>{e.subscribe(o,"__key__")},[o]),o.map(r=>e.values[r])}import{useContext as Oe}from"react";function Bt(){let{account:t,token:e,loading:o,authenticate:r,logout:i}=Oe(h);return{account:t,token:e,loading:o,authenticate:r,logout:i}}import{useContext as X,useEffect as je}from"react";function Yt(){let{token:t}=X(h),{sparkle:e}=X(I);if(!e)throw new Error("SparkleClient not found in context");return je(()=>{t&&e.setToken(t)},[t]),e.database}import{useCallback as Q,useContext as _e,useEffect as Ie,useState as Le}from"react";function Gt(...t){let[e,o]=Le({}),{token:r}=_e(h),i=Q(async(n,a)=>(a&&typeof a=="object"&&(a=JSON.stringify(a)),await fetch("http://localhost:4005/users",{method:"POST",body:JSON.stringify({action:"set",key:n,value:a}),headers:{Authorization:`Bearer ${r}`,"Content-Type":"application/json"}})),[]),l=Q(async n=>(await fetch("http://localhost:4005/users",{method:"POST",body:JSON.stringify({action:"get",key:n}),headers:{Authorization:`Bearer ${r}`,"Content-Type":"application/json"}})).json(),[]);return Ie(()=>{(async()=>{let a=await l("coins");o({coins:a})})()},[]),{set:i,get:l,incr:async(n,a)=>await fetch("http://localhost:4005/users",{method:"POST",body:JSON.stringify({action:"incr",key:n,value:a}),headers:{Authorization:`Bearer ${r}`,"Content-Type":"application/json"}}),decr:async(n,a)=>await fetch("http://localhost:4005/users",{method:"POST",body:JSON.stringify({action:"decr",key:n,value:a}),headers:{Authorization:`Bearer ${r}`,"Content-Type":"application/json"}}),del:async n=>await fetch("http://localhost:4005/users",{method:"POST",body:JSON.stringify({action:"del",key:n}),headers:{Authorization:`Bearer ${r}`,"Content-Type":"application/json"}}),user:e}}import{useContext as Ue,useEffect as G,useState as Je}from"react";function oo(t,e){let o=Ue(x),[r,i]=Je([]);if(!o)throw new Error("You must use useHook inside a SparkleProvider");return G(()=>{let l=n=>{i(a=>[...a,n]),e?.(n)};return o.on(t,l),()=>{o.off(t,l)}},[]),G(()=>{o.subscribe([t],"__hook__")},[t]),{events:r,lastEvent:r[r.length-1]}}export{I as SparkleAppContext,_t as SparkleProvider,Bt as useAuth,Yt as useDatabase,oo as useHook,Jt as useRealtime,Gt as useUser};
1
+ import b,{useContext as ze,useEffect as Y,useState as q,createContext as Pe}from"react";import*as g from"react";import{motion as L}from"framer-motion";import{Loader2 as ee}from"lucide-react";function A({authenticate:t,loading:e}){return g.createElement("div",{className:"absolute inset-0 bg-black/60 backdrop-blur-xl"},g.createElement("div",{className:"absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 z-50 space-y-3 flex flex-col items-center max-w-xs w-full"},g.createElement("h3",{className:"font-semibold tracking-tight text-2xl"},"Counter Manager"),g.createElement(L.button,{layout:!0,className:"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground shadow hover:bg-primary/90 h-9 px-4 py-2 overflow-hidden",onClick:t,disabled:e},g.createElement(L.div,{layout:!0,key:e?"loading":"loaded",initial:{opacity:0},animate:{opacity:1},exit:{opacity:0}},e?g.createElement(ee,{className:"animate-spin"}):g.createElement("span",null,"Login with Twitch"))),g.createElement("span",{className:"text-xs"},"Powered by Sparkle")))}import m,{useContext as he}from"react";import{Loader2 as fe}from"lucide-react";import{motion as me}from"framer-motion";import*as B from"react";import{createContext as le,useCallback as F,useEffect as M,useState as O}from"react";var U=async(t,e)=>fetch("http://localhost:4005/auth/oat",{method:"POST",headers:{"Content-Type":"application/json","Api-Key":t.apiKey,"Project-Id":t.projectId},body:JSON.stringify({oat:e})});import{useCallback as J,useState as te,useRef as oe,useLayoutEffect as re}from"react";var E=()=>{};function k(t,...e){t&&t.addEventListener&&t.addEventListener(...e)}function S(t,...e){t&&t.removeEventListener&&t.removeEventListener(...e)}var C=typeof window<"u";var ne=(t,e,o)=>{if(!C)return[e,E,E];if(!t)throw new Error("useLocalStorage key may not be falsy");let r=o?o.raw?s=>s:o.deserializer:JSON.parse,i=oe(s=>{try{let c=o?o.raw?String:o.serializer:JSON.stringify,p=localStorage.getItem(s);return p!==null?r(p):(e&&localStorage.setItem(s,c(e)),e)}catch{return e}}),[l,n]=te(()=>i.current(t));re(()=>n(i.current(t)),[t]);let a=J(s=>{try{let c=typeof s=="function"?s(l):s;if(typeof c>"u")return;let p;o?o.raw?typeof c=="string"?p=c:p=JSON.stringify(c):o.serializer?p=o.serializer(c):p=JSON.stringify(c):p=JSON.stringify(c),localStorage.setItem(t,p),n(r(p))}catch{}},[t,n]),d=J(()=>{try{localStorage.removeItem(t),n(void 0)}catch{}},[t,n]);return[l,a,d]},N=ne;import{useEffect as ie,useState as ae}from"react";var W=(t,e)=>new URLSearchParams(t).get(e),se=t=>{let e=window.location,[o,r]=ae(()=>W(e.search,t));return ie(()=>{let i=()=>{r(W(e.search,t))};return k(window,"popstate",i),k(window,"pushstate",i),k(window,"replacestate",i),()=>{S(window,"popstate",i),S(window,"pushstate",i),S(window,"replacestate",i)}},[]),o},ce=()=>null,R=C?se:ce;var T=t=>({exp:1e3}),de="u9lt242tz2pn5hl5x444ls2xllnvip",pe="twitch_access_token",ue=[],h=le({account:null,token:null,loading:!0,authenticationMethod:"JWT",authenticate:()=>{},logout:()=>{}}),D=({children:t,config:e})=>{let[o,r]=N(pe,null),[i,l]=N("twitch"),n=e.oat||R("oat"),[a,d]=O(null),[s,c]=O(!1),[p,P]=O("JWT");M(()=>{if(o){let u=T(o);if(console.log(u),u.exp*1e3<Date.now()){r(null),d(null);return}d(u)}},[]),M(()=>{n&&(c(!0),U(e,n).then(u=>u.json()).then(u=>{r(u.accessToken);let w=T(u.accessToken);d(w)}).finally(()=>{c(!1),P("OAT")}))},[n]);let V=F(()=>{r(null),d(null)},[]);M(()=>{let u=new URLSearchParams(window.location.hash).get("#access_token");u&&(l(u),c(!0),fetch("http://localhost:4005/auth",{method:"POST",headers:{"Content-Type":"application/json","Api-Key":e.apiKey,"Project-Id":e.projectId},body:JSON.stringify({oat:u})}).then(w=>w.json()).then(w=>{r(w.accessToken);let v=T(w.accessToken);d(v)}).finally(()=>{c(!1),window.history.replaceState({},document.title,"/")}))},[]);let Z=F(async()=>{let u="http://localhost:3000",w=ue.join(" ");c(!0);try{if(!o)window.location.replace(`https://id.twitch.tv/oauth2/authorize?client_id=${de}&redirect_uri=${u}&response_type=token&scope=${w}&force_verify=true`);else{let v=T(o);d(v)}}catch(v){console.error("Erreur lors de l'authentification :",v)}finally{}},[o]);return B.createElement(h.Provider,{value:{authenticationMethod:p,account:a,token:o,loading:s,authenticate:Z,logout:V}},t)};function j({user:t,loading:e,logout:o}){let{authenticationMethod:r}=he(h);return r==="OAT"?null:m.createElement(me.div,{className:"bg-popover flex items-start fixed right-3 bottom-3 rounded-md ring-1 ring-white/10 flex-col p-3 gap-3 cursor-pointer shadow-md bg-black text-white",layout:!0},e||!t?m.createElement("div",{className:"flex flex-row text-muted-foreground items-center gap-2"},m.createElement("div",{className:"text-sm"},"Authenticating with Twitch..."),m.createElement(fe,{className:"animate-spin",size:16})):m.createElement("div",{className:"flex w-full flex-row items-center gap-3"},m.createElement("div",{className:"flex h-[34px] w-[34px] flex-shrink-0 items-center justify-center overflow-hidden rounded-lg bg-[#313131] text-sm"},m.createElement("img",{src:t?.profilePictureUrl||"",alt:t?.displayName+"'s profile picture",width:34,height:34})),m.createElement("div",{className:"flex w-full flex-col justify-center min-w-[124px]"},m.createElement("div",{className:"space-x-2"},m.createElement("span",{className:"text-primary text-sm font-medium capitalize"},t?.displayName)),m.createElement("span",{className:"text-muted-foreground text-xs font-normal"},"Broadcaster")),m.createElement("button",{className:"bg-red-500 rounded-md p-2 text-xs whitespace-nowrap",onClick:o},"Log Out")))}import ye,{useCallback as ve,useContext as xe,useRef as ke}from"react";import{createContext as Se,useEffect as H,useState as Ce}from"react";import f from"zod";import ge from"events";var we=f.object({type:f.literal("subscribe"),channels:f.array(f.string()),scope:f.string()}),be=f.object({type:f.literal("unsubscribe"),channels:f.string()}),ut=f.object({scope:f.enum(["__key__","__hook__"]),type:f.string(),payload:f.string()}),ht=f.union([we,be]),z=class extends ge{constructor(o){super();this.socket=null;this.queue=[];this.subscriptions=[];this.isAuthenticating=!1;this.jwt=null;this.url=o}send(o){this.socket?.readyState===WebSocket.OPEN?this.socket?.send(JSON.stringify(o)):this.queue.push(o)}authenticate(o){this.isAuthenticating||(this.isAuthenticating=!0,this.jwt=o,this.connect())}connect(){let o=this.url+"?jwt="+this.jwt;this.socket=new WebSocket(o),this.socket.onopen=()=>{this.queue.forEach(r=>this.send(r)),this.queue=[]},this.socket.onmessage=r=>{let i=JSON.parse(r.data);this.emit("message",i)},this.socket.onclose=()=>{this.reconnect()}}reconnect(){setTimeout(()=>{this.queue=[{type:"subscribe",channels:this.subscriptions,scope:"key"}],console.log("try reconnecting"),this.connect()},5e3)}subscribe(o,r="key"){let i=o.filter(l=>!this.subscriptions.includes(l));i.length&&(this.subscriptions=[...this.subscriptions,...i],console.log("subscribe",r,o),this.send({type:"subscribe",channels:o,scope:r}))}unsubscribe(o){this.send({type:"unsubscribe",channels:o})}disconnect(){this.socket&&(this.socket.onclose=()=>{},this.socket.close())}};import Te from"events";var x=Se({subscribe:()=>{},values:{},on:()=>{},off:()=>{}}),_=new Te,$=({children:t})=>{let[e,o]=Ce({}),r=ke(),{token:i}=xe(h),l=(d,s)=>{_.on(d,s)},n=(d,s)=>{_.off(d,s)};H(()=>(r.current=new z("ws://localhost:8000"),r.current.on("message",d=>{let{scope:s,payload:c,type:p}=d;if(s==="__hook__"){_.emit(p,JSON.parse(c));return}s==="__key__"&&o(P=>({...P,[p]:JSON.parse(c)}))}),()=>{r.current?.disconnect()}),[]),H(()=>{!r.current||!i||r.current.authenticate(i)},[i]);let a=ve((d,s)=>{r.current?.subscribe(d,s)},[r]);return ye.createElement(x.Provider,{value:{subscribe:a,values:e,on:l,off:n}},t)};var K=t=>({set:async(e,o)=>t.httpCall({action:"set",key:e,value:o}),get:async e=>t.httpCall({action:"get",key:e}),incr:async(e,o)=>t.httpCall({action:"incr",key:e,value:o}),decr:async(e,o)=>t.httpCall({action:"decr",key:e,value:o}),del:async e=>t.httpCall({action:"del",key:e})});var y=class{constructor(e){this.config=e,this.token=""}setToken(e){this.token=e}get database(){return K(this)}get twitch(){return null}get hook(){return null}async httpCall(e){return await fetch("http://localhost:4005/actions",{method:"POST",body:JSON.stringify(e),headers:{Authorization:`Bearer ${this.token}`,"Content-Type":"application/json"}})}},Tt=new y({apiKey:"123",projectId:"123"});var Ae=({children:t})=>{let[e,o]=q(!1),{authenticate:r,logout:i,token:l,account:n,loading:a}=ze(h);return Y(()=>{o(!0)},[]),e?l?b.createElement(b.Fragment,null,b.createElement(j,{user:n,logout:i,loading:a}),n&&t):b.createElement(A,{authenticate:r,loading:a}):null},I=Pe({sparkle:void 0}),jt=({children:t,config:e})=>{let[o,r]=q();return Y(()=>{e&&r(new y(e))},[e]),b.createElement(I.Provider,{value:{sparkle:o}},b.createElement(D,{config:e},b.createElement($,{config:e},b.createElement(Ae,null,t))))};import{useContext as Ee,useEffect as Ne,useMemo as Me}from"react";function Ut(...t){let e=Ee(x),o=Me(()=>t,[t.join(",")]);if(!e)throw new Error("You must use useRealtime inside a SparkleProvider");return Ne(()=>{e.subscribe(o,"__key__")},[o]),o.map(r=>e.values[r])}import{useContext as Oe}from"react";function Ft(){let{account:t,token:e,loading:o,authenticate:r,logout:i}=Oe(h);return{account:t,token:e,loading:o,authenticate:r,logout:i}}import{useContext as X,useEffect as je}from"react";function Kt(){let{token:t}=X(h),{sparkle:e}=X(I);if(!e)throw new Error("SparkleClient not found in context");return je(()=>{t&&e.setToken(t)},[t]),e.database}import{useCallback as Q,useContext as _e,useEffect as Ie,useState as Le}from"react";function Qt(...t){let[e,o]=Le({}),{token:r}=_e(h),i=Q(async(n,a)=>(a&&typeof a=="object"&&(a=JSON.stringify(a)),await fetch("http://localhost:4005/users",{method:"POST",body:JSON.stringify({action:"set",key:n,value:a}),headers:{Authorization:`Bearer ${r}`,"Content-Type":"application/json"}})),[]),l=Q(async n=>(await fetch("http://localhost:4005/users",{method:"POST",body:JSON.stringify({action:"get",key:n}),headers:{Authorization:`Bearer ${r}`,"Content-Type":"application/json"}})).json(),[]);return Ie(()=>{(async()=>{let a=await l("coins");o({coins:a})})()},[]),{set:i,get:l,incr:async(n,a)=>await fetch("http://localhost:4005/users",{method:"POST",body:JSON.stringify({action:"incr",key:n,value:a}),headers:{Authorization:`Bearer ${r}`,"Content-Type":"application/json"}}),decr:async(n,a)=>await fetch("http://localhost:4005/users",{method:"POST",body:JSON.stringify({action:"decr",key:n,value:a}),headers:{Authorization:`Bearer ${r}`,"Content-Type":"application/json"}}),del:async n=>await fetch("http://localhost:4005/users",{method:"POST",body:JSON.stringify({action:"del",key:n}),headers:{Authorization:`Bearer ${r}`,"Content-Type":"application/json"}}),user:e}}import{useContext as Ue,useEffect as G,useState as Je}from"react";function to(t,e){let o=Ue(x),[r,i]=Je([]);if(!o)throw new Error("You must use useHook inside a SparkleProvider");return G(()=>{let l=n=>{i(a=>[...a,n]),e?.(n)};return o.on(t,l),()=>{o.off(t,l)}},[]),G(()=>{o.subscribe([t],"__hook__")},[t]),{events:r,lastEvent:r[r.length-1]}}export{I as SparkleAppContext,jt as SparkleProvider,Ft as useAuth,Kt as useDatabase,to as useHook,Ut as useRealtime,Qt as useUser};
2
2
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/provider.tsx","../src/components/login-form.tsx","../src/components/user-info.tsx","../src/providers/authProvider.tsx","../src/lib/auth.ts","../src/utils/hooks/useLocalStorage.ts","../src/utils/utils.ts","../src/utils/hooks/useSearchParam.ts","../src/providers/realtimeProvider.tsx","../src/lib/websocket.ts","../src/core/resources/database.ts","../src/core/index.ts","../src/hooks/useRealtime.ts","../src/hooks/useAuth.ts","../src/hooks/useDatabase.ts","../src/hooks/useUser.ts","../src/hooks/useHook.ts"],"sourcesContent":["import React, {\n type ReactNode,\n useContext,\n useEffect,\n useState,\n createContext,\n} from \"react\"\nimport LoginForm from \"./components/login-form\"\nimport UserInfo from \"./components/user-info\"\nimport { AuthProvider, SparkleAuthContext } from \"./providers/authProvider\"\nimport { WebSocketProvider } from \"./providers/realtimeProvider\"\nimport { SparkleConfig } from \"./utils/config\"\nimport SparkleClient from \"./core\"\n\nconst Provider = ({ children }: { children: ReactNode }) => {\n const [isClientReady, setIsClientReady] = useState(false)\n const { authenticate, logout, token, account, loading } =\n useContext(SparkleAuthContext)\n\n useEffect(() => {\n setIsClientReady(true)\n }, [])\n\n if (!isClientReady) {\n return null\n }\n\n if (!token) {\n return <LoginForm authenticate={authenticate} loading={loading} />\n }\n\n return (\n <>\n <UserInfo user={account} logout={logout} loading={loading} />\n {account && children}\n </>\n )\n}\n\nexport interface SparkleProviderProps {\n config: SparkleConfig\n children: ReactNode\n}\n\nexport const SparkleAppContext = createContext<{\n sparkle: SparkleClient | undefined\n}>({\n sparkle: undefined,\n})\n\nexport const SparkleProvider = ({ children, config }: SparkleProviderProps) => {\n const [sparkle, setSparkle] = useState<SparkleClient>()\n\n useEffect(() => {\n if (config) {\n setSparkle(new SparkleClient(config))\n }\n }, [config])\n\n return (\n <SparkleAppContext.Provider value={{ sparkle }}>\n <AuthProvider config={config}>\n <WebSocketProvider config={config}>\n <Provider>{children}</Provider>\n </WebSocketProvider>\n </AuthProvider>\n </SparkleAppContext.Provider>\n )\n}\n","import * as React from \"react\"\nimport { motion } from \"framer-motion\"\nimport { Loader2 } from \"lucide-react\"\n\ninterface LoginFormProps {\n authenticate: () => void\n loading: boolean\n}\n\nexport default function LoginForm({ authenticate, loading }: LoginFormProps) {\n return (\n <div className=\"absolute inset-0 bg-black/60 backdrop-blur-xl\">\n <div className=\"absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 z-50 space-y-3 flex flex-col items-center max-w-xs w-full\">\n <h3 className=\"font-semibold tracking-tight text-2xl\">\n Counter Manager\n </h3>\n <motion.button\n layout\n className=\"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground shadow hover:bg-primary/90 h-9 px-4 py-2 overflow-hidden\"\n onClick={authenticate}\n disabled={loading}\n >\n <motion.div\n layout\n key={loading ? \"loading\" : \"loaded\"}\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n >\n {loading ? (\n <Loader2 className=\"animate-spin\" />\n ) : (\n <span>Login with Twitch</span>\n )}\n </motion.div>\n </motion.button>\n\n <span className=\"text-xs\">Powered by Sparkle</span>\n </div>\n </div>\n )\n}\n","import React, { useContext } from \"react\"\n\nimport { Loader2 } from \"lucide-react\"\nimport { motion } from \"framer-motion\"\nimport { TokenInfo } from \"../utils/types\"\nimport { SparkleAuthContext } from \"../providers/authProvider\"\n\ninterface UserInfoProps {\n user: TokenInfo | null\n loading: boolean\n logout: () => void\n}\n\nexport default function UserInfo({ user, loading, logout }: UserInfoProps) {\n const { authenticationMethod } = useContext(SparkleAuthContext)\n\n if (authenticationMethod === \"OAT\") {\n return null\n }\n\n return (\n <motion.div\n className=\"bg-popover flex items-start fixed right-3 bottom-3 rounded-md ring-1 ring-white/10 flex-col p-3 gap-3 cursor-pointer shadow-md bg-black text-white\"\n layout\n >\n {loading || !user ? (\n <div className=\"flex flex-row text-muted-foreground items-center gap-2\">\n <div className=\"text-sm\">Authenticating with Twitch...</div>\n <Loader2 className=\"animate-spin\" size={16} />\n </div>\n ) : (\n <div className=\"flex w-full flex-row items-center gap-3\">\n <div className=\"flex h-[34px] w-[34px] flex-shrink-0 items-center justify-center overflow-hidden rounded-lg bg-[#313131] text-sm\">\n <img\n src={user?.profilePictureUrl || \"\"}\n alt={user?.displayName + \"'s profile picture\"}\n width={34}\n height={34}\n />\n </div>\n <div className=\"flex w-full flex-col justify-center min-w-[124px]\">\n <div className=\"space-x-2\">\n <span className=\"text-primary text-sm font-medium capitalize\">\n {user?.displayName}\n </span>\n </div>\n <span className=\"text-muted-foreground text-xs font-normal\">\n Broadcaster\n </span>\n </div>\n <button\n className=\"bg-red-500 rounded-md p-2 text-xs whitespace-nowrap\"\n onClick={logout}\n >\n Log Out\n </button>\n </div>\n )}\n </motion.div>\n )\n}\n","import * as React from \"react\"\n\nimport {\n type ReactNode,\n createContext,\n useCallback,\n useEffect,\n useState,\n} from \"react\"\n\nimport { decode } from \"jsonwebtoken\"\n\nimport { TokenInfo } from \"../utils/types\"\nimport { SparkleConfig } from \"../utils/config\"\nimport { authWithCode } from \"../lib/auth\"\n\nimport useLocalStorage from \"../utils/hooks/useLocalStorage\"\nimport useSearchParam from \"../utils/hooks/useSearchParam\"\n\ninterface AuthContextType {\n account: TokenInfo | null\n token: string | undefined | null\n loading: boolean\n authenticationMethod: AuthenticationMethod\n authenticate: () => void\n logout: () => void\n}\n\nconst TWITCH_CLIENT_ID = \"u9lt242tz2pn5hl5x444ls2xllnvip\"\nconst STORAGE_KEY = \"twitch_access_token\"\n\nconst SCOPES = [\n // \"openid\",\n // \"user:read:email\",\n]\n\nexport const SparkleAuthContext = createContext<AuthContextType>({\n account: null,\n token: null,\n loading: true,\n authenticationMethod: \"JWT\",\n authenticate: () => {},\n logout: () => {},\n})\n\ninterface AuthProviderProps {\n config: SparkleConfig\n children: ReactNode\n}\n\ntype AuthenticationMethod = \"OAT\" | \"JWT\"\n\nexport const AuthProvider = ({ children, config }: AuthProviderProps) => {\n const [accessToken, setAccessToken] = useLocalStorage(STORAGE_KEY, null)\n const [_, setTwitch] = useLocalStorage(\"twitch\")\n const oat = config.oat || useSearchParam(\"oat\")\n\n const [account, setAccount] = useState<TokenInfo | null>(null)\n const [loading, setLoading] = useState(false)\n const [authenticationMethod, setAuthenticationMethod] =\n useState<AuthenticationMethod>(\"JWT\")\n\n useEffect(() => {\n if (accessToken) {\n const decoded = decode(accessToken) as TokenInfo\n\n console.log(decoded)\n\n if (decoded.exp * 1000 < Date.now()) {\n setAccessToken(null)\n setAccount(null)\n return\n }\n\n setAccount(decoded as TokenInfo)\n }\n }, [])\n\n useEffect(() => {\n if (!oat) return\n\n setLoading(true)\n\n authWithCode(config, oat)\n .then((res) => res.json())\n .then((res) => {\n setAccessToken(res.accessToken)\n const decoded = decode(res.accessToken)\n setAccount(decoded as TokenInfo)\n })\n .finally(() => {\n setLoading(false)\n setAuthenticationMethod(\"OAT\")\n })\n }, [oat])\n\n const logout = useCallback(() => {\n setAccessToken(null)\n setAccount(null)\n }, [])\n\n useEffect(() => {\n let accessToken = new URLSearchParams(window.location.hash).get(\n \"#access_token\"\n )\n\n if (!accessToken) return\n\n setTwitch(accessToken)\n\n setLoading(true)\n\n fetch(\"http://localhost:4005/auth\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Api-Key\": config.apiKey,\n \"Project-Id\": config.projectId,\n },\n body: JSON.stringify({ oat: accessToken }),\n })\n .then((res) => res.json())\n .then((res) => {\n setAccessToken(res.accessToken)\n const decoded = decode(res.accessToken)\n setAccount(decoded as TokenInfo)\n })\n .finally(() => {\n setLoading(false)\n window.history.replaceState({}, document.title, \"/\")\n })\n }, [])\n\n const authenticate = useCallback(async () => {\n const redirectUri = \"http://localhost:3000\"\n const scope = SCOPES.join(\" \")\n\n setLoading(true)\n\n try {\n if (!accessToken) {\n window.location.replace(\n `https://id.twitch.tv/oauth2/authorize?client_id=${TWITCH_CLIENT_ID}&redirect_uri=${redirectUri}&response_type=token&scope=${scope}&force_verify=true`\n )\n } else {\n const decoded = decode(accessToken)\n setAccount(decoded as TokenInfo)\n }\n } catch (error) {\n console.error(\"Erreur lors de l'authentification :\", error)\n } finally {\n }\n }, [accessToken])\n\n return (\n <SparkleAuthContext.Provider\n value={{\n authenticationMethod,\n account,\n token: accessToken,\n loading,\n authenticate,\n logout,\n }}\n >\n {children}\n </SparkleAuthContext.Provider>\n )\n}\n","import { SparkleConfig } from \"../utils/config\"\n\nexport const authWithCode = async (config: SparkleConfig, oat: string) => {\n return fetch(\"http://localhost:4005/auth/oat\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Api-Key\": config.apiKey,\n \"Project-Id\": config.projectId,\n },\n body: JSON.stringify({ oat }),\n })\n}\n\nexport const authWithJwt = async (config: SparkleConfig, jwt: string) => {\n return fetch(\"http://localhost:4005/auth\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Api-Key\": config.apiKey,\n \"Project-Id\": config.projectId,\n },\n body: JSON.stringify({ jwt }),\n })\n}\n","import {\n Dispatch,\n SetStateAction,\n useCallback,\n useState,\n useRef,\n useLayoutEffect,\n} from \"react\"\nimport { isBrowser, noop } from \"../utils\"\n\ntype parserOptions<T> =\n | {\n raw: true\n }\n | {\n raw: false\n serializer: (value: T) => string\n deserializer: (value: string) => T\n }\n\nconst useLocalStorage = <T>(\n key: string,\n initialValue?: T,\n options?: parserOptions<T>\n): [T | undefined, Dispatch<SetStateAction<T | undefined>>, () => void] => {\n if (!isBrowser) {\n return [initialValue as T, noop, noop]\n }\n if (!key) {\n throw new Error(\"useLocalStorage key may not be falsy\")\n }\n\n const deserializer = options\n ? options.raw\n ? (value) => value\n : options.deserializer\n : JSON.parse\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const initializer = useRef((key: string) => {\n try {\n const serializer = options\n ? options.raw\n ? String\n : options.serializer\n : JSON.stringify\n\n const localStorageValue = localStorage.getItem(key)\n if (localStorageValue !== null) {\n return deserializer(localStorageValue)\n } else {\n initialValue && localStorage.setItem(key, serializer(initialValue))\n return initialValue\n }\n } catch {\n // If user is in private mode or has storage restriction\n // localStorage can throw. JSON.parse and JSON.stringify\n // can throw, too.\n return initialValue\n }\n })\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const [state, setState] = useState<T | undefined>(() =>\n initializer.current(key)\n )\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useLayoutEffect(() => setState(initializer.current(key)), [key])\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const set: Dispatch<SetStateAction<T | undefined>> = useCallback(\n (valOrFunc) => {\n try {\n const newState =\n typeof valOrFunc === \"function\"\n ? (valOrFunc as Function)(state)\n : valOrFunc\n if (typeof newState === \"undefined\") return\n let value: string\n\n if (options)\n if (options.raw)\n if (typeof newState === \"string\") value = newState\n else value = JSON.stringify(newState)\n else if (options.serializer) value = options.serializer(newState)\n else value = JSON.stringify(newState)\n else value = JSON.stringify(newState)\n\n localStorage.setItem(key, value)\n setState(deserializer(value))\n } catch {\n // If user is in private mode or has storage restriction\n // localStorage can throw. Also JSON.stringify can throw.\n }\n },\n [key, setState]\n )\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const remove = useCallback(() => {\n try {\n localStorage.removeItem(key)\n setState(undefined)\n } catch {\n // If user is in private mode or has storage restriction\n // localStorage can throw.\n }\n }, [key, setState])\n\n return [state, set, remove]\n}\n\nexport default useLocalStorage\n","export const noop = () => {}\n\nexport function on<T extends Window | Document | HTMLElement | EventTarget>(\n obj: T | null,\n ...args: Parameters<T[\"addEventListener\"]> | [string, Function | null, ...any]\n): void {\n if (obj && obj.addEventListener) {\n obj.addEventListener(\n ...(args as Parameters<HTMLElement[\"addEventListener\"]>)\n )\n }\n}\n\nexport function off<T extends Window | Document | HTMLElement | EventTarget>(\n obj: T | null,\n ...args:\n | Parameters<T[\"removeEventListener\"]>\n | [string, Function | null, ...any]\n): void {\n if (obj && obj.removeEventListener) {\n obj.removeEventListener(\n ...(args as Parameters<HTMLElement[\"removeEventListener\"]>)\n )\n }\n}\n\nexport const isBrowser = typeof window !== \"undefined\"\n\nexport const isNavigator = typeof navigator !== \"undefined\"\n","import { useEffect, useState } from \"react\"\nimport { isBrowser, off, on } from \"../utils\"\n\nconst getValue = (search: string, param: string) =>\n new URLSearchParams(search).get(param)\n\nexport type UseQueryParam = (param: string) => string | null\n\nconst useSearchParam: UseQueryParam = (param) => {\n const location = window.location\n const [value, setValue] = useState<string | null>(() =>\n getValue(location.search, param)\n )\n\n useEffect(() => {\n const onChange = () => {\n setValue(getValue(location.search, param))\n }\n\n on(window, \"popstate\", onChange)\n on(window, \"pushstate\", onChange)\n on(window, \"replacestate\", onChange)\n\n return () => {\n off(window, \"popstate\", onChange)\n off(window, \"pushstate\", onChange)\n off(window, \"replacestate\", onChange)\n }\n }, [])\n\n return value\n}\n\nconst useSearchParamServer = () => null\n\nexport default isBrowser ? useSearchParam : useSearchParamServer\n","import React, { ReactNode, useCallback, useContext, useRef } from \"react\"\n\nimport { createContext, useEffect, useState } from \"react\"\nimport { SparkleAuthContext } from \"./authProvider\"\nimport { UpdateMessage, WebSocketClient } from \"../lib/websocket\"\nimport { SparkleConfig } from \"../utils/config\"\nimport EventEmitter from \"events\"\n\ninterface WebSocketContextType {\n subscribe: (keys: string[], scope: string) => void\n values: Record<string, any>\n\n on: (event: string, listener: (message: any) => void) => void\n off: (event: string, listener: (message: any) => void) => void\n}\n\nexport const SparkleContext = createContext<WebSocketContextType>({\n subscribe: () => {},\n values: {},\n on: () => {},\n off: () => {},\n})\n\ntype State = Record<string, any>\n\ninterface WebSocketProviderProps {\n config: SparkleConfig\n children: ReactNode\n}\n\nconst eventEmitter = new EventEmitter()\n\nexport const WebSocketProvider = ({ children }: WebSocketProviderProps) => {\n const [values, setValues] = useState<State>({})\n\n const socket = useRef<WebSocketClient>()\n\n const { token } = useContext(SparkleAuthContext)\n\n const on = (event: string, listener: (payload: any) => void) => {\n eventEmitter.on(event, listener)\n }\n\n const off = (event: string, listener: (payload: any) => void) => {\n eventEmitter.off(event, listener)\n }\n\n useEffect(() => {\n socket.current = new WebSocketClient(\"ws://localhost:8000\")\n\n socket.current.on(\"message\", (message: UpdateMessage) => {\n const { scope, payload, type } = message\n\n if (scope === \"__hook__\") {\n eventEmitter.emit(type, JSON.parse(payload))\n return\n }\n\n if (scope === \"__key__\") {\n setValues((prev) => ({ ...prev, [type]: JSON.parse(payload) }))\n }\n })\n\n return () => {\n socket.current?.disconnect()\n }\n }, [])\n\n useEffect(() => {\n if (!socket.current || !token) return\n socket.current.authenticate(token)\n }, [token])\n\n const subscribe = useCallback(\n (keys: string[], scope: string) => {\n socket.current?.subscribe(keys, scope)\n },\n [socket]\n )\n\n return (\n <SparkleContext.Provider\n value={{\n subscribe,\n values,\n on,\n off,\n }}\n >\n {children}\n </SparkleContext.Provider>\n )\n}\n","import z from \"zod\"\nimport EventEmitter from \"events\"\n\nconst subscribeSchema = z.object({\n type: z.literal(\"subscribe\"),\n channels: z.array(z.string()),\n scope: z.string(),\n})\n\nconst unsubscribeSchema = z.object({\n type: z.literal(\"unsubscribe\"),\n channels: z.string(),\n})\n\nconst updateSchema = z.object({\n scope: z.enum([\"__key__\", \"__hook__\"]),\n type: z.string(),\n payload: z.string(),\n})\n\nconst messageSchema = z.union([subscribeSchema, unsubscribeSchema])\n\nexport type Message = z.infer<typeof messageSchema>\n\nexport type UpdateMessage = z.infer<typeof updateSchema>\n\nexport type SubscribeMessage = z.infer<typeof subscribeSchema>\nexport type UnsubscribeMessage = z.infer<typeof unsubscribeSchema>\n\nexport class WebSocketClient extends EventEmitter {\n private socket: WebSocket | null = null\n private queue: Message[] = []\n\n private subscriptions: string[] = []\n\n private isAuthenticating = false\n\n private url: string\n private jwt: string | null = null\n\n constructor(url: string) {\n super()\n this.url = url\n }\n\n private send(data: Message) {\n if (this.socket?.readyState === WebSocket.OPEN) {\n this.socket?.send(JSON.stringify(data))\n } else {\n this.queue.push(data)\n }\n }\n\n authenticate(jwt: string) {\n if (this.isAuthenticating) return\n this.isAuthenticating = true\n this.jwt = jwt\n this.connect()\n }\n\n private connect() {\n const authenticatedUrl = this.url + \"?jwt=\" + this.jwt\n this.socket = new WebSocket(authenticatedUrl)\n\n this.socket.onopen = () => {\n this.queue.forEach((data) => this.send(data))\n this.queue = []\n }\n\n this.socket.onmessage = (event) => {\n const data = JSON.parse(event.data)\n this.emit(\"message\", data)\n }\n\n this.socket.onclose = () => {\n this.reconnect()\n }\n }\n\n reconnect() {\n setTimeout(() => {\n this.queue = [\n {\n type: \"subscribe\",\n channels: this.subscriptions,\n scope: \"key\",\n },\n ]\n\n console.log(\"try reconnecting\")\n\n this.connect()\n }, 5000)\n }\n\n subscribe(channels: string[], scope = \"key\") {\n const newChannels = channels.filter(\n (channel) => !this.subscriptions.includes(channel)\n )\n\n if (!newChannels.length) return\n this.subscriptions = [...this.subscriptions, ...newChannels]\n\n console.log(\"subscribe\", scope, channels)\n\n this.send({\n type: \"subscribe\",\n channels,\n scope,\n })\n }\n\n unsubscribe(channels: string) {\n this.send({ type: \"unsubscribe\", channels })\n }\n\n disconnect() {\n if (!this.socket) return\n\n this.socket.onclose = () => {}\n this.socket.close()\n }\n}\n","import SparkleClient from \"..\"\n\nexport const createDataResource = (client: SparkleClient) => {\n return {\n set: async (key: string, value: any) =>\n client.httpCall({\n action: \"set\",\n key,\n value,\n }),\n\n get: async (key: string) =>\n client.httpCall({\n action: \"get\",\n key,\n }),\n\n incr: async (key: string, value: number) =>\n client.httpCall({\n action: \"incr\",\n key,\n value,\n }),\n\n decr: async (key: string, value: number) =>\n client.httpCall({\n action: \"decr\",\n key,\n value,\n }),\n\n del: async (key: string) =>\n client.httpCall({\n action: \"del\",\n key,\n }),\n }\n}\n","import { SparkleConfig } from \"../utils/config\"\nimport { createDataResource } from \"./resources/database\"\n\nexport default class SparkleClient {\n private config: SparkleConfig\n private token: string\n\n constructor(config: SparkleConfig) {\n this.config = config\n this.token = \"\"\n }\n\n setToken(token: string) {\n this.token = token\n }\n\n get database() {\n return createDataResource(this)\n }\n\n get twitch() {\n return null\n }\n\n get hook() {\n return null\n }\n\n async httpCall(body: any) {\n const result = await fetch(\"http://localhost:4005/actions\", {\n method: \"POST\",\n body: JSON.stringify(body),\n headers: {\n Authorization: `Bearer ${this.token}`,\n \"Content-Type\": \"application/json\",\n },\n })\n\n return result\n }\n}\n\nconst client = new SparkleClient({\n apiKey: \"123\",\n projectId: \"123\",\n})\n","import { useContext, useEffect, useMemo } from \"react\"\nimport { SparkleContext } from \"../providers/realtimeProvider\"\n\nexport function useRealtime<T>(...keyInputs: string[]) {\n const context = useContext(SparkleContext)\n\n const keys = useMemo(() => keyInputs, [keyInputs.join(\",\")])\n\n if (!context) {\n throw new Error(\"You must use useRealtime inside a SparkleProvider\")\n }\n\n useEffect(() => {\n context.subscribe(keys, \"__key__\")\n }, [keys])\n\n return keys.map((k) => context.values[k])\n}\n","import { useContext } from \"react\"\nimport { SparkleAuthContext } from \"../providers/authProvider\"\n\nexport function useAuth() {\n const {\n account,\n token: accessToken,\n loading,\n authenticate,\n logout,\n } = useContext(SparkleAuthContext)\n\n return {\n account,\n token: accessToken,\n loading,\n authenticate,\n logout,\n }\n}\n","import { useContext, useEffect } from \"react\"\nimport { SparkleAuthContext } from \"../providers/authProvider\"\nimport { SparkleAppContext } from \"../provider\"\n\nexport function useDatabase<T extends string>() {\n const { token } = useContext(SparkleAuthContext)\n const { sparkle } = useContext(SparkleAppContext)\n\n if (!sparkle) throw new Error(\"SparkleClient not found in context\")\n\n useEffect(() => {\n if (!token) return\n sparkle.setToken(token)\n }, [token])\n\n return sparkle.database\n}\n","import { useCallback, useContext, useEffect, useState } from \"react\"\nimport { SparkleAuthContext } from \"../providers/authProvider\"\n\nexport function useUser<T extends string>(...keys: T[]) {\n const [user, setUser] = useState({})\n const { token } = useContext(SparkleAuthContext)\n\n const set = useCallback(async (key: string, value: any) => {\n if (value && typeof value === \"object\") {\n value = JSON.stringify(value)\n }\n\n return await fetch(\"http://localhost:4005/users\", {\n method: \"POST\",\n body: JSON.stringify({\n action: \"set\",\n key,\n value,\n }),\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n })\n }, [])\n\n const get = useCallback(async (key: string) => {\n const value = await fetch(\"http://localhost:4005/users\", {\n method: \"POST\",\n body: JSON.stringify({ action: \"get\", key }),\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n })\n\n return value.json()\n\n // return JSON.parse(value.)\n }, [])\n\n // admin / read - write\n // modo / read - write with policies\n // viewer / read only with policies\n // other, same like viewer\n\n useEffect(() => {\n const fetch = async () => {\n const coins = await get(\"coins\")\n setUser({\n coins,\n })\n }\n\n fetch()\n }, [])\n\n return {\n set,\n get,\n incr: async (key: string, value: number) => {\n return await fetch(\"http://localhost:4005/users\", {\n method: \"POST\",\n body: JSON.stringify({ action: \"incr\", key, value }),\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n })\n },\n decr: async (key: string, value: number) => {\n return await fetch(\"http://localhost:4005/users\", {\n method: \"POST\",\n body: JSON.stringify({ action: \"decr\", key, value }),\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n })\n },\n del: async (key: string) => {\n return await fetch(\"http://localhost:4005/users\", {\n method: \"POST\",\n body: JSON.stringify({ action: \"del\", key }),\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n })\n },\n user,\n }\n}\n","import { useContext, useEffect, useMemo, useState } from \"react\"\nimport { SparkleContext } from \"../providers/realtimeProvider\"\nimport type { EventTypeMap } from \"../hooks\"\n\nexport function useHook<T extends keyof EventTypeMap>(\n event: T,\n callback?: (data: EventTypeMap[T]) => void\n) {\n const context = useContext(SparkleContext)\n const [messages, setMessages] = useState<EventTypeMap[T][]>([])\n\n if (!context) {\n throw new Error(\"You must use useHook inside a SparkleProvider\")\n }\n\n useEffect(() => {\n const handler = (message: T) => {\n setMessages((messages) => [...messages, message])\n callback?.(message)\n }\n\n context.on(event, handler)\n\n return () => {\n context.off(event, handler)\n }\n }, [])\n\n useEffect(() => {\n context.subscribe([event], \"__hook__\")\n }, [event])\n\n return {\n events: messages,\n lastEvent: messages[messages.length - 1] as EventTypeMap[T] | undefined,\n }\n}\n"],"mappings":"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","names":["React","useContext","useEffect","useState","createContext","React","motion","Loader2","LoginForm","authenticate","loading","React","useContext","Loader2","motion","React","createContext","useCallback","useEffect","useState","decode","authWithCode","config","oat","useCallback","useState","useRef","useLayoutEffect","noop","on","obj","args","off","isBrowser","useLocalStorage","key","initialValue","options","isBrowser","noop","deserializer","value","initializer","useRef","serializer","localStorageValue","state","setState","useState","useLayoutEffect","set","useCallback","valOrFunc","newState","remove","useLocalStorage_default","useEffect","useState","getValue","search","param","useSearchParam","location","value","setValue","useState","useEffect","onChange","on","off","useSearchParamServer","useSearchParam_default","isBrowser","TWITCH_CLIENT_ID","STORAGE_KEY","SCOPES","SparkleAuthContext","createContext","AuthProvider","children","config","accessToken","setAccessToken","useLocalStorage_default","_","setTwitch","oat","useSearchParam_default","account","setAccount","useState","loading","setLoading","authenticationMethod","setAuthenticationMethod","useEffect","decoded","decode","authWithCode","res","logout","useCallback","authenticate","redirectUri","scope","error","UserInfo","user","loading","logout","authenticationMethod","useContext","SparkleAuthContext","React","motion","Loader2","React","useCallback","useContext","useRef","createContext","useEffect","useState","z","EventEmitter","subscribeSchema","unsubscribeSchema","updateSchema","messageSchema","WebSocketClient","url","data","jwt","authenticatedUrl","event","channels","scope","newChannels","channel","EventEmitter","SparkleContext","createContext","eventEmitter","WebSocketProvider","children","values","setValues","useState","socket","useRef","token","useContext","SparkleAuthContext","on","event","listener","off","useEffect","WebSocketClient","message","scope","payload","type","prev","subscribe","useCallback","keys","React","createDataResource","client","key","value","SparkleClient","config","token","createDataResource","body","client","Provider","children","isClientReady","setIsClientReady","useState","authenticate","logout","token","account","loading","useContext","SparkleAuthContext","useEffect","React","UserInfo","LoginForm","SparkleAppContext","createContext","SparkleProvider","config","sparkle","setSparkle","SparkleClient","AuthProvider","WebSocketProvider","useContext","useEffect","useMemo","useRealtime","keyInputs","context","useContext","SparkleContext","keys","useMemo","useEffect","k","useContext","useAuth","account","accessToken","loading","authenticate","logout","useContext","SparkleAuthContext","useContext","useEffect","useDatabase","token","useContext","SparkleAuthContext","sparkle","SparkleAppContext","useEffect","useCallback","useContext","useEffect","useState","useUser","keys","user","setUser","useState","token","useContext","SparkleAuthContext","set","useCallback","key","value","get","useEffect","coins","useContext","useEffect","useState","useHook","event","callback","context","useContext","SparkleContext","messages","setMessages","useState","useEffect","handler","message"]}
1
+ {"version":3,"sources":["../src/provider.tsx","../src/components/login-form.tsx","../src/components/user-info.tsx","../src/providers/authProvider.tsx","../src/lib/auth.ts","../src/utils/hooks/useLocalStorage.ts","../src/utils/utils.ts","../src/utils/hooks/useSearchParam.ts","../src/providers/realtimeProvider.tsx","../src/lib/websocket.ts","../src/core/resources/database.ts","../src/core/index.ts","../src/hooks/useRealtime.ts","../src/hooks/useAuth.ts","../src/hooks/useDatabase.ts","../src/hooks/useUser.ts","../src/hooks/useHook.ts"],"sourcesContent":["import React, {\n type ReactNode,\n useContext,\n useEffect,\n useState,\n createContext,\n} from \"react\"\nimport LoginForm from \"./components/login-form\"\nimport UserInfo from \"./components/user-info\"\nimport { AuthProvider, SparkleAuthContext } from \"./providers/authProvider\"\nimport { WebSocketProvider } from \"./providers/realtimeProvider\"\nimport { SparkleConfig } from \"./utils/config\"\nimport SparkleClient from \"./core\"\n\nconst Provider = ({ children }: { children: ReactNode }) => {\n const [isClientReady, setIsClientReady] = useState(false)\n const { authenticate, logout, token, account, loading } =\n useContext(SparkleAuthContext)\n\n useEffect(() => {\n setIsClientReady(true)\n }, [])\n\n if (!isClientReady) {\n return null\n }\n\n if (!token) {\n return <LoginForm authenticate={authenticate} loading={loading} />\n }\n\n return (\n <>\n <UserInfo user={account} logout={logout} loading={loading} />\n {account && children}\n </>\n )\n}\n\nexport interface SparkleProviderProps {\n config: SparkleConfig\n children: ReactNode\n}\n\nexport const SparkleAppContext = createContext<{\n sparkle: SparkleClient | undefined\n}>({\n sparkle: undefined,\n})\n\nexport const SparkleProvider = ({ children, config }: SparkleProviderProps) => {\n const [sparkle, setSparkle] = useState<SparkleClient>()\n\n useEffect(() => {\n if (config) {\n setSparkle(new SparkleClient(config))\n }\n }, [config])\n\n return (\n <SparkleAppContext.Provider value={{ sparkle }}>\n <AuthProvider config={config}>\n <WebSocketProvider config={config}>\n <Provider>{children}</Provider>\n </WebSocketProvider>\n </AuthProvider>\n </SparkleAppContext.Provider>\n )\n}\n","import * as React from \"react\"\nimport { motion } from \"framer-motion\"\nimport { Loader2 } from \"lucide-react\"\n\ninterface LoginFormProps {\n authenticate: () => void\n loading: boolean\n}\n\nexport default function LoginForm({ authenticate, loading }: LoginFormProps) {\n return (\n <div className=\"absolute inset-0 bg-black/60 backdrop-blur-xl\">\n <div className=\"absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 z-50 space-y-3 flex flex-col items-center max-w-xs w-full\">\n <h3 className=\"font-semibold tracking-tight text-2xl\">\n Counter Manager\n </h3>\n <motion.button\n layout\n className=\"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 bg-primary text-primary-foreground shadow hover:bg-primary/90 h-9 px-4 py-2 overflow-hidden\"\n onClick={authenticate}\n disabled={loading}\n >\n <motion.div\n layout\n key={loading ? \"loading\" : \"loaded\"}\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n >\n {loading ? (\n <Loader2 className=\"animate-spin\" />\n ) : (\n <span>Login with Twitch</span>\n )}\n </motion.div>\n </motion.button>\n\n <span className=\"text-xs\">Powered by Sparkle</span>\n </div>\n </div>\n )\n}\n","import React, { useContext } from \"react\"\n\nimport { Loader2 } from \"lucide-react\"\nimport { motion } from \"framer-motion\"\nimport { TokenInfo } from \"../utils/types\"\nimport { SparkleAuthContext } from \"../providers/authProvider\"\n\ninterface UserInfoProps {\n user: TokenInfo | null\n loading: boolean\n logout: () => void\n}\n\nexport default function UserInfo({ user, loading, logout }: UserInfoProps) {\n const { authenticationMethod } = useContext(SparkleAuthContext)\n\n if (authenticationMethod === \"OAT\") {\n return null\n }\n\n return (\n <motion.div\n className=\"bg-popover flex items-start fixed right-3 bottom-3 rounded-md ring-1 ring-white/10 flex-col p-3 gap-3 cursor-pointer shadow-md bg-black text-white\"\n layout\n >\n {loading || !user ? (\n <div className=\"flex flex-row text-muted-foreground items-center gap-2\">\n <div className=\"text-sm\">Authenticating with Twitch...</div>\n <Loader2 className=\"animate-spin\" size={16} />\n </div>\n ) : (\n <div className=\"flex w-full flex-row items-center gap-3\">\n <div className=\"flex h-[34px] w-[34px] flex-shrink-0 items-center justify-center overflow-hidden rounded-lg bg-[#313131] text-sm\">\n <img\n src={user?.profilePictureUrl || \"\"}\n alt={user?.displayName + \"'s profile picture\"}\n width={34}\n height={34}\n />\n </div>\n <div className=\"flex w-full flex-col justify-center min-w-[124px]\">\n <div className=\"space-x-2\">\n <span className=\"text-primary text-sm font-medium capitalize\">\n {user?.displayName}\n </span>\n </div>\n <span className=\"text-muted-foreground text-xs font-normal\">\n Broadcaster\n </span>\n </div>\n <button\n className=\"bg-red-500 rounded-md p-2 text-xs whitespace-nowrap\"\n onClick={logout}\n >\n Log Out\n </button>\n </div>\n )}\n </motion.div>\n )\n}\n","import * as React from \"react\"\n\nimport {\n type ReactNode,\n createContext,\n useCallback,\n useEffect,\n useState,\n} from \"react\"\n\n// import { decode } from \"jsonwebtoken\"\n\nconst decode = (code: string) => {\n return {\n exp: 1000,\n }\n}\n\nimport { TokenInfo } from \"../utils/types\"\nimport { SparkleConfig } from \"../utils/config\"\nimport { authWithCode } from \"../lib/auth\"\n\nimport useLocalStorage from \"../utils/hooks/useLocalStorage\"\nimport useSearchParam from \"../utils/hooks/useSearchParam\"\n\ninterface AuthContextType {\n account: TokenInfo | null\n token: string | undefined | null\n loading: boolean\n authenticationMethod: AuthenticationMethod\n authenticate: () => void\n logout: () => void\n}\n\nconst TWITCH_CLIENT_ID = \"u9lt242tz2pn5hl5x444ls2xllnvip\"\nconst STORAGE_KEY = \"twitch_access_token\"\n\nconst SCOPES = [\n // \"openid\",\n // \"user:read:email\",\n]\n\nexport const SparkleAuthContext = createContext<AuthContextType>({\n account: null,\n token: null,\n loading: true,\n authenticationMethod: \"JWT\",\n authenticate: () => {},\n logout: () => {},\n})\n\ninterface AuthProviderProps {\n config: SparkleConfig\n children: ReactNode\n}\n\ntype AuthenticationMethod = \"OAT\" | \"JWT\"\n\nexport const AuthProvider = ({ children, config }: AuthProviderProps) => {\n const [accessToken, setAccessToken] = useLocalStorage(STORAGE_KEY, null)\n const [_, setTwitch] = useLocalStorage(\"twitch\")\n const oat = config.oat || useSearchParam(\"oat\")\n\n const [account, setAccount] = useState<TokenInfo | null>(null)\n const [loading, setLoading] = useState(false)\n const [authenticationMethod, setAuthenticationMethod] =\n useState<AuthenticationMethod>(\"JWT\")\n\n useEffect(() => {\n if (accessToken) {\n const decoded = decode(accessToken) as TokenInfo\n\n console.log(decoded)\n\n if (decoded.exp * 1000 < Date.now()) {\n setAccessToken(null)\n setAccount(null)\n return\n }\n\n setAccount(decoded as TokenInfo)\n }\n }, [])\n\n useEffect(() => {\n if (!oat) return\n\n setLoading(true)\n\n authWithCode(config, oat)\n .then((res) => res.json())\n .then((res) => {\n setAccessToken(res.accessToken)\n const decoded = decode(res.accessToken)\n setAccount(decoded as TokenInfo)\n })\n .finally(() => {\n setLoading(false)\n setAuthenticationMethod(\"OAT\")\n })\n }, [oat])\n\n const logout = useCallback(() => {\n setAccessToken(null)\n setAccount(null)\n }, [])\n\n useEffect(() => {\n let accessToken = new URLSearchParams(window.location.hash).get(\n \"#access_token\"\n )\n\n if (!accessToken) return\n\n setTwitch(accessToken)\n\n setLoading(true)\n\n fetch(\"http://localhost:4005/auth\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Api-Key\": config.apiKey,\n \"Project-Id\": config.projectId,\n },\n body: JSON.stringify({ oat: accessToken }),\n })\n .then((res) => res.json())\n .then((res) => {\n setAccessToken(res.accessToken)\n const decoded = decode(res.accessToken)\n setAccount(decoded as TokenInfo)\n })\n .finally(() => {\n setLoading(false)\n window.history.replaceState({}, document.title, \"/\")\n })\n }, [])\n\n const authenticate = useCallback(async () => {\n const redirectUri = \"http://localhost:3000\"\n const scope = SCOPES.join(\" \")\n\n setLoading(true)\n\n try {\n if (!accessToken) {\n window.location.replace(\n `https://id.twitch.tv/oauth2/authorize?client_id=${TWITCH_CLIENT_ID}&redirect_uri=${redirectUri}&response_type=token&scope=${scope}&force_verify=true`\n )\n } else {\n const decoded = decode(accessToken)\n setAccount(decoded as TokenInfo)\n }\n } catch (error) {\n console.error(\"Erreur lors de l'authentification :\", error)\n } finally {\n }\n }, [accessToken])\n\n return (\n <SparkleAuthContext.Provider\n value={{\n authenticationMethod,\n account,\n token: accessToken,\n loading,\n authenticate,\n logout,\n }}\n >\n {children}\n </SparkleAuthContext.Provider>\n )\n}\n","import { SparkleConfig } from \"../utils/config\"\n\nexport const authWithCode = async (config: SparkleConfig, oat: string) => {\n return fetch(\"http://localhost:4005/auth/oat\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Api-Key\": config.apiKey,\n \"Project-Id\": config.projectId,\n },\n body: JSON.stringify({ oat }),\n })\n}\n\nexport const authWithJwt = async (config: SparkleConfig, jwt: string) => {\n return fetch(\"http://localhost:4005/auth\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Api-Key\": config.apiKey,\n \"Project-Id\": config.projectId,\n },\n body: JSON.stringify({ jwt }),\n })\n}\n","import {\n Dispatch,\n SetStateAction,\n useCallback,\n useState,\n useRef,\n useLayoutEffect,\n} from \"react\"\nimport { isBrowser, noop } from \"../utils\"\n\ntype parserOptions<T> =\n | {\n raw: true\n }\n | {\n raw: false\n serializer: (value: T) => string\n deserializer: (value: string) => T\n }\n\nconst useLocalStorage = <T>(\n key: string,\n initialValue?: T,\n options?: parserOptions<T>\n): [T | undefined, Dispatch<SetStateAction<T | undefined>>, () => void] => {\n if (!isBrowser) {\n return [initialValue as T, noop, noop]\n }\n if (!key) {\n throw new Error(\"useLocalStorage key may not be falsy\")\n }\n\n const deserializer = options\n ? options.raw\n ? (value) => value\n : options.deserializer\n : JSON.parse\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const initializer = useRef((key: string) => {\n try {\n const serializer = options\n ? options.raw\n ? String\n : options.serializer\n : JSON.stringify\n\n const localStorageValue = localStorage.getItem(key)\n if (localStorageValue !== null) {\n return deserializer(localStorageValue)\n } else {\n initialValue && localStorage.setItem(key, serializer(initialValue))\n return initialValue\n }\n } catch {\n // If user is in private mode or has storage restriction\n // localStorage can throw. JSON.parse and JSON.stringify\n // can throw, too.\n return initialValue\n }\n })\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const [state, setState] = useState<T | undefined>(() =>\n initializer.current(key)\n )\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n useLayoutEffect(() => setState(initializer.current(key)), [key])\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const set: Dispatch<SetStateAction<T | undefined>> = useCallback(\n (valOrFunc) => {\n try {\n const newState =\n typeof valOrFunc === \"function\"\n ? (valOrFunc as Function)(state)\n : valOrFunc\n if (typeof newState === \"undefined\") return\n let value: string\n\n if (options)\n if (options.raw)\n if (typeof newState === \"string\") value = newState\n else value = JSON.stringify(newState)\n else if (options.serializer) value = options.serializer(newState)\n else value = JSON.stringify(newState)\n else value = JSON.stringify(newState)\n\n localStorage.setItem(key, value)\n setState(deserializer(value))\n } catch {\n // If user is in private mode or has storage restriction\n // localStorage can throw. Also JSON.stringify can throw.\n }\n },\n [key, setState]\n )\n\n // eslint-disable-next-line react-hooks/rules-of-hooks\n const remove = useCallback(() => {\n try {\n localStorage.removeItem(key)\n setState(undefined)\n } catch {\n // If user is in private mode or has storage restriction\n // localStorage can throw.\n }\n }, [key, setState])\n\n return [state, set, remove]\n}\n\nexport default useLocalStorage\n","export const noop = () => {}\n\nexport function on<T extends Window | Document | HTMLElement | EventTarget>(\n obj: T | null,\n ...args: Parameters<T[\"addEventListener\"]> | [string, Function | null, ...any]\n): void {\n if (obj && obj.addEventListener) {\n obj.addEventListener(\n ...(args as Parameters<HTMLElement[\"addEventListener\"]>)\n )\n }\n}\n\nexport function off<T extends Window | Document | HTMLElement | EventTarget>(\n obj: T | null,\n ...args:\n | Parameters<T[\"removeEventListener\"]>\n | [string, Function | null, ...any]\n): void {\n if (obj && obj.removeEventListener) {\n obj.removeEventListener(\n ...(args as Parameters<HTMLElement[\"removeEventListener\"]>)\n )\n }\n}\n\nexport const isBrowser = typeof window !== \"undefined\"\n\nexport const isNavigator = typeof navigator !== \"undefined\"\n","import { useEffect, useState } from \"react\"\nimport { isBrowser, off, on } from \"../utils\"\n\nconst getValue = (search: string, param: string) =>\n new URLSearchParams(search).get(param)\n\nexport type UseQueryParam = (param: string) => string | null\n\nconst useSearchParam: UseQueryParam = (param) => {\n const location = window.location\n const [value, setValue] = useState<string | null>(() =>\n getValue(location.search, param)\n )\n\n useEffect(() => {\n const onChange = () => {\n setValue(getValue(location.search, param))\n }\n\n on(window, \"popstate\", onChange)\n on(window, \"pushstate\", onChange)\n on(window, \"replacestate\", onChange)\n\n return () => {\n off(window, \"popstate\", onChange)\n off(window, \"pushstate\", onChange)\n off(window, \"replacestate\", onChange)\n }\n }, [])\n\n return value\n}\n\nconst useSearchParamServer = () => null\n\nexport default isBrowser ? useSearchParam : useSearchParamServer\n","import React, { ReactNode, useCallback, useContext, useRef } from \"react\"\n\nimport { createContext, useEffect, useState } from \"react\"\nimport { SparkleAuthContext } from \"./authProvider\"\nimport { UpdateMessage, WebSocketClient } from \"../lib/websocket\"\nimport { SparkleConfig } from \"../utils/config\"\nimport EventEmitter from \"events\"\n\ninterface WebSocketContextType {\n subscribe: (keys: string[], scope: string) => void\n values: Record<string, any>\n\n on: (event: string, listener: (message: any) => void) => void\n off: (event: string, listener: (message: any) => void) => void\n}\n\nexport const SparkleContext = createContext<WebSocketContextType>({\n subscribe: () => {},\n values: {},\n on: () => {},\n off: () => {},\n})\n\ntype State = Record<string, any>\n\ninterface WebSocketProviderProps {\n config: SparkleConfig\n children: ReactNode\n}\n\nconst eventEmitter = new EventEmitter()\n\nexport const WebSocketProvider = ({ children }: WebSocketProviderProps) => {\n const [values, setValues] = useState<State>({})\n\n const socket = useRef<WebSocketClient>()\n\n const { token } = useContext(SparkleAuthContext)\n\n const on = (event: string, listener: (payload: any) => void) => {\n eventEmitter.on(event, listener)\n }\n\n const off = (event: string, listener: (payload: any) => void) => {\n eventEmitter.off(event, listener)\n }\n\n useEffect(() => {\n socket.current = new WebSocketClient(\"ws://localhost:8000\")\n\n socket.current.on(\"message\", (message: UpdateMessage) => {\n const { scope, payload, type } = message\n\n if (scope === \"__hook__\") {\n eventEmitter.emit(type, JSON.parse(payload))\n return\n }\n\n if (scope === \"__key__\") {\n setValues((prev) => ({ ...prev, [type]: JSON.parse(payload) }))\n }\n })\n\n return () => {\n socket.current?.disconnect()\n }\n }, [])\n\n useEffect(() => {\n if (!socket.current || !token) return\n socket.current.authenticate(token)\n }, [token])\n\n const subscribe = useCallback(\n (keys: string[], scope: string) => {\n socket.current?.subscribe(keys, scope)\n },\n [socket]\n )\n\n return (\n <SparkleContext.Provider\n value={{\n subscribe,\n values,\n on,\n off,\n }}\n >\n {children}\n </SparkleContext.Provider>\n )\n}\n","import z from \"zod\"\nimport EventEmitter from \"events\"\n\nconst subscribeSchema = z.object({\n type: z.literal(\"subscribe\"),\n channels: z.array(z.string()),\n scope: z.string(),\n})\n\nconst unsubscribeSchema = z.object({\n type: z.literal(\"unsubscribe\"),\n channels: z.string(),\n})\n\nconst updateSchema = z.object({\n scope: z.enum([\"__key__\", \"__hook__\"]),\n type: z.string(),\n payload: z.string(),\n})\n\nconst messageSchema = z.union([subscribeSchema, unsubscribeSchema])\n\nexport type Message = z.infer<typeof messageSchema>\n\nexport type UpdateMessage = z.infer<typeof updateSchema>\n\nexport type SubscribeMessage = z.infer<typeof subscribeSchema>\nexport type UnsubscribeMessage = z.infer<typeof unsubscribeSchema>\n\nexport class WebSocketClient extends EventEmitter {\n private socket: WebSocket | null = null\n private queue: Message[] = []\n\n private subscriptions: string[] = []\n\n private isAuthenticating = false\n\n private url: string\n private jwt: string | null = null\n\n constructor(url: string) {\n super()\n this.url = url\n }\n\n private send(data: Message) {\n if (this.socket?.readyState === WebSocket.OPEN) {\n this.socket?.send(JSON.stringify(data))\n } else {\n this.queue.push(data)\n }\n }\n\n authenticate(jwt: string) {\n if (this.isAuthenticating) return\n this.isAuthenticating = true\n this.jwt = jwt\n this.connect()\n }\n\n private connect() {\n const authenticatedUrl = this.url + \"?jwt=\" + this.jwt\n this.socket = new WebSocket(authenticatedUrl)\n\n this.socket.onopen = () => {\n this.queue.forEach((data) => this.send(data))\n this.queue = []\n }\n\n this.socket.onmessage = (event) => {\n const data = JSON.parse(event.data)\n this.emit(\"message\", data)\n }\n\n this.socket.onclose = () => {\n this.reconnect()\n }\n }\n\n reconnect() {\n setTimeout(() => {\n this.queue = [\n {\n type: \"subscribe\",\n channels: this.subscriptions,\n scope: \"key\",\n },\n ]\n\n console.log(\"try reconnecting\")\n\n this.connect()\n }, 5000)\n }\n\n subscribe(channels: string[], scope = \"key\") {\n const newChannels = channels.filter(\n (channel) => !this.subscriptions.includes(channel)\n )\n\n if (!newChannels.length) return\n this.subscriptions = [...this.subscriptions, ...newChannels]\n\n console.log(\"subscribe\", scope, channels)\n\n this.send({\n type: \"subscribe\",\n channels,\n scope,\n })\n }\n\n unsubscribe(channels: string) {\n this.send({ type: \"unsubscribe\", channels })\n }\n\n disconnect() {\n if (!this.socket) return\n\n this.socket.onclose = () => {}\n this.socket.close()\n }\n}\n","import SparkleClient from \"..\"\n\nexport const createDataResource = (client: SparkleClient) => {\n return {\n set: async (key: string, value: any) =>\n client.httpCall({\n action: \"set\",\n key,\n value,\n }),\n\n get: async (key: string) =>\n client.httpCall({\n action: \"get\",\n key,\n }),\n\n incr: async (key: string, value: number) =>\n client.httpCall({\n action: \"incr\",\n key,\n value,\n }),\n\n decr: async (key: string, value: number) =>\n client.httpCall({\n action: \"decr\",\n key,\n value,\n }),\n\n del: async (key: string) =>\n client.httpCall({\n action: \"del\",\n key,\n }),\n }\n}\n","import { SparkleConfig } from \"../utils/config\"\nimport { createDataResource } from \"./resources/database\"\n\nexport default class SparkleClient {\n private config: SparkleConfig\n private token: string\n\n constructor(config: SparkleConfig) {\n this.config = config\n this.token = \"\"\n }\n\n setToken(token: string) {\n this.token = token\n }\n\n get database() {\n return createDataResource(this)\n }\n\n get twitch() {\n return null\n }\n\n get hook() {\n return null\n }\n\n async httpCall(body: any) {\n const result = await fetch(\"http://localhost:4005/actions\", {\n method: \"POST\",\n body: JSON.stringify(body),\n headers: {\n Authorization: `Bearer ${this.token}`,\n \"Content-Type\": \"application/json\",\n },\n })\n\n return result\n }\n}\n\nconst client = new SparkleClient({\n apiKey: \"123\",\n projectId: \"123\",\n})\n","import { useContext, useEffect, useMemo } from \"react\"\nimport { SparkleContext } from \"../providers/realtimeProvider\"\n\nexport function useRealtime<T>(...keyInputs: string[]) {\n const context = useContext(SparkleContext)\n\n const keys = useMemo(() => keyInputs, [keyInputs.join(\",\")])\n\n if (!context) {\n throw new Error(\"You must use useRealtime inside a SparkleProvider\")\n }\n\n useEffect(() => {\n context.subscribe(keys, \"__key__\")\n }, [keys])\n\n return keys.map((k) => context.values[k])\n}\n","import { useContext } from \"react\"\nimport { SparkleAuthContext } from \"../providers/authProvider\"\n\nexport function useAuth() {\n const {\n account,\n token: accessToken,\n loading,\n authenticate,\n logout,\n } = useContext(SparkleAuthContext)\n\n return {\n account,\n token: accessToken,\n loading,\n authenticate,\n logout,\n }\n}\n","import { useContext, useEffect } from \"react\"\nimport { SparkleAuthContext } from \"../providers/authProvider\"\nimport { SparkleAppContext } from \"../provider\"\n\nexport function useDatabase<T extends string>() {\n const { token } = useContext(SparkleAuthContext)\n const { sparkle } = useContext(SparkleAppContext)\n\n if (!sparkle) throw new Error(\"SparkleClient not found in context\")\n\n useEffect(() => {\n if (!token) return\n sparkle.setToken(token)\n }, [token])\n\n return sparkle.database\n}\n","import { useCallback, useContext, useEffect, useState } from \"react\"\nimport { SparkleAuthContext } from \"../providers/authProvider\"\n\nexport function useUser<T extends string>(...keys: T[]) {\n const [user, setUser] = useState({})\n const { token } = useContext(SparkleAuthContext)\n\n const set = useCallback(async (key: string, value: any) => {\n if (value && typeof value === \"object\") {\n value = JSON.stringify(value)\n }\n\n return await fetch(\"http://localhost:4005/users\", {\n method: \"POST\",\n body: JSON.stringify({\n action: \"set\",\n key,\n value,\n }),\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n })\n }, [])\n\n const get = useCallback(async (key: string) => {\n const value = await fetch(\"http://localhost:4005/users\", {\n method: \"POST\",\n body: JSON.stringify({ action: \"get\", key }),\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n })\n\n return value.json()\n\n // return JSON.parse(value.)\n }, [])\n\n // admin / read - write\n // modo / read - write with policies\n // viewer / read only with policies\n // other, same like viewer\n\n useEffect(() => {\n const fetch = async () => {\n const coins = await get(\"coins\")\n setUser({\n coins,\n })\n }\n\n fetch()\n }, [])\n\n return {\n set,\n get,\n incr: async (key: string, value: number) => {\n return await fetch(\"http://localhost:4005/users\", {\n method: \"POST\",\n body: JSON.stringify({ action: \"incr\", key, value }),\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n })\n },\n decr: async (key: string, value: number) => {\n return await fetch(\"http://localhost:4005/users\", {\n method: \"POST\",\n body: JSON.stringify({ action: \"decr\", key, value }),\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n })\n },\n del: async (key: string) => {\n return await fetch(\"http://localhost:4005/users\", {\n method: \"POST\",\n body: JSON.stringify({ action: \"del\", key }),\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n })\n },\n user,\n }\n}\n","import { useContext, useEffect, useMemo, useState } from \"react\"\nimport { SparkleContext } from \"../providers/realtimeProvider\"\nimport type { EventTypeMap } from \"../hooks\"\n\nexport function useHook<T extends keyof EventTypeMap>(\n event: T,\n callback?: (data: EventTypeMap[T]) => void\n) {\n const context = useContext(SparkleContext)\n const [messages, setMessages] = useState<EventTypeMap[T][]>([])\n\n if (!context) {\n throw new Error(\"You must use useHook inside a SparkleProvider\")\n }\n\n useEffect(() => {\n const handler = (message: T) => {\n setMessages((messages) => [...messages, message])\n callback?.(message)\n }\n\n context.on(event, handler)\n\n return () => {\n context.off(event, handler)\n }\n }, [])\n\n useEffect(() => {\n context.subscribe([event], \"__hook__\")\n }, [event])\n\n return {\n events: messages,\n lastEvent: messages[messages.length - 1] as EventTypeMap[T] | undefined,\n }\n}\n"],"mappings":"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","names":["React","useContext","useEffect","useState","createContext","React","motion","Loader2","LoginForm","authenticate","loading","React","useContext","Loader2","motion","React","createContext","useCallback","useEffect","useState","authWithCode","config","oat","useCallback","useState","useRef","useLayoutEffect","noop","on","obj","args","off","isBrowser","useLocalStorage","key","initialValue","options","isBrowser","noop","deserializer","value","initializer","useRef","serializer","localStorageValue","state","setState","useState","useLayoutEffect","set","useCallback","valOrFunc","newState","remove","useLocalStorage_default","useEffect","useState","getValue","search","param","useSearchParam","location","value","setValue","useState","useEffect","onChange","on","off","useSearchParamServer","useSearchParam_default","isBrowser","decode","code","TWITCH_CLIENT_ID","STORAGE_KEY","SCOPES","SparkleAuthContext","createContext","AuthProvider","children","config","accessToken","setAccessToken","useLocalStorage_default","_","setTwitch","oat","useSearchParam_default","account","setAccount","useState","loading","setLoading","authenticationMethod","setAuthenticationMethod","useEffect","decoded","authWithCode","res","logout","useCallback","authenticate","redirectUri","scope","error","UserInfo","user","loading","logout","authenticationMethod","useContext","SparkleAuthContext","React","motion","Loader2","React","useCallback","useContext","useRef","createContext","useEffect","useState","z","EventEmitter","subscribeSchema","unsubscribeSchema","updateSchema","messageSchema","WebSocketClient","url","data","jwt","authenticatedUrl","event","channels","scope","newChannels","channel","EventEmitter","SparkleContext","createContext","eventEmitter","WebSocketProvider","children","values","setValues","useState","socket","useRef","token","useContext","SparkleAuthContext","on","event","listener","off","useEffect","WebSocketClient","message","scope","payload","type","prev","subscribe","useCallback","keys","React","createDataResource","client","key","value","SparkleClient","config","token","createDataResource","body","client","Provider","children","isClientReady","setIsClientReady","useState","authenticate","logout","token","account","loading","useContext","SparkleAuthContext","useEffect","React","UserInfo","LoginForm","SparkleAppContext","createContext","SparkleProvider","config","sparkle","setSparkle","SparkleClient","AuthProvider","WebSocketProvider","useContext","useEffect","useMemo","useRealtime","keyInputs","context","useContext","SparkleContext","keys","useMemo","useEffect","k","useContext","useAuth","account","accessToken","loading","authenticate","logout","useContext","SparkleAuthContext","useContext","useEffect","useDatabase","token","useContext","SparkleAuthContext","sparkle","SparkleAppContext","useEffect","useCallback","useContext","useEffect","useState","useUser","keys","user","setUser","useState","token","useContext","SparkleAuthContext","set","useCallback","key","value","get","useEffect","coins","useContext","useEffect","useState","useHook","event","callback","context","useContext","SparkleContext","messages","setMessages","useState","useEffect","handler","message"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sparkle-react",
3
- "version": "0.0.12",
3
+ "version": "0.0.13",
4
4
  "files": [
5
5
  "dist"
6
6
  ],
@@ -18,7 +18,6 @@
18
18
  },
19
19
  "dependencies": {
20
20
  "framer-motion": "^10.16.16",
21
- "jsonwebtoken": "^9.0.2",
22
21
  "lucide-react": "^0.294.0",
23
22
  "react": "^18.2.0",
24
23
  "zod": "^3.22.4"