├── LICENSE
├── client
├── .gitignore
├── index.html
├── package-lock.json
├── package.json
├── postcss.config.cjs
├── public
│ └── vite.svg
├── src
│ ├── components
│ │ ├── Button.tsx
│ │ ├── FullScreenCard.tsx
│ │ ├── Input.tsx
│ │ └── Link.tsx
│ ├── context
│ │ └── AuthContext.tsx
│ ├── hooks
│ │ └── useLocalStorage.ts
│ ├── index.css
│ ├── main.tsx
│ ├── pages
│ │ ├── Home.tsx
│ │ ├── Login.tsx
│ │ ├── Signup.tsx
│ │ ├── channel
│ │ │ └── new.tsx
│ │ └── layouts
│ │ │ ├── AuthLayout.tsx
│ │ │ └── RootLayout.tsx
│ ├── router.tsx
│ └── vite-env.d.ts
├── tailwind.config.cjs
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts
└── server
├── .gitignore
├── package-lock.json
├── package.json
├── routes
└── users.ts
└── server.ts
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 WebDevSimplified
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/client/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
26 | .env
27 |
--------------------------------------------------------------------------------
/client/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React + TS
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "client",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "tsc && vite build",
9 | "preview": "vite preview"
10 | },
11 | "dependencies": {
12 | "@tanstack/react-query": "^4.22.0",
13 | "axios": "^1.2.2",
14 | "react": "^18.2.0",
15 | "react-dom": "^18.2.0",
16 | "react-router-dom": "^6.6.2",
17 | "react-select": "^5.7.0",
18 | "stream-chat": "^8.2.1",
19 | "stream-chat-react": "^10.5.0"
20 | },
21 | "devDependencies": {
22 | "@types/react": "^18.0.26",
23 | "@types/react-dom": "^18.0.9",
24 | "@vitejs/plugin-react-swc": "^3.0.0",
25 | "autoprefixer": "^10.4.13",
26 | "postcss": "^8.4.21",
27 | "tailwindcss": "^3.2.4",
28 | "typescript": "^4.9.3",
29 | "vite": "^4.0.0"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/client/postcss.config.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/client/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client/src/components/Button.tsx:
--------------------------------------------------------------------------------
1 | import { DetailedHTMLProps, forwardRef, ButtonHTMLAttributes } from "react"
2 |
3 | export const Button = forwardRef<
4 | HTMLButtonElement,
5 | DetailedHTMLProps, HTMLButtonElement>
6 | >(({ className, children, ...rest }, ref) => {
7 | return (
8 |
13 | {children}
14 |
15 | )
16 | })
17 |
--------------------------------------------------------------------------------
/client/src/components/FullScreenCard.tsx:
--------------------------------------------------------------------------------
1 | import { ReactNode } from "react"
2 |
3 | type FullScreenCardProps = {
4 | children: ReactNode
5 | }
6 |
7 | export function FullScreenCard({ children }: FullScreenCardProps) {
8 | return (
9 |
12 | )
13 | }
14 |
15 | FullScreenCard.Body = function ({ children }: FullScreenCardProps) {
16 | return {children}
17 | }
18 |
19 | FullScreenCard.BelowCard = function ({ children }: FullScreenCardProps) {
20 | return {children}
21 | }
22 |
--------------------------------------------------------------------------------
/client/src/components/Input.tsx:
--------------------------------------------------------------------------------
1 | import { DetailedHTMLProps, forwardRef, InputHTMLAttributes } from "react"
2 |
3 | export const Input = forwardRef<
4 | HTMLInputElement,
5 | DetailedHTMLProps, HTMLInputElement>
6 | >(({ className, ...rest }, ref) => {
7 | return (
8 |
13 | )
14 | })
15 |
--------------------------------------------------------------------------------
/client/src/components/Link.tsx:
--------------------------------------------------------------------------------
1 | import { LinkProps, Link as RouterLink } from "react-router-dom"
2 |
3 | export function Link({ children, className, ...rest }: LinkProps) {
4 | return (
5 |
9 | {children}
10 |
11 | )
12 | }
13 |
--------------------------------------------------------------------------------
/client/src/context/AuthContext.tsx:
--------------------------------------------------------------------------------
1 | import { useMutation } from "@tanstack/react-query"
2 | import {
3 | UseMutationOptions,
4 | UseMutationResult,
5 | } from "@tanstack/react-query/build/lib/types"
6 | import axios, { AxiosResponse } from "axios"
7 | import {
8 | createContext,
9 | ReactNode,
10 | useContext,
11 | useEffect,
12 | useState,
13 | } from "react"
14 | import { useNavigate } from "react-router-dom"
15 | import { StreamChat } from "stream-chat"
16 | import { useLocalStorage } from "../hooks/useLocalStorage"
17 |
18 | type AuthContext = {
19 | user?: User
20 | streamChat?: StreamChat
21 | signup: UseMutationResult
22 | login: UseMutationResult<{ token: string; user: User }, unknown, string>
23 | logout: UseMutationResult
24 | }
25 |
26 | type User = {
27 | id: string
28 | name: string
29 | image?: string
30 | }
31 |
32 | const Context = createContext(null)
33 |
34 | export function useAuth() {
35 | return useContext(Context) as AuthContext
36 | }
37 |
38 | export function useLoggedInAuth() {
39 | return useContext(Context) as AuthContext &
40 | Required>
41 | }
42 |
43 | type AuthProviderProps = {
44 | children: ReactNode
45 | }
46 |
47 | export function AuthProvider({ children }: AuthProviderProps) {
48 | const navigate = useNavigate()
49 | const [user, setUser] = useLocalStorage("user")
50 | const [token, setToken] = useLocalStorage("token")
51 | const [streamChat, setStreamChat] = useState()
52 |
53 | const signup = useMutation({
54 | mutationFn: (user: User) => {
55 | return axios.post(`${import.meta.env.VITE_SERVER_URL}/signup`, user)
56 | },
57 | onSuccess() {
58 | navigate("/login")
59 | },
60 | })
61 |
62 | const login = useMutation({
63 | mutationFn: (id: string) => {
64 | return axios
65 | .post(`${import.meta.env.VITE_SERVER_URL}/login`, { id })
66 | .then(res => {
67 | return res.data as { token: string; user: User }
68 | })
69 | },
70 | onSuccess(data) {
71 | setUser(data.user)
72 | setToken(data.token)
73 | },
74 | })
75 |
76 | const logout = useMutation({
77 | mutationFn: () => {
78 | return axios.post(`${import.meta.env.VITE_SERVER_URL}/logout`, { token })
79 | },
80 | onSuccess() {
81 | setUser(undefined)
82 | setToken(undefined)
83 | setStreamChat(undefined)
84 | },
85 | })
86 |
87 | useEffect(() => {
88 | if (token == null || user == null) return
89 | const chat = new StreamChat(import.meta.env.VITE_STREAM_API_KEY!)
90 |
91 | if (chat.tokenManager.token === token && chat.userID === user.id) return
92 |
93 | let isInterrupted = false
94 | const connectPromise = chat.connectUser(user, token).then(() => {
95 | if (isInterrupted) return
96 | setStreamChat(chat)
97 | })
98 |
99 | return () => {
100 | isInterrupted = true
101 | setStreamChat(undefined)
102 |
103 | connectPromise.then(() => {
104 | chat.disconnectUser()
105 | })
106 | }
107 | }, [token, user])
108 |
109 | return (
110 |
111 | {children}
112 |
113 | )
114 | }
115 |
--------------------------------------------------------------------------------
/client/src/hooks/useLocalStorage.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react"
2 |
3 | export function useLocalStorage(
4 | key: string,
5 | initialValue?: T | undefined | (() => T | undefined)
6 | ) {
7 | const [value, setValue] = useState(() => {
8 | const jsonValue = localStorage.getItem(key)
9 | if (jsonValue == null) {
10 | if (typeof initialValue === "function") {
11 | return (initialValue as () => T | undefined)()
12 | } else {
13 | return initialValue
14 | }
15 | } else {
16 | return JSON.parse(jsonValue)
17 | }
18 | })
19 |
20 | useEffect(() => {
21 | if (value === undefined) {
22 | localStorage.removeItem(key)
23 | return
24 | }
25 |
26 | localStorage.setItem(key, JSON.stringify(value))
27 | }, [value, key])
28 |
29 | return [value, setValue] as [T | undefined, typeof setValue]
30 | }
31 |
--------------------------------------------------------------------------------
/client/src/index.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
--------------------------------------------------------------------------------
/client/src/main.tsx:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import ReactDOM from "react-dom/client"
3 | import "./index.css"
4 | import { RouterProvider } from "react-router-dom"
5 | import { router } from "./router"
6 | import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
7 | import "stream-chat-react/dist/css/index.css"
8 |
9 | const queryClient = new QueryClient()
10 |
11 | ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
12 |
13 |
14 |
15 |
16 |
17 | )
18 |
--------------------------------------------------------------------------------
/client/src/pages/Home.tsx:
--------------------------------------------------------------------------------
1 | import { useNavigate } from "react-router-dom"
2 | import {
3 | LoadingIndicator,
4 | Chat,
5 | ChannelList,
6 | Channel,
7 | Window,
8 | MessageInput,
9 | MessageList,
10 | ChannelHeader,
11 | } from "stream-chat-react"
12 | import { ChannelListMessengerProps } from "stream-chat-react/dist/components"
13 | import { useChatContext } from "stream-chat-react/dist/context"
14 | import { Button } from "../components/Button"
15 | import { useLoggedInAuth } from "../context/AuthContext"
16 |
17 | export function Home() {
18 | const { user, streamChat } = useLoggedInAuth()
19 |
20 | if (streamChat == null) return
21 |
22 | return (
23 |
24 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | )
38 | }
39 |
40 | function Channels({ loadedChannels }: ChannelListMessengerProps) {
41 | const navigate = useNavigate()
42 | const { logout } = useLoggedInAuth()
43 | const { setActiveChannel, channel: activeChannel } = useChatContext()
44 |
45 | return (
46 |
47 |
navigate("/channel/new")}>New Conversation
48 |
49 | {loadedChannels != null && loadedChannels.length > 0
50 | ? loadedChannels.map(channel => {
51 | const isActive = channel === activeChannel
52 | const extraClasses = isActive
53 | ? "bg-blue-500 text-white"
54 | : "hover:bg-blue-100 bg-gray-100"
55 | return (
56 |
setActiveChannel(channel)}
58 | disabled={isActive}
59 | className={`p-4 rounded-lg flex gap-3 items-center ${extraClasses}`}
60 | key={channel.id}
61 | >
62 | {channel.data?.image && (
63 |
67 | )}
68 |
69 | {channel.data?.name || channel.id}
70 |
71 |
72 | )
73 | })
74 | : "No Conversations"}
75 |
76 |
logout.mutate()} disabled={logout.isLoading}>
77 | Logout
78 |
79 |
80 | )
81 | }
82 |
--------------------------------------------------------------------------------
/client/src/pages/Login.tsx:
--------------------------------------------------------------------------------
1 | import { FormEvent, useRef } from "react"
2 | import { Navigate } from "react-router-dom"
3 | import { Button } from "../components/Button"
4 | import { Input } from "../components/Input"
5 | import { useAuth } from "../context/AuthContext"
6 |
7 | export function Login() {
8 | const { login, user } = useAuth()
9 | const usernameRef = useRef(null)
10 |
11 | if (user != null) return
12 |
13 | function handleSubmit(e: FormEvent) {
14 | e.preventDefault()
15 | if (login.isLoading) return
16 |
17 | const username = usernameRef.current?.value
18 | if (username == null || username === "") {
19 | return
20 | }
21 |
22 | login.mutate(username)
23 | }
24 |
25 | return (
26 | <>
27 | Login
28 |
42 | >
43 | )
44 | }
45 |
--------------------------------------------------------------------------------
/client/src/pages/Signup.tsx:
--------------------------------------------------------------------------------
1 | import { FormEvent, useRef } from "react"
2 | import { Button } from "../components/Button"
3 | import { Input } from "../components/Input"
4 | import { useAuth } from "../context/AuthContext"
5 |
6 | export function Signup() {
7 | const { signup } = useAuth()
8 | const usernameRef = useRef(null)
9 | const nameRef = useRef(null)
10 | const imageUrlRef = useRef(null)
11 |
12 | function handleSubmit(e: FormEvent) {
13 | e.preventDefault()
14 | if (signup.isLoading) return
15 |
16 | const username = usernameRef.current?.value
17 | const name = nameRef.current?.value
18 | const imageUrl = imageUrlRef.current?.value
19 | if (username == null || username === "" || name == null || name === "") {
20 | return
21 | }
22 |
23 | signup.mutate({ id: username, name, image: imageUrl })
24 | }
25 |
26 | return (
27 | <>
28 | Sign Up
29 |
47 | >
48 | )
49 | }
50 |
--------------------------------------------------------------------------------
/client/src/pages/channel/new.tsx:
--------------------------------------------------------------------------------
1 | import { useMutation, useQuery } from "@tanstack/react-query"
2 | import { FormEvent, useRef } from "react"
3 | import { Button } from "../../components/Button"
4 | import { FullScreenCard } from "../../components/FullScreenCard"
5 | import { Input } from "../../components/Input"
6 | import { Link } from "../../components/Link"
7 | import Select, { SelectInstance } from "react-select"
8 | import { useLoggedInAuth } from "../../context/AuthContext"
9 | import { useNavigate } from "react-router-dom"
10 |
11 | export function NewChannel() {
12 | const { streamChat, user } = useLoggedInAuth()
13 | const navigate = useNavigate()
14 | const createChannel = useMutation({
15 | mutationFn: ({
16 | name,
17 | memberIds,
18 | imageUrl,
19 | }: {
20 | name: string
21 | memberIds: string[]
22 | imageUrl?: string
23 | }) => {
24 | if (streamChat == null) throw Error("Not connected")
25 |
26 | return streamChat
27 | .channel("messaging", crypto.randomUUID(), {
28 | name,
29 | image: imageUrl,
30 | members: [user.id, ...memberIds],
31 | })
32 | .create()
33 | },
34 | onSuccess() {
35 | navigate("/")
36 | },
37 | })
38 | const nameRef = useRef(null)
39 | const imageUrlRef = useRef(null)
40 | const memberIdsRef =
41 | useRef>(null)
42 |
43 | const users = useQuery({
44 | queryKey: ["stream", "users"],
45 | queryFn: () =>
46 | streamChat!.queryUsers({ id: { $ne: user.id } }, { name: 1 }),
47 | enabled: streamChat != null,
48 | })
49 |
50 | function handleSubmit(e: FormEvent) {
51 | e.preventDefault()
52 |
53 | const name = nameRef.current?.value
54 | const imageUrl = imageUrlRef.current?.value
55 | const selectOptions = memberIdsRef.current?.getValue()
56 | if (
57 | name == null ||
58 | name === "" ||
59 | selectOptions == null ||
60 | selectOptions.length === 0
61 | ) {
62 | return
63 | }
64 |
65 | createChannel.mutate({
66 | name,
67 | imageUrl,
68 | memberIds: selectOptions.map(option => option.value),
69 | })
70 | }
71 |
72 | return (
73 |
74 |
75 |
76 | New Conversation
77 |
78 |
106 |
107 |
108 | Back
109 |
110 |
111 | )
112 | }
113 |
--------------------------------------------------------------------------------
/client/src/pages/layouts/AuthLayout.tsx:
--------------------------------------------------------------------------------
1 | import { Outlet, useLocation } from "react-router-dom"
2 | import { FullScreenCard } from "../../components/FullScreenCard"
3 | import { Link } from "../../components/Link"
4 |
5 | export function AuthLayout() {
6 | const location = useLocation()
7 | const isLoginPage = location.pathname === "/login"
8 | return (
9 |
10 |
11 |
12 |
13 |
14 |
15 | {isLoginPage ? "Create Account" : "Login"}
16 |
17 |
18 |
19 | )
20 | }
21 |
--------------------------------------------------------------------------------
/client/src/pages/layouts/RootLayout.tsx:
--------------------------------------------------------------------------------
1 | import { Navigate, Outlet } from "react-router-dom"
2 | import { useAuth } from "../../context/AuthContext"
3 |
4 | export function RootLayout() {
5 | const { user } = useAuth()
6 | if (user == null) return
7 |
8 | return
9 | }
10 |
--------------------------------------------------------------------------------
/client/src/router.tsx:
--------------------------------------------------------------------------------
1 | import { createBrowserRouter, Outlet } from "react-router-dom"
2 | import { AuthProvider } from "./context/AuthContext"
3 | import { NewChannel } from "./pages/channel/new"
4 | import { Home } from "./pages/Home"
5 | import { AuthLayout } from "./pages/layouts/AuthLayout"
6 | import { RootLayout } from "./pages/layouts/RootLayout"
7 | import { Login } from "./pages/Login"
8 | import { Signup } from "./pages/Signup"
9 |
10 | export const router = createBrowserRouter([
11 | {
12 | element: ,
13 | children: [
14 | {
15 | path: "/",
16 | element: ,
17 | children: [
18 | { index: true, element: },
19 | {
20 | path: "/channel",
21 | children: [{ path: "new", element: }],
22 | },
23 | ],
24 | },
25 | {
26 | element: ,
27 | children: [
28 | { path: "login", element: },
29 | { path: "signup", element: },
30 | ],
31 | },
32 | ],
33 | },
34 | ])
35 |
36 | function ContextWrapper() {
37 | return (
38 |
39 |
40 |
41 | )
42 | }
43 |
--------------------------------------------------------------------------------
/client/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/client/tailwind.config.cjs:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
4 | theme: {
5 | extend: {},
6 | },
7 | plugins: [],
8 | }
9 |
--------------------------------------------------------------------------------
/client/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "ESNext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx"
18 | },
19 | "include": ["src"],
20 | "references": [{ "path": "./tsconfig.node.json" }]
21 | }
22 |
--------------------------------------------------------------------------------
/client/tsconfig.node.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "composite": true,
4 | "module": "ESNext",
5 | "moduleResolution": "Node",
6 | "allowSyntheticDefaultImports": true
7 | },
8 | "include": ["vite.config.ts"]
9 | }
10 |
--------------------------------------------------------------------------------
/client/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react-swc'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/server/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
26 | .env
--------------------------------------------------------------------------------
/server/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "server",
3 | "version": "1.0.0",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "server",
9 | "version": "1.0.0",
10 | "license": "ISC",
11 | "dependencies": {
12 | "@fastify/cors": "^8.2.0",
13 | "dotenv": "^16.0.3",
14 | "fastify": "^4.11.0",
15 | "stream-chat": "^8.2.1"
16 | },
17 | "devDependencies": {
18 | "@types/node": "^18.11.18",
19 | "nodemon": "^2.0.20",
20 | "ts-node": "^10.9.1"
21 | }
22 | },
23 | "node_modules/@babel/runtime": {
24 | "version": "7.20.7",
25 | "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.7.tgz",
26 | "integrity": "sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==",
27 | "dependencies": {
28 | "regenerator-runtime": "^0.13.11"
29 | },
30 | "engines": {
31 | "node": ">=6.9.0"
32 | }
33 | },
34 | "node_modules/@cspotcode/source-map-support": {
35 | "version": "0.8.1",
36 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
37 | "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
38 | "dev": true,
39 | "dependencies": {
40 | "@jridgewell/trace-mapping": "0.3.9"
41 | },
42 | "engines": {
43 | "node": ">=12"
44 | }
45 | },
46 | "node_modules/@fastify/ajv-compiler": {
47 | "version": "3.5.0",
48 | "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-3.5.0.tgz",
49 | "integrity": "sha512-ebbEtlI7dxXF5ziNdr05mOY8NnDiPB1XvAlLHctRt/Rc+C3LCOVW5imUVX+mhvUhnNzmPBHewUkOFgGlCxgdAA==",
50 | "dependencies": {
51 | "ajv": "^8.11.0",
52 | "ajv-formats": "^2.1.1",
53 | "fast-uri": "^2.0.0"
54 | }
55 | },
56 | "node_modules/@fastify/cors": {
57 | "version": "8.2.0",
58 | "resolved": "https://registry.npmjs.org/@fastify/cors/-/cors-8.2.0.tgz",
59 | "integrity": "sha512-qDgwpmg6C4D0D3nh8MTMuRXWyEwPnDZDBODaJv90FP2o9ukbahJByW4FtrM5Bpod5KbTf1oIExBmpItbUTQmHg==",
60 | "dependencies": {
61 | "fastify-plugin": "^4.0.0",
62 | "mnemonist": "0.39.5"
63 | }
64 | },
65 | "node_modules/@fastify/deepmerge": {
66 | "version": "1.3.0",
67 | "resolved": "https://registry.npmjs.org/@fastify/deepmerge/-/deepmerge-1.3.0.tgz",
68 | "integrity": "sha512-J8TOSBq3SoZbDhM9+R/u77hP93gz/rajSA+K2kGyijPpORPWUXHUpTaleoj+92As0S9uPRP7Oi8IqMf0u+ro6A=="
69 | },
70 | "node_modules/@fastify/error": {
71 | "version": "3.2.0",
72 | "resolved": "https://registry.npmjs.org/@fastify/error/-/error-3.2.0.tgz",
73 | "integrity": "sha512-KAfcLa+CnknwVi5fWogrLXgidLic+GXnLjijXdpl8pvkvbXU5BGa37iZO9FGvsh9ZL4y+oFi5cbHBm5UOG+dmQ=="
74 | },
75 | "node_modules/@fastify/fast-json-stringify-compiler": {
76 | "version": "4.2.0",
77 | "resolved": "https://registry.npmjs.org/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-4.2.0.tgz",
78 | "integrity": "sha512-ypZynRvXA3dibfPykQN3RB5wBdEUgSGgny8Qc6k163wYPLD4mEGEDkACp+00YmqkGvIm8D/xYoHajwyEdWD/eg==",
79 | "dependencies": {
80 | "fast-json-stringify": "^5.0.0"
81 | }
82 | },
83 | "node_modules/@jridgewell/resolve-uri": {
84 | "version": "3.1.0",
85 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
86 | "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
87 | "dev": true,
88 | "engines": {
89 | "node": ">=6.0.0"
90 | }
91 | },
92 | "node_modules/@jridgewell/sourcemap-codec": {
93 | "version": "1.4.14",
94 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
95 | "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
96 | "dev": true
97 | },
98 | "node_modules/@jridgewell/trace-mapping": {
99 | "version": "0.3.9",
100 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
101 | "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
102 | "dev": true,
103 | "dependencies": {
104 | "@jridgewell/resolve-uri": "^3.0.3",
105 | "@jridgewell/sourcemap-codec": "^1.4.10"
106 | }
107 | },
108 | "node_modules/@tsconfig/node10": {
109 | "version": "1.0.9",
110 | "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
111 | "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==",
112 | "dev": true
113 | },
114 | "node_modules/@tsconfig/node12": {
115 | "version": "1.0.11",
116 | "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
117 | "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
118 | "dev": true
119 | },
120 | "node_modules/@tsconfig/node14": {
121 | "version": "1.0.3",
122 | "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
123 | "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
124 | "dev": true
125 | },
126 | "node_modules/@tsconfig/node16": {
127 | "version": "1.0.3",
128 | "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz",
129 | "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==",
130 | "dev": true
131 | },
132 | "node_modules/@types/jsonwebtoken": {
133 | "version": "9.0.1",
134 | "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.1.tgz",
135 | "integrity": "sha512-c5ltxazpWabia/4UzhIoaDcIza4KViOQhdbjRlfcIGVnsE3c3brkz9Z+F/EeJIECOQP7W7US2hNE930cWWkPiw==",
136 | "dependencies": {
137 | "@types/node": "*"
138 | }
139 | },
140 | "node_modules/@types/node": {
141 | "version": "18.11.18",
142 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz",
143 | "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA=="
144 | },
145 | "node_modules/@types/ws": {
146 | "version": "7.4.7",
147 | "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz",
148 | "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==",
149 | "dependencies": {
150 | "@types/node": "*"
151 | }
152 | },
153 | "node_modules/abbrev": {
154 | "version": "1.1.1",
155 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
156 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
157 | "dev": true
158 | },
159 | "node_modules/abort-controller": {
160 | "version": "3.0.0",
161 | "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
162 | "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
163 | "dependencies": {
164 | "event-target-shim": "^5.0.0"
165 | },
166 | "engines": {
167 | "node": ">=6.5"
168 | }
169 | },
170 | "node_modules/abstract-logging": {
171 | "version": "2.0.1",
172 | "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz",
173 | "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA=="
174 | },
175 | "node_modules/acorn": {
176 | "version": "8.8.1",
177 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
178 | "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==",
179 | "dev": true,
180 | "bin": {
181 | "acorn": "bin/acorn"
182 | },
183 | "engines": {
184 | "node": ">=0.4.0"
185 | }
186 | },
187 | "node_modules/acorn-walk": {
188 | "version": "8.2.0",
189 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
190 | "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
191 | "dev": true,
192 | "engines": {
193 | "node": ">=0.4.0"
194 | }
195 | },
196 | "node_modules/ajv": {
197 | "version": "8.12.0",
198 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
199 | "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
200 | "dependencies": {
201 | "fast-deep-equal": "^3.1.1",
202 | "json-schema-traverse": "^1.0.0",
203 | "require-from-string": "^2.0.2",
204 | "uri-js": "^4.2.2"
205 | },
206 | "funding": {
207 | "type": "github",
208 | "url": "https://github.com/sponsors/epoberezkin"
209 | }
210 | },
211 | "node_modules/ajv-formats": {
212 | "version": "2.1.1",
213 | "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
214 | "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
215 | "dependencies": {
216 | "ajv": "^8.0.0"
217 | },
218 | "peerDependencies": {
219 | "ajv": "^8.0.0"
220 | },
221 | "peerDependenciesMeta": {
222 | "ajv": {
223 | "optional": true
224 | }
225 | }
226 | },
227 | "node_modules/anymatch": {
228 | "version": "3.1.3",
229 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
230 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
231 | "dev": true,
232 | "dependencies": {
233 | "normalize-path": "^3.0.0",
234 | "picomatch": "^2.0.4"
235 | },
236 | "engines": {
237 | "node": ">= 8"
238 | }
239 | },
240 | "node_modules/archy": {
241 | "version": "1.0.0",
242 | "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz",
243 | "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw=="
244 | },
245 | "node_modules/arg": {
246 | "version": "4.1.3",
247 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
248 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
249 | "dev": true
250 | },
251 | "node_modules/asynckit": {
252 | "version": "0.4.0",
253 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
254 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
255 | },
256 | "node_modules/atomic-sleep": {
257 | "version": "1.0.0",
258 | "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
259 | "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==",
260 | "engines": {
261 | "node": ">=8.0.0"
262 | }
263 | },
264 | "node_modules/avvio": {
265 | "version": "8.2.0",
266 | "resolved": "https://registry.npmjs.org/avvio/-/avvio-8.2.0.tgz",
267 | "integrity": "sha512-bbCQdg7bpEv6kGH41RO/3B2/GMMmJSo2iBK+X8AWN9mujtfUipMDfIjsgHCfpnKqoGEQrrmCDKSa5OQ19+fDmg==",
268 | "dependencies": {
269 | "archy": "^1.0.0",
270 | "debug": "^4.0.0",
271 | "fastq": "^1.6.1"
272 | }
273 | },
274 | "node_modules/axios": {
275 | "version": "0.22.0",
276 | "resolved": "https://registry.npmjs.org/axios/-/axios-0.22.0.tgz",
277 | "integrity": "sha512-Z0U3uhqQeg1oNcihswf4ZD57O3NrR1+ZXhxaROaWpDmsDTx7T2HNBV2ulBtie2hwJptu8UvgnJoK+BIqdzh/1w==",
278 | "dependencies": {
279 | "follow-redirects": "^1.14.4"
280 | }
281 | },
282 | "node_modules/balanced-match": {
283 | "version": "1.0.2",
284 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
285 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
286 | "dev": true
287 | },
288 | "node_modules/base64-js": {
289 | "version": "1.5.1",
290 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
291 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
292 | "funding": [
293 | {
294 | "type": "github",
295 | "url": "https://github.com/sponsors/feross"
296 | },
297 | {
298 | "type": "patreon",
299 | "url": "https://www.patreon.com/feross"
300 | },
301 | {
302 | "type": "consulting",
303 | "url": "https://feross.org/support"
304 | }
305 | ]
306 | },
307 | "node_modules/binary-extensions": {
308 | "version": "2.2.0",
309 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
310 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
311 | "dev": true,
312 | "engines": {
313 | "node": ">=8"
314 | }
315 | },
316 | "node_modules/brace-expansion": {
317 | "version": "1.1.11",
318 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
319 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
320 | "dev": true,
321 | "dependencies": {
322 | "balanced-match": "^1.0.0",
323 | "concat-map": "0.0.1"
324 | }
325 | },
326 | "node_modules/braces": {
327 | "version": "3.0.2",
328 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
329 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
330 | "dev": true,
331 | "dependencies": {
332 | "fill-range": "^7.0.1"
333 | },
334 | "engines": {
335 | "node": ">=8"
336 | }
337 | },
338 | "node_modules/buffer": {
339 | "version": "6.0.3",
340 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
341 | "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
342 | "funding": [
343 | {
344 | "type": "github",
345 | "url": "https://github.com/sponsors/feross"
346 | },
347 | {
348 | "type": "patreon",
349 | "url": "https://www.patreon.com/feross"
350 | },
351 | {
352 | "type": "consulting",
353 | "url": "https://feross.org/support"
354 | }
355 | ],
356 | "dependencies": {
357 | "base64-js": "^1.3.1",
358 | "ieee754": "^1.2.1"
359 | }
360 | },
361 | "node_modules/buffer-equal-constant-time": {
362 | "version": "1.0.1",
363 | "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
364 | "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="
365 | },
366 | "node_modules/chokidar": {
367 | "version": "3.5.3",
368 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
369 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
370 | "dev": true,
371 | "funding": [
372 | {
373 | "type": "individual",
374 | "url": "https://paulmillr.com/funding/"
375 | }
376 | ],
377 | "dependencies": {
378 | "anymatch": "~3.1.2",
379 | "braces": "~3.0.2",
380 | "glob-parent": "~5.1.2",
381 | "is-binary-path": "~2.1.0",
382 | "is-glob": "~4.0.1",
383 | "normalize-path": "~3.0.0",
384 | "readdirp": "~3.6.0"
385 | },
386 | "engines": {
387 | "node": ">= 8.10.0"
388 | },
389 | "optionalDependencies": {
390 | "fsevents": "~2.3.2"
391 | }
392 | },
393 | "node_modules/combined-stream": {
394 | "version": "1.0.8",
395 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
396 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
397 | "dependencies": {
398 | "delayed-stream": "~1.0.0"
399 | },
400 | "engines": {
401 | "node": ">= 0.8"
402 | }
403 | },
404 | "node_modules/concat-map": {
405 | "version": "0.0.1",
406 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
407 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
408 | "dev": true
409 | },
410 | "node_modules/content-type": {
411 | "version": "1.0.4",
412 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
413 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
414 | "engines": {
415 | "node": ">= 0.6"
416 | }
417 | },
418 | "node_modules/cookie": {
419 | "version": "0.5.0",
420 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
421 | "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
422 | "engines": {
423 | "node": ">= 0.6"
424 | }
425 | },
426 | "node_modules/create-require": {
427 | "version": "1.1.1",
428 | "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
429 | "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
430 | "dev": true
431 | },
432 | "node_modules/debug": {
433 | "version": "4.3.4",
434 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
435 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
436 | "dependencies": {
437 | "ms": "2.1.2"
438 | },
439 | "engines": {
440 | "node": ">=6.0"
441 | },
442 | "peerDependenciesMeta": {
443 | "supports-color": {
444 | "optional": true
445 | }
446 | }
447 | },
448 | "node_modules/delayed-stream": {
449 | "version": "1.0.0",
450 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
451 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
452 | "engines": {
453 | "node": ">=0.4.0"
454 | }
455 | },
456 | "node_modules/diff": {
457 | "version": "4.0.2",
458 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
459 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
460 | "dev": true,
461 | "engines": {
462 | "node": ">=0.3.1"
463 | }
464 | },
465 | "node_modules/dotenv": {
466 | "version": "16.0.3",
467 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz",
468 | "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==",
469 | "engines": {
470 | "node": ">=12"
471 | }
472 | },
473 | "node_modules/ecdsa-sig-formatter": {
474 | "version": "1.0.11",
475 | "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
476 | "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
477 | "dependencies": {
478 | "safe-buffer": "^5.0.1"
479 | }
480 | },
481 | "node_modules/event-target-shim": {
482 | "version": "5.0.1",
483 | "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
484 | "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
485 | "engines": {
486 | "node": ">=6"
487 | }
488 | },
489 | "node_modules/events": {
490 | "version": "3.3.0",
491 | "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
492 | "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
493 | "engines": {
494 | "node": ">=0.8.x"
495 | }
496 | },
497 | "node_modules/fast-decode-uri-component": {
498 | "version": "1.0.1",
499 | "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz",
500 | "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="
501 | },
502 | "node_modules/fast-deep-equal": {
503 | "version": "3.1.3",
504 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
505 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
506 | },
507 | "node_modules/fast-json-stringify": {
508 | "version": "5.5.0",
509 | "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-5.5.0.tgz",
510 | "integrity": "sha512-rmw2Z8/mLkND8zI+3KTYIkNPEoF5v6GqDP/o+g7H3vjdWjBwuKpgAYFHIzL6ORRB+iqDjjtJnLIW9Mzxn5szOA==",
511 | "dependencies": {
512 | "@fastify/deepmerge": "^1.0.0",
513 | "ajv": "^8.10.0",
514 | "ajv-formats": "^2.1.1",
515 | "fast-deep-equal": "^3.1.3",
516 | "fast-uri": "^2.1.0",
517 | "rfdc": "^1.2.0"
518 | }
519 | },
520 | "node_modules/fast-querystring": {
521 | "version": "1.1.0",
522 | "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.0.tgz",
523 | "integrity": "sha512-LWkjBCZlxjnSanuPpZ6mHswjy8hQv3VcPJsQB3ltUF2zjvrycr0leP3TSTEEfvQ1WEMSRl5YNsGqaft9bjLqEw==",
524 | "dependencies": {
525 | "fast-decode-uri-component": "^1.0.1"
526 | }
527 | },
528 | "node_modules/fast-redact": {
529 | "version": "3.1.2",
530 | "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.1.2.tgz",
531 | "integrity": "sha512-+0em+Iya9fKGfEQGcd62Yv6onjBmmhV1uh86XVfOU8VwAe6kaFdQCWI9s0/Nnugx5Vd9tdbZ7e6gE2tR9dzXdw==",
532 | "engines": {
533 | "node": ">=6"
534 | }
535 | },
536 | "node_modules/fast-uri": {
537 | "version": "2.2.0",
538 | "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-2.2.0.tgz",
539 | "integrity": "sha512-cIusKBIt/R/oI6z/1nyfe2FvGKVTohVRfvkOhvx0nCEW+xf5NoCXjAHcWp93uOUBchzYcsvPlrapAdX1uW+YGg=="
540 | },
541 | "node_modules/fastify": {
542 | "version": "4.11.0",
543 | "resolved": "https://registry.npmjs.org/fastify/-/fastify-4.11.0.tgz",
544 | "integrity": "sha512-JteZ8pjEqd+6n+azQnQfSJV8MUMxAmxbvC2Dx/Mybj039Lf/u3kda9Kq84uy/huCpqCzZoyHIZS5JFGF3wLztw==",
545 | "dependencies": {
546 | "@fastify/ajv-compiler": "^3.3.1",
547 | "@fastify/error": "^3.0.0",
548 | "@fastify/fast-json-stringify-compiler": "^4.1.0",
549 | "abstract-logging": "^2.0.1",
550 | "avvio": "^8.2.0",
551 | "content-type": "^1.0.4",
552 | "find-my-way": "^7.3.0",
553 | "light-my-request": "^5.6.1",
554 | "pino": "^8.5.0",
555 | "process-warning": "^2.0.0",
556 | "proxy-addr": "^2.0.7",
557 | "rfdc": "^1.3.0",
558 | "secure-json-parse": "^2.5.0",
559 | "semver": "^7.3.7",
560 | "tiny-lru": "^10.0.0"
561 | }
562 | },
563 | "node_modules/fastify-plugin": {
564 | "version": "4.5.0",
565 | "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-4.5.0.tgz",
566 | "integrity": "sha512-79ak0JxddO0utAXAQ5ccKhvs6vX2MGyHHMMsmZkBANrq3hXc1CHzvNPHOcvTsVMEPl5I+NT+RO4YKMGehOfSIg=="
567 | },
568 | "node_modules/fastq": {
569 | "version": "1.15.0",
570 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
571 | "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
572 | "dependencies": {
573 | "reusify": "^1.0.4"
574 | }
575 | },
576 | "node_modules/fill-range": {
577 | "version": "7.0.1",
578 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
579 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
580 | "dev": true,
581 | "dependencies": {
582 | "to-regex-range": "^5.0.1"
583 | },
584 | "engines": {
585 | "node": ">=8"
586 | }
587 | },
588 | "node_modules/find-my-way": {
589 | "version": "7.4.0",
590 | "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-7.4.0.tgz",
591 | "integrity": "sha512-JFT7eURLU5FumlZ3VBGnveId82cZz7UR7OUu+THQJOwdQXxmS/g8v0KLoFhv97HreycOrmAbqjXD/4VG2j0uMQ==",
592 | "dependencies": {
593 | "fast-deep-equal": "^3.1.3",
594 | "fast-querystring": "^1.0.0",
595 | "safe-regex2": "^2.0.0"
596 | },
597 | "engines": {
598 | "node": ">=14"
599 | }
600 | },
601 | "node_modules/follow-redirects": {
602 | "version": "1.15.2",
603 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
604 | "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
605 | "funding": [
606 | {
607 | "type": "individual",
608 | "url": "https://github.com/sponsors/RubenVerborgh"
609 | }
610 | ],
611 | "engines": {
612 | "node": ">=4.0"
613 | },
614 | "peerDependenciesMeta": {
615 | "debug": {
616 | "optional": true
617 | }
618 | }
619 | },
620 | "node_modules/form-data": {
621 | "version": "4.0.0",
622 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
623 | "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
624 | "dependencies": {
625 | "asynckit": "^0.4.0",
626 | "combined-stream": "^1.0.8",
627 | "mime-types": "^2.1.12"
628 | },
629 | "engines": {
630 | "node": ">= 6"
631 | }
632 | },
633 | "node_modules/forwarded": {
634 | "version": "0.2.0",
635 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
636 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
637 | "engines": {
638 | "node": ">= 0.6"
639 | }
640 | },
641 | "node_modules/fsevents": {
642 | "version": "2.3.2",
643 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
644 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
645 | "dev": true,
646 | "hasInstallScript": true,
647 | "optional": true,
648 | "os": [
649 | "darwin"
650 | ],
651 | "engines": {
652 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
653 | }
654 | },
655 | "node_modules/glob-parent": {
656 | "version": "5.1.2",
657 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
658 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
659 | "dev": true,
660 | "dependencies": {
661 | "is-glob": "^4.0.1"
662 | },
663 | "engines": {
664 | "node": ">= 6"
665 | }
666 | },
667 | "node_modules/has-flag": {
668 | "version": "3.0.0",
669 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
670 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
671 | "dev": true,
672 | "engines": {
673 | "node": ">=4"
674 | }
675 | },
676 | "node_modules/ieee754": {
677 | "version": "1.2.1",
678 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
679 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
680 | "funding": [
681 | {
682 | "type": "github",
683 | "url": "https://github.com/sponsors/feross"
684 | },
685 | {
686 | "type": "patreon",
687 | "url": "https://www.patreon.com/feross"
688 | },
689 | {
690 | "type": "consulting",
691 | "url": "https://feross.org/support"
692 | }
693 | ]
694 | },
695 | "node_modules/ignore-by-default": {
696 | "version": "1.0.1",
697 | "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
698 | "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
699 | "dev": true
700 | },
701 | "node_modules/ipaddr.js": {
702 | "version": "1.9.1",
703 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
704 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
705 | "engines": {
706 | "node": ">= 0.10"
707 | }
708 | },
709 | "node_modules/is-binary-path": {
710 | "version": "2.1.0",
711 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
712 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
713 | "dev": true,
714 | "dependencies": {
715 | "binary-extensions": "^2.0.0"
716 | },
717 | "engines": {
718 | "node": ">=8"
719 | }
720 | },
721 | "node_modules/is-extglob": {
722 | "version": "2.1.1",
723 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
724 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
725 | "dev": true,
726 | "engines": {
727 | "node": ">=0.10.0"
728 | }
729 | },
730 | "node_modules/is-glob": {
731 | "version": "4.0.3",
732 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
733 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
734 | "dev": true,
735 | "dependencies": {
736 | "is-extglob": "^2.1.1"
737 | },
738 | "engines": {
739 | "node": ">=0.10.0"
740 | }
741 | },
742 | "node_modules/is-number": {
743 | "version": "7.0.0",
744 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
745 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
746 | "dev": true,
747 | "engines": {
748 | "node": ">=0.12.0"
749 | }
750 | },
751 | "node_modules/isomorphic-ws": {
752 | "version": "4.0.1",
753 | "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz",
754 | "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==",
755 | "peerDependencies": {
756 | "ws": "*"
757 | }
758 | },
759 | "node_modules/json-schema-traverse": {
760 | "version": "1.0.0",
761 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
762 | "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
763 | },
764 | "node_modules/jsonwebtoken": {
765 | "version": "9.0.0",
766 | "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz",
767 | "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==",
768 | "dependencies": {
769 | "jws": "^3.2.2",
770 | "lodash": "^4.17.21",
771 | "ms": "^2.1.1",
772 | "semver": "^7.3.8"
773 | },
774 | "engines": {
775 | "node": ">=12",
776 | "npm": ">=6"
777 | }
778 | },
779 | "node_modules/jwa": {
780 | "version": "1.4.1",
781 | "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
782 | "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
783 | "dependencies": {
784 | "buffer-equal-constant-time": "1.0.1",
785 | "ecdsa-sig-formatter": "1.0.11",
786 | "safe-buffer": "^5.0.1"
787 | }
788 | },
789 | "node_modules/jws": {
790 | "version": "3.2.2",
791 | "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
792 | "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
793 | "dependencies": {
794 | "jwa": "^1.4.1",
795 | "safe-buffer": "^5.0.1"
796 | }
797 | },
798 | "node_modules/light-my-request": {
799 | "version": "5.8.0",
800 | "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-5.8.0.tgz",
801 | "integrity": "sha512-4BtD5C+VmyTpzlDPCZbsatZMJVgUIciSOwYhJDCbLffPZ35KoDkDj4zubLeHDEb35b4kkPeEv5imbh+RJxK/Pg==",
802 | "dependencies": {
803 | "cookie": "^0.5.0",
804 | "process-warning": "^2.0.0",
805 | "set-cookie-parser": "^2.4.1"
806 | }
807 | },
808 | "node_modules/lodash": {
809 | "version": "4.17.21",
810 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
811 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
812 | },
813 | "node_modules/lru-cache": {
814 | "version": "6.0.0",
815 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
816 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
817 | "dependencies": {
818 | "yallist": "^4.0.0"
819 | },
820 | "engines": {
821 | "node": ">=10"
822 | }
823 | },
824 | "node_modules/make-error": {
825 | "version": "1.3.6",
826 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
827 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
828 | "dev": true
829 | },
830 | "node_modules/mime-db": {
831 | "version": "1.52.0",
832 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
833 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
834 | "engines": {
835 | "node": ">= 0.6"
836 | }
837 | },
838 | "node_modules/mime-types": {
839 | "version": "2.1.35",
840 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
841 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
842 | "dependencies": {
843 | "mime-db": "1.52.0"
844 | },
845 | "engines": {
846 | "node": ">= 0.6"
847 | }
848 | },
849 | "node_modules/minimatch": {
850 | "version": "3.1.2",
851 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
852 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
853 | "dev": true,
854 | "dependencies": {
855 | "brace-expansion": "^1.1.7"
856 | },
857 | "engines": {
858 | "node": "*"
859 | }
860 | },
861 | "node_modules/mnemonist": {
862 | "version": "0.39.5",
863 | "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.39.5.tgz",
864 | "integrity": "sha512-FPUtkhtJ0efmEFGpU14x7jGbTB+s18LrzRL2KgoWz9YvcY3cPomz8tih01GbHwnGk/OmkOKfqd/RAQoc8Lm7DQ==",
865 | "dependencies": {
866 | "obliterator": "^2.0.1"
867 | }
868 | },
869 | "node_modules/ms": {
870 | "version": "2.1.2",
871 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
872 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
873 | },
874 | "node_modules/nodemon": {
875 | "version": "2.0.20",
876 | "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz",
877 | "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==",
878 | "dev": true,
879 | "dependencies": {
880 | "chokidar": "^3.5.2",
881 | "debug": "^3.2.7",
882 | "ignore-by-default": "^1.0.1",
883 | "minimatch": "^3.1.2",
884 | "pstree.remy": "^1.1.8",
885 | "semver": "^5.7.1",
886 | "simple-update-notifier": "^1.0.7",
887 | "supports-color": "^5.5.0",
888 | "touch": "^3.1.0",
889 | "undefsafe": "^2.0.5"
890 | },
891 | "bin": {
892 | "nodemon": "bin/nodemon.js"
893 | },
894 | "engines": {
895 | "node": ">=8.10.0"
896 | },
897 | "funding": {
898 | "type": "opencollective",
899 | "url": "https://opencollective.com/nodemon"
900 | }
901 | },
902 | "node_modules/nodemon/node_modules/debug": {
903 | "version": "3.2.7",
904 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
905 | "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
906 | "dev": true,
907 | "dependencies": {
908 | "ms": "^2.1.1"
909 | }
910 | },
911 | "node_modules/nodemon/node_modules/semver": {
912 | "version": "5.7.1",
913 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
914 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
915 | "dev": true,
916 | "bin": {
917 | "semver": "bin/semver"
918 | }
919 | },
920 | "node_modules/nopt": {
921 | "version": "1.0.10",
922 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
923 | "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==",
924 | "dev": true,
925 | "dependencies": {
926 | "abbrev": "1"
927 | },
928 | "bin": {
929 | "nopt": "bin/nopt.js"
930 | },
931 | "engines": {
932 | "node": "*"
933 | }
934 | },
935 | "node_modules/normalize-path": {
936 | "version": "3.0.0",
937 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
938 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
939 | "dev": true,
940 | "engines": {
941 | "node": ">=0.10.0"
942 | }
943 | },
944 | "node_modules/obliterator": {
945 | "version": "2.0.4",
946 | "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.4.tgz",
947 | "integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ=="
948 | },
949 | "node_modules/on-exit-leak-free": {
950 | "version": "2.1.0",
951 | "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.0.tgz",
952 | "integrity": "sha512-VuCaZZAjReZ3vUwgOB8LxAosIurDiAW0s13rI1YwmaP++jvcxP77AWoQvenZebpCA2m8WC1/EosPYPMjnRAp/w=="
953 | },
954 | "node_modules/picomatch": {
955 | "version": "2.3.1",
956 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
957 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
958 | "dev": true,
959 | "engines": {
960 | "node": ">=8.6"
961 | },
962 | "funding": {
963 | "url": "https://github.com/sponsors/jonschlinkert"
964 | }
965 | },
966 | "node_modules/pino": {
967 | "version": "8.8.0",
968 | "resolved": "https://registry.npmjs.org/pino/-/pino-8.8.0.tgz",
969 | "integrity": "sha512-cF8iGYeu2ODg2gIwgAHcPrtR63ILJz3f7gkogaHC/TXVVXxZgInmNYiIpDYEwgEkxZti2Se6P2W2DxlBIZe6eQ==",
970 | "dependencies": {
971 | "atomic-sleep": "^1.0.0",
972 | "fast-redact": "^3.1.1",
973 | "on-exit-leak-free": "^2.1.0",
974 | "pino-abstract-transport": "v1.0.0",
975 | "pino-std-serializers": "^6.0.0",
976 | "process-warning": "^2.0.0",
977 | "quick-format-unescaped": "^4.0.3",
978 | "real-require": "^0.2.0",
979 | "safe-stable-stringify": "^2.3.1",
980 | "sonic-boom": "^3.1.0",
981 | "thread-stream": "^2.0.0"
982 | },
983 | "bin": {
984 | "pino": "bin.js"
985 | }
986 | },
987 | "node_modules/pino-abstract-transport": {
988 | "version": "1.0.0",
989 | "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.0.0.tgz",
990 | "integrity": "sha512-c7vo5OpW4wIS42hUVcT5REsL8ZljsUfBjqV/e2sFxmFEFZiq1XLUp5EYLtuDH6PEHq9W1egWqRbnLUP5FuZmOA==",
991 | "dependencies": {
992 | "readable-stream": "^4.0.0",
993 | "split2": "^4.0.0"
994 | }
995 | },
996 | "node_modules/pino-std-serializers": {
997 | "version": "6.1.0",
998 | "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-6.1.0.tgz",
999 | "integrity": "sha512-KO0m2f1HkrPe9S0ldjx7za9BJjeHqBku5Ch8JyxETxT8dEFGz1PwgrHaOQupVYitpzbFSYm7nnljxD8dik2c+g=="
1000 | },
1001 | "node_modules/process": {
1002 | "version": "0.11.10",
1003 | "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
1004 | "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
1005 | "engines": {
1006 | "node": ">= 0.6.0"
1007 | }
1008 | },
1009 | "node_modules/process-warning": {
1010 | "version": "2.1.0",
1011 | "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-2.1.0.tgz",
1012 | "integrity": "sha512-9C20RLxrZU/rFnxWncDkuF6O999NdIf3E1ws4B0ZeY3sRVPzWBMsYDE2lxjxhiXxg464cQTgKUGm8/i6y2YGXg=="
1013 | },
1014 | "node_modules/proxy-addr": {
1015 | "version": "2.0.7",
1016 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
1017 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
1018 | "dependencies": {
1019 | "forwarded": "0.2.0",
1020 | "ipaddr.js": "1.9.1"
1021 | },
1022 | "engines": {
1023 | "node": ">= 0.10"
1024 | }
1025 | },
1026 | "node_modules/pstree.remy": {
1027 | "version": "1.1.8",
1028 | "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
1029 | "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
1030 | "dev": true
1031 | },
1032 | "node_modules/punycode": {
1033 | "version": "2.2.0",
1034 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.2.0.tgz",
1035 | "integrity": "sha512-LN6QV1IJ9ZhxWTNdktaPClrNfp8xdSAYS0Zk2ddX7XsXZAxckMHPCBcHRo0cTcEIgYPRiGEkmji3Idkh2yFtYw==",
1036 | "engines": {
1037 | "node": ">=6"
1038 | }
1039 | },
1040 | "node_modules/quick-format-unescaped": {
1041 | "version": "4.0.4",
1042 | "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz",
1043 | "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="
1044 | },
1045 | "node_modules/readable-stream": {
1046 | "version": "4.3.0",
1047 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.3.0.tgz",
1048 | "integrity": "sha512-MuEnA0lbSi7JS8XM+WNJlWZkHAAdm7gETHdFK//Q/mChGyj2akEFtdLZh32jSdkWGbRwCW9pn6g3LWDdDeZnBQ==",
1049 | "dependencies": {
1050 | "abort-controller": "^3.0.0",
1051 | "buffer": "^6.0.3",
1052 | "events": "^3.3.0",
1053 | "process": "^0.11.10"
1054 | },
1055 | "engines": {
1056 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
1057 | }
1058 | },
1059 | "node_modules/readdirp": {
1060 | "version": "3.6.0",
1061 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
1062 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
1063 | "dev": true,
1064 | "dependencies": {
1065 | "picomatch": "^2.2.1"
1066 | },
1067 | "engines": {
1068 | "node": ">=8.10.0"
1069 | }
1070 | },
1071 | "node_modules/real-require": {
1072 | "version": "0.2.0",
1073 | "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz",
1074 | "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==",
1075 | "engines": {
1076 | "node": ">= 12.13.0"
1077 | }
1078 | },
1079 | "node_modules/regenerator-runtime": {
1080 | "version": "0.13.11",
1081 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
1082 | "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
1083 | },
1084 | "node_modules/require-from-string": {
1085 | "version": "2.0.2",
1086 | "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
1087 | "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
1088 | "engines": {
1089 | "node": ">=0.10.0"
1090 | }
1091 | },
1092 | "node_modules/ret": {
1093 | "version": "0.2.2",
1094 | "resolved": "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz",
1095 | "integrity": "sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==",
1096 | "engines": {
1097 | "node": ">=4"
1098 | }
1099 | },
1100 | "node_modules/reusify": {
1101 | "version": "1.0.4",
1102 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
1103 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
1104 | "engines": {
1105 | "iojs": ">=1.0.0",
1106 | "node": ">=0.10.0"
1107 | }
1108 | },
1109 | "node_modules/rfdc": {
1110 | "version": "1.3.0",
1111 | "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz",
1112 | "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA=="
1113 | },
1114 | "node_modules/safe-buffer": {
1115 | "version": "5.2.1",
1116 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
1117 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
1118 | "funding": [
1119 | {
1120 | "type": "github",
1121 | "url": "https://github.com/sponsors/feross"
1122 | },
1123 | {
1124 | "type": "patreon",
1125 | "url": "https://www.patreon.com/feross"
1126 | },
1127 | {
1128 | "type": "consulting",
1129 | "url": "https://feross.org/support"
1130 | }
1131 | ]
1132 | },
1133 | "node_modules/safe-regex2": {
1134 | "version": "2.0.0",
1135 | "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-2.0.0.tgz",
1136 | "integrity": "sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==",
1137 | "dependencies": {
1138 | "ret": "~0.2.0"
1139 | }
1140 | },
1141 | "node_modules/safe-stable-stringify": {
1142 | "version": "2.4.2",
1143 | "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.2.tgz",
1144 | "integrity": "sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA==",
1145 | "engines": {
1146 | "node": ">=10"
1147 | }
1148 | },
1149 | "node_modules/secure-json-parse": {
1150 | "version": "2.7.0",
1151 | "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz",
1152 | "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw=="
1153 | },
1154 | "node_modules/semver": {
1155 | "version": "7.3.8",
1156 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
1157 | "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
1158 | "dependencies": {
1159 | "lru-cache": "^6.0.0"
1160 | },
1161 | "bin": {
1162 | "semver": "bin/semver.js"
1163 | },
1164 | "engines": {
1165 | "node": ">=10"
1166 | }
1167 | },
1168 | "node_modules/set-cookie-parser": {
1169 | "version": "2.5.1",
1170 | "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.5.1.tgz",
1171 | "integrity": "sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ=="
1172 | },
1173 | "node_modules/simple-update-notifier": {
1174 | "version": "1.1.0",
1175 | "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz",
1176 | "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==",
1177 | "dev": true,
1178 | "dependencies": {
1179 | "semver": "~7.0.0"
1180 | },
1181 | "engines": {
1182 | "node": ">=8.10.0"
1183 | }
1184 | },
1185 | "node_modules/simple-update-notifier/node_modules/semver": {
1186 | "version": "7.0.0",
1187 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz",
1188 | "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==",
1189 | "dev": true,
1190 | "bin": {
1191 | "semver": "bin/semver.js"
1192 | }
1193 | },
1194 | "node_modules/sonic-boom": {
1195 | "version": "3.2.1",
1196 | "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.2.1.tgz",
1197 | "integrity": "sha512-iITeTHxy3B9FGu8aVdiDXUVAcHMF9Ss0cCsAOo2HfCrmVGT3/DT5oYaeu0M/YKZDlKTvChEyPq0zI9Hf33EX6A==",
1198 | "dependencies": {
1199 | "atomic-sleep": "^1.0.0"
1200 | }
1201 | },
1202 | "node_modules/split2": {
1203 | "version": "4.1.0",
1204 | "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz",
1205 | "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==",
1206 | "engines": {
1207 | "node": ">= 10.x"
1208 | }
1209 | },
1210 | "node_modules/stream-chat": {
1211 | "version": "8.2.1",
1212 | "resolved": "https://registry.npmjs.org/stream-chat/-/stream-chat-8.2.1.tgz",
1213 | "integrity": "sha512-8f+Zkcz2JmSOSw3Q+1ZyC7JLFnB7HezE8TGTY4oeLG54g5r4cCwV0MVGlPaWERZ5darG987xasbOx6eU1Jjesg==",
1214 | "dependencies": {
1215 | "@babel/runtime": "^7.16.3",
1216 | "@types/jsonwebtoken": "~9.0.0",
1217 | "@types/ws": "^7.4.0",
1218 | "axios": "^0.22.0",
1219 | "base64-js": "^1.5.1",
1220 | "form-data": "^4.0.0",
1221 | "isomorphic-ws": "^4.0.1",
1222 | "jsonwebtoken": "~9.0.0",
1223 | "ws": "^7.4.4"
1224 | },
1225 | "engines": {
1226 | "node": ">=16"
1227 | }
1228 | },
1229 | "node_modules/supports-color": {
1230 | "version": "5.5.0",
1231 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
1232 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
1233 | "dev": true,
1234 | "dependencies": {
1235 | "has-flag": "^3.0.0"
1236 | },
1237 | "engines": {
1238 | "node": ">=4"
1239 | }
1240 | },
1241 | "node_modules/thread-stream": {
1242 | "version": "2.3.0",
1243 | "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-2.3.0.tgz",
1244 | "integrity": "sha512-kaDqm1DET9pp3NXwR8382WHbnpXnRkN9xGN9dQt3B2+dmXiW8X1SOwmFOxAErEQ47ObhZ96J6yhZNXuyCOL7KA==",
1245 | "dependencies": {
1246 | "real-require": "^0.2.0"
1247 | }
1248 | },
1249 | "node_modules/tiny-lru": {
1250 | "version": "10.0.1",
1251 | "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-10.0.1.tgz",
1252 | "integrity": "sha512-Vst+6kEsWvb17Zpz14sRJV/f8bUWKhqm6Dc+v08iShmIJ/WxqWytHzCTd6m88pS33rE2zpX34TRmOpAJPloNCA==",
1253 | "engines": {
1254 | "node": ">=6"
1255 | }
1256 | },
1257 | "node_modules/to-regex-range": {
1258 | "version": "5.0.1",
1259 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
1260 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
1261 | "dev": true,
1262 | "dependencies": {
1263 | "is-number": "^7.0.0"
1264 | },
1265 | "engines": {
1266 | "node": ">=8.0"
1267 | }
1268 | },
1269 | "node_modules/touch": {
1270 | "version": "3.1.0",
1271 | "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
1272 | "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==",
1273 | "dev": true,
1274 | "dependencies": {
1275 | "nopt": "~1.0.10"
1276 | },
1277 | "bin": {
1278 | "nodetouch": "bin/nodetouch.js"
1279 | }
1280 | },
1281 | "node_modules/ts-node": {
1282 | "version": "10.9.1",
1283 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
1284 | "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
1285 | "dev": true,
1286 | "dependencies": {
1287 | "@cspotcode/source-map-support": "^0.8.0",
1288 | "@tsconfig/node10": "^1.0.7",
1289 | "@tsconfig/node12": "^1.0.7",
1290 | "@tsconfig/node14": "^1.0.0",
1291 | "@tsconfig/node16": "^1.0.2",
1292 | "acorn": "^8.4.1",
1293 | "acorn-walk": "^8.1.1",
1294 | "arg": "^4.1.0",
1295 | "create-require": "^1.1.0",
1296 | "diff": "^4.0.1",
1297 | "make-error": "^1.1.1",
1298 | "v8-compile-cache-lib": "^3.0.1",
1299 | "yn": "3.1.1"
1300 | },
1301 | "bin": {
1302 | "ts-node": "dist/bin.js",
1303 | "ts-node-cwd": "dist/bin-cwd.js",
1304 | "ts-node-esm": "dist/bin-esm.js",
1305 | "ts-node-script": "dist/bin-script.js",
1306 | "ts-node-transpile-only": "dist/bin-transpile.js",
1307 | "ts-script": "dist/bin-script-deprecated.js"
1308 | },
1309 | "peerDependencies": {
1310 | "@swc/core": ">=1.2.50",
1311 | "@swc/wasm": ">=1.2.50",
1312 | "@types/node": "*",
1313 | "typescript": ">=2.7"
1314 | },
1315 | "peerDependenciesMeta": {
1316 | "@swc/core": {
1317 | "optional": true
1318 | },
1319 | "@swc/wasm": {
1320 | "optional": true
1321 | }
1322 | }
1323 | },
1324 | "node_modules/typescript": {
1325 | "version": "4.9.4",
1326 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz",
1327 | "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==",
1328 | "dev": true,
1329 | "peer": true,
1330 | "bin": {
1331 | "tsc": "bin/tsc",
1332 | "tsserver": "bin/tsserver"
1333 | },
1334 | "engines": {
1335 | "node": ">=4.2.0"
1336 | }
1337 | },
1338 | "node_modules/undefsafe": {
1339 | "version": "2.0.5",
1340 | "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
1341 | "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
1342 | "dev": true
1343 | },
1344 | "node_modules/uri-js": {
1345 | "version": "4.4.1",
1346 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
1347 | "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
1348 | "dependencies": {
1349 | "punycode": "^2.1.0"
1350 | }
1351 | },
1352 | "node_modules/v8-compile-cache-lib": {
1353 | "version": "3.0.1",
1354 | "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
1355 | "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
1356 | "dev": true
1357 | },
1358 | "node_modules/ws": {
1359 | "version": "7.5.9",
1360 | "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
1361 | "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
1362 | "engines": {
1363 | "node": ">=8.3.0"
1364 | },
1365 | "peerDependencies": {
1366 | "bufferutil": "^4.0.1",
1367 | "utf-8-validate": "^5.0.2"
1368 | },
1369 | "peerDependenciesMeta": {
1370 | "bufferutil": {
1371 | "optional": true
1372 | },
1373 | "utf-8-validate": {
1374 | "optional": true
1375 | }
1376 | }
1377 | },
1378 | "node_modules/yallist": {
1379 | "version": "4.0.0",
1380 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
1381 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
1382 | },
1383 | "node_modules/yn": {
1384 | "version": "3.1.1",
1385 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
1386 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
1387 | "dev": true,
1388 | "engines": {
1389 | "node": ">=6"
1390 | }
1391 | }
1392 | }
1393 | }
1394 |
--------------------------------------------------------------------------------
/server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "server",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "dev": "nodemon server.ts"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "@fastify/cors": "^8.2.0",
14 | "dotenv": "^16.0.3",
15 | "fastify": "^4.11.0",
16 | "stream-chat": "^8.2.1"
17 | },
18 | "devDependencies": {
19 | "@types/node": "^18.11.18",
20 | "nodemon": "^2.0.20",
21 | "ts-node": "^10.9.1"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/server/routes/users.ts:
--------------------------------------------------------------------------------
1 | import { FastifyInstance } from "fastify"
2 | import { StreamChat } from "stream-chat"
3 |
4 | const streamChat = StreamChat.getInstance(
5 | process.env.STREAM_API_KEY!,
6 | process.env.STREAM_PRIVATE_API_KEY!
7 | )
8 |
9 | const TOKEN_USER_ID_MAP = new Map()
10 |
11 | export async function userRoutes(app: FastifyInstance) {
12 | app.post<{ Body: { id: string; name: string; image?: string } }>(
13 | "/signup",
14 | async (req, res) => {
15 | const { id, name, image } = req.body
16 | if (id == null || id === "" || name == null || name === "") {
17 | return res.status(400).send
18 | }
19 |
20 | const existingUsers = await streamChat.queryUsers({ id })
21 | if (existingUsers.users.length > 0) {
22 | return res.status(400).send("User ID taken")
23 | }
24 |
25 | await streamChat.upsertUser({ id, name, image })
26 | }
27 | )
28 |
29 | app.post<{ Body: { id: string } }>("/login", async (req, res) => {
30 | const { id } = req.body
31 | if (id == null || id === "") {
32 | return res.status(400).send
33 | }
34 |
35 | const {
36 | users: [user],
37 | } = await streamChat.queryUsers({ id })
38 | if (user == null) return res.status(401).send()
39 |
40 | const token = streamChat.createToken(id)
41 | TOKEN_USER_ID_MAP.set(token, user.id)
42 |
43 | return {
44 | token,
45 | user: { name: user.name, id: user.id, image: user.image },
46 | }
47 | })
48 |
49 | app.post<{ Body: { token: string } }>("/logout", async (req, res) => {
50 | const token = req.body.token
51 | if (token == null || token === "") return res.status(400).send()
52 |
53 | const id = TOKEN_USER_ID_MAP.get(token)
54 | if (id == null) return res.status(400).send()
55 |
56 | await streamChat.revokeUserToken(id, new Date())
57 | TOKEN_USER_ID_MAP.delete(token)
58 | })
59 | }
60 |
--------------------------------------------------------------------------------
/server/server.ts:
--------------------------------------------------------------------------------
1 | import { config } from "dotenv"
2 | config()
3 |
4 | import fastify from "fastify"
5 | import cors from "@fastify/cors"
6 | import { userRoutes } from "./routes/users"
7 |
8 | const app = fastify()
9 | app.register(cors, { origin: process.env.CLIENT_URL })
10 | app.register(userRoutes)
11 |
12 | app.listen({ port: parseInt(process.env.PORT!) })
13 |
--------------------------------------------------------------------------------