sparkle-react 0.0.14 → 0.0.17

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.css CHANGED
@@ -1,2 +1,2 @@
1
- *,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.fixed{position:fixed}.absolute{position:absolute}.inset-0{inset:0}.bottom-3{bottom:.75rem}.left-1\/2{left:50%}.right-3{right:.75rem}.top-1\/2{top:50%}.z-50{z-index:50}.flex{display:flex}.inline-flex{display:inline-flex}.h-9{height:2.25rem}.h-\[34px\]{height:34px}.w-\[34px\]{width:34px}.w-full{width:100%}.min-w-\[124px\]{min-width:124px}.max-w-xs{max-width:20rem}.flex-shrink-0{flex-shrink:0}.-translate-x-1\/2{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-pointer{cursor:pointer}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-center{justify-content:center}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.5rem * var(--tw-space-x-reverse));margin-left:calc(.5rem * calc(1 - var(--tw-space-x-reverse)))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.overflow-hidden{overflow:hidden}.whitespace-nowrap{white-space:nowrap}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.bg-\[\#313131\]{--tw-bg-opacity: 1;background-color:rgb(49 49 49 / var(--tw-bg-opacity))}.bg-black{--tw-bg-opacity: 1;background-color:rgb(0 0 0 / var(--tw-bg-opacity))}.bg-black\/60{background-color:#0009}.bg-red-500{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity))}.p-2{padding:.5rem}.p-3{padding:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.text-2xl{font-size:1.5rem;line-height:2rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.capitalize{text-transform:capitalize}.tracking-tight{letter-spacing:-.025em}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.ring-1{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-white\/10{--tw-ring-color: rgb(255 255 255 / .1)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-xl{--tw-backdrop-blur: blur(24px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition-colors{transition-property:color,background-color,border-color,fill,stroke,-webkit-text-decoration-color;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,-webkit-text-decoration-color;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:ring-1:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:opacity-50:disabled{opacity:.5}
1
+ *,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}
2
2
  /*# sourceMappingURL=index.css.map */
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/globals.css"],"sourcesContent":["/*\n! tailwindcss v3.3.0 | MIT License | https://tailwindcss.com\n*//*\n1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)\n2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)\n*/\n\n*,\n::before,\n::after {\n box-sizing: border-box; /* 1 */\n border-width: 0; /* 2 */\n border-style: solid; /* 2 */\n border-color: #e5e7eb; /* 2 */\n}\n\n::before,\n::after {\n --tw-content: '';\n}\n\n/*\n1. Use a consistent sensible line-height in all browsers.\n2. Prevent adjustments of font size after orientation changes in iOS.\n3. Use a more readable tab size.\n4. Use the user's configured `sans` font-family by default.\n5. Use the user's configured `sans` font-feature-settings by default.\n6. Use the user's configured `sans` font-variation-settings by default.\n*/\n\nhtml {\n line-height: 1.5; /* 1 */\n -webkit-text-size-adjust: 100%; /* 2 */\n -moz-tab-size: 4; /* 3 */\n -o-tab-size: 4;\n tab-size: 4; /* 3 */\n font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\"; /* 4 */\n font-feature-settings: normal; /* 5 */\n font-variation-settings: normal; /* 6 */\n}\n\n/*\n1. Remove the margin in all browsers.\n2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.\n*/\n\nbody {\n margin: 0; /* 1 */\n line-height: inherit; /* 2 */\n}\n\n/*\n1. Add the correct height in Firefox.\n2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)\n3. Ensure horizontal rules are visible by default.\n*/\n\nhr {\n height: 0; /* 1 */\n color: inherit; /* 2 */\n border-top-width: 1px; /* 3 */\n}\n\n/*\nAdd the correct text decoration in Chrome, Edge, and Safari.\n*/\n\nabbr:where([title]) {\n -webkit-text-decoration: underline dotted;\n text-decoration: underline dotted;\n}\n\n/*\nRemove the default font size and weight for headings.\n*/\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n font-size: inherit;\n font-weight: inherit;\n}\n\n/*\nReset links to optimize for opt-in styling instead of opt-out.\n*/\n\na {\n color: inherit;\n text-decoration: inherit;\n}\n\n/*\nAdd the correct font weight in Edge and Safari.\n*/\n\nb,\nstrong {\n font-weight: bolder;\n}\n\n/*\n1. Use the user's configured `mono` font family by default.\n2. Correct the odd `em` font sizing in all browsers.\n*/\n\ncode,\nkbd,\nsamp,\npre {\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace; /* 1 */\n font-size: 1em; /* 2 */\n}\n\n/*\nAdd the correct font size in all browsers.\n*/\n\nsmall {\n font-size: 80%;\n}\n\n/*\nPrevent `sub` and `sup` elements from affecting the line height in all browsers.\n*/\n\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\n\nsub {\n bottom: -0.25em;\n}\n\nsup {\n top: -0.5em;\n}\n\n/*\n1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)\n2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)\n3. Remove gaps between table borders by default.\n*/\n\ntable {\n text-indent: 0; /* 1 */\n border-color: inherit; /* 2 */\n border-collapse: collapse; /* 3 */\n}\n\n/*\n1. Change the font styles in all browsers.\n2. Remove the margin in Firefox and Safari.\n3. Remove default padding in all browsers.\n*/\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n font-family: inherit; /* 1 */\n font-size: 100%; /* 1 */\n font-weight: inherit; /* 1 */\n line-height: inherit; /* 1 */\n color: inherit; /* 1 */\n margin: 0; /* 2 */\n padding: 0; /* 3 */\n}\n\n/*\nRemove the inheritance of text transform in Edge and Firefox.\n*/\n\nbutton,\nselect {\n text-transform: none;\n}\n\n/*\n1. Correct the inability to style clickable types in iOS and Safari.\n2. Remove default button styles.\n*/\n\nbutton,\n[type='button'],\n[type='reset'],\n[type='submit'] {\n -webkit-appearance: button; /* 1 */\n background-color: transparent; /* 2 */\n background-image: none; /* 2 */\n}\n\n/*\nUse the modern Firefox focus style for all focusable elements.\n*/\n\n:-moz-focusring {\n outline: auto;\n}\n\n/*\nRemove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)\n*/\n\n:-moz-ui-invalid {\n box-shadow: none;\n}\n\n/*\nAdd the correct vertical alignment in Chrome and Firefox.\n*/\n\nprogress {\n vertical-align: baseline;\n}\n\n/*\nCorrect the cursor style of increment and decrement buttons in Safari.\n*/\n\n::-webkit-inner-spin-button,\n::-webkit-outer-spin-button {\n height: auto;\n}\n\n/*\n1. Correct the odd appearance in Chrome and Safari.\n2. Correct the outline style in Safari.\n*/\n\n[type='search'] {\n -webkit-appearance: textfield; /* 1 */\n outline-offset: -2px; /* 2 */\n}\n\n/*\nRemove the inner padding in Chrome and Safari on macOS.\n*/\n\n::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n/*\n1. Correct the inability to style clickable types in iOS and Safari.\n2. Change font properties to `inherit` in Safari.\n*/\n\n::-webkit-file-upload-button {\n -webkit-appearance: button; /* 1 */\n font: inherit; /* 2 */\n}\n\n/*\nAdd the correct display in Chrome and Safari.\n*/\n\nsummary {\n display: list-item;\n}\n\n/*\nRemoves the default spacing and border for appropriate elements.\n*/\n\nblockquote,\ndl,\ndd,\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\nhr,\nfigure,\np,\npre {\n margin: 0;\n}\n\nfieldset {\n margin: 0;\n padding: 0;\n}\n\nlegend {\n padding: 0;\n}\n\nol,\nul,\nmenu {\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n/*\nPrevent resizing textareas horizontally by default.\n*/\n\ntextarea {\n resize: vertical;\n}\n\n/*\n1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)\n2. Set the default placeholder color to the user's configured gray 400 color.\n*/\n\ninput::-moz-placeholder, textarea::-moz-placeholder {\n opacity: 1; /* 1 */\n color: #9ca3af; /* 2 */\n}\n\ninput::placeholder,\ntextarea::placeholder {\n opacity: 1; /* 1 */\n color: #9ca3af; /* 2 */\n}\n\n/*\nSet the default cursor for buttons.\n*/\n\nbutton,\n[role=\"button\"] {\n cursor: pointer;\n}\n\n/*\nMake sure disabled buttons don't get the pointer cursor.\n*/\n:disabled {\n cursor: default;\n}\n\n/*\n1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)\n2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)\n This can trigger a poorly considered lint error in some tools but is included by design.\n*/\n\nimg,\nsvg,\nvideo,\ncanvas,\naudio,\niframe,\nembed,\nobject {\n display: block; /* 1 */\n vertical-align: middle; /* 2 */\n}\n\n/*\nConstrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)\n*/\n\nimg,\nvideo {\n max-width: 100%;\n height: auto;\n}\n\n/* Make elements with the HTML hidden attribute stay hidden by default */\n[hidden] {\n display: none;\n}\n\n*, ::before, ::after {\n --tw-border-spacing-x: 0;\n --tw-border-spacing-y: 0;\n --tw-translate-x: 0;\n --tw-translate-y: 0;\n --tw-rotate: 0;\n --tw-skew-x: 0;\n --tw-skew-y: 0;\n --tw-scale-x: 1;\n --tw-scale-y: 1;\n --tw-pan-x: ;\n --tw-pan-y: ;\n --tw-pinch-zoom: ;\n --tw-scroll-snap-strictness: proximity;\n --tw-ordinal: ;\n --tw-slashed-zero: ;\n --tw-numeric-figure: ;\n --tw-numeric-spacing: ;\n --tw-numeric-fraction: ;\n --tw-ring-inset: ;\n --tw-ring-offset-width: 0px;\n --tw-ring-offset-color: #fff;\n --tw-ring-color: rgb(59 130 246 / 0.5);\n --tw-ring-offset-shadow: 0 0 #0000;\n --tw-ring-shadow: 0 0 #0000;\n --tw-shadow: 0 0 #0000;\n --tw-shadow-colored: 0 0 #0000;\n --tw-blur: ;\n --tw-brightness: ;\n --tw-contrast: ;\n --tw-grayscale: ;\n --tw-hue-rotate: ;\n --tw-invert: ;\n --tw-saturate: ;\n --tw-sepia: ;\n --tw-drop-shadow: ;\n --tw-backdrop-blur: ;\n --tw-backdrop-brightness: ;\n --tw-backdrop-contrast: ;\n --tw-backdrop-grayscale: ;\n --tw-backdrop-hue-rotate: ;\n --tw-backdrop-invert: ;\n --tw-backdrop-opacity: ;\n --tw-backdrop-saturate: ;\n --tw-backdrop-sepia: ;\n}\n\n::backdrop {\n --tw-border-spacing-x: 0;\n --tw-border-spacing-y: 0;\n --tw-translate-x: 0;\n --tw-translate-y: 0;\n --tw-rotate: 0;\n --tw-skew-x: 0;\n --tw-skew-y: 0;\n --tw-scale-x: 1;\n --tw-scale-y: 1;\n --tw-pan-x: ;\n --tw-pan-y: ;\n --tw-pinch-zoom: ;\n --tw-scroll-snap-strictness: proximity;\n --tw-ordinal: ;\n --tw-slashed-zero: ;\n --tw-numeric-figure: ;\n --tw-numeric-spacing: ;\n --tw-numeric-fraction: ;\n --tw-ring-inset: ;\n --tw-ring-offset-width: 0px;\n --tw-ring-offset-color: #fff;\n --tw-ring-color: rgb(59 130 246 / 0.5);\n --tw-ring-offset-shadow: 0 0 #0000;\n --tw-ring-shadow: 0 0 #0000;\n --tw-shadow: 0 0 #0000;\n --tw-shadow-colored: 0 0 #0000;\n --tw-blur: ;\n --tw-brightness: ;\n --tw-contrast: ;\n --tw-grayscale: ;\n --tw-hue-rotate: ;\n --tw-invert: ;\n --tw-saturate: ;\n --tw-sepia: ;\n --tw-drop-shadow: ;\n --tw-backdrop-blur: ;\n --tw-backdrop-brightness: ;\n --tw-backdrop-contrast: ;\n --tw-backdrop-grayscale: ;\n --tw-backdrop-hue-rotate: ;\n --tw-backdrop-invert: ;\n --tw-backdrop-opacity: ;\n --tw-backdrop-saturate: ;\n --tw-backdrop-sepia: ;\n}\n.fixed {\n position: fixed;\n}\n.absolute {\n position: absolute;\n}\n.inset-0 {\n inset: 0px;\n}\n.bottom-3 {\n bottom: 0.75rem;\n}\n.left-1\\/2 {\n left: 50%;\n}\n.right-3 {\n right: 0.75rem;\n}\n.top-1\\/2 {\n top: 50%;\n}\n.z-50 {\n z-index: 50;\n}\n.flex {\n display: flex;\n}\n.inline-flex {\n display: inline-flex;\n}\n.h-9 {\n height: 2.25rem;\n}\n.h-\\[34px\\] {\n height: 34px;\n}\n.w-\\[34px\\] {\n width: 34px;\n}\n.w-full {\n width: 100%;\n}\n.min-w-\\[124px\\] {\n min-width: 124px;\n}\n.max-w-xs {\n max-width: 20rem;\n}\n.flex-shrink-0 {\n flex-shrink: 0;\n}\n.-translate-x-1\\/2 {\n --tw-translate-x: -50%;\n transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n}\n.-translate-y-1\\/2 {\n --tw-translate-y: -50%;\n transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n}\n@keyframes spin {\n\n to {\n transform: rotate(360deg);\n }\n}\n.animate-spin {\n animation: spin 1s linear infinite;\n}\n.cursor-pointer {\n cursor: pointer;\n}\n.flex-row {\n flex-direction: row;\n}\n.flex-col {\n flex-direction: column;\n}\n.items-start {\n align-items: flex-start;\n}\n.items-center {\n align-items: center;\n}\n.justify-center {\n justify-content: center;\n}\n.gap-2 {\n gap: 0.5rem;\n}\n.gap-3 {\n gap: 0.75rem;\n}\n.space-x-2 > :not([hidden]) ~ :not([hidden]) {\n --tw-space-x-reverse: 0;\n margin-right: calc(0.5rem * var(--tw-space-x-reverse));\n margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse)));\n}\n.space-y-3 > :not([hidden]) ~ :not([hidden]) {\n --tw-space-y-reverse: 0;\n margin-top: calc(0.75rem * calc(1 - var(--tw-space-y-reverse)));\n margin-bottom: calc(0.75rem * var(--tw-space-y-reverse));\n}\n.overflow-hidden {\n overflow: hidden;\n}\n.whitespace-nowrap {\n white-space: nowrap;\n}\n.rounded-lg {\n border-radius: 0.5rem;\n}\n.rounded-md {\n border-radius: 0.375rem;\n}\n.bg-\\[\\#313131\\] {\n --tw-bg-opacity: 1;\n background-color: rgb(49 49 49 / var(--tw-bg-opacity));\n}\n.bg-black {\n --tw-bg-opacity: 1;\n background-color: rgb(0 0 0 / var(--tw-bg-opacity));\n}\n.bg-black\\/60 {\n background-color: rgb(0 0 0 / 0.6);\n}\n.bg-red-500 {\n --tw-bg-opacity: 1;\n background-color: rgb(239 68 68 / var(--tw-bg-opacity));\n}\n.p-2 {\n padding: 0.5rem;\n}\n.p-3 {\n padding: 0.75rem;\n}\n.px-4 {\n padding-left: 1rem;\n padding-right: 1rem;\n}\n.py-2 {\n padding-top: 0.5rem;\n padding-bottom: 0.5rem;\n}\n.text-2xl {\n font-size: 1.5rem;\n line-height: 2rem;\n}\n.text-sm {\n font-size: 0.875rem;\n line-height: 1.25rem;\n}\n.text-xs {\n font-size: 0.75rem;\n line-height: 1rem;\n}\n.font-medium {\n font-weight: 500;\n}\n.font-normal {\n font-weight: 400;\n}\n.font-semibold {\n font-weight: 600;\n}\n.capitalize {\n text-transform: capitalize;\n}\n.tracking-tight {\n letter-spacing: -0.025em;\n}\n.text-white {\n --tw-text-opacity: 1;\n color: rgb(255 255 255 / var(--tw-text-opacity));\n}\n.shadow {\n --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);\n --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);\n box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n}\n.shadow-md {\n --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);\n --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);\n box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n}\n.ring-1 {\n --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);\n --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);\n box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);\n}\n.ring-white\\/10 {\n --tw-ring-color: rgb(255 255 255 / 0.1);\n}\n.filter {\n filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);\n}\n.backdrop-blur-xl {\n --tw-backdrop-blur: blur(24px);\n -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);\n backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);\n}\n.transition-colors {\n transition-property: color, background-color, border-color, fill, stroke, -webkit-text-decoration-color;\n transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;\n transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, -webkit-text-decoration-color;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n}\n.focus-visible\\:outline-none:focus-visible {\n outline: 2px solid transparent;\n outline-offset: 2px;\n}\n.focus-visible\\:ring-1:focus-visible {\n --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);\n --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);\n box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000);\n}\n.disabled\\:pointer-events-none:disabled {\n pointer-events: none;\n}\n.disabled\\:opacity-50:disabled {\n opacity: 0.5;\n}\n"],"mappings":"AAOA,EACA,QACA,OACE,WAAY,WACZ,aAAc,EACd,aAAc,MACd,aAAc,OAChB,CAEA,QACA,OACE,cAAc,EAChB,CAWA,KACE,YAAa,IACb,yBAA0B,KAC1B,cAAe,EACf,YAAa,EACV,SAAU,EACb,YAAa,aAAa,CAAE,SAAS,CAAE,aAAa,CAAE,kBAAkB,CAAE,QAAU,CAAE,MAAM,CAAE,cAAgB,CAAE,KAAK,CAAE,SAAW,CAAE,UAAU,CAAE,mBAAmB,CAAE,gBAAgB,CAAE,eAAiB,CAAE,mBAC1M,sBAAuB,OACvB,wBAAyB,MAC3B,CAOA,KA9CA,OA+CU,EACR,YAAa,OACf,CAQA,GACE,OAAQ,EACR,MAAO,QACP,iBAAkB,GACpB,CAMA,IAAI,OAAO,CAAC,QACV,wBAAyB,UAAU,OAC3B,gBAAiB,UAAU,MACrC,CAMA,GACA,GACA,GACA,GACA,GACA,GACE,UAAW,QACX,YAAa,OACf,CAMA,EACE,MAAO,QACP,gBAAiB,OACnB,CAMA,EACA,OACE,YAAa,MACf,CAOA,KACA,IACA,KACA,IACE,YAAa,YAAY,CAAE,cAAc,CAAE,KAAK,CAAE,MAAM,CAAE,QAAQ,CAAE,eAAiB,CAAE,WAAa,CAAE,UACtG,UAAW,GACb,CAMA,MACE,UAAW,GACb,CAMA,IACA,IACE,UAAW,IACX,YAAa,EACb,SAAU,SACV,eAAgB,QAClB,CAEA,IACE,OAAQ,MACV,CAEA,IACE,IAAK,KACP,CAQA,MACE,YAAa,EACb,aAAc,QACd,gBAAiB,QACnB,CAQA,OACA,MACA,SACA,OACA,SACE,YAAa,QACb,UAAW,KACX,YAAa,QACb,YAAa,QACb,MAAO,QA5KT,OA6KU,EA7KV,QA8KW,CACX,CAMA,OACA,OACE,eAAgB,IAClB,CAOA,OACA,CAAC,aACD,CAAC,YACD,CAAC,aACC,mBAAoB,OACpB,iBAAkB,YAClB,iBAAkB,IACpB,CAMA,gBACE,QAAS,IACX,CAMA,iBACE,WAAY,IACd,CAMA,SACE,eAAgB,QAClB,CAMA,4BACA,4BACE,OAAQ,IACV,CAOA,CAAC,aACC,mBAAoB,UACpB,eAAgB,IAClB,CAMA,4BACE,mBAAoB,IACtB,CAOA,6BACE,mBAAoB,OACpB,KAAM,OACR,CAMA,QACE,QAAS,SACX,CAMA,WACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,GACA,OACA,EACA,IA7RA,OA8RU,CACV,CAEA,SAjSA,OAkSU,EAlSV,QAmSW,CACX,CAEA,OAtSA,QAuSW,CACX,CAEA,GACA,GACA,KACE,WAAY,KA7Sd,OA8SU,EA9SV,QA+SW,CACX,CAMA,SACE,OAAQ,QACV,CAOA,KAAK,mBAAoB,QAAQ,mBAC/B,QAAS,EACT,MAAO,OACT,CAEA,KAAK,cACL,QAAQ,cACN,QAAS,EACT,MAAO,OACT,CAMA,OACA,CAAC,aACC,OAAQ,OACV,CAKA,UACE,OAAQ,OACV,CAQA,IACA,IACA,MACA,OACA,MACA,OACA,MACA,OACE,QAAS,MACT,eAAgB,MAClB,CAMA,IACA,MACE,UAAW,KACX,OAAQ,IACV,CAGA,CAAC,QACC,QAAS,IACX,CAEA,EAAG,QAAU,OACX,uBAAuB,EACvB,uBAAuB,EACvB,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,aAAa,EACb,cAAc,EACd,cAAc,EACd,aACA,aACA,kBACA,6BAA6B,UAC7B,eACA,oBACA,sBACA,uBACA,wBACA,kBACA,wBAAwB,IACxB,wBAAwB,KACxB,iBAAiB,IAAI,GAAG,IAAI,IAAI,EAAE,IAClC,yBAAyB,EAAE,EAAE,MAC7B,kBAAkB,EAAE,EAAE,MACtB,aAAa,EAAE,EAAE,MACjB,qBAAqB,EAAE,EAAE,MACzB,YACA,kBACA,gBACA,iBACA,kBACA,cACA,gBACA,aACA,mBACA,qBACA,2BACA,yBACA,0BACA,2BACA,uBACA,wBACA,yBACA,qBACF,CAEA,WACE,uBAAuB,EACvB,uBAAuB,EACvB,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,aAAa,EACb,cAAc,EACd,cAAc,EACd,aACA,aACA,kBACA,6BAA6B,UAC7B,eACA,oBACA,sBACA,uBACA,wBACA,kBACA,wBAAwB,IACxB,wBAAwB,KACxB,iBAAiB,IAAI,GAAG,IAAI,IAAI,EAAE,IAClC,yBAAyB,EAAE,EAAE,MAC7B,kBAAkB,EAAE,EAAE,MACtB,aAAa,EAAE,EAAE,MACjB,qBAAqB,EAAE,EAAE,MACzB,YACA,kBACA,gBACA,iBACA,kBACA,cACA,gBACA,aACA,mBACA,qBACA,2BACA,yBACA,0BACA,2BACA,uBACA,wBACA,yBACA,qBACF,CACA,CAAC,MACC,SAAU,KACZ,CACA,CAAC,SACC,SAAU,QACZ,CACA,CAAC,QA9dD,MA+dS,CACT,CACA,CAAC,SACC,OAAQ,MACV,CACA,CAAC,UACC,KAAM,GACR,CACA,CAAC,QACC,MAAO,MACT,CACA,CAAC,SACC,IAAK,GACP,CACA,CAAC,KACC,QAAS,EACX,CACA,CAAC,KACC,QAAS,IACX,CACA,CAAC,YACC,QAAS,WACX,CACA,CAAC,IACC,OAAQ,OACV,CACA,CAAC,WACC,OAAQ,IACV,CACA,CAAC,WACC,MAAO,IACT,CACA,CAAC,OACC,MAAO,IACT,CACA,CAAC,gBACC,UAAW,KACb,CACA,CAAC,SACC,UAAW,KACb,CACA,CAAC,cACC,YAAa,CACf,CACA,CAAC,kBACC,kBAAkB,KAClB,UAAW,UAAU,IAAI,iBAAiB,CAAE,IAAI,mBAAmB,OAAO,IAAI,cAAc,KAAM,IAAI,cAAc,MAAM,IAAI,cAAc,OAAO,IAAI,eAAe,OAAO,IAAI,cACnL,CACA,CAAC,kBACC,kBAAkB,KAClB,UAAW,UAAU,IAAI,iBAAiB,CAAE,IAAI,mBAAmB,OAAO,IAAI,cAAc,KAAM,IAAI,cAAc,MAAM,IAAI,cAAc,OAAO,IAAI,eAAe,OAAO,IAAI,cACnL,CACA,WAAW,KAET,GACE,UAAW,OAAO,OACpB,CACF,CACA,CAAC,aACC,UAAW,KAAK,GAAG,OAAO,QAC5B,CACA,CAAC,eACC,OAAQ,OACV,CACA,CAAC,SACC,eAAgB,GAClB,CACA,CAAC,SACC,eAAgB,MAClB,CACA,CAAC,YACC,YAAa,UACf,CACA,CAAC,aACC,YAAa,MACf,CACA,CAAC,eACC,gBAAiB,MACnB,CACA,CAAC,MACC,IAAK,KACP,CACA,CAAC,MACC,IAAK,MACP,CACA,CAAC,SAAU,CAAE,KAAK,CAAC,QAAS,CAAE,KAAK,CAAC,SAClC,sBAAsB,EACtB,aAAc,KAAK,MAAO,EAAE,IAAI,uBAChC,YAAa,KAAK,MAAO,EAAE,KAAK,EAAE,EAAE,IAAI,uBAC1C,CACA,CAAC,SAAU,CAAE,KAAK,CAAC,QAAS,CAAE,KAAK,CAAC,SAClC,sBAAsB,EACtB,WAAY,KAAK,OAAQ,EAAE,KAAK,EAAE,EAAE,IAAI,wBACxC,cAAe,KAAK,OAAQ,EAAE,IAAI,sBACpC,CACA,CAAC,gBACC,SAAU,MACZ,CACA,CAAC,kBACC,YAAa,MACf,CACA,CAAC,WApkBD,cAqkBiB,KACjB,CACA,CAAC,WAvkBD,cAwkBiB,OACjB,CACA,CAAC,gBACC,iBAAiB,EACjB,iBAAkB,IAAI,GAAG,GAAG,GAAG,EAAE,IAAI,iBACvC,CACA,CAAC,SACC,iBAAiB,EACjB,iBAAkB,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,iBACpC,CACA,CAAC,aACC,iBAAkB,KACpB,CACA,CAAC,WACC,iBAAiB,EACjB,iBAAkB,IAAI,IAAI,GAAG,GAAG,EAAE,IAAI,iBACxC,CACA,CAAC,IAzlBD,QA0lBW,KACX,CACA,CAAC,IA5lBD,QA6lBW,MACX,CACA,CAAC,KACC,aAAc,KACd,cAAe,IACjB,CACA,CAAC,KACC,YAAa,MACb,eAAgB,KAClB,CACA,CAAC,SACC,UAAW,OACX,YAAa,IACf,CACA,CAAC,QACC,UAAW,QACX,YAAa,OACf,CACA,CAAC,QACC,UAAW,OACX,YAAa,IACf,CACA,CAAC,YACC,YAAa,GACf,CACA,CAAC,YACC,YAAa,GACf,CACA,CAAC,cACC,YAAa,GACf,CACA,CAAC,WACC,eAAgB,UAClB,CACA,CAAC,eACC,eAAgB,OAClB,CACA,CAAC,WACC,mBAAmB,EACnB,MAAO,IAAI,IAAI,IAAI,IAAI,EAAE,IAAI,mBAC/B,CACA,CAAC,OACC,aAAa,EAAE,IAAI,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,GAAI,EAAE,EAAE,IAAI,IAAI,KAAK,IAAI,EAAE,EAAE,EAAE,EAAE,IACtE,qBAAqB,EAAE,IAAI,IAAI,EAAE,IAAI,kBAAkB,EAAE,EAAE,IAAI,IAAI,KAAK,IAAI,mBAC5E,WAAY,IAAI,uBAAuB,EAAE,EAAE,EAAE,MAAM,CAAE,IAAI,gBAAgB,EAAE,EAAE,EAAE,MAAM,CAAE,IAAI,YAC7F,CACA,CAAC,UACC,aAAa,EAAE,IAAI,IAAI,KAAK,IAAI,EAAE,EAAE,EAAE,EAAE,GAAI,EAAE,EAAE,IAAI,IAAI,KAAK,IAAI,EAAE,EAAE,EAAE,EAAE,IACzE,qBAAqB,EAAE,IAAI,IAAI,KAAK,IAAI,kBAAkB,EAAE,EAAE,IAAI,IAAI,KAAK,IAAI,mBAC/E,WAAY,IAAI,uBAAuB,EAAE,EAAE,EAAE,MAAM,CAAE,IAAI,gBAAgB,EAAE,EAAE,EAAE,MAAM,CAAE,IAAI,YAC7F,CACA,CAAC,OACC,yBAAyB,IAAI,iBAAiB,EAAE,EAAE,EAAE,IAAI,wBAAwB,IAAI,wBACpF,kBAAkB,IAAI,iBAAiB,EAAE,EAAE,EAAE,KAAK,IAAI,EAAE,IAAI,yBAAyB,IAAI,iBACzF,WAAY,IAAI,wBAAwB,CAAE,IAAI,iBAAiB,CAAE,IAAI,WAAW,EAAE,EAAE,EAAE,MACxF,CACA,CAAC,eACC,iBAAiB,IAAI,IAAI,IAAI,IAAI,EAAE,GACrC,CACA,CAAC,OACC,OAAQ,IAAI,WAAW,IAAI,iBAAiB,IAAI,eAAe,IAAI,gBAAgB,IAAI,iBAAiB,IAAI,aAAa,IAAI,eAAe,IAAI,YAAY,IAAI,iBAClK,CACA,CAAC,iBACC,oBAAoB,KAAK,MACzB,wBAAyB,IAAI,oBAAoB,IAAI,0BAA0B,IAAI,wBAAwB,IAAI,yBAAyB,IAAI,0BAA0B,IAAI,sBAAsB,IAAI,uBAAuB,IAAI,wBAAwB,IAAI,qBACnP,gBAAiB,IAAI,oBAAoB,IAAI,0BAA0B,IAAI,wBAAwB,IAAI,yBAAyB,IAAI,0BAA0B,IAAI,sBAAsB,IAAI,uBAAuB,IAAI,wBAAwB,IAAI,oBAC7P,CACA,CAAC,kBACC,oBAAqB,KAAK,CAAE,gBAAgB,CAAE,YAAY,CAAE,IAAI,CAAE,MAAM,CAAE,8BAC1E,oBAAqB,KAAK,CAAE,gBAAgB,CAAE,YAAY,CAAE,qBAAqB,CAAE,IAAI,CAAE,OACzF,oBAAqB,KAAK,CAAE,gBAAgB,CAAE,YAAY,CAAE,qBAAqB,CAAE,IAAI,CAAE,MAAM,CAAE,8BACjG,2BAA4B,aAAa,EAAG,CAAE,CAAC,CAAE,EAAG,CAAE,GACtD,oBAAqB,IACvB,CACA,CAAC,2BAA2B,eAC1B,QAAS,IAAI,MAAM,YACnB,eAAgB,GAClB,CACA,CAAC,qBAAqB,eACpB,yBAAyB,IAAI,iBAAiB,EAAE,EAAE,EAAE,IAAI,wBAAwB,IAAI,wBACpF,kBAAkB,IAAI,iBAAiB,EAAE,EAAE,EAAE,KAAK,IAAI,EAAE,IAAI,yBAAyB,IAAI,iBACzF,WAAY,IAAI,wBAAwB,CAAE,IAAI,iBAAiB,CAAE,IAAI,WAAW,EAAE,EAAE,EAAE,MACxF,CACA,CAAC,6BAA6B,UAC5B,eAAgB,IAClB,CACA,CAAC,oBAAoB,UACnB,QAAS,EACX","names":[]}
1
+ {"version":3,"sources":["../src/globals.css"],"sourcesContent":["/*\n! tailwindcss v3.3.0 | MIT License | https://tailwindcss.com\n*//*\n1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)\n2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)\n*/\n\n*,\n::before,\n::after {\n box-sizing: border-box; /* 1 */\n border-width: 0; /* 2 */\n border-style: solid; /* 2 */\n border-color: #e5e7eb; /* 2 */\n}\n\n::before,\n::after {\n --tw-content: '';\n}\n\n/*\n1. Use a consistent sensible line-height in all browsers.\n2. Prevent adjustments of font size after orientation changes in iOS.\n3. Use a more readable tab size.\n4. Use the user's configured `sans` font-family by default.\n5. Use the user's configured `sans` font-feature-settings by default.\n6. Use the user's configured `sans` font-variation-settings by default.\n*/\n\nhtml {\n line-height: 1.5; /* 1 */\n -webkit-text-size-adjust: 100%; /* 2 */\n -moz-tab-size: 4; /* 3 */\n -o-tab-size: 4;\n tab-size: 4; /* 3 */\n font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\"; /* 4 */\n font-feature-settings: normal; /* 5 */\n font-variation-settings: normal; /* 6 */\n}\n\n/*\n1. Remove the margin in all browsers.\n2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.\n*/\n\nbody {\n margin: 0; /* 1 */\n line-height: inherit; /* 2 */\n}\n\n/*\n1. Add the correct height in Firefox.\n2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)\n3. Ensure horizontal rules are visible by default.\n*/\n\nhr {\n height: 0; /* 1 */\n color: inherit; /* 2 */\n border-top-width: 1px; /* 3 */\n}\n\n/*\nAdd the correct text decoration in Chrome, Edge, and Safari.\n*/\n\nabbr:where([title]) {\n -webkit-text-decoration: underline dotted;\n text-decoration: underline dotted;\n}\n\n/*\nRemove the default font size and weight for headings.\n*/\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n font-size: inherit;\n font-weight: inherit;\n}\n\n/*\nReset links to optimize for opt-in styling instead of opt-out.\n*/\n\na {\n color: inherit;\n text-decoration: inherit;\n}\n\n/*\nAdd the correct font weight in Edge and Safari.\n*/\n\nb,\nstrong {\n font-weight: bolder;\n}\n\n/*\n1. Use the user's configured `mono` font family by default.\n2. Correct the odd `em` font sizing in all browsers.\n*/\n\ncode,\nkbd,\nsamp,\npre {\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace; /* 1 */\n font-size: 1em; /* 2 */\n}\n\n/*\nAdd the correct font size in all browsers.\n*/\n\nsmall {\n font-size: 80%;\n}\n\n/*\nPrevent `sub` and `sup` elements from affecting the line height in all browsers.\n*/\n\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\n\nsub {\n bottom: -0.25em;\n}\n\nsup {\n top: -0.5em;\n}\n\n/*\n1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)\n2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)\n3. Remove gaps between table borders by default.\n*/\n\ntable {\n text-indent: 0; /* 1 */\n border-color: inherit; /* 2 */\n border-collapse: collapse; /* 3 */\n}\n\n/*\n1. Change the font styles in all browsers.\n2. Remove the margin in Firefox and Safari.\n3. Remove default padding in all browsers.\n*/\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n font-family: inherit; /* 1 */\n font-size: 100%; /* 1 */\n font-weight: inherit; /* 1 */\n line-height: inherit; /* 1 */\n color: inherit; /* 1 */\n margin: 0; /* 2 */\n padding: 0; /* 3 */\n}\n\n/*\nRemove the inheritance of text transform in Edge and Firefox.\n*/\n\nbutton,\nselect {\n text-transform: none;\n}\n\n/*\n1. Correct the inability to style clickable types in iOS and Safari.\n2. Remove default button styles.\n*/\n\nbutton,\n[type='button'],\n[type='reset'],\n[type='submit'] {\n -webkit-appearance: button; /* 1 */\n background-color: transparent; /* 2 */\n background-image: none; /* 2 */\n}\n\n/*\nUse the modern Firefox focus style for all focusable elements.\n*/\n\n:-moz-focusring {\n outline: auto;\n}\n\n/*\nRemove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)\n*/\n\n:-moz-ui-invalid {\n box-shadow: none;\n}\n\n/*\nAdd the correct vertical alignment in Chrome and Firefox.\n*/\n\nprogress {\n vertical-align: baseline;\n}\n\n/*\nCorrect the cursor style of increment and decrement buttons in Safari.\n*/\n\n::-webkit-inner-spin-button,\n::-webkit-outer-spin-button {\n height: auto;\n}\n\n/*\n1. Correct the odd appearance in Chrome and Safari.\n2. Correct the outline style in Safari.\n*/\n\n[type='search'] {\n -webkit-appearance: textfield; /* 1 */\n outline-offset: -2px; /* 2 */\n}\n\n/*\nRemove the inner padding in Chrome and Safari on macOS.\n*/\n\n::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n/*\n1. Correct the inability to style clickable types in iOS and Safari.\n2. Change font properties to `inherit` in Safari.\n*/\n\n::-webkit-file-upload-button {\n -webkit-appearance: button; /* 1 */\n font: inherit; /* 2 */\n}\n\n/*\nAdd the correct display in Chrome and Safari.\n*/\n\nsummary {\n display: list-item;\n}\n\n/*\nRemoves the default spacing and border for appropriate elements.\n*/\n\nblockquote,\ndl,\ndd,\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\nhr,\nfigure,\np,\npre {\n margin: 0;\n}\n\nfieldset {\n margin: 0;\n padding: 0;\n}\n\nlegend {\n padding: 0;\n}\n\nol,\nul,\nmenu {\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n/*\nPrevent resizing textareas horizontally by default.\n*/\n\ntextarea {\n resize: vertical;\n}\n\n/*\n1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)\n2. Set the default placeholder color to the user's configured gray 400 color.\n*/\n\ninput::-moz-placeholder, textarea::-moz-placeholder {\n opacity: 1; /* 1 */\n color: #9ca3af; /* 2 */\n}\n\ninput::placeholder,\ntextarea::placeholder {\n opacity: 1; /* 1 */\n color: #9ca3af; /* 2 */\n}\n\n/*\nSet the default cursor for buttons.\n*/\n\nbutton,\n[role=\"button\"] {\n cursor: pointer;\n}\n\n/*\nMake sure disabled buttons don't get the pointer cursor.\n*/\n:disabled {\n cursor: default;\n}\n\n/*\n1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)\n2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)\n This can trigger a poorly considered lint error in some tools but is included by design.\n*/\n\nimg,\nsvg,\nvideo,\ncanvas,\naudio,\niframe,\nembed,\nobject {\n display: block; /* 1 */\n vertical-align: middle; /* 2 */\n}\n\n/*\nConstrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)\n*/\n\nimg,\nvideo {\n max-width: 100%;\n height: auto;\n}\n\n/* Make elements with the HTML hidden attribute stay hidden by default */\n[hidden] {\n display: none;\n}\n\n*, ::before, ::after {\n --tw-border-spacing-x: 0;\n --tw-border-spacing-y: 0;\n --tw-translate-x: 0;\n --tw-translate-y: 0;\n --tw-rotate: 0;\n --tw-skew-x: 0;\n --tw-skew-y: 0;\n --tw-scale-x: 1;\n --tw-scale-y: 1;\n --tw-pan-x: ;\n --tw-pan-y: ;\n --tw-pinch-zoom: ;\n --tw-scroll-snap-strictness: proximity;\n --tw-ordinal: ;\n --tw-slashed-zero: ;\n --tw-numeric-figure: ;\n --tw-numeric-spacing: ;\n --tw-numeric-fraction: ;\n --tw-ring-inset: ;\n --tw-ring-offset-width: 0px;\n --tw-ring-offset-color: #fff;\n --tw-ring-color: rgb(59 130 246 / 0.5);\n --tw-ring-offset-shadow: 0 0 #0000;\n --tw-ring-shadow: 0 0 #0000;\n --tw-shadow: 0 0 #0000;\n --tw-shadow-colored: 0 0 #0000;\n --tw-blur: ;\n --tw-brightness: ;\n --tw-contrast: ;\n --tw-grayscale: ;\n --tw-hue-rotate: ;\n --tw-invert: ;\n --tw-saturate: ;\n --tw-sepia: ;\n --tw-drop-shadow: ;\n --tw-backdrop-blur: ;\n --tw-backdrop-brightness: ;\n --tw-backdrop-contrast: ;\n --tw-backdrop-grayscale: ;\n --tw-backdrop-hue-rotate: ;\n --tw-backdrop-invert: ;\n --tw-backdrop-opacity: ;\n --tw-backdrop-saturate: ;\n --tw-backdrop-sepia: ;\n}\n\n::backdrop {\n --tw-border-spacing-x: 0;\n --tw-border-spacing-y: 0;\n --tw-translate-x: 0;\n --tw-translate-y: 0;\n --tw-rotate: 0;\n --tw-skew-x: 0;\n --tw-skew-y: 0;\n --tw-scale-x: 1;\n --tw-scale-y: 1;\n --tw-pan-x: ;\n --tw-pan-y: ;\n --tw-pinch-zoom: ;\n --tw-scroll-snap-strictness: proximity;\n --tw-ordinal: ;\n --tw-slashed-zero: ;\n --tw-numeric-figure: ;\n --tw-numeric-spacing: ;\n --tw-numeric-fraction: ;\n --tw-ring-inset: ;\n --tw-ring-offset-width: 0px;\n --tw-ring-offset-color: #fff;\n --tw-ring-color: rgb(59 130 246 / 0.5);\n --tw-ring-offset-shadow: 0 0 #0000;\n --tw-ring-shadow: 0 0 #0000;\n --tw-shadow: 0 0 #0000;\n --tw-shadow-colored: 0 0 #0000;\n --tw-blur: ;\n --tw-brightness: ;\n --tw-contrast: ;\n --tw-grayscale: ;\n --tw-hue-rotate: ;\n --tw-invert: ;\n --tw-saturate: ;\n --tw-sepia: ;\n --tw-drop-shadow: ;\n --tw-backdrop-blur: ;\n --tw-backdrop-brightness: ;\n --tw-backdrop-contrast: ;\n --tw-backdrop-grayscale: ;\n --tw-backdrop-hue-rotate: ;\n --tw-backdrop-invert: ;\n --tw-backdrop-opacity: ;\n --tw-backdrop-saturate: ;\n --tw-backdrop-sepia: ;\n}\r\n.filter {\n filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);\n}\r\n"],"mappings":"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","names":[]}
package/dist/index.d.mts CHANGED
@@ -1,333 +1,33 @@
1
1
  import React, { ReactNode } from 'react';
2
+ import { z } from 'zod';
3
+ import { ApiClient } from '@twurple/api';
2
4
 
3
- interface SparkleConfig {
5
+ declare const sparkleConfig: z.ZodObject<{
6
+ apiKey: z.ZodString;
7
+ projectId: z.ZodString;
8
+ }, "strip", z.ZodTypeAny, {
4
9
  apiKey: string;
5
10
  projectId: string;
6
- oat?: string;
7
- }
8
-
9
- declare class SparkleClient {
10
- private config;
11
- private token;
12
- constructor(config: SparkleConfig);
13
- setToken(token: string): void;
14
- get database(): {
15
- set: (key: string, value: any) => Promise<Response>;
16
- get: (key: string) => Promise<Response>;
17
- incr: (key: string, value: number) => Promise<Response>;
18
- decr: (key: string, value: number) => Promise<Response>;
19
- del: (key: string) => Promise<Response>;
20
- };
21
- get twitch(): null;
22
- get hook(): null;
23
- httpCall(body: any): Promise<Response>;
24
- }
11
+ }, {
12
+ apiKey: string;
13
+ projectId: string;
14
+ }>;
15
+ type SparkleConfig = z.infer<typeof sparkleConfig>;
25
16
 
26
17
  interface SparkleProviderProps {
27
18
  config: SparkleConfig;
28
19
  children: ReactNode;
29
20
  }
30
- declare const SparkleAppContext: React.Context<{
31
- sparkle: SparkleClient | undefined;
32
- }>;
33
21
  declare const SparkleProvider: ({ children, config }: SparkleProviderProps) => React.JSX.Element;
34
22
 
35
23
  declare function useRealtime<T>(...keyInputs: string[]): any[];
36
24
 
37
- interface TokenInfo {
38
- userId: string;
39
- displayName: string;
40
- profilePictureUrl: string;
41
- exp: number;
42
- }
43
-
44
25
  declare function useAuth(): {
45
- account: TokenInfo | null;
46
26
  token: string | null | undefined;
47
- loading: boolean;
48
- authenticate: () => void;
49
- logout: () => void;
50
- };
51
-
52
- declare function useDatabase<T extends string>(): {
53
- set: (key: string, value: any) => Promise<Response>;
54
- get: (key: string) => Promise<Response>;
55
- incr: (key: string, value: number) => Promise<Response>;
56
- decr: (key: string, value: number) => Promise<Response>;
57
- del: (key: string) => Promise<Response>;
58
- };
59
-
60
- declare function useUser<T extends string>(...keys: T[]): {
61
- set: (key: string, value: any) => Promise<Response>;
62
- get: (key: string) => Promise<any>;
63
- incr: (key: string, value: number) => Promise<Response>;
64
- decr: (key: string, value: number) => Promise<Response>;
65
- del: (key: string) => Promise<Response>;
66
- user: {};
67
27
  };
68
28
 
69
- type CCL =
70
- | "DrugsIntoxication"
71
- | "Gambling"
72
- | "MatureGame"
73
- | "ProfanityVulgarity"
74
- | "SexualThemes"
75
- | "ViolentGraphic"
76
-
77
- type EventTypeMap = {
78
- // Notifications
79
- "notification.follow": EventSubFollowEvent
80
- "notification.subscribe": EventSubSubscribeEvent
81
- "notification.cheer": EventSubCheerEvent
82
-
83
- // Streams
84
- "stream.online": EventSubStreamOnlineEvent
85
- "stream.offline": EventSubStreamOfflineEvent
86
- "stream.update": EventSubStreamUpdateEvent
87
-
88
- // Rewards
89
- "reward.add": EventSubRewardAddEvent
90
- "reward.update": EventSubRewardUpdateEvent
91
- "reward.remove": EventSubRewardRemoveEvent
92
- "reward.redemption.claim": EventSubRedemptionClaimEvent
93
- "reward.redemption.update": EventSubRedemptionUpdateEvent
94
-
95
- // Polls
96
- "poll.begin": EventSubPollBeginEvent
97
- "poll.progress": EventSubPollProgressEvent
98
- "poll.end": EventSubPollEndEvent
99
-
100
- // Predictions
101
- "prediction.begin": EventSubPredictionBeginEvent
102
- "prediction.progress": EventSubPredictionProgressEvent
103
- "prediction.lock": EventSubPredictionLockEvent
104
- "prediction.end": EventSubPredictionEndEvent
105
-
106
- // Moderations
107
- "moderator.add": EventSubModeratorAddEvent
108
- "moderator.remove": EventSubModeratorRemoveEvent
109
-
110
- "moderator.ban": EventSubModeratorBanEvent
111
- "moderator.unban": EventSubModeratorUnbanEvent
112
-
113
- "moderator.shield_mode.begin": EventSubModeratorShieldModeBeginEvent
114
- }
115
-
116
- /**
117
- * Notifications Events
118
- */
119
-
120
- interface EventSubFollowEvent {
121
- user_id: string
122
- user_login: string
123
- user_name: string
124
- followed_at: string
125
- }
126
-
127
- interface EventSubSubscribeEvent {
128
- user_id: string
129
- user_login: string
130
- user_name: string
131
- tier: string
132
- is_gift: boolean
133
- }
134
-
135
- interface EventSubCheerEvent {
136
- is_anonymous: boolean
137
- user_id?: string
138
- user_login?: string
139
- user_name?: string
140
- message: string
141
- bits: number
142
- }
143
-
144
- /**
145
- * Stream Events
146
- */
147
-
148
- interface EventSubStreamOnlineEvent {
149
- id: string
150
- type: "live" | "playlist" | "watch_party" | "premiere" | "rerun"
151
- started_at: string
152
- }
153
-
154
- interface EventSubStreamOfflineEvent {}
155
-
156
- interface EventSubStreamUpdateEvent {
157
- title: string
158
- language: string
159
- category_id: string
160
- category_name: string
161
- content_classification_labels: CCL[]
162
- }
163
-
164
- /**
165
- * Rewards Events
166
- */
167
-
168
- interface RewardImage {
169
- url_1x: string | null
170
- url_2x: string | null
171
- url_4x: string | null
172
- }
173
-
174
- interface RewardCooldown {
175
- is_enabled: boolean
176
- value: number
177
- }
178
-
179
- interface EventSubRewardAddEvent {
180
- id: string
181
- is_enabled: boolean
182
- is_paused: boolean
183
- is_in_stock: boolean
184
- title: string
185
- cost: number
186
- prompt: string
187
- is_user_input_required: boolean
188
- should_redemptions_skip_request_queue: boolean
189
- max_per_stream: RewardCooldown
190
- max_per_user_per_stream: RewardCooldown
191
- background_color: string
192
- image: RewardImage | null
193
- default_image: RewardImage
194
- global_cooldown: RewardCooldown
195
- cooldown_expires_at: string | null
196
- redemptions_redeemed_current_stream: number | null
197
- }
198
-
199
- interface EventSubRewardUpdateEvent extends EventSubRewardAddEvent {}
200
- interface EventSubRewardRemoveEvent extends EventSubRewardAddEvent {}
201
-
202
- interface RewardInfo {
203
- id: string // Identifiant de la récompense
204
- title: string // Nom de la récompense
205
- cost: number // Coût de la récompense
206
- prompt: string // Description de la récompense
207
- }
208
-
209
- interface EventSubRedemptionClaimEvent {
210
- id: string // Identifiant du rachat de la récompense
211
- user_id: string // ID de l'utilisateur ayant racheté la récompense
212
- user_login: string // Nom d'utilisateur de l'utilisateur ayant racheté la récompense
213
- user_name: string // Nom d'affichage de l'utilisateur ayant racheté la récompense
214
- user_input: string // Entrée de l'utilisateur fournie. Chaîne vide si non fournie.
215
- status: "unknown" | "unfulfilled" | "fulfilled" | "canceled" // Statut du rachat de la récompense. Les valeurs possibles sont "unknown", "unfulfilled", "fulfilled" et "canceled".
216
- reward: RewardInfo // Informations de base sur la récompense qui a été rachetée au moment du rachat
217
- redeemed_at: string // Horodatage RFC3339 du moment où la récompense a été rachetée
218
- }
219
-
220
- interface EventSubRedemptionUpdateEvent extends EventSubRedemptionClaimEvent {}
221
-
222
- /**
223
- * Polls Events
224
- */
225
-
226
- interface PollChoice {
227
- id: string
228
- title: string
229
- channel_points_votes: number
230
- votes: number
231
- }
232
-
233
- interface PollChannelPointsVoting {
234
- is_enabled: boolean
235
- amount_per_vote: number
236
- }
237
-
238
- interface EventSubPollBeginEvent {
239
- id: string
240
- title: string
241
- choices: PollChoice[]
242
- channel_points_voting: PollChannelPointsVoting
243
- started_at: string
244
- ends_at: string
245
- }
246
-
247
- interface EventSubPollProgressEvent extends EventSubPollBeginEvent {}
248
-
249
- interface EventSubPollEndEvent extends EventSubPollBeginEvent {
250
- status: "completed" | "archived" | "terminated"
251
- }
252
-
253
- /**
254
- * Predictions Events
255
- */
256
-
257
- interface TopPredictor {
258
- user_id: string // ID de l'utilisateur
259
- user_login: string // Nom d'utilisateur de l'utilisateur
260
- user_name: string // Nom d'affichage de l'utilisateur
261
- channel_points_won: number | null // Nombre de Points de Chaîne gagnés (toujours null dans les événements de progression et de verrouillage de la prédiction)
262
- channel_points_used: number // Nombre de Points de Chaîne utilisés pour participer à la prédiction
263
- }
264
-
265
- interface Outcome {
266
- id: string // ID du résultat
267
- title: string // Titre du résultat
268
- color: "pink" | "blue" // Couleur du résultat. Les valeurs valides sont "pink" et "blue".
269
- users: number // Nombre d'utilisateurs ayant utilisé des Points de Chaîne pour ce résultat
270
- channel_points: number // Nombre total de Points de Chaîne utilisés pour ce résultat
271
- top_predictors: TopPredictor[] // Un tableau d'utilisateurs ayant utilisé le plus de Points de Chaîne sur ce résultat
272
- }
273
-
274
- interface EventSubPredictionBeginEvent {
275
- id: string // ID de la prédiction de Points de Chaîne
276
- title: string // Titre de la prédiction de Points de Chaîne
277
- outcomes: Outcome[] // Un tableau de résultats (outcomes) pour la prédiction de Points de Chaîne
278
- started_at: string // Heure de début de la prédiction de Points de Chaîne
279
- locks_at: string // Heure à laquelle la prédiction de Points de Chaîne se verrouillera automatiquement
280
- }
281
-
282
- interface EventSubPredictionProgressEvent
283
- extends EventSubPredictionBeginEvent {}
284
- interface EventSubPredictionLockEvent extends EventSubPredictionBeginEvent {}
285
-
286
- interface EventSubPredictionEndEvent extends EventSubPredictionBeginEvent {
287
- ended_at: string // Heure de fin de la prédiction de Points de Chaîne
288
- }
289
-
290
- /**
291
- * Moderations Events
292
- */
293
-
294
- interface EventSubModeratorAddEvent {
295
- user_id: string
296
- user_login: string
297
- user_name: string
298
- }
299
-
300
- interface EventSubModeratorRemoveEvent {
301
- user_id: string
302
- user_login: string
303
- user_name: string
304
- }
305
-
306
- interface EventSubModeratorBanEvent {
307
- user_id: string
308
- user_login: string
309
- user_name: string
310
- moderator_user_id: string
311
- moderator_user_login: string
312
- moderator_user_name: string
313
- reason: string
314
- banned_at: string
315
- ends_at: string | null
316
- is_permanent: boolean
317
- }
318
-
319
- interface EventSubModeratorUnbanEvent {
320
- user_id: string
321
- user_login: string
322
- user_name: string
323
- moderator_user_id: string
324
- moderator_user_login: string
325
- moderator_user_name: string
326
- }
327
-
328
- declare function useHook<T extends keyof EventTypeMap>(event: T, callback?: (data: EventTypeMap[T]) => void): {
329
- events: EventTypeMap[T][];
330
- lastEvent: EventTypeMap[T] | undefined;
29
+ declare function useTwitch(asUser?: string | number): {
30
+ apiClient: ApiClient | null;
331
31
  };
332
32
 
333
- export { SparkleAppContext, SparkleProvider, type SparkleProviderProps, useAuth, useDatabase, useHook, useRealtime, useUser };
33
+ export { SparkleProvider, type SparkleProviderProps, useAuth, useRealtime, useTwitch };
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import g,{useContext as St,useEffect as K,useState as Y,createContext as Ct}from"react";import*as m from"react";import{motion as L}from"framer-motion";import{Loader2 as Z}from"lucide-react";function z({authenticate:e,loading:t}){return m.createElement("div",{className:"absolute inset-0 bg-black/60 backdrop-blur-xl"},m.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"},m.createElement("h3",{className:"font-semibold tracking-tight text-2xl"},"Counter Manager"),m.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:e,disabled:t},m.createElement(L.div,{layout:!0,key:t?"loading":"loaded",initial:{opacity:0},animate:{opacity:1},exit:{opacity:0}},t?m.createElement(Z,{className:"animate-spin"}):m.createElement("span",null,"Login with Twitch"))),m.createElement("span",{className:"text-xs"},"Powered by Sparkle")))}import f,{useContext as ut}from"react";import{Loader2 as ht}from"lucide-react";import{motion as ft}from"framer-motion";import*as F from"react";import{createContext as ct,useCallback as R,useEffect as N,useState as O}from"react";var _=async(e,t)=>fetch("http://localhost:4005/auth/oat",{method:"POST",headers:{"Content-Type":"application/json","Api-Key":e.apiKey,"Project-Id":e.projectId},body:JSON.stringify({oat:t})});import{useCallback as U,useState as tt,useRef as et,useLayoutEffect as rt}from"react";var A=()=>{};function x(e,...t){e&&e.addEventListener&&e.addEventListener(...t)}function k(e,...t){e&&e.removeEventListener&&e.removeEventListener(...t)}var S=typeof window<"u";var ot=(e,t,r)=>{if(!S)return[t,A,A];if(!e)throw new Error("useLocalStorage key may not be falsy");let o=r?r.raw?s=>s:r.deserializer:JSON.parse,i=et(s=>{try{let c=r?r.raw?String:r.serializer:JSON.stringify,p=localStorage.getItem(s);return p!==null?o(p):(t&&localStorage.setItem(s,c(t)),t)}catch{return t}}),[l,n]=tt(()=>i.current(e));rt(()=>n(i.current(e)),[e]);let a=U(s=>{try{let c=typeof s=="function"?s(l):s;if(typeof c>"u")return;let p;r?r.raw?typeof c=="string"?p=c:p=JSON.stringify(c):r.serializer?p=r.serializer(c):p=JSON.stringify(c):p=JSON.stringify(c),localStorage.setItem(e,p),n(o(p))}catch{}},[e,n]),d=U(()=>{try{localStorage.removeItem(e),n(void 0)}catch{}},[e,n]);return[l,a,d]},E=ot;import{useEffect as nt,useState as it}from"react";var J=(e,t)=>new URLSearchParams(e).get(t),at=e=>{let t=window.location,[r,o]=it(()=>J(t.search,e));return nt(()=>{let i=()=>{o(J(t.search,e))};return x(window,"popstate",i),x(window,"pushstate",i),x(window,"replacestate",i),()=>{k(window,"popstate",i),k(window,"pushstate",i),k(window,"replacestate",i)}},[]),r},st=()=>null,W=S?at:st;var C=e=>({exp:1e3}),lt="u9lt242tz2pn5hl5x444ls2xllnvip",dt="twitch_access_token",pt=[],h=ct({account:null,token:null,loading:!0,authenticationMethod:"JWT",authenticate:()=>{},logout:()=>{}}),B=({children:e,config:t})=>{let[r,o]=E(dt,null),[i,l]=E("twitch"),n=t.oat||W("oat"),[a,d]=O(null),[s,c]=O(!1),[p,P]=O("JWT");N(()=>{if(r){let u=C(r);if(console.log(u),u.exp*1e3<Date.now()){o(null),d(null);return}d(u)}},[]),N(()=>{n&&(c(!0),_(t,n).then(u=>u.json()).then(u=>{o(u.accessToken);let w=C(u.accessToken);d(w)}).finally(()=>{c(!1),P("OAT")}))},[n]);let G=R(()=>{o(null),d(null)},[]);N(()=>{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":t.apiKey,"Project-Id":t.projectId},body:JSON.stringify({oat:u})}).then(w=>w.json()).then(w=>{o(w.accessToken);let y=C(w.accessToken);d(y)}).finally(()=>{c(!1),window.history.replaceState({},document.title,"/")}))},[]);let V=R(async()=>{let u="http://localhost:3000",w=pt.join(" ");c(!0);try{if(!r)window.location.replace(`https://id.twitch.tv/oauth2/authorize?client_id=${lt}&redirect_uri=${u}&response_type=token&scope=${w}&force_verify=true`);else{let y=C(r);d(y)}}catch(y){console.error("Erreur lors de l'authentification :",y)}finally{}},[r]);return F.createElement(h.Provider,{value:{authenticationMethod:p,account:a,token:r,loading:s,authenticate:V,logout:G}},e)};function M({user:e,loading:t,logout:r}){let{authenticationMethod:o}=ut(h);return o==="OAT"?null:f.createElement(ft.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},t||!e?f.createElement("div",{className:"flex flex-row text-muted-foreground items-center gap-2"},f.createElement("div",{className:"text-sm"},"Authenticating with Twitch..."),f.createElement(ht,{className:"animate-spin",size:16})):f.createElement("div",{className:"flex w-full flex-row items-center gap-3"},f.createElement("div",{className:"flex h-[34px] w-[34px] flex-shrink-0 items-center justify-center overflow-hidden rounded-lg bg-[#313131] text-sm"},f.createElement("img",{src:e?.profilePictureUrl||"",alt:e?.displayName+"'s profile picture",width:34,height:34})),f.createElement("div",{className:"flex w-full flex-col justify-center min-w-[124px]"},f.createElement("div",{className:"space-x-2"},f.createElement("span",{className:"text-primary text-sm font-medium capitalize"},e?.displayName)),f.createElement("span",{className:"text-muted-foreground text-xs font-normal"},"Broadcaster")),f.createElement("button",{className:"bg-red-500 rounded-md p-2 text-xs whitespace-nowrap",onClick:r},"Log Out")))}import wt,{useCallback as gt,useContext as bt,useRef as yt}from"react";import{createContext as vt,useEffect as D,useState as xt}from"react";import mt from"events";var T=class extends mt{constructor(r){super();this.socket=null;this.queue=[];this.subscriptions=[];this.isAuthenticating=!1;this.jwt=null;this.url=r}send(r){this.socket?.readyState===WebSocket.OPEN?this.socket?.send(JSON.stringify(r)):this.queue.push(r)}authenticate(r){this.isAuthenticating||(this.isAuthenticating=!0,this.jwt=r,this.connect())}connect(){let r=this.url+"?jwt="+this.jwt;this.socket=new WebSocket(r),this.socket.onopen=()=>{this.queue.forEach(o=>this.send(o)),this.queue=[]},this.socket.onmessage=o=>{let i=JSON.parse(o.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(r,o="key"){let i=r.filter(l=>!this.subscriptions.includes(l));i.length&&(this.subscriptions=[...this.subscriptions,...i],console.log("subscribe",o,r),this.send({type:"subscribe",channels:r,scope:o}))}unsubscribe(r){this.send({type:"unsubscribe",channels:r})}disconnect(){this.socket&&(this.socket.onclose=()=>{},this.socket.close())}};import kt from"events";var v=vt({subscribe:()=>{},values:{},on:()=>{},off:()=>{}}),j=new kt,H=({children:e})=>{let[t,r]=xt({}),o=yt(),{token:i}=bt(h),l=(d,s)=>{j.on(d,s)},n=(d,s)=>{j.off(d,s)};D(()=>(o.current=new T("ws://localhost:8000"),o.current.on("message",d=>{let{scope:s,payload:c,type:p}=d;if(s==="__hook__"){j.emit(p,JSON.parse(c));return}s==="__key__"&&r(P=>({...P,[p]:JSON.parse(c)}))}),()=>{o.current?.disconnect()}),[]),D(()=>{!o.current||!i||o.current.authenticate(i)},[i]);let a=gt((d,s)=>{o.current?.subscribe(d,s)},[o]);return wt.createElement(v.Provider,{value:{subscribe:a,values:t,on:l,off:n}},e)};var $=e=>({set:async(t,r)=>e.httpCall({action:"set",key:t,value:r}),get:async t=>e.httpCall({action:"get",key:t}),incr:async(t,r)=>e.httpCall({action:"incr",key:t,value:r}),decr:async(t,r)=>e.httpCall({action:"decr",key:t,value:r}),del:async t=>e.httpCall({action:"del",key:t})});var b=class{constructor(t){this.config=t,this.token=""}setToken(t){this.token=t}get database(){return $(this)}get twitch(){return null}get hook(){return null}async httpCall(t){return await fetch("http://localhost:4005/actions",{method:"POST",body:JSON.stringify(t),headers:{Authorization:`Bearer ${this.token}`,"Content-Type":"application/json"}})}},ye=new b({apiKey:"123",projectId:"123"});var Tt=({children:e})=>{let[t,r]=Y(!1),{authenticate:o,logout:i,token:l,account:n,loading:a}=St(h);return K(()=>{r(!0)},[]),t?l?g.createElement(g.Fragment,null,g.createElement(M,{user:n,logout:i,loading:a}),n&&e):g.createElement(z,{authenticate:o,loading:a}):null},I=Ct({sparkle:void 0}),ze=({children:e,config:t})=>{let[r,o]=Y();return K(()=>{t&&o(new b(t))},[t]),g.createElement(I.Provider,{value:{sparkle:r}},g.createElement(B,{config:t},g.createElement(H,{config:t},g.createElement(Tt,null,e))))};import{useContext as Pt,useEffect as zt,useMemo as At}from"react";function Oe(...e){let t=Pt(v),r=At(()=>e,[e.join(",")]);if(!t)throw new Error("You must use useRealtime inside a SparkleProvider");return zt(()=>{t.subscribe(r,"__key__")},[r]),r.map(o=>t.values[o])}import{useContext as Et}from"react";function Le(){let{account:e,token:t,loading:r,authenticate:o,logout:i}=Et(h);return{account:e,token:t,loading:r,authenticate:o,logout:i}}import{useContext as q,useEffect as Nt}from"react";function Re(){let{token:e}=q(h),{sparkle:t}=q(I);if(!t)throw new Error("SparkleClient not found in context");return Nt(()=>{e&&t.setToken(e)},[e]),t.database}import{useCallback as X,useContext as Ot,useEffect as Mt,useState as jt}from"react";function He(...e){let[t,r]=jt({}),{token:o}=Ot(h),i=X(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 ${o}`,"Content-Type":"application/json"}})),[]),l=X(async n=>(await fetch("http://localhost:4005/users",{method:"POST",body:JSON.stringify({action:"get",key:n}),headers:{Authorization:`Bearer ${o}`,"Content-Type":"application/json"}})).json(),[]);return Mt(()=>{(async()=>{let a=await l("coins");r({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 ${o}`,"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 ${o}`,"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 ${o}`,"Content-Type":"application/json"}}),user:t}}import{useContext as It,useEffect as Q,useState as Lt}from"react";function Xe(e,t){let r=It(v),[o,i]=Lt([]);if(!r)throw new Error("You must use useHook inside a SparkleProvider");return Q(()=>{let l=n=>{i(a=>[...a,n]),t?.(n)};return r.on(e,l),()=>{r.off(e,l)}},[]),Q(()=>{r.subscribe([e],"__hook__")},[e]),{events:o,lastEvent:o[o.length-1]}}export{I as SparkleAppContext,ze as SparkleProvider,Le as useAuth,Re as useDatabase,Xe as useHook,Oe as useRealtime,He as useUser};
1
+ import v,{useEffect as B,useState as Q}from"react";import*as x from"react";import{createContext as N,useEffect as U,useState as W}from"react";import{useEffect as E,useState as R}from"react";var w=()=>{};function h(t,...r){t&&t.addEventListener&&t.addEventListener(...r)}function f(t,...r){t&&t.removeEventListener&&t.removeEventListener(...r)}var m=typeof window<"u";var S=(t,r)=>new URLSearchParams(t).get(r),M=t=>{let r=window.location,[e,o]=R(()=>S(r.search,t));return E(()=>{let n=()=>{o(S(r.search,t))};return h(window,"popstate",n),h(window,"pushstate",n),h(window,"replacestate",n),()=>{f(window,"popstate",n),f(window,"pushstate",n),f(window,"replacestate",n)}},[]),e},L=()=>null,k=m?M:L;var d=N({token:null}),C=({children:t,config:r})=>{let[e,o]=W(null),n=k("oat");return U(()=>{n&&o(n)},[n]),x.createElement(d.Provider,{value:{token:e}},t)};import F,{useCallback as _,useContext as J,useRef as D}from"react";import{createContext as H,useEffect as z,useState as q}from"react";import O from"events";import i from"zod";var j=i.object({type:i.literal("subscribe"),channels:i.array(i.string())}),I=i.object({type:i.literal("unsubscribe"),channels:i.string()}),be=i.object({event:i.literal("update"),data:i.object({key:i.string(),value:i.string()})}),we=i.union([j,I]),g=class extends O{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(o=>this.send(o)),this.queue=[]},this.socket.onmessage=o=>{let n=JSON.parse(o.data);this.emit("update",n)},this.socket.onclose=()=>{this.reconnect()}}reconnect(){setTimeout(()=>{this.queue=[{type:"subscribe",channels:this.subscriptions}],console.log("try reconnecting"),this.connect()},5e3)}subscribe(e){let o=e.filter(n=>!this.subscriptions.includes(n));o.length&&(this.subscriptions=[...this.subscriptions,...o],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 y=H({subscribe:()=>{},values:{}}),P=({children:t})=>{let[r,e]=q({}),o=D(),{token:n}=J(d);z(()=>(o.current=new g("http://localhost:4005/ws"),o.current.on("update",s=>{console.log("receive values",s);let{data:p}=s;e(b=>({...b,[p.key]:p.value}))}),()=>{o.current?.disconnect()}),[]),z(()=>{!o.current||!n||o.current.authenticate(n)},[n]);let u=_(s=>{o.current?.subscribe(s)},[o]);return F.createElement(y.Provider,{value:{subscribe:u,values:r}},t)};var Y=({children:t})=>{let[r,e]=Q(!1);return B(()=>{e(!0)},[]),r?t:null},Le=({children:t,config:r})=>v.createElement(C,{config:r},v.createElement(P,{config:r},v.createElement(Y,null,t)));import{useContext as G,useEffect as K,useMemo as V}from"react";function Oe(...t){let r=G(y),e=V(()=>t,[t.join(",")]);if(!r)throw new Error("You must use useDatabase inside a SparkleProvider");return K(()=>{r.subscribe(e)},[e]),e.map(o=>r.values[o])}import{useContext as X}from"react";function _e(){let{token:t}=X(d);return{token:t}}import{ApiClient as re}from"@twurple/api";import{StaticAuthProvider as oe}from"@twurple/auth";import{useEffect as ne,useState as ie}from"react";import{useCallback as T,useState as Z,useRef as $,useLayoutEffect as ee}from"react";var te=(t,r,e)=>{if(!m)return[r,w,w];if(!t)throw new Error("useLocalStorage key may not be falsy");let o=e?e.raw?l=>l:e.deserializer:JSON.parse,n=$(l=>{try{let c=e?e.raw?String:e.serializer:JSON.stringify,a=localStorage.getItem(l);return a!==null?o(a):(r&&localStorage.setItem(l,c(r)),r)}catch{return r}}),[u,s]=Z(()=>n.current(t));ee(()=>s(n.current(t)),[t]);let p=T(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(o(a))}catch{}},[t,s]),b=T(()=>{try{localStorage.removeItem(t),s(void 0)}catch{}},[t,s]);return[u,p,b]},A=te;function Xe(t){let[r,e]=ie(null),[o]=A("twitch");return ne(()=>{console.log("env",process.env.TWITCH_CLIENT_ID),console.log("init");let n=new re({authProvider:new oe("u9lt242tz2pn5hl5x444ls2xllnvip",o,["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(n),()=>{e(null)}},[]),{apiClient:r}}export{Le as SparkleProvider,_e as useAuth,Oe as useRealtime,Xe as useTwitch};
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\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 EventEmitter from \"events\"\n\ninterface Message {\n type: \"subscribe\" | \"unsubscribe\"\n channels: string | string[]\n scope?: string\n}\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","EventEmitter","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/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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sparkle-react",
3
- "version": "0.0.14",
3
+ "version": "0.0.17",
4
4
  "files": [
5
5
  "dist"
6
6
  ],
@@ -17,9 +17,13 @@
17
17
  "typescript": "^5.3.3"
18
18
  },
19
19
  "dependencies": {
20
+ "@twurple/api": "^7.0.6",
21
+ "@twurple/auth": "^7.0.6",
20
22
  "framer-motion": "^10.16.16",
23
+ "jsonwebtoken": "^9.0.2",
21
24
  "lucide-react": "^0.294.0",
22
- "react": "^18.2.0"
25
+ "react": "^18.2.0",
26
+ "zod": "^3.22.4"
23
27
  },
24
28
  "scripts": {
25
29
  "dev": "tsup --watch",