sparkle-react 0.0.17 → 0.0.18
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 +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import
|
|
1
|
+
import b,{useEffect as j,useState as I}from"react";import*as w from"react";import{createContext as z,useEffect as T,useState as P}from"react";var d=z({token:null}),y=({children:t,config:o})=>{let[e,r]=P(null),i="alxios";return T(()=>{i&&r(i)},[i]),w.createElement(d.Provider,{value:{token:e}},t)};import M,{useCallback as L,useContext as N,useRef as U}from"react";import{createContext as W,useEffect as v,useState as O}from"react";import A from"events";import n from"zod";var E=n.object({type:n.literal("subscribe"),channels:n.array(n.string())}),R=n.object({type:n.literal("unsubscribe"),channels:n.string()}),ie=n.object({event:n.literal("update"),data:n.object({key:n.string(),value:n.string()})}),ne=n.union([E,R]),h=class extends A{constructor(e){super();this.socket=null;this.queue=[];this.subscriptions=[];this.isAuthenticating=!1;this.jwt=null;this.url=e}send(e){this.socket?.readyState===WebSocket.OPEN?this.socket?.send(JSON.stringify(e)):this.queue.push(e)}authenticate(e){this.isAuthenticating||(this.isAuthenticating=!0,this.jwt=e,this.connect())}connect(){let e=this.url+"?jwt="+this.jwt;this.socket=new WebSocket(e),this.socket.onopen=()=>{this.queue.forEach(r=>this.send(r)),this.queue=[]},this.socket.onmessage=r=>{let i=JSON.parse(r.data);this.emit("update",i)},this.socket.onclose=()=>{this.reconnect()}}reconnect(){setTimeout(()=>{this.queue=[{type:"subscribe",channels:this.subscriptions}],console.log("try reconnecting"),this.connect()},5e3)}subscribe(e){let r=e.filter(i=>!this.subscriptions.includes(i));r.length&&(this.subscriptions=[...this.subscriptions,...r],console.log("subscribe",e),this.send({type:"subscribe",channels:e}))}unsubscribe(e){this.send({type:"unsubscribe",channels:e})}disconnect(){this.socket&&(this.socket.onclose=()=>{},this.socket.close())}};var m=W({subscribe:()=>{},values:{}}),S=({children:t})=>{let[o,e]=O({}),r=U(),{token:i}=N(d);v(()=>(r.current=new h("http://localhost:4005/ws"),r.current.on("update",s=>{console.log("receive values",s);let{data:p}=s;e(f=>({...f,[p.key]:p.value}))}),()=>{r.current?.disconnect()}),[]),v(()=>{!r.current||!i||r.current.authenticate(i)},[i]);let u=L(s=>{r.current?.subscribe(s)},[r]);return M.createElement(m.Provider,{value:{subscribe:u,values:o}},t)};var F=({children:t})=>{let[o,e]=I(!1);return j(()=>{e(!0)},[]),o?t:null},ye=({children:t,config:o})=>b.createElement(y,{config:o},b.createElement(S,{config:o},b.createElement(F,null,t)));import{useContext as _,useEffect as J,useMemo as D}from"react";function xe(...t){let o=_(m),e=D(()=>t,[t.join(",")]);if(!o)throw new Error("You must use useDatabase inside a SparkleProvider");return J(()=>{o.subscribe(e)},[e]),e.map(r=>o.values[r])}import{useContext as H}from"react";function Pe(){let{token:t}=H(d);return{token:t}}import{ApiClient as K}from"@twurple/api";import{StaticAuthProvider as Q}from"@twurple/auth";import{useEffect as X,useState as Z}from"react";import{useCallback as x,useState as q,useRef as B,useLayoutEffect as Y}from"react";var g=()=>{};var k=typeof window<"u";var G=(t,o,e)=>{if(!k)return[o,g,g];if(!t)throw new Error("useLocalStorage key may not be falsy");let r=e?e.raw?l=>l:e.deserializer:JSON.parse,i=B(l=>{try{let c=e?e.raw?String:e.serializer:JSON.stringify,a=localStorage.getItem(l);return a!==null?r(a):(o&&localStorage.setItem(l,c(o)),o)}catch{return o}}),[u,s]=q(()=>i.current(t));Y(()=>s(i.current(t)),[t]);let p=x(l=>{try{let c=typeof l=="function"?l(u):l;if(typeof c>"u")return;let a;e?e.raw?typeof c=="string"?a=c:a=JSON.stringify(c):e.serializer?a=e.serializer(c):a=JSON.stringify(c):a=JSON.stringify(c),localStorage.setItem(t,a),s(r(a))}catch{}},[t,s]),f=x(()=>{try{localStorage.removeItem(t),s(void 0)}catch{}},[t,s]);return[u,p,f]},C=G;function Fe(t){let[o,e]=Z(null),[r]=C("twitch");return X(()=>{console.log("env",process.env.TWITCH_CLIENT_ID),console.log("init");let i=new K({authProvider:new Q("u9lt242tz2pn5hl5x444ls2xllnvip",r,["bits:read","channel:manage:moderators","channel:manage:polls","channel:manage:predictions","channel:manage:redemptions","channel:manage:vips","channel:read:polls","channel:read:predictions","channel:read:redemptions","channel:read:subscriptions","channel:read:vips","moderation:read","moderator:manage:announcements","channel:moderate","moderator:read:blocked_terms","moderator:read:chatters","moderator:read:followers","user:read:email"])});return e(i),()=>{e(null)}},[]),{apiClient:o}}export{ye as SparkleProvider,Pe as useAuth,xe as useRealtime,Fe as useTwitch};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/provider.tsx","../src/providers/authProvider.tsx","../src/utils/hooks/useSearchParam.ts","../src/utils/utils.ts","../src/providers/realtimeProvider.tsx","../src/lib/websocket.ts","../src/hooks/useRealtime.ts","../src/hooks/useAuth.ts","../src/hooks/useTwitch.ts","../src/utils/hooks/useLocalStorage.ts"],"sourcesContent":["import React, { type ReactNode, useContext, useEffect, useState } from \"react\"\r\nimport { AuthProvider, SparkleAuthContext } from \"./providers/authProvider\"\r\nimport { WebSocketProvider } from \"./providers/realtimeProvider\"\r\nimport { SparkleConfig } from \"./utils/config\"\r\n\r\nconst Provider = ({ children }: { children: ReactNode }) => {\r\n const [isClientReady, setIsClientReady] = useState(false)\r\n\r\n useEffect(() => {\r\n setIsClientReady(true)\r\n }, [])\r\n\r\n if (!isClientReady) {\r\n return null\r\n }\r\n\r\n // if (!token) {\r\n // return <LoginForm authenticate={authenticate} loading={loading} />\r\n // }\r\n\r\n // return (\r\n // <>\r\n // <UserInfo user={account} logout={logout} loading={loading} />\r\n // {account && children}\r\n // </>\r\n // )\r\n\r\n return children\r\n}\r\n\r\nexport interface SparkleProviderProps {\r\n config: SparkleConfig\r\n children: ReactNode\r\n}\r\n\r\nexport const SparkleProvider = ({ children, config }: SparkleProviderProps) => {\r\n return (\r\n <AuthProvider config={config}>\r\n <WebSocketProvider config={config}>\r\n <Provider>{children}</Provider>\r\n </WebSocketProvider>\r\n </AuthProvider>\r\n )\r\n}\r\n","import * as React from \"react\"\r\n\r\nimport { type ReactNode, createContext, useEffect, useState } from \"react\"\r\n\r\nimport { SparkleConfig } from \"../utils/config\"\r\nimport useSearchParam from \"../utils/hooks/useSearchParam\"\r\n\r\ninterface AuthContextType {\r\n token: string | undefined | null\r\n}\r\n\r\nconst STORAGE_KEY = \"twitch_access_token\"\r\n\r\nexport const SparkleAuthContext = createContext<AuthContextType>({\r\n token: null,\r\n})\r\n\r\ninterface AuthProviderProps {\r\n config: SparkleConfig\r\n children: ReactNode\r\n}\r\n\r\ntype AuthenticationMethod = \"OAT\" | \"JWT\"\r\n\r\nexport const AuthProvider = ({ children, config }: AuthProviderProps) => {\r\n const [accessToken, setAccessToken] = useState<string | null>(null)\r\n const oat = useSearchParam(\"oat\")\r\n\r\n useEffect(() => {\r\n if (oat) {\r\n setAccessToken(oat)\r\n }\r\n }, [oat])\r\n\r\n return (\r\n <SparkleAuthContext.Provider\r\n value={{\r\n token: accessToken,\r\n }}\r\n >\r\n {children}\r\n </SparkleAuthContext.Provider>\r\n )\r\n}\r\n","import { useEffect, useState } from \"react\"\r\nimport { isBrowser, off, on } from \"../utils\"\r\n\r\nconst getValue = (search: string, param: string) =>\r\n new URLSearchParams(search).get(param)\r\n\r\nexport type UseQueryParam = (param: string) => string | null\r\n\r\nconst useSearchParam: UseQueryParam = (param) => {\r\n const location = window.location\r\n const [value, setValue] = useState<string | null>(() =>\r\n getValue(location.search, param)\r\n )\r\n\r\n useEffect(() => {\r\n const onChange = () => {\r\n setValue(getValue(location.search, param))\r\n }\r\n\r\n on(window, \"popstate\", onChange)\r\n on(window, \"pushstate\", onChange)\r\n on(window, \"replacestate\", onChange)\r\n\r\n return () => {\r\n off(window, \"popstate\", onChange)\r\n off(window, \"pushstate\", onChange)\r\n off(window, \"replacestate\", onChange)\r\n }\r\n }, [])\r\n\r\n return value\r\n}\r\n\r\nconst useSearchParamServer = () => null\r\n\r\nexport default isBrowser ? useSearchParam : useSearchParamServer\r\n","export const noop = () => {}\r\n\r\nexport function on<T extends Window | Document | HTMLElement | EventTarget>(\r\n obj: T | null,\r\n ...args: Parameters<T[\"addEventListener\"]> | [string, Function | null, ...any]\r\n): void {\r\n if (obj && obj.addEventListener) {\r\n obj.addEventListener(\r\n ...(args as Parameters<HTMLElement[\"addEventListener\"]>)\r\n )\r\n }\r\n}\r\n\r\nexport function off<T extends Window | Document | HTMLElement | EventTarget>(\r\n obj: T | null,\r\n ...args:\r\n | Parameters<T[\"removeEventListener\"]>\r\n | [string, Function | null, ...any]\r\n): void {\r\n if (obj && obj.removeEventListener) {\r\n obj.removeEventListener(\r\n ...(args as Parameters<HTMLElement[\"removeEventListener\"]>)\r\n )\r\n }\r\n}\r\n\r\nexport const isBrowser = typeof window !== \"undefined\"\r\n\r\nexport const isNavigator = typeof navigator !== \"undefined\"\r\n","import React, { ReactNode, useCallback, useContext, useRef } from \"react\"\r\n\r\nimport { createContext, useEffect, useState } from \"react\"\r\nimport { SparkleAuthContext } from \"./authProvider\"\r\nimport { UpdateMessage, WebSocketClient } from \"../lib/websocket\"\r\nimport { SparkleConfig } from \"../utils/config\"\r\n\r\ninterface WebSocketContextType {\r\n subscribe: (keys: string[]) => void\r\n values: Record<string, any>\r\n}\r\n\r\nexport const SparkleContext = createContext<WebSocketContextType>({\r\n subscribe: () => {},\r\n values: {},\r\n})\r\n\r\ntype State = Record<string, any>\r\n\r\ninterface WebSocketProviderProps {\r\n config: SparkleConfig\r\n children: ReactNode\r\n}\r\n\r\nexport const WebSocketProvider = ({ children }: WebSocketProviderProps) => {\r\n const [values, setValues] = useState<State>({})\r\n const socket = useRef<WebSocketClient>()\r\n\r\n const { token } = useContext(SparkleAuthContext)\r\n\r\n useEffect(() => {\r\n socket.current = new WebSocketClient(\"http://localhost:4005/ws\")\r\n\r\n socket.current.on(\"update\", (message: UpdateMessage) => {\r\n console.log(\"receive values\", message)\r\n const { data } = message\r\n setValues((prev) => ({ ...prev, [data.key]: data.value }))\r\n })\r\n\r\n return () => {\r\n socket.current?.disconnect()\r\n }\r\n }, [])\r\n\r\n useEffect(() => {\r\n if (!socket.current || !token) return\r\n\r\n socket.current.authenticate(token)\r\n }, [token])\r\n\r\n const subscribe = useCallback(\r\n (keys: string[]) => {\r\n socket.current?.subscribe(keys)\r\n },\r\n [socket],\r\n )\r\n\r\n return (\r\n <SparkleContext.Provider\r\n value={{\r\n subscribe,\r\n values,\r\n }}\r\n >\r\n {children}\r\n </SparkleContext.Provider>\r\n )\r\n}\r\n","import EventEmitter from \"events\"\r\nimport z from \"zod\"\r\n\r\nconst subscribeSchema = z.object({\r\n type: z.literal(\"subscribe\"),\r\n channels: z.array(z.string()),\r\n})\r\n\r\nconst unsubscribeSchema = z.object({\r\n type: z.literal(\"unsubscribe\"),\r\n channels: z.string(),\r\n})\r\n\r\nconst updateSchema = z.object({\r\n event: z.literal(\"update\"),\r\n data: z.object({\r\n key: z.string(),\r\n value: z.string(),\r\n }),\r\n})\r\n\r\nconst messageSchema = z.union([subscribeSchema, unsubscribeSchema])\r\n\r\nexport type Message = z.infer<typeof messageSchema>\r\n\r\nexport type UpdateMessage = z.infer<typeof updateSchema>\r\nexport type SubscribeMessage = z.infer<typeof subscribeSchema>\r\nexport type UnsubscribeMessage = z.infer<typeof unsubscribeSchema>\r\n\r\nexport class WebSocketClient extends EventEmitter {\r\n private socket: WebSocket | null = null\r\n private queue: Message[] = []\r\n private subscriptions: string[] = []\r\n private isAuthenticating = false\r\n\r\n private url: string\r\n private jwt: string | null = null\r\n\r\n constructor(url: string) {\r\n super()\r\n this.url = url\r\n }\r\n\r\n private send(data: Message) {\r\n if (this.socket?.readyState === WebSocket.OPEN) {\r\n this.socket?.send(JSON.stringify(data))\r\n } else {\r\n this.queue.push(data)\r\n }\r\n }\r\n\r\n authenticate(jwt: string) {\r\n if (this.isAuthenticating) return\r\n this.isAuthenticating = true\r\n this.jwt = jwt\r\n this.connect()\r\n }\r\n\r\n private connect() {\r\n const authenticatedUrl = this.url + \"?jwt=\" + this.jwt\r\n this.socket = new WebSocket(authenticatedUrl)\r\n\r\n this.socket.onopen = () => {\r\n this.queue.forEach((data) => this.send(data))\r\n this.queue = []\r\n }\r\n\r\n this.socket.onmessage = (event) => {\r\n const data = JSON.parse(event.data)\r\n this.emit(\"update\", data)\r\n }\r\n\r\n this.socket.onclose = () => {\r\n this.reconnect()\r\n }\r\n }\r\n\r\n reconnect() {\r\n setTimeout(() => {\r\n this.queue = [\r\n {\r\n type: \"subscribe\",\r\n channels: this.subscriptions,\r\n },\r\n ]\r\n\r\n console.log(\"try reconnecting\")\r\n\r\n this.connect()\r\n }, 5000)\r\n }\r\n\r\n subscribe(channels: string[]) {\r\n const newChannels = channels.filter(\r\n (channel) => !this.subscriptions.includes(channel)\r\n )\r\n\r\n if (!newChannels.length) return\r\n this.subscriptions = [...this.subscriptions, ...newChannels]\r\n\r\n console.log(\"subscribe\", channels)\r\n\r\n this.send({\r\n type: \"subscribe\",\r\n channels,\r\n })\r\n }\r\n\r\n unsubscribe(channels: string) {\r\n this.send({ type: \"unsubscribe\", channels })\r\n }\r\n\r\n disconnect() {\r\n if (!this.socket) return\r\n\r\n this.socket.onclose = () => {}\r\n this.socket.close()\r\n }\r\n}\r\n","import { useContext, useEffect, useMemo } from \"react\"\r\nimport { SparkleContext } from \"../providers/realtimeProvider\"\r\n\r\nexport function useRealtime<T>(...keyInputs: string[]) {\r\n const context = useContext(SparkleContext)\r\n\r\n const keys = useMemo(() => keyInputs, [keyInputs.join(\",\")])\r\n\r\n if (!context) {\r\n throw new Error(\"You must use useDatabase inside a SparkleProvider\")\r\n }\r\n\r\n useEffect(() => {\r\n context.subscribe(keys)\r\n }, [keys])\r\n\r\n return keys.map((k) => context.values[k])\r\n}\r\n","import { useContext } from \"react\"\r\nimport { SparkleAuthContext } from \"../providers/authProvider\"\r\n\r\nexport function useAuth() {\r\n const { token: accessToken } = useContext(SparkleAuthContext)\r\n\r\n return {\r\n token: accessToken,\r\n }\r\n}\r\n","import { ApiClient } from \"@twurple/api\"\r\nimport { StaticAuthProvider } from \"@twurple/auth\"\r\nimport { useEffect, useState } from \"react\"\r\nimport useLocalStorage from \"../utils/hooks/useLocalStorage\"\r\n\r\nexport function useTwitch(asUser?: string | number) {\r\n const [apiClient, setApiClient] = useState<ApiClient | null>(null)\r\n const [twitch] = useLocalStorage<string>(\"twitch\")\r\n\r\n useEffect(() => {\r\n console.log(\"env\", process.env.TWITCH_CLIENT_ID)\r\n\r\n console.log(\"init\")\r\n\r\n const apiClient = new ApiClient({\r\n authProvider: new StaticAuthProvider(\r\n \"u9lt242tz2pn5hl5x444ls2xllnvip\",\r\n twitch!,\r\n [\r\n \"bits:read\",\r\n \"channel:manage:moderators\",\r\n \"channel:manage:polls\",\r\n \"channel:manage:predictions\",\r\n \"channel:manage:redemptions\",\r\n \"channel:manage:vips\",\r\n\r\n \"channel:read:polls\",\r\n \"channel:read:predictions\",\r\n \"channel:read:redemptions\",\r\n \"channel:read:subscriptions\",\r\n \"channel:read:vips\",\r\n \"moderation:read\",\r\n \"moderator:manage:announcements\",\r\n \"channel:moderate\",\r\n \"moderator:read:blocked_terms\",\r\n \"moderator:read:chatters\",\r\n \"moderator:read:followers\",\r\n \"user:read:email\",\r\n ]\r\n ),\r\n })\r\n\r\n setApiClient(apiClient)\r\n\r\n return () => {\r\n setApiClient(null)\r\n }\r\n }, [])\r\n\r\n return {\r\n apiClient,\r\n }\r\n}\r\n","import {\r\n Dispatch,\r\n SetStateAction,\r\n useCallback,\r\n useState,\r\n useRef,\r\n useLayoutEffect,\r\n} from \"react\"\r\nimport { isBrowser, noop } from \"../utils\"\r\n\r\ntype parserOptions<T> =\r\n | {\r\n raw: true\r\n }\r\n | {\r\n raw: false\r\n serializer: (value: T) => string\r\n deserializer: (value: string) => T\r\n }\r\n\r\nconst useLocalStorage = <T>(\r\n key: string,\r\n initialValue?: T,\r\n options?: parserOptions<T>\r\n): [T | undefined, Dispatch<SetStateAction<T | undefined>>, () => void] => {\r\n if (!isBrowser) {\r\n return [initialValue as T, noop, noop]\r\n }\r\n if (!key) {\r\n throw new Error(\"useLocalStorage key may not be falsy\")\r\n }\r\n\r\n const deserializer = options\r\n ? options.raw\r\n ? (value) => value\r\n : options.deserializer\r\n : JSON.parse\r\n\r\n // eslint-disable-next-line react-hooks/rules-of-hooks\r\n const initializer = useRef((key: string) => {\r\n try {\r\n const serializer = options\r\n ? options.raw\r\n ? String\r\n : options.serializer\r\n : JSON.stringify\r\n\r\n const localStorageValue = localStorage.getItem(key)\r\n if (localStorageValue !== null) {\r\n return deserializer(localStorageValue)\r\n } else {\r\n initialValue && localStorage.setItem(key, serializer(initialValue))\r\n return initialValue\r\n }\r\n } catch {\r\n // If user is in private mode or has storage restriction\r\n // localStorage can throw. JSON.parse and JSON.stringify\r\n // can throw, too.\r\n return initialValue\r\n }\r\n })\r\n\r\n // eslint-disable-next-line react-hooks/rules-of-hooks\r\n const [state, setState] = useState<T | undefined>(() =>\r\n initializer.current(key)\r\n )\r\n\r\n // eslint-disable-next-line react-hooks/rules-of-hooks\r\n useLayoutEffect(() => setState(initializer.current(key)), [key])\r\n\r\n // eslint-disable-next-line react-hooks/rules-of-hooks\r\n const set: Dispatch<SetStateAction<T | undefined>> = useCallback(\r\n (valOrFunc) => {\r\n try {\r\n const newState =\r\n typeof valOrFunc === \"function\"\r\n ? (valOrFunc as Function)(state)\r\n : valOrFunc\r\n if (typeof newState === \"undefined\") return\r\n let value: string\r\n\r\n if (options)\r\n if (options.raw)\r\n if (typeof newState === \"string\") value = newState\r\n else value = JSON.stringify(newState)\r\n else if (options.serializer) value = options.serializer(newState)\r\n else value = JSON.stringify(newState)\r\n else value = JSON.stringify(newState)\r\n\r\n localStorage.setItem(key, value)\r\n setState(deserializer(value))\r\n } catch {\r\n // If user is in private mode or has storage restriction\r\n // localStorage can throw. Also JSON.stringify can throw.\r\n }\r\n },\r\n [key, setState]\r\n )\r\n\r\n // eslint-disable-next-line react-hooks/rules-of-hooks\r\n const remove = useCallback(() => {\r\n try {\r\n localStorage.removeItem(key)\r\n setState(undefined)\r\n } catch {\r\n // If user is in private mode or has storage restriction\r\n // localStorage can throw.\r\n }\r\n }, [key, setState])\r\n\r\n return [state, set, remove]\r\n}\r\n\r\nexport default useLocalStorage\r\n"],"mappings":"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","names":["React","useEffect","useState","React","createContext","useEffect","useState","useEffect","useState","noop","on","obj","args","off","isBrowser","getValue","search","param","useSearchParam","location","value","setValue","useState","useEffect","onChange","on","off","useSearchParamServer","useSearchParam_default","isBrowser","SparkleAuthContext","createContext","AuthProvider","children","config","accessToken","setAccessToken","useState","oat","useSearchParam_default","useEffect","React","useCallback","useContext","useRef","createContext","useEffect","useState","EventEmitter","z","subscribeSchema","unsubscribeSchema","updateSchema","messageSchema","WebSocketClient","url","data","jwt","authenticatedUrl","event","channels","newChannels","channel","SparkleContext","createContext","WebSocketProvider","children","values","setValues","useState","socket","useRef","token","useContext","SparkleAuthContext","useEffect","WebSocketClient","message","data","prev","subscribe","useCallback","keys","React","Provider","children","isClientReady","setIsClientReady","useState","useEffect","SparkleProvider","config","React","AuthProvider","WebSocketProvider","useContext","useEffect","useMemo","useRealtime","keyInputs","context","useContext","SparkleContext","keys","useMemo","useEffect","k","useContext","useAuth","accessToken","useContext","SparkleAuthContext","ApiClient","StaticAuthProvider","useEffect","useState","useCallback","useState","useRef","useLayoutEffect","useLocalStorage","key","initialValue","options","isBrowser","noop","deserializer","value","initializer","useRef","serializer","localStorageValue","state","setState","useState","useLayoutEffect","set","useCallback","valOrFunc","newState","remove","useLocalStorage_default","useTwitch","asUser","apiClient","setApiClient","useState","twitch","useLocalStorage_default","useEffect","ApiClient","StaticAuthProvider"]}
|
|
1
|
+
{"version":3,"sources":["../src/provider.tsx","../src/providers/authProvider.tsx","../src/providers/realtimeProvider.tsx","../src/lib/websocket.ts","../src/hooks/useRealtime.ts","../src/hooks/useAuth.ts","../src/hooks/useTwitch.ts","../src/utils/hooks/useLocalStorage.ts","../src/utils/utils.ts"],"sourcesContent":["import React, { type ReactNode, useContext, useEffect, useState } from \"react\"\r\nimport { AuthProvider, SparkleAuthContext } from \"./providers/authProvider\"\r\nimport { WebSocketProvider } from \"./providers/realtimeProvider\"\r\nimport { SparkleConfig } from \"./utils/config\"\r\n\r\nconst Provider = ({ children }: { children: ReactNode }) => {\r\n const [isClientReady, setIsClientReady] = useState(false)\r\n\r\n useEffect(() => {\r\n setIsClientReady(true)\r\n }, [])\r\n\r\n if (!isClientReady) {\r\n return null\r\n }\r\n\r\n // if (!token) {\r\n // return <LoginForm authenticate={authenticate} loading={loading} />\r\n // }\r\n\r\n // return (\r\n // <>\r\n // <UserInfo user={account} logout={logout} loading={loading} />\r\n // {account && children}\r\n // </>\r\n // )\r\n\r\n return children\r\n}\r\n\r\nexport interface SparkleProviderProps {\r\n config: SparkleConfig\r\n children: ReactNode\r\n}\r\n\r\nexport const SparkleProvider = ({ children, config }: SparkleProviderProps) => {\r\n return (\r\n <AuthProvider config={config}>\r\n <WebSocketProvider config={config}>\r\n <Provider>{children}</Provider>\r\n </WebSocketProvider>\r\n </AuthProvider>\r\n )\r\n}\r\n","import * as React from \"react\"\r\n\r\nimport { type ReactNode, createContext, useEffect, useState } from \"react\"\r\n\r\nimport { SparkleConfig } from \"../utils/config\"\r\nimport useSearchParam from \"../utils/hooks/useSearchParam\"\r\n\r\ninterface AuthContextType {\r\n token: string | undefined | null\r\n}\r\n\r\nconst STORAGE_KEY = \"twitch_access_token\"\r\n\r\nexport const SparkleAuthContext = createContext<AuthContextType>({\r\n token: null,\r\n})\r\n\r\ninterface AuthProviderProps {\r\n config: SparkleConfig\r\n children: ReactNode\r\n}\r\n\r\ntype AuthenticationMethod = \"OAT\" | \"JWT\"\r\n\r\nexport const AuthProvider = ({ children, config }: AuthProviderProps) => {\r\n const [accessToken, setAccessToken] = useState<string | null>(null)\r\n const oat = \"alxios\"\r\n\r\n useEffect(() => {\r\n if (oat) {\r\n setAccessToken(oat)\r\n }\r\n }, [oat])\r\n\r\n return (\r\n <SparkleAuthContext.Provider\r\n value={{\r\n token: accessToken,\r\n }}\r\n >\r\n {children}\r\n </SparkleAuthContext.Provider>\r\n )\r\n}\r\n","import React, { ReactNode, useCallback, useContext, useRef } from \"react\"\r\n\r\nimport { createContext, useEffect, useState } from \"react\"\r\nimport { SparkleAuthContext } from \"./authProvider\"\r\nimport { UpdateMessage, WebSocketClient } from \"../lib/websocket\"\r\nimport { SparkleConfig } from \"../utils/config\"\r\n\r\ninterface WebSocketContextType {\r\n subscribe: (keys: string[]) => void\r\n values: Record<string, any>\r\n}\r\n\r\nexport const SparkleContext = createContext<WebSocketContextType>({\r\n subscribe: () => {},\r\n values: {},\r\n})\r\n\r\ntype State = Record<string, any>\r\n\r\ninterface WebSocketProviderProps {\r\n config: SparkleConfig\r\n children: ReactNode\r\n}\r\n\r\nexport const WebSocketProvider = ({ children }: WebSocketProviderProps) => {\r\n const [values, setValues] = useState<State>({})\r\n const socket = useRef<WebSocketClient>()\r\n\r\n const { token } = useContext(SparkleAuthContext)\r\n\r\n useEffect(() => {\r\n socket.current = new WebSocketClient(\"http://localhost:4005/ws\")\r\n\r\n socket.current.on(\"update\", (message: UpdateMessage) => {\r\n console.log(\"receive values\", message)\r\n const { data } = message\r\n setValues((prev) => ({ ...prev, [data.key]: data.value }))\r\n })\r\n\r\n return () => {\r\n socket.current?.disconnect()\r\n }\r\n }, [])\r\n\r\n useEffect(() => {\r\n if (!socket.current || !token) return\r\n\r\n socket.current.authenticate(token)\r\n }, [token])\r\n\r\n const subscribe = useCallback(\r\n (keys: string[]) => {\r\n socket.current?.subscribe(keys)\r\n },\r\n [socket],\r\n )\r\n\r\n return (\r\n <SparkleContext.Provider\r\n value={{\r\n subscribe,\r\n values,\r\n }}\r\n >\r\n {children}\r\n </SparkleContext.Provider>\r\n )\r\n}\r\n","import EventEmitter from \"events\"\r\nimport z from \"zod\"\r\n\r\nconst subscribeSchema = z.object({\r\n type: z.literal(\"subscribe\"),\r\n channels: z.array(z.string()),\r\n})\r\n\r\nconst unsubscribeSchema = z.object({\r\n type: z.literal(\"unsubscribe\"),\r\n channels: z.string(),\r\n})\r\n\r\nconst updateSchema = z.object({\r\n event: z.literal(\"update\"),\r\n data: z.object({\r\n key: z.string(),\r\n value: z.string(),\r\n }),\r\n})\r\n\r\nconst messageSchema = z.union([subscribeSchema, unsubscribeSchema])\r\n\r\nexport type Message = z.infer<typeof messageSchema>\r\n\r\nexport type UpdateMessage = z.infer<typeof updateSchema>\r\nexport type SubscribeMessage = z.infer<typeof subscribeSchema>\r\nexport type UnsubscribeMessage = z.infer<typeof unsubscribeSchema>\r\n\r\nexport class WebSocketClient extends EventEmitter {\r\n private socket: WebSocket | null = null\r\n private queue: Message[] = []\r\n private subscriptions: string[] = []\r\n private isAuthenticating = false\r\n\r\n private url: string\r\n private jwt: string | null = null\r\n\r\n constructor(url: string) {\r\n super()\r\n this.url = url\r\n }\r\n\r\n private send(data: Message) {\r\n if (this.socket?.readyState === WebSocket.OPEN) {\r\n this.socket?.send(JSON.stringify(data))\r\n } else {\r\n this.queue.push(data)\r\n }\r\n }\r\n\r\n authenticate(jwt: string) {\r\n if (this.isAuthenticating) return\r\n this.isAuthenticating = true\r\n this.jwt = jwt\r\n this.connect()\r\n }\r\n\r\n private connect() {\r\n const authenticatedUrl = this.url + \"?jwt=\" + this.jwt\r\n this.socket = new WebSocket(authenticatedUrl)\r\n\r\n this.socket.onopen = () => {\r\n this.queue.forEach((data) => this.send(data))\r\n this.queue = []\r\n }\r\n\r\n this.socket.onmessage = (event) => {\r\n const data = JSON.parse(event.data)\r\n this.emit(\"update\", data)\r\n }\r\n\r\n this.socket.onclose = () => {\r\n this.reconnect()\r\n }\r\n }\r\n\r\n reconnect() {\r\n setTimeout(() => {\r\n this.queue = [\r\n {\r\n type: \"subscribe\",\r\n channels: this.subscriptions,\r\n },\r\n ]\r\n\r\n console.log(\"try reconnecting\")\r\n\r\n this.connect()\r\n }, 5000)\r\n }\r\n\r\n subscribe(channels: string[]) {\r\n const newChannels = channels.filter(\r\n (channel) => !this.subscriptions.includes(channel)\r\n )\r\n\r\n if (!newChannels.length) return\r\n this.subscriptions = [...this.subscriptions, ...newChannels]\r\n\r\n console.log(\"subscribe\", channels)\r\n\r\n this.send({\r\n type: \"subscribe\",\r\n channels,\r\n })\r\n }\r\n\r\n unsubscribe(channels: string) {\r\n this.send({ type: \"unsubscribe\", channels })\r\n }\r\n\r\n disconnect() {\r\n if (!this.socket) return\r\n\r\n this.socket.onclose = () => {}\r\n this.socket.close()\r\n }\r\n}\r\n","import { useContext, useEffect, useMemo } from \"react\"\r\nimport { SparkleContext } from \"../providers/realtimeProvider\"\r\n\r\nexport function useRealtime<T>(...keyInputs: string[]) {\r\n const context = useContext(SparkleContext)\r\n\r\n const keys = useMemo(() => keyInputs, [keyInputs.join(\",\")])\r\n\r\n if (!context) {\r\n throw new Error(\"You must use useDatabase inside a SparkleProvider\")\r\n }\r\n\r\n useEffect(() => {\r\n context.subscribe(keys)\r\n }, [keys])\r\n\r\n return keys.map((k) => context.values[k])\r\n}\r\n","import { useContext } from \"react\"\r\nimport { SparkleAuthContext } from \"../providers/authProvider\"\r\n\r\nexport function useAuth() {\r\n const { token: accessToken } = useContext(SparkleAuthContext)\r\n\r\n return {\r\n token: accessToken,\r\n }\r\n}\r\n","import { ApiClient } from \"@twurple/api\"\r\nimport { StaticAuthProvider } from \"@twurple/auth\"\r\nimport { useEffect, useState } from \"react\"\r\nimport useLocalStorage from \"../utils/hooks/useLocalStorage\"\r\n\r\nexport function useTwitch(asUser?: string | number) {\r\n const [apiClient, setApiClient] = useState<ApiClient | null>(null)\r\n const [twitch] = useLocalStorage<string>(\"twitch\")\r\n\r\n useEffect(() => {\r\n console.log(\"env\", process.env.TWITCH_CLIENT_ID)\r\n\r\n console.log(\"init\")\r\n\r\n const apiClient = new ApiClient({\r\n authProvider: new StaticAuthProvider(\r\n \"u9lt242tz2pn5hl5x444ls2xllnvip\",\r\n twitch!,\r\n [\r\n \"bits:read\",\r\n \"channel:manage:moderators\",\r\n \"channel:manage:polls\",\r\n \"channel:manage:predictions\",\r\n \"channel:manage:redemptions\",\r\n \"channel:manage:vips\",\r\n\r\n \"channel:read:polls\",\r\n \"channel:read:predictions\",\r\n \"channel:read:redemptions\",\r\n \"channel:read:subscriptions\",\r\n \"channel:read:vips\",\r\n \"moderation:read\",\r\n \"moderator:manage:announcements\",\r\n \"channel:moderate\",\r\n \"moderator:read:blocked_terms\",\r\n \"moderator:read:chatters\",\r\n \"moderator:read:followers\",\r\n \"user:read:email\",\r\n ]\r\n ),\r\n })\r\n\r\n setApiClient(apiClient)\r\n\r\n return () => {\r\n setApiClient(null)\r\n }\r\n }, [])\r\n\r\n return {\r\n apiClient,\r\n }\r\n}\r\n","import {\r\n Dispatch,\r\n SetStateAction,\r\n useCallback,\r\n useState,\r\n useRef,\r\n useLayoutEffect,\r\n} from \"react\"\r\nimport { isBrowser, noop } from \"../utils\"\r\n\r\ntype parserOptions<T> =\r\n | {\r\n raw: true\r\n }\r\n | {\r\n raw: false\r\n serializer: (value: T) => string\r\n deserializer: (value: string) => T\r\n }\r\n\r\nconst useLocalStorage = <T>(\r\n key: string,\r\n initialValue?: T,\r\n options?: parserOptions<T>\r\n): [T | undefined, Dispatch<SetStateAction<T | undefined>>, () => void] => {\r\n if (!isBrowser) {\r\n return [initialValue as T, noop, noop]\r\n }\r\n if (!key) {\r\n throw new Error(\"useLocalStorage key may not be falsy\")\r\n }\r\n\r\n const deserializer = options\r\n ? options.raw\r\n ? (value) => value\r\n : options.deserializer\r\n : JSON.parse\r\n\r\n // eslint-disable-next-line react-hooks/rules-of-hooks\r\n const initializer = useRef((key: string) => {\r\n try {\r\n const serializer = options\r\n ? options.raw\r\n ? String\r\n : options.serializer\r\n : JSON.stringify\r\n\r\n const localStorageValue = localStorage.getItem(key)\r\n if (localStorageValue !== null) {\r\n return deserializer(localStorageValue)\r\n } else {\r\n initialValue && localStorage.setItem(key, serializer(initialValue))\r\n return initialValue\r\n }\r\n } catch {\r\n // If user is in private mode or has storage restriction\r\n // localStorage can throw. JSON.parse and JSON.stringify\r\n // can throw, too.\r\n return initialValue\r\n }\r\n })\r\n\r\n // eslint-disable-next-line react-hooks/rules-of-hooks\r\n const [state, setState] = useState<T | undefined>(() =>\r\n initializer.current(key)\r\n )\r\n\r\n // eslint-disable-next-line react-hooks/rules-of-hooks\r\n useLayoutEffect(() => setState(initializer.current(key)), [key])\r\n\r\n // eslint-disable-next-line react-hooks/rules-of-hooks\r\n const set: Dispatch<SetStateAction<T | undefined>> = useCallback(\r\n (valOrFunc) => {\r\n try {\r\n const newState =\r\n typeof valOrFunc === \"function\"\r\n ? (valOrFunc as Function)(state)\r\n : valOrFunc\r\n if (typeof newState === \"undefined\") return\r\n let value: string\r\n\r\n if (options)\r\n if (options.raw)\r\n if (typeof newState === \"string\") value = newState\r\n else value = JSON.stringify(newState)\r\n else if (options.serializer) value = options.serializer(newState)\r\n else value = JSON.stringify(newState)\r\n else value = JSON.stringify(newState)\r\n\r\n localStorage.setItem(key, value)\r\n setState(deserializer(value))\r\n } catch {\r\n // If user is in private mode or has storage restriction\r\n // localStorage can throw. Also JSON.stringify can throw.\r\n }\r\n },\r\n [key, setState]\r\n )\r\n\r\n // eslint-disable-next-line react-hooks/rules-of-hooks\r\n const remove = useCallback(() => {\r\n try {\r\n localStorage.removeItem(key)\r\n setState(undefined)\r\n } catch {\r\n // If user is in private mode or has storage restriction\r\n // localStorage can throw.\r\n }\r\n }, [key, setState])\r\n\r\n return [state, set, remove]\r\n}\r\n\r\nexport default useLocalStorage\r\n","export const noop = () => {}\r\n\r\nexport function on<T extends Window | Document | HTMLElement | EventTarget>(\r\n obj: T | null,\r\n ...args: Parameters<T[\"addEventListener\"]> | [string, Function | null, ...any]\r\n): void {\r\n if (obj && obj.addEventListener) {\r\n obj.addEventListener(\r\n ...(args as Parameters<HTMLElement[\"addEventListener\"]>)\r\n )\r\n }\r\n}\r\n\r\nexport function off<T extends Window | Document | HTMLElement | EventTarget>(\r\n obj: T | null,\r\n ...args:\r\n | Parameters<T[\"removeEventListener\"]>\r\n | [string, Function | null, ...any]\r\n): void {\r\n if (obj && obj.removeEventListener) {\r\n obj.removeEventListener(\r\n ...(args as Parameters<HTMLElement[\"removeEventListener\"]>)\r\n )\r\n }\r\n}\r\n\r\nexport const isBrowser = typeof window !== \"undefined\"\r\n\r\nexport const isNavigator = typeof navigator !== \"undefined\"\r\n"],"mappings":"AAAA,OAAOA,GAAqC,aAAAC,EAAW,YAAAC,MAAgB,QCAvE,UAAYC,MAAW,QAEvB,OAAyB,iBAAAC,EAAe,aAAAC,EAAW,YAAAC,MAAgB,QAW5D,IAAMC,EAAqBC,EAA+B,CAC/D,MAAO,IACT,CAAC,EASYC,EAAe,CAAC,CAAE,SAAAC,EAAU,OAAAC,CAAO,IAAyB,CACvE,GAAM,CAACC,EAAaC,CAAc,EAAIC,EAAwB,IAAI,EAC5DC,EAAM,SAEZ,OAAAC,EAAU,IAAM,CACVD,GACFF,EAAeE,CAAG,CAEtB,EAAG,CAACA,CAAG,CAAC,EAGN,gBAACR,EAAmB,SAAnB,CACC,MAAO,CACL,MAAOK,CACT,GAECF,CACH,CAEJ,EC3CA,OAAOO,GAAoB,eAAAC,EAAa,cAAAC,EAAY,UAAAC,MAAc,QAElE,OAAS,iBAAAC,EAAe,aAAAC,EAAW,YAAAC,MAAgB,QCFnD,OAAOC,MAAkB,SACzB,OAAOC,MAAO,MAEd,IAAMC,EAAkBD,EAAE,OAAO,CAC/B,KAAMA,EAAE,QAAQ,WAAW,EAC3B,SAAUA,EAAE,MAAMA,EAAE,OAAO,CAAC,CAC9B,CAAC,EAEKE,EAAoBF,EAAE,OAAO,CACjC,KAAMA,EAAE,QAAQ,aAAa,EAC7B,SAAUA,EAAE,OAAO,CACrB,CAAC,EAEKG,GAAeH,EAAE,OAAO,CAC5B,MAAOA,EAAE,QAAQ,QAAQ,EACzB,KAAMA,EAAE,OAAO,CACb,IAAKA,EAAE,OAAO,EACd,MAAOA,EAAE,OAAO,CAClB,CAAC,CACH,CAAC,EAEKI,GAAgBJ,EAAE,MAAM,CAACC,EAAiBC,CAAiB,CAAC,EAQrDG,EAAN,cAA8BN,CAAa,CAShD,YAAYO,EAAa,CACvB,MAAM,EATR,KAAQ,OAA2B,KACnC,KAAQ,MAAmB,CAAC,EAC5B,KAAQ,cAA0B,CAAC,EACnC,KAAQ,iBAAmB,GAG3B,KAAQ,IAAqB,KAI3B,KAAK,IAAMA,CACb,CAEQ,KAAKC,EAAe,CACtB,KAAK,QAAQ,aAAe,UAAU,KACxC,KAAK,QAAQ,KAAK,KAAK,UAAUA,CAAI,CAAC,EAEtC,KAAK,MAAM,KAAKA,CAAI,CAExB,CAEA,aAAaC,EAAa,CACpB,KAAK,mBACT,KAAK,iBAAmB,GACxB,KAAK,IAAMA,EACX,KAAK,QAAQ,EACf,CAEQ,SAAU,CAChB,IAAMC,EAAmB,KAAK,IAAM,QAAU,KAAK,IACnD,KAAK,OAAS,IAAI,UAAUA,CAAgB,EAE5C,KAAK,OAAO,OAAS,IAAM,CACzB,KAAK,MAAM,QAASF,GAAS,KAAK,KAAKA,CAAI,CAAC,EAC5C,KAAK,MAAQ,CAAC,CAChB,EAEA,KAAK,OAAO,UAAaG,GAAU,CACjC,IAAMH,EAAO,KAAK,MAAMG,EAAM,IAAI,EAClC,KAAK,KAAK,SAAUH,CAAI,CAC1B,EAEA,KAAK,OAAO,QAAU,IAAM,CAC1B,KAAK,UAAU,CACjB,CACF,CAEA,WAAY,CACV,WAAW,IAAM,CACf,KAAK,MAAQ,CACX,CACE,KAAM,YACN,SAAU,KAAK,aACjB,CACF,EAEA,QAAQ,IAAI,kBAAkB,EAE9B,KAAK,QAAQ,CACf,EAAG,GAAI,CACT,CAEA,UAAUI,EAAoB,CAC5B,IAAMC,EAAcD,EAAS,OAC1BE,GAAY,CAAC,KAAK,cAAc,SAASA,CAAO,CACnD,EAEKD,EAAY,SACjB,KAAK,cAAgB,CAAC,GAAG,KAAK,cAAe,GAAGA,CAAW,EAE3D,QAAQ,IAAI,YAAaD,CAAQ,EAEjC,KAAK,KAAK,CACR,KAAM,YACN,SAAAA,CACF,CAAC,EACH,CAEA,YAAYA,EAAkB,CAC5B,KAAK,KAAK,CAAE,KAAM,cAAe,SAAAA,CAAS,CAAC,CAC7C,CAEA,YAAa,CACN,KAAK,SAEV,KAAK,OAAO,QAAU,IAAM,CAAC,EAC7B,KAAK,OAAO,MAAM,EACpB,CACF,ED1GO,IAAMG,EAAiBC,EAAoC,CAChE,UAAW,IAAM,CAAC,EAClB,OAAQ,CAAC,CACX,CAAC,EASYC,EAAoB,CAAC,CAAE,SAAAC,CAAS,IAA8B,CACzE,GAAM,CAACC,EAAQC,CAAS,EAAIC,EAAgB,CAAC,CAAC,EACxCC,EAASC,EAAwB,EAEjC,CAAE,MAAAC,CAAM,EAAIC,EAAWC,CAAkB,EAE/CC,EAAU,KACRL,EAAO,QAAU,IAAIM,EAAgB,0BAA0B,EAE/DN,EAAO,QAAQ,GAAG,SAAWO,GAA2B,CACtD,QAAQ,IAAI,iBAAkBA,CAAO,EACrC,GAAM,CAAE,KAAAC,CAAK,EAAID,EACjBT,EAAWW,IAAU,CAAE,GAAGA,EAAM,CAACD,EAAK,GAAG,EAAGA,EAAK,KAAM,EAAE,CAC3D,CAAC,EAEM,IAAM,CACXR,EAAO,SAAS,WAAW,CAC7B,GACC,CAAC,CAAC,EAELK,EAAU,IAAM,CACV,CAACL,EAAO,SAAW,CAACE,GAExBF,EAAO,QAAQ,aAAaE,CAAK,CACnC,EAAG,CAACA,CAAK,CAAC,EAEV,IAAMQ,EAAYC,EACfC,GAAmB,CAClBZ,EAAO,SAAS,UAAUY,CAAI,CAChC,EACA,CAACZ,CAAM,CACT,EAEA,OACEa,EAAA,cAACpB,EAAe,SAAf,CACC,MAAO,CACL,UAAAiB,EACA,OAAAb,CACF,GAECD,CACH,CAEJ,EF9DA,IAAMkB,EAAW,CAAC,CAAE,SAAAC,CAAS,IAA+B,CAC1D,GAAM,CAACC,EAAeC,CAAgB,EAAIC,EAAS,EAAK,EAMxD,OAJAC,EAAU,IAAM,CACdF,EAAiB,EAAI,CACvB,EAAG,CAAC,CAAC,EAEAD,EAeED,EAdE,IAeX,EAOaK,GAAkB,CAAC,CAAE,SAAAL,EAAU,OAAAM,CAAO,IAE/CC,EAAA,cAACC,EAAA,CAAa,OAAQF,GACpBC,EAAA,cAACE,EAAA,CAAkB,OAAQH,GACzBC,EAAA,cAACR,EAAA,KAAUC,CAAS,CACtB,CACF,EIzCJ,OAAS,cAAAU,EAAY,aAAAC,EAAW,WAAAC,MAAe,QAGxC,SAASC,MAAkBC,EAAqB,CACrD,IAAMC,EAAUC,EAAWC,CAAc,EAEnCC,EAAOC,EAAQ,IAAML,EAAW,CAACA,EAAU,KAAK,GAAG,CAAC,CAAC,EAE3D,GAAI,CAACC,EACH,MAAM,IAAI,MAAM,mDAAmD,EAGrE,OAAAK,EAAU,IAAM,CACdL,EAAQ,UAAUG,CAAI,CACxB,EAAG,CAACA,CAAI,CAAC,EAEFA,EAAK,IAAKG,GAAMN,EAAQ,OAAOM,CAAC,CAAC,CAC1C,CCjBA,OAAS,cAAAC,MAAkB,QAGpB,SAASC,IAAU,CACxB,GAAM,CAAE,MAAOC,CAAY,EAAIC,EAAWC,CAAkB,EAE5D,MAAO,CACL,MAAOF,CACT,CACF,CCTA,OAAS,aAAAG,MAAiB,eAC1B,OAAS,sBAAAC,MAA0B,gBACnC,OAAS,aAAAC,EAAW,YAAAC,MAAgB,QCFpC,OAGE,eAAAC,EACA,YAAAC,EACA,UAAAC,EACA,mBAAAC,MACK,QCPA,IAAMC,EAAO,IAAM,CAAC,EA0BpB,IAAMC,EAAY,OAAO,OAAW,IDN3C,IAAMC,EAAkB,CACtBC,EACAC,EACAC,IACyE,CACzE,GAAI,CAACC,EACH,MAAO,CAACF,EAAmBG,EAAMA,CAAI,EAEvC,GAAI,CAACJ,EACH,MAAM,IAAI,MAAM,sCAAsC,EAGxD,IAAMK,EAAeH,EACjBA,EAAQ,IACLI,GAAUA,EACXJ,EAAQ,aACV,KAAK,MAGHK,EAAcC,EAAQR,GAAgB,CAC1C,GAAI,CACF,IAAMS,EAAaP,EACfA,EAAQ,IACN,OACAA,EAAQ,WACV,KAAK,UAEHQ,EAAoB,aAAa,QAAQV,CAAG,EAClD,OAAIU,IAAsB,KACjBL,EAAaK,CAAiB,GAErCT,GAAgB,aAAa,QAAQD,EAAKS,EAAWR,CAAY,CAAC,EAC3DA,EAEX,MAAQ,CAIN,OAAOA,CACT,CACF,CAAC,EAGK,CAACU,EAAOC,CAAQ,EAAIC,EAAwB,IAChDN,EAAY,QAAQP,CAAG,CACzB,EAGAc,EAAgB,IAAMF,EAASL,EAAY,QAAQP,CAAG,CAAC,EAAG,CAACA,CAAG,CAAC,EAG/D,IAAMe,EAA+CC,EAClDC,GAAc,CACb,GAAI,CACF,IAAMC,EACJ,OAAOD,GAAc,WAChBA,EAAuBN,CAAK,EAC7BM,EACN,GAAI,OAAOC,EAAa,IAAa,OACrC,IAAIZ,EAEAJ,EACEA,EAAQ,IACN,OAAOgB,GAAa,SAAUZ,EAAQY,EACrCZ,EAAQ,KAAK,UAAUY,CAAQ,EAC7BhB,EAAQ,WAAYI,EAAQJ,EAAQ,WAAWgB,CAAQ,EAC3DZ,EAAQ,KAAK,UAAUY,CAAQ,EACjCZ,EAAQ,KAAK,UAAUY,CAAQ,EAEpC,aAAa,QAAQlB,EAAKM,CAAK,EAC/BM,EAASP,EAAaC,CAAK,CAAC,CAC9B,MAAQ,CAGR,CACF,EACA,CAACN,EAAKY,CAAQ,CAChB,EAGMO,EAASH,EAAY,IAAM,CAC/B,GAAI,CACF,aAAa,WAAWhB,CAAG,EAC3BY,EAAS,MAAS,CACpB,MAAQ,CAGR,CACF,EAAG,CAACZ,EAAKY,CAAQ,CAAC,EAElB,MAAO,CAACD,EAAOI,EAAKI,CAAM,CAC5B,EAEOC,EAAQrB,ED5GR,SAASsB,GAAUC,EAA0B,CAClD,GAAM,CAACC,EAAWC,CAAY,EAAIC,EAA2B,IAAI,EAC3D,CAACC,CAAM,EAAIC,EAAwB,QAAQ,EAEjD,OAAAC,EAAU,IAAM,CACd,QAAQ,IAAI,MAAO,QAAQ,IAAI,gBAAgB,EAE/C,QAAQ,IAAI,MAAM,EAElB,IAAML,EAAY,IAAIM,EAAU,CAC9B,aAAc,IAAIC,EAChB,iCACAJ,EACA,CACE,YACA,4BACA,uBACA,6BACA,6BACA,sBAEA,qBACA,2BACA,2BACA,6BACA,oBACA,kBACA,iCACA,mBACA,+BACA,0BACA,2BACA,iBACF,CACF,CACF,CAAC,EAED,OAAAF,EAAaD,CAAS,EAEf,IAAM,CACXC,EAAa,IAAI,CACnB,CACF,EAAG,CAAC,CAAC,EAEE,CACL,UAAAD,CACF,CACF","names":["React","useEffect","useState","React","createContext","useEffect","useState","SparkleAuthContext","createContext","AuthProvider","children","config","accessToken","setAccessToken","useState","oat","useEffect","React","useCallback","useContext","useRef","createContext","useEffect","useState","EventEmitter","z","subscribeSchema","unsubscribeSchema","updateSchema","messageSchema","WebSocketClient","url","data","jwt","authenticatedUrl","event","channels","newChannels","channel","SparkleContext","createContext","WebSocketProvider","children","values","setValues","useState","socket","useRef","token","useContext","SparkleAuthContext","useEffect","WebSocketClient","message","data","prev","subscribe","useCallback","keys","React","Provider","children","isClientReady","setIsClientReady","useState","useEffect","SparkleProvider","config","React","AuthProvider","WebSocketProvider","useContext","useEffect","useMemo","useRealtime","keyInputs","context","useContext","SparkleContext","keys","useMemo","useEffect","k","useContext","useAuth","accessToken","useContext","SparkleAuthContext","ApiClient","StaticAuthProvider","useEffect","useState","useCallback","useState","useRef","useLayoutEffect","noop","isBrowser","useLocalStorage","key","initialValue","options","isBrowser","noop","deserializer","value","initializer","useRef","serializer","localStorageValue","state","setState","useState","useLayoutEffect","set","useCallback","valOrFunc","newState","remove","useLocalStorage_default","useTwitch","asUser","apiClient","setApiClient","useState","twitch","useLocalStorage_default","useEffect","ApiClient","StaticAuthProvider"]}
|