├── .gitignore
├── server-django
├── .gitignore
├── server
│ ├── __init__.py
│ ├── wsgi.py
│ ├── urls.py
│ ├── views.py
│ └── settings.py
├── db.sqlite3
├── requirements.txt
├── manage.py
└── README.md
├── server-fastapi
├── .gitignore
├── requirements.txt
├── README.md
└── main.py
├── server-nodejs
├── .gitignore
├── README.md
├── package.json
├── index.js
└── package-lock.json
├── client-vue
└── README.md
├── server-express
├── .gitignore
├── package.json
├── README.md
└── index.js
├── server-spring
├── src
│ └── main
│ │ ├── resources
│ │ └── application.properties
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── chatengine
│ │ └── serverspring
│ │ ├── ServerSpringApplication.java
│ │ └── UserController.java
├── README.md
├── .mvn
│ └── wrapper
│ │ ├── maven-wrapper.jar
│ │ └── maven-wrapper.properties
├── .gitignore
├── pom.xml
├── mvnw.cmd
└── mvnw
├── .DS_Store
├── client-react
├── .env
├── public
│ ├── robots.txt
│ ├── favicon.ico
│ ├── logo192.png
│ ├── manifest.json
│ └── index.html
├── src
│ ├── index.js
│ ├── app.js
│ ├── index.css
│ ├── chatsPage.js
│ └── authPage.js
├── .gitignore
├── package.json
└── README.md
├── server-flask
├── README.md
├── .env
├── requirements.txt
└── app.py
├── server-firebase
├── functions
│ ├── tsconfig.dev.json
│ ├── .gitignore
│ ├── tsconfig.json
│ ├── src
│ │ └── index.ts
│ ├── .eslintrc.js
│ └── package.json
├── .firebaserc
├── frontend
│ ├── public
│ │ ├── favicon.ico
│ │ ├── vercel.svg
│ │ ├── thirteen.svg
│ │ └── next.svg
│ ├── next.config.js
│ ├── pages
│ │ ├── _app.tsx
│ │ ├── Loading.tsx
│ │ ├── _document.tsx
│ │ ├── index.tsx
│ │ ├── ChatsPage.tsx
│ │ └── AuthPage.tsx
│ ├── .gitignore
│ ├── package.json
│ ├── firebase.ts
│ ├── tsconfig.json
│ ├── styles
│ │ └── globals.css
│ └── README.md
├── firebase.json
├── .gitignore
└── README.md
├── client-html
├── css
│ ├── valley.jpeg
│ └── style.css
├── chats.html
└── index.html
├── serverless-vue
├── src
│ ├── style.css
│ ├── main.js
│ ├── assets
│ │ └── vue.svg
│ ├── App.vue
│ └── pages
│ │ ├── AuthPage
│ │ ├── api.js
│ │ └── index.vue
│ │ └── ChatsPage
│ │ └── index.vue
├── .vscode
│ └── extensions.json
├── vite.config.js
├── .gitignore
├── index.html
├── package.json
├── README.md
└── public
│ └── vite.svg
├── README.md
└── requests.rest
/.gitignore:
--------------------------------------------------------------------------------
1 | venv/
--------------------------------------------------------------------------------
/server-django/.gitignore:
--------------------------------------------------------------------------------
1 | .env
--------------------------------------------------------------------------------
/server-django/server/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/server-fastapi/.gitignore:
--------------------------------------------------------------------------------
1 | venv/
2 |
--------------------------------------------------------------------------------
/server-nodejs/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
--------------------------------------------------------------------------------
/client-vue/README.md:
--------------------------------------------------------------------------------
1 | # Coming soon!
2 |
--------------------------------------------------------------------------------
/server-express/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .env
--------------------------------------------------------------------------------
/server-spring/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | server.port=3001
--------------------------------------------------------------------------------
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alamorre/fullstack-chat/HEAD/.DS_Store
--------------------------------------------------------------------------------
/client-react/.env:
--------------------------------------------------------------------------------
1 | REACT_APP_CHAT_ENGINE_PROJECT_ID=794653df-052a-4ad2-b0aa-d6c251a10aef
--------------------------------------------------------------------------------
/server-spring/README.md:
--------------------------------------------------------------------------------
1 | Install `mvn clean install`
2 | Run `mvn spring-boot:run`
3 |
--------------------------------------------------------------------------------
/server-flask/README.md:
--------------------------------------------------------------------------------
1 | # Coming soon!
2 |
3 | flask --app app run --host=0.0.0.0 --port=3001
4 |
--------------------------------------------------------------------------------
/server-django/db.sqlite3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alamorre/fullstack-chat/HEAD/server-django/db.sqlite3
--------------------------------------------------------------------------------
/server-firebase/functions/tsconfig.dev.json:
--------------------------------------------------------------------------------
1 | {
2 | "include": [
3 | ".eslintrc.js"
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/client-html/css/valley.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alamorre/fullstack-chat/HEAD/client-html/css/valley.jpeg
--------------------------------------------------------------------------------
/client-react/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/server-firebase/.firebaserc:
--------------------------------------------------------------------------------
1 | {
2 | "projects": {
3 | "default": "fullstack-chat-server"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/serverless-vue/src/style.css:
--------------------------------------------------------------------------------
1 | * {
2 | font-family: Avenir;
3 | }
4 |
5 | body {
6 | margin: 0px;
7 | }
--------------------------------------------------------------------------------
/client-react/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alamorre/fullstack-chat/HEAD/client-react/public/favicon.ico
--------------------------------------------------------------------------------
/client-react/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alamorre/fullstack-chat/HEAD/client-react/public/logo192.png
--------------------------------------------------------------------------------
/serverless-vue/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"]
3 | }
4 |
--------------------------------------------------------------------------------
/server-flask/.env:
--------------------------------------------------------------------------------
1 | CHAT_ENGINE_PROJECT_ID=5d498a31-cd23-42b7-b367-4fcc9463bd2f
2 | CHAT_ENGINE_PRIVATE_KEY=49a46286-91c3-4f9c-92bf-284ae51b7628
--------------------------------------------------------------------------------
/server-firebase/frontend/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alamorre/fullstack-chat/HEAD/server-firebase/frontend/public/favicon.ico
--------------------------------------------------------------------------------
/server-spring/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alamorre/fullstack-chat/HEAD/server-spring/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/serverless-vue/src/main.js:
--------------------------------------------------------------------------------
1 | import { createApp } from "vue";
2 | import "./style.css";
3 | import App from "./App.vue";
4 |
5 | createApp(App).mount("#app");
6 |
--------------------------------------------------------------------------------
/server-firebase/frontend/next.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | reactStrictMode: false,
4 | };
5 |
6 | module.exports = nextConfig;
7 |
--------------------------------------------------------------------------------
/serverless-vue/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import vue from '@vitejs/plugin-vue'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [vue()],
7 | })
8 |
--------------------------------------------------------------------------------
/server-firebase/functions/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled JavaScript files
2 | lib/**/*.js
3 | lib/**/*.js.map
4 |
5 | # TypeScript v1 declaration files
6 | typings/
7 |
8 | # Node.js dependency directory
9 | node_modules/
10 |
--------------------------------------------------------------------------------
/server-firebase/frontend/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import '@/styles/globals.css'
2 | import type { AppProps } from 'next/app'
3 |
4 | export default function App({ Component, pageProps }: AppProps) {
5 | return
6 | }
7 |
--------------------------------------------------------------------------------
/server-firebase/frontend/pages/Loading.tsx:
--------------------------------------------------------------------------------
1 | export default function Loading() {
2 | return (
3 |
4 |
☝️
5 |
Loading your info...
6 |
7 | );
8 | }
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Fullstack Chat project
2 |
3 | This project allows to setup fullstack chat for any frontend/backend combination!
4 |
5 | Connect React, Vue, or Angular and any backend you wish!
6 |
7 | This should fully support all your fullstack chat needs!
8 |
--------------------------------------------------------------------------------
/server-django/requirements.txt:
--------------------------------------------------------------------------------
1 | asgiref==3.5.2
2 | certifi==2022.9.24
3 | charset-normalizer==2.1.1
4 | Django==4.1.3
5 | django-environ==0.9.0
6 | djangorestframework==3.14.0
7 | idna==3.4
8 | pytz==2022.6
9 | requests==2.28.1
10 | sqlparse==0.4.3
11 | urllib3==1.26.13
12 |
--------------------------------------------------------------------------------
/server-spring/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.6/apache-maven-3.8.6-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar
3 |
--------------------------------------------------------------------------------
/client-react/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import "./index.css";
4 | import App from "./app";
5 |
6 | const root = ReactDOM.createRoot(document.getElementById("root"));
7 | root.render(
8 | //
9 |
10 | //
11 | );
12 |
--------------------------------------------------------------------------------
/server-firebase/frontend/pages/_document.tsx:
--------------------------------------------------------------------------------
1 | import { Html, Head, Main, NextScript } from 'next/document'
2 |
3 | export default function Document() {
4 | return (
5 |
6 |
8 |
9 |
10 |
11 |
12 | )
13 | }
14 |
--------------------------------------------------------------------------------
/server-nodejs/README.md:
--------------------------------------------------------------------------------
1 | ## NodeJS Server Setup
2 |
3 | ```
4 | npm init
5 | npm install express axios cors
6 | npm install --save-dev nodemon
7 | # Add: "scripts": { "start": "nodemon index.js" },
8 | echo node_modules/ > .gitignore
9 | touch index.js
10 | # Add the code
11 | npm run start
12 | ```
13 |
14 | Edit the package.json file
15 |
--------------------------------------------------------------------------------
/server-firebase/functions/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "noImplicitReturns": true,
5 | "noUnusedLocals": true,
6 | "outDir": "lib",
7 | "sourceMap": true,
8 | "strict": true,
9 | "target": "es2017"
10 | },
11 | "compileOnSave": true,
12 | "include": [
13 | "src"
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/server-flask/requirements.txt:
--------------------------------------------------------------------------------
1 | certifi==2022.9.24
2 | charset-normalizer==2.1.1
3 | click==8.1.3
4 | Flask==2.2.2
5 | Flask-Cors==3.0.10
6 | idna==3.4
7 | importlib-metadata==5.1.0
8 | itsdangerous==2.1.2
9 | Jinja2==3.1.2
10 | MarkupSafe==2.1.1
11 | python-dotenv==0.21.0
12 | requests==2.28.1
13 | six==1.16.0
14 | urllib3==1.26.13
15 | Werkzeug==2.2.2
16 | zipp==3.11.0
17 |
--------------------------------------------------------------------------------
/serverless-vue/.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 |
--------------------------------------------------------------------------------
/client-react/src/app.js:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 |
3 | import AuthPage from "./authPage";
4 | import ChatsPage from "./chatsPage";
5 |
6 | function App() {
7 | const [user, setUser] = useState();
8 |
9 | if (!user) {
10 | return setUser(user)} />;
11 | } else {
12 | return ;
13 | }
14 | }
15 |
16 | export default App;
17 |
--------------------------------------------------------------------------------
/requests.rest:
--------------------------------------------------------------------------------
1 |
2 | POST http://localhost:3001/login
3 | Content-Type: application/json
4 |
5 | {
6 | "username": "adam",
7 | "secret": "pass1234"
8 | }
9 |
10 | ###
11 |
12 | POST http://localhost:3001/signup
13 | Content-Type: application/json
14 |
15 | {
16 | "username": "zack",
17 | "secret": "pass1234",
18 | "email": "zack@gmail.com",
19 | "first_name": "Zack",
20 | "last_name": "Engine"
21 | }
22 |
--------------------------------------------------------------------------------
/serverless-vue/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + Vue
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/client-react/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/client-react/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/server-fastapi/requirements.txt:
--------------------------------------------------------------------------------
1 | anyio==3.6.2
2 | certifi==2022.12.7
3 | charset-normalizer==2.1.1
4 | click==8.1.3
5 | fastapi==0.88.0
6 | h11==0.14.0
7 | httptools==0.5.0
8 | idna==3.4
9 | pydantic==1.10.2
10 | python-dotenv==0.21.0
11 | PyYAML==6.0
12 | requests==2.28.1
13 | sniffio==1.3.0
14 | starlette==0.22.0
15 | typing_extensions==4.4.0
16 | urllib3==1.26.13
17 | uvicorn==0.20.0
18 | uvloop==0.17.0
19 | watchfiles==0.18.1
20 | websockets==10.4
21 |
--------------------------------------------------------------------------------
/server-nodejs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "server-node",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "nodemon index.js"
8 | },
9 | "author": "Adam La Morre",
10 | "license": "ISC",
11 | "devDependencies": {
12 | "nodemon": "^2.0.20"
13 | },
14 | "dependencies": {
15 | "axios": "^1.2.0",
16 | "cors": "^2.8.5",
17 | "express": "^4.18.2"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/server-firebase/firebase.json:
--------------------------------------------------------------------------------
1 | {
2 | "functions": [
3 | {
4 | "source": "functions",
5 | "codebase": "default",
6 | "ignore": [
7 | "node_modules",
8 | ".git",
9 | "firebase-debug.log",
10 | "firebase-debug.*.log"
11 | ],
12 | "predeploy": [
13 | "npm --prefix \"$RESOURCE_DIR\" run lint",
14 | "npm --prefix \"$RESOURCE_DIR\" run build"
15 | ]
16 | }
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/server-django/server/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for server project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/4.1/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'server.settings')
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/server-express/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "server-express",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "nodemon index.js"
8 | },
9 | "author": "Adam La Morre",
10 | "license": "ISC",
11 | "devDependencies": {
12 | "nodemon": "^2.0.20"
13 | },
14 | "dependencies": {
15 | "axios": "^1.2.0",
16 | "cors": "^2.8.5",
17 | "dotenv": "^16.0.3",
18 | "express": "^4.18.2"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/server-spring/src/main/java/com/example/chatengine/serverspring/ServerSpringApplication.java:
--------------------------------------------------------------------------------
1 | package com.example.chatengine.serverspring;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class ServerSpringApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(ServerSpringApplication.class, args);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/client-html/chats.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Your Chats
9 |
10 |
11 |
14 |
15 |
--------------------------------------------------------------------------------
/serverless-vue/src/assets/vue.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client-react/src/chatsPage.js:
--------------------------------------------------------------------------------
1 | import { PrettyChatWindow } from "react-chat-engine-pretty";
2 |
3 | const ChatsPage = (props) => {
4 | return (
5 |
13 | );
14 | };
15 |
16 | export default ChatsPage;
17 |
--------------------------------------------------------------------------------
/serverless-vue/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "serverless-vue",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "preview": "vite preview"
10 | },
11 | "dependencies": {
12 | "axios": "^1.2.2",
13 | "react-chat-engine-pretty": "^0.1.5",
14 | "veaury": "^2.3.11",
15 | "vue": "^3.2.45"
16 | },
17 | "devDependencies": {
18 | "@vitejs/plugin-vue": "^4.0.0",
19 | "vite": "^4.0.0"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/server-spring/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**/target/
5 | !**/src/test/**/target/
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 | !**/src/main/**/build/
30 | !**/src/test/**/build/
31 |
32 | ### VS Code ###
33 | .vscode/
34 |
--------------------------------------------------------------------------------
/serverless-vue/README.md:
--------------------------------------------------------------------------------
1 | # Vue 3 + Vite
2 |
3 | This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `
5 |
6 |
7 |
8 |
9 |
10 |
11 |
25 |
--------------------------------------------------------------------------------
/client-react/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/server-firebase/frontend/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 |
3 | import AuthPage from "./AuthPage";
4 | import ChatPage from "./ChatsPage";
5 | import Loading from "./Loading";
6 | import { auth } from "@/firebase";
7 | import { User } from "firebase/auth";
8 |
9 | export default function Home() {
10 | const [user, setUser] = useState();
11 | auth.onAuthStateChanged((user) => setUser(user));
12 |
13 | if (user === undefined) {
14 | return ;
15 | } else if (user === null) {
16 | return ;
17 | } else {
18 | return ;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/server-firebase/frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "frontend",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "next dev",
7 | "build": "next build",
8 | "start": "next start",
9 | "lint": "next lint"
10 | },
11 | "dependencies": {
12 | "@next/font": "13.1.6",
13 | "@types/node": "18.13.0",
14 | "@types/react": "18.0.27",
15 | "@types/react-dom": "18.0.10",
16 | "firebase": "^9.17.1",
17 | "next": "13.1.6",
18 | "react": "18.2.0",
19 | "react-chat-engine-pretty": "^0.1.8",
20 | "react-dom": "18.2.0",
21 | "typescript": "4.9.5"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/server-firebase/frontend/firebase.ts:
--------------------------------------------------------------------------------
1 | import { initializeApp } from "firebase/app";
2 | import { getAuth } from "firebase/auth";
3 |
4 | const firebaseConfig = {
5 | apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
6 | authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
7 | projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
8 | storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
9 | messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
10 | appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
11 | };
12 |
13 | export const app = initializeApp(firebaseConfig);
14 | export const auth = getAuth(app);
15 |
--------------------------------------------------------------------------------
/server-firebase/frontend/public/vercel.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/server-firebase/frontend/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "noEmit": true,
10 | "esModuleInterop": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "jsx": "preserve",
16 | "incremental": true,
17 | "baseUrl": ".",
18 | "paths": {
19 | "@/*": ["./*"]
20 | }
21 | },
22 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
23 | "exclude": ["node_modules"]
24 | }
25 |
--------------------------------------------------------------------------------
/serverless-vue/src/pages/AuthPage/api.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 |
3 | const loginRest = async (username, secret) => {
4 | return await axios.get("https://api.chatengine.io/users/me/", {
5 | headers: {
6 | "Project-ID": import.meta.env.VITE_CHAT_ENGINE_PROJECT_ID,
7 | "User-Name": username,
8 | "User-Secret": secret,
9 | },
10 | });
11 | };
12 |
13 | const signupRest = async (username, secret, email, first_name, last_name) => {
14 | return await axios.post(
15 | "https://api.chatengine.io/users/",
16 | { username, secret, email, first_name, last_name },
17 | { headers: { "Private-Key": import.meta.env.VITE_CHAT_ENGINE_PRIVATE_KEY } }
18 | );
19 | };
20 |
21 | export { loginRest, signupRest };
22 |
--------------------------------------------------------------------------------
/server-django/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """Django's command-line utility for administrative tasks."""
3 | import os
4 | import sys
5 |
6 |
7 | def main():
8 | """Run administrative tasks."""
9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'server.settings')
10 | try:
11 | from django.core.management import execute_from_command_line
12 | except ImportError as exc:
13 | raise ImportError(
14 | "Couldn't import Django. Are you sure it's installed and "
15 | "available on your PYTHONPATH environment variable? Did you "
16 | "forget to activate a virtual environment?"
17 | ) from exc
18 | execute_from_command_line(sys.argv)
19 |
20 |
21 | if __name__ == '__main__':
22 | main()
23 |
--------------------------------------------------------------------------------
/server-firebase/frontend/pages/ChatsPage.tsx:
--------------------------------------------------------------------------------
1 | import { auth } from "@/firebase";
2 | import { signOut, User } from "firebase/auth";
3 | import { PrettyChatWindow } from "react-chat-engine-pretty";
4 | interface ChatProps {
5 | user: User;
6 | }
7 |
8 | export default function Page(props: ChatProps) {
9 | return (
10 |
11 |
17 |
23 |
24 | );
25 | }
26 |
--------------------------------------------------------------------------------
/server-firebase/frontend/pages/AuthPage.tsx:
--------------------------------------------------------------------------------
1 | import { auth } from "@/firebase";
2 | import { signInWithRedirect, GoogleAuthProvider } from "firebase/auth";
3 |
4 | export default function AuthPage() {
5 | const onClick = () => {
6 | signInWithRedirect(auth, new GoogleAuthProvider());
7 | };
8 |
9 | return (
10 |
11 |
👋 🔥 💬
12 |
Welcome to Firebase Next Chat
13 |
14 | Log in with your account to continue
15 |
16 |
{" "}
19 |
22 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/server-firebase/functions/src/index.ts:
--------------------------------------------------------------------------------
1 | import * as functions from "firebase-functions";
2 |
3 | const axios = require("axios");
4 |
5 | exports.createChatEngineUser = functions.auth.user().onCreate((user) => {
6 | axios.post(
7 | "https://api.chatengine.io/users/",
8 | {
9 | username: user.email,
10 | secret: user.uid,
11 | email: user.email,
12 | first_name: user.displayName,
13 | },
14 | { headers: { "Private-Key": "8c63dbce-80a7-455a-890b-9368d16e1dcb" } }
15 | );
16 | });
17 |
18 | exports.deleteChatEngineUser = functions.auth.user().onDelete((user) => {
19 | axios.delete("https://api.chatengine.io/users/me/", {
20 | headers: {
21 | "Project-ID": "794653df-052a-4ad2-b0aa-d6c251a10aef",
22 | "User-Name": user.email,
23 | "User-Secret": user.uid,
24 | },
25 | });
26 | });
27 |
--------------------------------------------------------------------------------
/server-firebase/frontend/styles/globals.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0px;
3 | font-family: Söhne,ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,sans-serif,Helvetica Neue,Arial,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;
4 | font-size: .875rem;
5 | }
6 | .page {
7 | width: 100vw;
8 | height: 100vh;
9 | background-color: rgb(247,247,248);
10 | text-align: center;
11 | display: table-cell;
12 | vertical-align: middle;
13 | }
14 |
15 | /* Auth Page */
16 | .logo {
17 | font-size: 32px;
18 | padding-bottom: 12px;
19 | }
20 | .text {
21 | padding-bottom: 12px;
22 | }
23 | .button {
24 | background-color: #10a37f;
25 | border: none;
26 | padding: .5rem .75rem;
27 | color: white;
28 | font-size: .875rem;
29 | border-radius: .25rem;
30 | cursor: pointer;
31 | }
32 | .button:hover {
33 | background-color: #10886a;
34 | }
--------------------------------------------------------------------------------
/server-firebase/functions/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | es6: true,
5 | node: true,
6 | },
7 | extends: [
8 | "eslint:recommended",
9 | "plugin:import/errors",
10 | "plugin:import/warnings",
11 | "plugin:import/typescript",
12 | "google",
13 | "plugin:@typescript-eslint/recommended",
14 | ],
15 | parser: "@typescript-eslint/parser",
16 | parserOptions: {
17 | project: ["tsconfig.json", "tsconfig.dev.json"],
18 | sourceType: "module",
19 | },
20 | ignorePatterns: [
21 | "/lib/**/*", // Ignore built files.
22 | ],
23 | plugins: ["@typescript-eslint", "import"],
24 | rules: {
25 | // prettier-ignore
26 | "quotes": ["error", "double"],
27 | "import/no-unresolved": 0,
28 | // prettier-ignore
29 | "indent": ["off", "always"],
30 | "object-curly-spacing": ["off", "always"],
31 | "@typescript-eslint/no-var-requires": ["off", "always"],
32 | },
33 | };
34 |
--------------------------------------------------------------------------------
/client-html/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Welcome
9 |
10 |
11 |
28 |
29 |
--------------------------------------------------------------------------------
/server-django/server/urls.py:
--------------------------------------------------------------------------------
1 | """server URL Configuration
2 |
3 | The `urlpatterns` list routes URLs to views. For more information please see:
4 | https://docs.djangoproject.com/en/4.1/topics/http/urls/
5 | Examples:
6 | Function views
7 | 1. Add an import: from my_app import views
8 | 2. Add a URL to urlpatterns: path('', views.home, name='home')
9 | Class-based views
10 | 1. Add an import: from other_app.views import Home
11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
12 | Including another URLconf
13 | 1. Import the include() function: from django.urls import include, path
14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
15 | """
16 | from django.contrib import admin
17 | from django.urls import path
18 | from django.urls import re_path
19 |
20 |
21 | from . import views
22 |
23 | urlpatterns = [
24 | path('admin/', admin.site.urls),
25 | # Custom endpoints
26 | re_path('login', views.login),
27 | re_path('signup', views.signup),
28 | ]
29 |
--------------------------------------------------------------------------------
/server-firebase/functions/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "functions",
3 | "scripts": {
4 | "lint": "eslint --ext .js,.ts .",
5 | "build": "tsc",
6 | "build:watch": "tsc --watch",
7 | "serve": "npm run build && firebase emulators:start --only functions",
8 | "shell": "npm run build && firebase functions:shell",
9 | "start": "npm run shell",
10 | "deploy": "firebase deploy --only functions",
11 | "logs": "firebase functions:log"
12 | },
13 | "engines": {
14 | "node": "16"
15 | },
16 | "main": "lib/index.js",
17 | "dependencies": {
18 | "axios": "^1.3.2",
19 | "firebase-admin": "^10.0.2",
20 | "firebase-functions": "^3.18.0"
21 | },
22 | "devDependencies": {
23 | "@typescript-eslint/eslint-plugin": "^5.12.0",
24 | "@typescript-eslint/parser": "^5.12.0",
25 | "eslint": "^8.9.0",
26 | "eslint-config-google": "^0.14.0",
27 | "eslint-plugin-import": "^2.25.4",
28 | "firebase-functions-test": "^0.2.0",
29 | "typescript": "^4.5.4"
30 | },
31 | "private": true
32 | }
33 |
--------------------------------------------------------------------------------
/serverless-vue/src/pages/ChatsPage/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
18 |
19 |
44 |
--------------------------------------------------------------------------------
/client-react/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-pretty",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.16.5",
7 | "@testing-library/react": "^13.4.0",
8 | "@testing-library/user-event": "^13.5.0",
9 | "axios": "^1.2.0",
10 | "react": "^18.2.0",
11 | "react-chat-engine-advanced": "^0.1.25",
12 | "react-chat-engine-pretty": "^0.1.5",
13 | "react-dom": "^18.2.0",
14 | "react-scripts": "5.0.1",
15 | "web-vitals": "^2.1.4"
16 | },
17 | "scripts": {
18 | "start": "react-scripts start",
19 | "build": "react-scripts build",
20 | "test": "react-scripts test",
21 | "eject": "react-scripts eject"
22 | },
23 | "eslintConfig": {
24 | "extends": [
25 | "react-app",
26 | "react-app/jest"
27 | ]
28 | },
29 | "browserslist": {
30 | "production": [
31 | ">0.2%",
32 | "not dead",
33 | "not op_mini all"
34 | ],
35 | "development": [
36 | "last 1 chrome version",
37 | "last 1 firefox version",
38 | "last 1 safari version"
39 | ]
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/server-firebase/frontend/public/thirteen.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/server-flask/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, request
2 | from dotenv import load_dotenv
3 | from flask_cors import CORS
4 | import os, requests
5 |
6 | app = Flask(__name__)
7 | CORS(app)
8 | load_dotenv()
9 |
10 | @app.route('/login', methods=['POST'])
11 | def login():
12 | response = requests.get('https://api.chatengine.io/users/me/',
13 | headers={
14 | "Project-ID": os.environ['CHAT_ENGINE_PROJECT_ID'],
15 | "User-Name": request.get_json()['username'],
16 | "User-Secret": request.get_json()['secret']
17 | }
18 | )
19 | return response.json()
20 |
21 | @app.route('/signup', methods=['POST'])
22 | def signup():
23 | response = requests.post('https://api.chatengine.io/users/',
24 | data={
25 | "username": request.get_json()['username'],
26 | "secret": request.get_json()['secret'],
27 | "email": request.get_json()['email'],
28 | "first_name": request.get_json()['first_name'],
29 | "last_name": request.get_json()['last_name'],
30 | },
31 | headers={ "Private-Key": os.environ['CHAT_ENGINE_PRIVATE_KEY'] }
32 | )
33 | return response.json()
--------------------------------------------------------------------------------
/server-firebase/frontend/public/next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/server-fastapi/README.md:
--------------------------------------------------------------------------------
1 | # Connect FastAPI to Chat Engine!
2 |
3 | This simple repo shows how to easily add chat functionality into an Express project with [Chat Engine](https://chatengine.io).
4 |
5 | To understand the code, please watch [this video]()!
6 |
7 | ## Setup Steps
8 |
9 | Make your FastAPI server support chat - in 3 steps:
10 |
11 | ### 1 - Setup a Chat Engine server
12 |
13 | Go to [Chat Engine](https://chatengine.io) to setup your own chat server.
14 |
15 | - Click "New Project" and follow the steps
16 | - Your `Project ID` and `Private Key` will be required for step 2
17 |
18 | ### 2 - Connect `main.py` to Chat Engine
19 |
20 | Replace the following variables with your own Project ID and Private Key.
21 |
22 | (Perferrably as environment variables.)
23 |
24 | ```
25 | CHAT_ENGINE_PROJECT_ID=5d498a31-cd23-42b7-b367-4fcc9463bd2f
26 | CHAT_ENGINE_PRIVATE_KEY=49a46286-91c3-4f9c-92bf-284ae51b7628
27 | ```
28 |
29 | ### 3 - Install & Start
30 |
31 | Run the following two lines of code in `server-express/`.
32 |
33 | ```
34 | python3 -m venv venv
35 | source venv/bin/activate
36 | pip install -r requirements.txt
37 | uvicorn main:app --reload --port 3001
38 | ```
39 |
40 | Done! Your Express server is on `localhost:3001` and connected to Chat Engine!
41 |
42 | All new `/signup` users are on Chat Engine, and their credentiuals are found upon `/login`.
43 |
44 | To understand the code, please watch [this video]()!
45 |
--------------------------------------------------------------------------------
/server-express/README.md:
--------------------------------------------------------------------------------
1 | # Connect Express to Chat Engine!
2 |
3 | This simple repo shows how to easily add chat functionality into an Express project with [Chat Engine](https://chatengine.io).
4 |
5 | To understand the code, please watch [this video]()!
6 |
7 | ## Setup Steps
8 |
9 | Make your express server support chat - in 3 steps:
10 |
11 | ### 1 - Setup a Chat Engine server
12 |
13 | Go to [Chat Engine](https://chatengine.io) to setup your own chat server.
14 |
15 | - Click "New Project" and follow the steps
16 | - Your `Project ID` and `Private Key` will be required for step 2
17 |
18 | ### 2 - Connect `.env` to Chat Engine
19 |
20 | We will connect to your Chat Engine server with environment varibles.
21 |
22 | This allows you to connect to different chat-servers in local vs staging vs production.
23 |
24 | Replace the UUIDs below with your own. In `.env` write:
25 |
26 | ```
27 | CHAT_ENGINE_PROJECT_ID=5d498a31-cd23-42b7-b367-4fcc9463bd2f
28 | CHAT_ENGINE_PRIVATE_KEY=49a46286-91c3-4f9c-92bf-284ae51b7628
29 | ```
30 |
31 | ### 3 - Install & Start
32 |
33 | Run the following two lines of code in `server-express/`.
34 |
35 | ```
36 | npm install
37 | npm run start
38 | ```
39 |
40 | Done! Your Express server is on `localhost:3001` and connected to Chat Engine!
41 |
42 | All new `/signup` users are on Chat Engine, and their credentiuals are found upon `/login`.
43 |
44 | To understand the code, please watch [this video]()!
45 |
--------------------------------------------------------------------------------
/server-firebase/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | firebase-debug.log*
8 | firebase-debug.*.log*
9 |
10 | # Firebase cache
11 | .firebase/
12 |
13 | # Firebase config
14 |
15 | # Uncomment this if you'd like others to create their own Firebase project.
16 | # For a team working on the same Firebase project(s), it is recommended to leave
17 | # it commented so all members can deploy to the same project(s) in .firebaserc.
18 | # .firebaserc
19 |
20 | # Runtime data
21 | pids
22 | *.pid
23 | *.seed
24 | *.pid.lock
25 |
26 | # Directory for instrumented libs generated by jscoverage/JSCover
27 | lib-cov
28 |
29 | # Coverage directory used by tools like istanbul
30 | coverage
31 |
32 | # nyc test coverage
33 | .nyc_output
34 |
35 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
36 | .grunt
37 |
38 | # Bower dependency directory (https://bower.io/)
39 | bower_components
40 |
41 | # node-waf configuration
42 | .lock-wscript
43 |
44 | # Compiled binary addons (http://nodejs.org/api/addons.html)
45 | build/Release
46 |
47 | # Dependency directories
48 | node_modules/
49 |
50 | # Optional npm cache directory
51 | .npm
52 |
53 | # Optional eslint cache
54 | .eslintcache
55 |
56 | # Optional REPL history
57 | .node_repl_history
58 |
59 | # Output of 'npm pack'
60 | *.tgz
61 |
62 | # Yarn Integrity file
63 | .yarn-integrity
64 |
65 | # dotenv environment variables file
66 | .env
67 |
--------------------------------------------------------------------------------
/serverless-vue/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client-react/README.md:
--------------------------------------------------------------------------------
1 | # Connect React to Chat Engine!
2 |
3 | This simple repo shows how to easily add chat functionality into a React project with [Chat Engine](https://chatengine.io).
4 |
5 | To understand the code, please watch [this video]()!
6 |
7 | ## Setup Steps
8 |
9 | Setup this chat client in 3 steps below.
10 |
11 | These steps assume you have already setup one of the server projects in `../server-*` (for example, `server-express`).
12 |
13 | ### 1 - Setup a Chat Engine server
14 |
15 | Go to [Chat Engine](https://chatengine.io) to setup your own chat server.
16 |
17 | - Click "New Project" and follow the steps
18 | - Your `Project ID` and `Private Key` will be required for step 2
19 |
20 | ### 2 - Connect `.env` to Chat Engine
21 |
22 | We will connect to your Chat Engine server with environment varibles.
23 |
24 | This allows you to connect to different chat-servers in local vs staging vs production.
25 |
26 | Replace the UUID below with your own. In `.env` write:
27 |
28 | ```
29 | REACT_APP_CHAT_ENGINE_PROJECT_ID=5d498a31-cd23-42b7-b367-4fcc9463bd2f
30 | ```
31 |
32 | ### 3 - Install & Start
33 |
34 | Run the following two lines of code in `client-react/`.
35 |
36 | ```
37 | npm install
38 | npm run start
39 | ```
40 |
41 | Done! Your Express server is on `localhost:3000` and connected to Chat Engine!
42 |
43 | All new "Sign Up" users are on Chat Engine, and their credentiuals are found upon "Login".
44 |
45 | To understand the code, please watch [this video]()!
46 |
--------------------------------------------------------------------------------
/server-django/README.md:
--------------------------------------------------------------------------------
1 | # Connect Django to Chat Engine!
2 |
3 | This simple repo shows how to easily add chat functionality into an Express project with [Chat Engine](https://chatengine.io).
4 |
5 | To understand the code, please watch [this video]()!
6 |
7 | ## Setup Steps
8 |
9 | Make your express server support chat - in 3 steps:
10 |
11 | ### 1 - Setup a Chat Engine server
12 |
13 | Go to [Chat Engine](https://chatengine.io) to setup your own chat server.
14 |
15 | - Click "New Project" and follow the steps
16 | - Your `Project ID` and `Private Key` will be required for step 2
17 |
18 | ### 2 - Connect `server/.env` to Chat Engine
19 |
20 | We will connect to your Chat Engine server with environment varibles.
21 |
22 | This allows you to connect to different chat-servers in local vs staging vs production.
23 |
24 | Replace the UUIDs below with your own. In `server/.env` write:
25 |
26 | ```
27 | CHAT_ENGINE_PROJECT_ID=5d498a31-cd23-42b7-b367-4fcc9463bd2f
28 | CHAT_ENGINE_PRIVATE_KEY=49a46286-91c3-4f9c-92bf-284ae51b7628
29 | ```
30 |
31 | ### 3 - Install & Start
32 |
33 | Run the following two lines of code in `server-django/`.
34 |
35 | ```
36 | pip install -r requirements.txt
37 | ./manage.py runserver 0.0.0.0:3001
38 | ```
39 |
40 | Done! Your Express server is on `localhost:3001` and connected to Chat Engine!
41 |
42 | All new `/signup` users are on Chat Engine, and their credentiuals are found upon `/login`.
43 |
44 | To understand the code, please watch [this video]()!
45 |
--------------------------------------------------------------------------------
/server-nodejs/index.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const cors = require("cors");
3 | const axios = require("axios");
4 |
5 | const app = express();
6 | app.use(express.json());
7 | app.use(cors({ origin: true }));
8 |
9 | const CHAT_ENGINE_PROJECT_ID = "";
10 | const CHAT_ENGINE_PRIVATE_KEY = "";
11 |
12 | app.post("/signup", async (req, res) => {
13 | const { username, secret, email, first_name, last_name } = req.body;
14 |
15 | // Store a user-copy on Chat Engine!
16 | // Docs at rest.chatengine.io
17 | try {
18 | const r = await axios.post(
19 | "https://api.chatengine.io/users/",
20 | { username, secret, email, first_name, last_name },
21 | { headers: { "Private-Key": CHAT_ENGINE_PRIVATE_KEY } }
22 | );
23 | return res.status(r.status).json(r.data);
24 | } catch (e) {
25 | return res.status(e.response.status).json(e.response.data);
26 | }
27 | });
28 |
29 | app.post("/login", async (req, res) => {
30 | const { username, secret } = req.body;
31 |
32 | // Fetch this user from Chat Engine in this project!
33 | // Docs at rest.chatengine.io
34 | try {
35 | const r = await axios.get("https://api.chatengine.io/users/me/", {
36 | headers: {
37 | "Project-ID": CHAT_ENGINE_PROJECT_ID,
38 | "User-Name": username,
39 | "User-Secret": secret,
40 | },
41 | });
42 | return res.status(r.status).json(r.data);
43 | } catch (e) {
44 | return res.status(e.response.status).json(e.response.data);
45 | }
46 | });
47 |
48 | // vvv On port 3001!
49 | app.listen(3001);
50 |
--------------------------------------------------------------------------------
/server-express/index.js:
--------------------------------------------------------------------------------
1 | require("dotenv").config();
2 |
3 | const express = require("express");
4 | const cors = require("cors");
5 | const axios = require("axios");
6 |
7 | const app = express();
8 | app.use(express.json());
9 | app.use(cors({ origin: true }));
10 |
11 | app.post("/signup", async (req, res) => {
12 | const { username, secret, email, first_name, last_name } = req.body;
13 |
14 | // console.log("Write user into DB.");
15 | // return res.json({ user: {} });
16 |
17 | // Store a user-copy on Chat Engine!
18 | try {
19 | const r = await axios.post(
20 | "https://api.chatengine.io/users/",
21 | { username, secret, email, first_name, last_name },
22 | { headers: { "Private-Key": process.env.CHAT_ENGINE_PRIVATE_KEY } }
23 | );
24 | return res.status(r.status).json(r.data);
25 | } catch (e) {
26 | return res.status(e.response.status).json(e.response.data);
27 | }
28 | });
29 |
30 | app.post("/login", async (req, res) => {
31 | const { username, secret } = req.body;
32 |
33 | // console.log("Fetch user from DB.");
34 | // return res.json({ user: {} });
35 |
36 | // Fetch this user from Chat Engine in this project!
37 | try {
38 | const r = await axios.get("https://api.chatengine.io/users/me/", {
39 | headers: {
40 | "Project-ID": process.env.CHAT_ENGINE_PROJECT_ID,
41 | "User-Name": username,
42 | "User-Secret": secret,
43 | },
44 | });
45 | return res.status(r.status).json(r.data);
46 | } catch (e) {
47 | return res.status(e.response.status).json(e.response.data);
48 | }
49 | });
50 |
51 | // Docs at rest.chatengine.io
52 | // vvv On port 3001!
53 | app.listen(3001);
54 |
--------------------------------------------------------------------------------
/server-fastapi/main.py:
--------------------------------------------------------------------------------
1 | from fastapi import FastAPI
2 | from fastapi.middleware.cors import CORSMiddleware
3 | # pip install "uvicorn[standard]"
4 |
5 | from pydantic import BaseModel
6 | from typing import Union
7 |
8 | import requests
9 |
10 | app = FastAPI()
11 | app.add_middleware(
12 | CORSMiddleware,
13 | allow_origins=["*"],
14 | allow_credentials=True,
15 | allow_methods=["*"],
16 | allow_headers=["*"],
17 | )
18 |
19 | PROJECT_ID = "5d498a31-cd23-42b7-b367-4fcc9463bd2f"
20 | PRIVATE_KEY = "49a46286-91c3-4f9c-92bf-284ae51b7628"
21 |
22 | class User(BaseModel):
23 | username: str
24 | secret: str
25 | email: Union[str, None] = None
26 | first_name: Union[str, None] = None
27 | last_name: Union[str, None] = None
28 |
29 | @app.post('/login/')
30 | async def root(user: User):
31 | response = requests.get('https://api.chatengine.io/users/me/',
32 | headers={
33 | "Project-ID": PROJECT_ID,
34 | "User-Name": user.username,
35 | "User-Secret": user.secret
36 | }
37 | )
38 | return response.json()
39 |
40 | @app.post('/signup/')
41 | async def root(user: User):
42 | response = requests.post('https://api.chatengine.io/users/',
43 | data={
44 | "username": user.username,
45 | "secret": user.secret,
46 | "email": user.email,
47 | "first_name": user.first_name,
48 | "last_name": user.last_name,
49 | },
50 | headers={ "Private-Key": PRIVATE_KEY }
51 | )
52 | return response.json()
53 |
54 | # python3 -m venv venv
55 | # source venv/bin/activate
56 | # pip install --upgrade pip
57 | # pip install -r requirements.txt
58 | # uvicorn main:app --reload --port 3001
59 |
--------------------------------------------------------------------------------
/server-spring/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 3.0.0
9 |
10 |
11 | com.example.chatengine
12 | server-spring
13 | 0.0.1-SNAPSHOT
14 | server-spring
15 | Demo chat project for Spring Boot
16 |
17 | 19
18 |
19 |
20 |
21 | org.springframework.boot
22 | spring-boot-starter-web
23 |
24 |
25 |
26 | org.springframework.boot
27 | spring-boot-starter-test
28 | test
29 |
30 |
31 |
32 | org.json
33 | json
34 | 20180130
35 |
36 |
37 |
38 | com.google.code.gson
39 | gson
40 | 2.8.9
41 |
42 |
43 |
44 |
45 |
46 |
47 | org.springframework.boot
48 | spring-boot-maven-plugin
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/server-django/server/views.py:
--------------------------------------------------------------------------------
1 | from rest_framework import status
2 | from rest_framework.decorators import api_view
3 | from rest_framework.response import Response
4 |
5 | import requests
6 |
7 | import environ
8 | env = environ.Env()
9 | environ.Env.read_env()
10 |
11 | @api_view(['POST'])
12 | def signup(request):
13 | username = request.data['username']
14 | secret = request.data['secret']
15 | email = request.data['email']
16 | first_name = request.data['first_name']
17 | last_name = request.data['last_name']
18 |
19 | # user = User.objects.create(
20 | # username=username,
21 | # email=email,
22 | # password=make_password(secret),
23 | # first_name=first_name,
24 | # last_name=last_name
25 | # )
26 |
27 | response = requests.post('https://api.chatengine.io/users/',
28 | data={
29 | "username": username,
30 | "secret": secret,
31 | "email": email,
32 | "first_name": first_name,
33 | "last_name": last_name,
34 | },
35 | headers={ "Private-Key": env('CHAT_ENGINE_PRIVATE_KEY') }
36 | )
37 |
38 | return Response(response.json(), status=response.status_code)
39 |
40 | @api_view(['POST'])
41 | def login(request):
42 | username = request.data['username']
43 | secret = request.data['secret']
44 |
45 | # user = get_object_or_404(User, username=username)
46 | # if not user.check_password(secret):
47 | # return Response({}, status=status.HTTP_404_NOT_FOUND)
48 |
49 | response = requests.get('https://api.chatengine.io/users/me/',
50 | headers={
51 | "Project-ID": env('CHAT_ENGINE_PROJECT_ID'),
52 | "User-Name": username,
53 | "User-Secret": secret
54 | }
55 | )
56 |
57 | return Response(response.json(), status=response.status_code)
--------------------------------------------------------------------------------
/client-react/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/server-firebase/frontend/README.md:
--------------------------------------------------------------------------------
1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2 |
3 | ## Getting Started
4 |
5 | First, run the development server:
6 |
7 | ```bash
8 | npm run dev
9 | # or
10 | yarn dev
11 | # or
12 | pnpm dev
13 | ```
14 |
15 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
16 |
17 | You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.
18 |
19 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.
20 |
21 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
22 |
23 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
24 |
25 | ## Learn More
26 |
27 | To learn more about Next.js, take a look at the following resources:
28 |
29 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
30 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
31 |
32 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
33 |
34 | ## Deploy on Vercel
35 |
36 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
37 |
38 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
39 |
--------------------------------------------------------------------------------
/client-html/css/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-image: url('valley.jpeg');
3 | background-repeat: no-repeat;
4 | background-size: cover;
5 | height: 100vh;
6 | width: 100vw;
7 | margin: 0px;
8 | }
9 |
10 | .background {
11 | width: 100vw;
12 | height: 100vh;
13 | background: linear-gradient(75deg, rgb(40,43,54) 0%, rgb(40,43,54) 50%, rgba(40,43,54,0.8) 100%);
14 | /* Vertical center */
15 | display: table-cell;
16 | vertical-align: middle;
17 | }
18 |
19 | .form-card {
20 | width: 50%;
21 | max-width: 350px;
22 | padding: 0% 25% 0% 25%;
23 | }
24 |
25 | .form-title {
26 | font-size: 42px;
27 | font-family: 'Avenir';
28 | font-weight: 800;
29 | letter-spacing: 0.5px;
30 | color: #e8e8e8;
31 | padding-bottom: 12px;
32 | }
33 |
34 | .form-subtitle {
35 | font-size: 18px;
36 | font-family: 'Avenir';
37 | letter-spacing: 0.5px;
38 | color: #afafaf;
39 | padding-bottom: 24px;
40 | }
41 |
42 | .auth {
43 | position: relative;
44 | display: inline-block;
45 | width: 100%;
46 | padding-bottom: 12px;
47 | }
48 | .auth-label {
49 | position: absolute;
50 | top: 8px;
51 | left: 18px;
52 | font-size: 11px;
53 | color: rgb(175, 175, 175);
54 | font-family: Avenir;
55 | width: 100px;
56 | }
57 | .auth-input {
58 | background-color: #3e404b;
59 | color: white;
60 | font-family: "Avenir";
61 | outline: none;
62 | border: none;
63 | border-radius: 8px;
64 | padding: 24px 18px 12px 18px;
65 | width: calc(100% - 18px - 18px);
66 | margin-bottom: 12px;
67 | }
68 | .auth-button {
69 | width: 100%;
70 | height: 53px;
71 | color: white;
72 | background-color: #fa541c;
73 | border: none;
74 | outline: none;
75 | border-radius: 8px;
76 | font-family: "Avenir";
77 | cursor: pointer;
78 | transition: all .44s ease;
79 | -webkit-transition: all .44s ease;
80 | -moz-transition: all .44s ease;
81 | }
82 | .auth-button:hover { filter: brightness(145%); }
--------------------------------------------------------------------------------
/serverless-vue/src/pages/AuthPage/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
29 |
30 |
31 |
38 |
39 |
--------------------------------------------------------------------------------
/client-react/src/authPage.js:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import axios from "axios";
3 |
4 | const AuthPage = (props) => {
5 | const [username, setUsername] = useState();
6 | const [secret, setSecret] = useState();
7 | const [email, setEmail] = useState();
8 | const [first_name, setFirstName] = useState();
9 | const [last_name, setLastName] = useState();
10 |
11 | const onLogin = (e) => {
12 | e.preventDefault();
13 | axios
14 | .post("http://localhost:3001/login", { username, secret })
15 | .then((r) => props.onAuth({ ...r.data, secret })) // NOTE: over-ride secret
16 | .catch((e) => console.log(JSON.stringify(e.response.data)));
17 | };
18 |
19 | const onSignup = (e) => {
20 | e.preventDefault();
21 | axios
22 | .post("http://localhost:3001/signup", {
23 | username,
24 | secret,
25 | email,
26 | first_name,
27 | last_name,
28 | })
29 | .then((r) => props.onAuth({ ...r.data, secret })) // NOTE: over-ride secret
30 | .catch((e) => console.log(JSON.stringify(e.response.data)));
31 | };
32 |
33 | return (
34 |
35 |
36 | {/* Login Form */}
37 |
53 |
54 | {/* Sign Up Form */}
55 |
89 |
90 |
91 |
98 |
99 | );
100 | };
101 |
102 | export default AuthPage;
103 |
--------------------------------------------------------------------------------
/server-django/server/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for server project.
3 |
4 | Generated by 'django-admin startproject' using Django 4.1.3.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/4.1/topics/settings/
8 |
9 | For the full list of settings and their values, see
10 | https://docs.djangoproject.com/en/4.1/ref/settings/
11 | """
12 |
13 | from pathlib import Path
14 |
15 | # Build paths inside the project like this: BASE_DIR / 'subdir'.
16 | BASE_DIR = Path(__file__).resolve().parent.parent
17 |
18 |
19 | # Quick-start development settings - unsuitable for production
20 | # See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/
21 |
22 | # SECURITY WARNING: keep the secret key used in production secret!
23 | SECRET_KEY = 'django-insecure-@3o&&4rq6kbmkh-6nfu_44(j8mobq(bg+-g(a6(^b(a21bdnys'
24 |
25 | # SECURITY WARNING: don't run with debug turned on in production!
26 | DEBUG = True
27 |
28 | ALLOWED_HOSTS = ['*']
29 | CORS_ORIGIN_ALLOW_ALL = True
30 |
31 | # Application definition
32 |
33 | INSTALLED_APPS = [
34 | 'corsheaders',
35 | 'django.contrib.admin',
36 | 'django.contrib.auth',
37 | 'django.contrib.contenttypes',
38 | 'django.contrib.sessions',
39 | 'django.contrib.messages',
40 | 'django.contrib.staticfiles',
41 | 'rest_framework',
42 | ]
43 |
44 | MIDDLEWARE = [
45 | 'django.middleware.security.SecurityMiddleware',
46 | 'django.contrib.sessions.middleware.SessionMiddleware',
47 | 'corsheaders.middleware.CorsMiddleware',
48 | 'django.middleware.common.CommonMiddleware',
49 | 'django.middleware.csrf.CsrfViewMiddleware',
50 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
51 | 'django.contrib.messages.middleware.MessageMiddleware',
52 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
53 | ]
54 |
55 | ROOT_URLCONF = 'server.urls'
56 |
57 | TEMPLATES = [
58 | {
59 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
60 | 'DIRS': [],
61 | 'APP_DIRS': True,
62 | 'OPTIONS': {
63 | 'context_processors': [
64 | 'django.template.context_processors.debug',
65 | 'django.template.context_processors.request',
66 | 'django.contrib.auth.context_processors.auth',
67 | 'django.contrib.messages.context_processors.messages',
68 | ],
69 | },
70 | },
71 | ]
72 |
73 | WSGI_APPLICATION = 'server.wsgi.application'
74 |
75 |
76 | # Database
77 | # https://docs.djangoproject.com/en/4.1/ref/settings/#databases
78 |
79 | DATABASES = {
80 | 'default': {
81 | 'ENGINE': 'django.db.backends.sqlite3',
82 | 'NAME': BASE_DIR / 'db.sqlite3',
83 | }
84 | }
85 |
86 | # Password validation
87 | # https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators
88 |
89 | AUTH_PASSWORD_VALIDATORS = [
90 | {
91 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
92 | },
93 | {
94 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
95 | },
96 | {
97 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
98 | },
99 | {
100 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
101 | },
102 | ]
103 |
104 |
105 | # Internationalization
106 | # https://docs.djangoproject.com/en/4.1/topics/i18n/
107 |
108 | LANGUAGE_CODE = 'en-us'
109 |
110 | TIME_ZONE = 'UTC'
111 |
112 | USE_I18N = True
113 |
114 | USE_TZ = True
115 |
116 |
117 | # Static files (CSS, JavaScript, Images)
118 | # https://docs.djangoproject.com/en/4.1/howto/static-files/
119 |
120 | STATIC_URL = 'static/'
121 |
122 | # Default primary key field type
123 | # https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field
124 |
125 | DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
126 |
--------------------------------------------------------------------------------
/server-spring/src/main/java/com/example/chatengine/serverspring/UserController.java:
--------------------------------------------------------------------------------
1 | package com.example.chatengine.serverspring;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.InputStreamReader;
5 | import java.io.OutputStream;
6 | import java.net.HttpURLConnection;
7 | import java.net.URL;
8 | import java.util.HashMap;
9 | import java.util.Map;
10 |
11 | import org.json.JSONObject;
12 | import org.springframework.http.HttpStatus;
13 | import org.springframework.http.ResponseEntity;
14 | import org.springframework.web.bind.annotation.CrossOrigin;
15 | import org.springframework.web.bind.annotation.RequestBody;
16 | import org.springframework.web.bind.annotation.RequestMapping;
17 | import org.springframework.web.bind.annotation.RequestMethod;
18 | import org.springframework.web.bind.annotation.RestController;
19 |
20 | import com.google.gson.Gson;
21 | import com.google.gson.reflect.TypeToken;
22 |
23 | @RestController
24 | public class UserController {
25 | private static String CHAT_ENGINE_PROJECT_ID = "5d498a31-cd23-42b7-b367-4fcc9463bd2f";
26 | private static String CHAT_ENGINE_PRIVATE_KEY = "49a46286-91c3-4f9c-92bf-284ae51b7628";
27 |
28 | @CrossOrigin
29 | @RequestMapping(path = "/login", method = RequestMethod.POST)
30 | public ResponseEntity getLogin(@RequestBody HashMap request) {
31 | HttpURLConnection con = null;
32 | try {
33 | // Create GET request
34 | URL url = new URL("https://api.chatengine.io/users/me");
35 | con = (HttpURLConnection) url.openConnection();
36 | con.setRequestMethod("GET");
37 | // Set headers
38 | con.setRequestProperty("Content-Type", "application/json");
39 | con.setRequestProperty("Accept", "application/json");
40 | con.setRequestProperty("Project-ID", CHAT_ENGINE_PROJECT_ID);
41 | con.setRequestProperty("User-Name", request.get("username"));
42 | con.setRequestProperty("User-Secret", request.get("secret"));
43 | // Generate response String
44 | StringBuilder responseStr = new StringBuilder();
45 | try (BufferedReader br = new BufferedReader(
46 | new InputStreamReader(con.getInputStream(), "utf-8"))) {
47 | String responseLine = null;
48 | while ((responseLine = br.readLine()) != null) {
49 | responseStr.append(responseLine.trim());
50 | }
51 | }
52 | // Jsonify + return response
53 | Map response = new Gson().fromJson(
54 | responseStr.toString(), new TypeToken>() {
55 | }.getType());
56 | return new ResponseEntity<>(response, HttpStatus.OK);
57 | } catch (Exception e) {
58 | e.printStackTrace();
59 | return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
60 | } finally {
61 | if (con != null) {
62 | con.disconnect();
63 | }
64 | }
65 | }
66 |
67 | @CrossOrigin
68 | @RequestMapping(path = "/signup", method = RequestMethod.POST)
69 | public ResponseEntity newSignup(@RequestBody HashMap request) {
70 | HttpURLConnection con = null;
71 | try {
72 | // Create POST request
73 | URL url = new URL("https://api.chatengine.io/users");
74 | con = (HttpURLConnection) url.openConnection();
75 | con.setRequestMethod("POST");
76 | // Set headers
77 | con.setRequestProperty("Content-Type", "application/json");
78 | con.setRequestProperty("Accept", "application/json");
79 | con.setRequestProperty("Private-Key", CHAT_ENGINE_PRIVATE_KEY);
80 | // Add request body
81 | con.setDoOutput(true);
82 | Map body = new HashMap();
83 | body.put("username", request.get("username"));
84 | body.put("secret", request.get("secret"));
85 | body.put("email", request.get("email"));
86 | body.put("first_name", request.get("first_name"));
87 | body.put("last_name", request.get("last_name"));
88 | String jsonInputString = new JSONObject(body).toString();
89 | try (OutputStream os = con.getOutputStream()) {
90 | byte[] input = jsonInputString.getBytes("utf-8");
91 | os.write(input, 0, input.length);
92 | }
93 | // Generate response String
94 | StringBuilder responseStr = new StringBuilder();
95 | try (BufferedReader br = new BufferedReader(
96 | new InputStreamReader(con.getInputStream(), "utf-8"))) {
97 | String responseLine = null;
98 | while ((responseLine = br.readLine()) != null) {
99 | responseStr.append(responseLine.trim());
100 | }
101 | }
102 | // Jsonify + return response
103 | Map response = new Gson().fromJson(
104 | responseStr.toString(), new TypeToken>() {
105 | }.getType());
106 | return new ResponseEntity<>(response, HttpStatus.OK);
107 | } catch (Exception e) {
108 | e.printStackTrace();
109 | return new ResponseEntity<>(null, HttpStatus.BAD_REQUEST);
110 | } finally {
111 | if (con != null) {
112 | con.disconnect();
113 | }
114 | }
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/server-spring/mvnw.cmd:
--------------------------------------------------------------------------------
1 | @REM ----------------------------------------------------------------------------
2 | @REM Licensed to the Apache Software Foundation (ASF) under one
3 | @REM or more contributor license agreements. See the NOTICE file
4 | @REM distributed with this work for additional information
5 | @REM regarding copyright ownership. The ASF licenses this file
6 | @REM to you under the Apache License, Version 2.0 (the
7 | @REM "License"); you may not use this file except in compliance
8 | @REM with the License. You may obtain a copy of the License at
9 | @REM
10 | @REM https://www.apache.org/licenses/LICENSE-2.0
11 | @REM
12 | @REM Unless required by applicable law or agreed to in writing,
13 | @REM software distributed under the License is distributed on an
14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | @REM KIND, either express or implied. See the License for the
16 | @REM specific language governing permissions and limitations
17 | @REM under the License.
18 | @REM ----------------------------------------------------------------------------
19 |
20 | @REM ----------------------------------------------------------------------------
21 | @REM Maven Start Up Batch script
22 | @REM
23 | @REM Required ENV vars:
24 | @REM JAVA_HOME - location of a JDK home dir
25 | @REM
26 | @REM Optional ENV vars
27 | @REM M2_HOME - location of maven2's installed home dir
28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
31 | @REM e.g. to debug Maven itself, use
32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34 | @REM ----------------------------------------------------------------------------
35 |
36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
37 | @echo off
38 | @REM set title of command window
39 | title %0
40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
42 |
43 | @REM set %HOME% to equivalent of $HOME
44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
45 |
46 | @REM Execute a user defined script before this one
47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
49 | if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
50 | if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
51 | :skipRcPre
52 |
53 | @setlocal
54 |
55 | set ERROR_CODE=0
56 |
57 | @REM To isolate internal variables from possible post scripts, we use another setlocal
58 | @setlocal
59 |
60 | @REM ==== START VALIDATION ====
61 | if not "%JAVA_HOME%" == "" goto OkJHome
62 |
63 | echo.
64 | echo Error: JAVA_HOME not found in your environment. >&2
65 | echo Please set the JAVA_HOME variable in your environment to match the >&2
66 | echo location of your Java installation. >&2
67 | echo.
68 | goto error
69 |
70 | :OkJHome
71 | if exist "%JAVA_HOME%\bin\java.exe" goto init
72 |
73 | echo.
74 | echo Error: JAVA_HOME is set to an invalid directory. >&2
75 | echo JAVA_HOME = "%JAVA_HOME%" >&2
76 | echo Please set the JAVA_HOME variable in your environment to match the >&2
77 | echo location of your Java installation. >&2
78 | echo.
79 | goto error
80 |
81 | @REM ==== END VALIDATION ====
82 |
83 | :init
84 |
85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
86 | @REM Fallback to current working directory if not found.
87 |
88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
90 |
91 | set EXEC_DIR=%CD%
92 | set WDIR=%EXEC_DIR%
93 | :findBaseDir
94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
95 | cd ..
96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
97 | set WDIR=%CD%
98 | goto findBaseDir
99 |
100 | :baseDirFound
101 | set MAVEN_PROJECTBASEDIR=%WDIR%
102 | cd "%EXEC_DIR%"
103 | goto endDetectBaseDir
104 |
105 | :baseDirNotFound
106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
107 | cd "%EXEC_DIR%"
108 |
109 | :endDetectBaseDir
110 |
111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
112 |
113 | @setlocal EnableExtensions EnableDelayedExpansion
114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
116 |
117 | :endReadAdditionalConfig
118 |
119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
122 |
123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
124 |
125 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
127 | )
128 |
129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data.
131 | if exist %WRAPPER_JAR% (
132 | if "%MVNW_VERBOSE%" == "true" (
133 | echo Found %WRAPPER_JAR%
134 | )
135 | ) else (
136 | if not "%MVNW_REPOURL%" == "" (
137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
138 | )
139 | if "%MVNW_VERBOSE%" == "true" (
140 | echo Couldn't find %WRAPPER_JAR%, downloading it ...
141 | echo Downloading from: %DOWNLOAD_URL%
142 | )
143 |
144 | powershell -Command "&{"^
145 | "$webclient = new-object System.Net.WebClient;"^
146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
148 | "}"^
149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
150 | "}"
151 | if "%MVNW_VERBOSE%" == "true" (
152 | echo Finished downloading %WRAPPER_JAR%
153 | )
154 | )
155 | @REM End of extension
156 |
157 | @REM Provide a "standardized" way to retrieve the CLI args that will
158 | @REM work with both Windows and non-Windows executions.
159 | set MAVEN_CMD_LINE_ARGS=%*
160 |
161 | %MAVEN_JAVA_EXE% ^
162 | %JVM_CONFIG_MAVEN_PROPS% ^
163 | %MAVEN_OPTS% ^
164 | %MAVEN_DEBUG_OPTS% ^
165 | -classpath %WRAPPER_JAR% ^
166 | "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
167 | %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
168 | if ERRORLEVEL 1 goto error
169 | goto end
170 |
171 | :error
172 | set ERROR_CODE=1
173 |
174 | :end
175 | @endlocal & set ERROR_CODE=%ERROR_CODE%
176 |
177 | if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
178 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
179 | if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
180 | if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
181 | :skipRcPost
182 |
183 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
184 | if "%MAVEN_BATCH_PAUSE%"=="on" pause
185 |
186 | if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
187 |
188 | cmd /C exit /B %ERROR_CODE%
189 |
--------------------------------------------------------------------------------
/server-spring/mvnw:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # ----------------------------------------------------------------------------
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # https://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | # ----------------------------------------------------------------------------
20 |
21 | # ----------------------------------------------------------------------------
22 | # Maven Start Up Batch script
23 | #
24 | # Required ENV vars:
25 | # ------------------
26 | # JAVA_HOME - location of a JDK home dir
27 | #
28 | # Optional ENV vars
29 | # -----------------
30 | # M2_HOME - location of maven2's installed home dir
31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven
32 | # e.g. to debug Maven itself, use
33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files
35 | # ----------------------------------------------------------------------------
36 |
37 | if [ -z "$MAVEN_SKIP_RC" ] ; then
38 |
39 | if [ -f /usr/local/etc/mavenrc ] ; then
40 | . /usr/local/etc/mavenrc
41 | fi
42 |
43 | if [ -f /etc/mavenrc ] ; then
44 | . /etc/mavenrc
45 | fi
46 |
47 | if [ -f "$HOME/.mavenrc" ] ; then
48 | . "$HOME/.mavenrc"
49 | fi
50 |
51 | fi
52 |
53 | # OS specific support. $var _must_ be set to either true or false.
54 | cygwin=false;
55 | darwin=false;
56 | mingw=false
57 | case "`uname`" in
58 | CYGWIN*) cygwin=true ;;
59 | MINGW*) mingw=true;;
60 | Darwin*) darwin=true
61 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
62 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
63 | if [ -z "$JAVA_HOME" ]; then
64 | if [ -x "/usr/libexec/java_home" ]; then
65 | export JAVA_HOME="`/usr/libexec/java_home`"
66 | else
67 | export JAVA_HOME="/Library/Java/Home"
68 | fi
69 | fi
70 | ;;
71 | esac
72 |
73 | if [ -z "$JAVA_HOME" ] ; then
74 | if [ -r /etc/gentoo-release ] ; then
75 | JAVA_HOME=`java-config --jre-home`
76 | fi
77 | fi
78 |
79 | if [ -z "$M2_HOME" ] ; then
80 | ## resolve links - $0 may be a link to maven's home
81 | PRG="$0"
82 |
83 | # need this for relative symlinks
84 | while [ -h "$PRG" ] ; do
85 | ls=`ls -ld "$PRG"`
86 | link=`expr "$ls" : '.*-> \(.*\)$'`
87 | if expr "$link" : '/.*' > /dev/null; then
88 | PRG="$link"
89 | else
90 | PRG="`dirname "$PRG"`/$link"
91 | fi
92 | done
93 |
94 | saveddir=`pwd`
95 |
96 | M2_HOME=`dirname "$PRG"`/..
97 |
98 | # make it fully qualified
99 | M2_HOME=`cd "$M2_HOME" && pwd`
100 |
101 | cd "$saveddir"
102 | # echo Using m2 at $M2_HOME
103 | fi
104 |
105 | # For Cygwin, ensure paths are in UNIX format before anything is touched
106 | if $cygwin ; then
107 | [ -n "$M2_HOME" ] &&
108 | M2_HOME=`cygpath --unix "$M2_HOME"`
109 | [ -n "$JAVA_HOME" ] &&
110 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
111 | [ -n "$CLASSPATH" ] &&
112 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
113 | fi
114 |
115 | # For Mingw, ensure paths are in UNIX format before anything is touched
116 | if $mingw ; then
117 | [ -n "$M2_HOME" ] &&
118 | M2_HOME="`(cd "$M2_HOME"; pwd)`"
119 | [ -n "$JAVA_HOME" ] &&
120 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
121 | fi
122 |
123 | if [ -z "$JAVA_HOME" ]; then
124 | javaExecutable="`which javac`"
125 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
126 | # readlink(1) is not available as standard on Solaris 10.
127 | readLink=`which readlink`
128 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
129 | if $darwin ; then
130 | javaHome="`dirname \"$javaExecutable\"`"
131 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
132 | else
133 | javaExecutable="`readlink -f \"$javaExecutable\"`"
134 | fi
135 | javaHome="`dirname \"$javaExecutable\"`"
136 | javaHome=`expr "$javaHome" : '\(.*\)/bin'`
137 | JAVA_HOME="$javaHome"
138 | export JAVA_HOME
139 | fi
140 | fi
141 | fi
142 |
143 | if [ -z "$JAVACMD" ] ; then
144 | if [ -n "$JAVA_HOME" ] ; then
145 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
146 | # IBM's JDK on AIX uses strange locations for the executables
147 | JAVACMD="$JAVA_HOME/jre/sh/java"
148 | else
149 | JAVACMD="$JAVA_HOME/bin/java"
150 | fi
151 | else
152 | JAVACMD="`\\unset -f command; \\command -v java`"
153 | fi
154 | fi
155 |
156 | if [ ! -x "$JAVACMD" ] ; then
157 | echo "Error: JAVA_HOME is not defined correctly." >&2
158 | echo " We cannot execute $JAVACMD" >&2
159 | exit 1
160 | fi
161 |
162 | if [ -z "$JAVA_HOME" ] ; then
163 | echo "Warning: JAVA_HOME environment variable is not set."
164 | fi
165 |
166 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
167 |
168 | # traverses directory structure from process work directory to filesystem root
169 | # first directory with .mvn subdirectory is considered project base directory
170 | find_maven_basedir() {
171 |
172 | if [ -z "$1" ]
173 | then
174 | echo "Path not specified to find_maven_basedir"
175 | return 1
176 | fi
177 |
178 | basedir="$1"
179 | wdir="$1"
180 | while [ "$wdir" != '/' ] ; do
181 | if [ -d "$wdir"/.mvn ] ; then
182 | basedir=$wdir
183 | break
184 | fi
185 | # workaround for JBEAP-8937 (on Solaris 10/Sparc)
186 | if [ -d "${wdir}" ]; then
187 | wdir=`cd "$wdir/.."; pwd`
188 | fi
189 | # end of workaround
190 | done
191 | echo "${basedir}"
192 | }
193 |
194 | # concatenates all lines of a file
195 | concat_lines() {
196 | if [ -f "$1" ]; then
197 | echo "$(tr -s '\n' ' ' < "$1")"
198 | fi
199 | }
200 |
201 | BASE_DIR=`find_maven_basedir "$(pwd)"`
202 | if [ -z "$BASE_DIR" ]; then
203 | exit 1;
204 | fi
205 |
206 | ##########################################################################################
207 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
208 | # This allows using the maven wrapper in projects that prohibit checking in binary data.
209 | ##########################################################################################
210 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
211 | if [ "$MVNW_VERBOSE" = true ]; then
212 | echo "Found .mvn/wrapper/maven-wrapper.jar"
213 | fi
214 | else
215 | if [ "$MVNW_VERBOSE" = true ]; then
216 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
217 | fi
218 | if [ -n "$MVNW_REPOURL" ]; then
219 | jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
220 | else
221 | jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar"
222 | fi
223 | while IFS="=" read key value; do
224 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
225 | esac
226 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
227 | if [ "$MVNW_VERBOSE" = true ]; then
228 | echo "Downloading from: $jarUrl"
229 | fi
230 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
231 | if $cygwin; then
232 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
233 | fi
234 |
235 | if command -v wget > /dev/null; then
236 | if [ "$MVNW_VERBOSE" = true ]; then
237 | echo "Found wget ... using wget"
238 | fi
239 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
240 | wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
241 | else
242 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
243 | fi
244 | elif command -v curl > /dev/null; then
245 | if [ "$MVNW_VERBOSE" = true ]; then
246 | echo "Found curl ... using curl"
247 | fi
248 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
249 | curl -o "$wrapperJarPath" "$jarUrl" -f
250 | else
251 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
252 | fi
253 |
254 | else
255 | if [ "$MVNW_VERBOSE" = true ]; then
256 | echo "Falling back to using Java to download"
257 | fi
258 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
259 | # For Cygwin, switch paths to Windows format before running javac
260 | if $cygwin; then
261 | javaClass=`cygpath --path --windows "$javaClass"`
262 | fi
263 | if [ -e "$javaClass" ]; then
264 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
265 | if [ "$MVNW_VERBOSE" = true ]; then
266 | echo " - Compiling MavenWrapperDownloader.java ..."
267 | fi
268 | # Compiling the Java class
269 | ("$JAVA_HOME/bin/javac" "$javaClass")
270 | fi
271 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
272 | # Running the downloader
273 | if [ "$MVNW_VERBOSE" = true ]; then
274 | echo " - Running MavenWrapperDownloader.java ..."
275 | fi
276 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
277 | fi
278 | fi
279 | fi
280 | fi
281 | ##########################################################################################
282 | # End of extension
283 | ##########################################################################################
284 |
285 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
286 | if [ "$MVNW_VERBOSE" = true ]; then
287 | echo $MAVEN_PROJECTBASEDIR
288 | fi
289 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
290 |
291 | # For Cygwin, switch paths to Windows format before running java
292 | if $cygwin; then
293 | [ -n "$M2_HOME" ] &&
294 | M2_HOME=`cygpath --path --windows "$M2_HOME"`
295 | [ -n "$JAVA_HOME" ] &&
296 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
297 | [ -n "$CLASSPATH" ] &&
298 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
299 | [ -n "$MAVEN_PROJECTBASEDIR" ] &&
300 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
301 | fi
302 |
303 | # Provide a "standardized" way to retrieve the CLI args that will
304 | # work with both Windows and non-Windows executions.
305 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
306 | export MAVEN_CMD_LINE_ARGS
307 |
308 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
309 |
310 | exec "$JAVACMD" \
311 | $MAVEN_OPTS \
312 | $MAVEN_DEBUG_OPTS \
313 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
314 | "-Dmaven.home=${M2_HOME}" \
315 | "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
316 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
317 |
--------------------------------------------------------------------------------
/server-firebase/README.md:
--------------------------------------------------------------------------------
1 | # Build a scalable chat app with Firebase, Next JS, and ChatEngine.io
2 |
3 | In this post, we'll be building (and deploying) a scalable, full-stack chat application using Firebase, NextJS, and ChatEngine.io!
4 |
5 | - Firebase is a Backend as a Service (BaaS) plaform which is made by Google.
6 | - NextJS is a Server Side Rendering Framework (SSRF) in React JS
7 | - ChatEngine.io provides chat APIs and components for building chat apps easily.
8 |
9 | Here, we will connect the three to make the amazing chat app above - in about 15 minutes of work!
10 |
11 | ## 1. Setting up a firebase project
12 |
13 | Taking a step back, let's make the folder we'll run this project inside:
14 |
15 | ```bash
16 | mkdir chat-firebase-next
17 | cd chat-firebase-next
18 | code .
19 | ```
20 |
21 | To setup a firebase project, make sure you have the [Firebase CLI](https://firebase.google.com/docs/cli) installed and a [Firebase account](https://firebase.google.com/).
22 |
23 | Now, open a terminal in this new folder, and start a firebase project with `firebase init` command. Make sure you pick the following options below:
24 |
25 | - Select / enable `functions`
26 | - Select "Create a new project"
27 | - I named my project and ID "fullstack-chat-server"
28 | - I used Javascript, but TypeScript works too
29 |
30 | Now, when you run a free command you should see the following:
31 |
32 | ```bash
33 | .
34 | ├── .firebaserc
35 | ├── .gitignore
36 | ├── firebase.json
37 | └── functions/
38 | ```
39 |
40 | I'll list each item below:
41 |
42 | - `.firebaserc` links this folder to your new Firebase project
43 | - `.gitignore` ignores certain files and folders for your repo
44 | - `firebase.json` hosts settings for your local Firebase project
45 | - `functions` is where we'll be writing our backend code ;)
46 |
47 | On that note, let's setup an Express JS server in Cloud Functions.
48 |
49 | ## 2. Coding your backend
50 |
51 | We'll be connect all our Users to Chat Engine so they can use Chat Engine's chat infrastructure. The Chat Engine backend will handle all our web-sockets, chat storage, and everything else.
52 |
53 | We need to make Rest API calls to Chat Engine whenever a new user Signs Up, and delete their account whenever they leave.
54 |
55 | To start, hop in `functions` to install axios and hop back out:
56 |
57 | ```bash
58 | cd functions
59 | npm i axios
60 | cd ..
61 | ```
62 |
63 | The dependency `axios` will make our API calls to Chat Engine.
64 |
65 | Open the `functions/src/index.js` file in your IDE and the following code:
66 |
67 | ```typescript
68 | import * as functions from "firebase-functions";
69 |
70 | exports.createChatEngineUser = functions.auth.user().onCreate((user) => {
71 | console.log("create", user);
72 | });
73 |
74 | exports.deleteChatEngineUser = functions.auth.user().onDelete((user) => {
75 | console.log("delete", user);
76 | });
77 | ```
78 |
79 | This will simple state when a user signs up or deleted their account.
80 |
81 | To deploy this, just run `firebase deploy`. You will be prompted to enable Authentication and the Blaze plan if you haven't already.
82 |
83 | I just enabled Google Authentication and followed the steps in the website.
84 |
85 | ```bash
86 | firebase deploy
87 | ```
88 |
89 | Your backend be good to go! And you should see the following in your functions tab online:
90 |
91 | [TODO: image of firebase console]
92 |
93 | Now, let's connect this backend to ChatEngine.io!
94 |
95 | ## 3. Connect Firebase to Chat Engine
96 |
97 | Chat Engine's APIs let us host chatrooms on their platform, and provide us tools to build pretty chat UIs. We'll be signing up our new Firebase users to Chat Engine automatically here.
98 |
99 | Here is the documentation on Chat Engine's APIs: https://rest.chatengine.io
100 |
101 | In particular, we'll be using their [Create User API](https://rest.chatengine.io/#6bd8427f-d6e0-4f25-8b96-e753aa73f99a) and their [Delete User API](https://rest.chatengine.io/#902cf1ff-3f42-4430-8f0d-3a7067d3213b).
102 |
103 | To start, go to https://chatengine.io, create an account, and set up a new Project. The Private Key and Project ID will be needed for our API calls.
104 |
105 | Now, let's add the code to `functions/src/index.js` and be sure to replace `XXX` and `YYY` with your Private Key and Project ID, respectively.
106 |
107 | ```typescript
108 | import * as functions from "firebase-functions";
109 |
110 | const axios = require("axios");
111 |
112 | exports.createChatEngineUser = functions.auth.user().onCreate((user) => {
113 | axios.post(
114 | "https://api.chatengine.io/users/",
115 | {
116 | username: user.email,
117 | secret: user.uid,
118 | email: user.email,
119 | first_name: user.displayName,
120 | },
121 | { headers: { "Private-Key": "8c63dbce-80a7-455a-890b-9368d16e1dcb" } }
122 | );
123 | });
124 |
125 | exports.deleteChatEngineUser = functions.auth.user().onDelete((user) => {
126 | axios.delete("https://api.chatengine.io/users/me/", {
127 | headers: {
128 | "Project-ID": "794653df-052a-4ad2-b0aa-d6c251a10aef",
129 | "User-Name": user.email,
130 | "User-Secret": user.uid,
131 | },
132 | });
133 | });
134 | ```
135 |
136 | If you're using TypeScript, you may need to modify the rules in `.eslintrc.js` like I did below:
137 |
138 | ```json
139 | rules: {
140 | // prettier-ignore
141 | "quotes": ["error", "double"],
142 | "import/no-unresolved": 0,
143 | // prettier-ignore
144 | "indent": ["off", "always"],
145 | "object-curly-spacing": ["off", "always"],
146 | "@typescript-eslint/no-var-requires": ["off", "always"],
147 | }
148 | ```
149 |
150 | Our backend is complete! Now users have access to Chat Engine when they sign up and their account goes away is they delete their data!
151 |
152 | Let's setup a frontend and connect it to Firebase and Chat Engine!
153 |
154 | ## 4. Set up the Frontend
155 |
156 | At the top level of our project, we'll run the command below to make a NextJS project. Be sure to select the following too:
157 |
158 | ```bash
159 | npx create-next-app@latest --ts
160 | ```
161 |
162 | - Name the project "frontend"
163 | - "No" for using .eslint
164 | - "No" for using the `src/` directory
165 | - "No" for using the `app/` directory
166 | - "Yes" for using the `@` imports
167 |
168 | I highly recommend TypeScript with Chat Engine, you'll see why soon :)
169 |
170 | Now you should have a `frontend/` folder right next to `functions/`.
171 |
172 | Important side note: Replace `styles/gloabl.css` with [the following code too](https://raw.githubusercontent.com/alamorre/fullstack-chat/main/server-firebase/frontend/styles/globals.css).
173 |
174 | Let's CD into this folder, install dependencies, and run in dev-mode.
175 |
176 | ```bash
177 | cd frontend
178 | npm install
179 | npm run dev
180 | ```
181 |
182 | And now you should see a pretty website on http://localhost:3000
183 |
184 | For the final push, let's add all the code we need to our frontend!
185 |
186 | ## 5. Coding the Frontend
187 |
188 | To start, diable StrictMode in `next.config.js` and re-run the server with `yarn dev`.
189 |
190 | ```javascript
191 | /** @type {import('next').NextConfig} */
192 | const nextConfig = {
193 | reactStrictMode: false,
194 | };
195 |
196 | module.exports = nextConfig;
197 | ```
198 |
199 | This allows us to connect web-sockets in a NextJS project.
200 |
201 | Next, let's delete the following:
202 |
203 | - `styles/Home.module.css`
204 | - The `pages/api` directory
205 |
206 | Next, let's create an auth page (`pages/AuthPage.tsx`) with the following code
207 |
208 | ```typescript
209 | export default function Page() {
210 | return ;
211 | }
212 | ```
213 |
214 | Next, let's create an chats page (`pages/ChatsPage.tsx`) with the following code
215 |
216 | - `pages/ChatsPage.tsx`
217 |
218 | ```typescript
219 | import { User } from "firebase/auth";
220 |
221 | interface ChatProps {
222 | user: User;
223 | }
224 |
225 | export default function Page(props: ChatProps) {
226 | return ;
227 | }
228 | ```
229 |
230 | Next, add a loading page (`pages/Loading.tsx`) with the following code:
231 |
232 | ```typescript
233 | export default function Loading() {
234 | return (
235 |
236 |
☝️
237 |
Loading your info...
238 |
239 | );
240 | }
241 | ```
242 |
243 | Finally, modify the `pages/index.tsx` file to load the pages based on auth state:
244 |
245 | ```typescript
246 | import { useState } from "react";
247 |
248 | import AuthPage from "./AuthPage";
249 | import ChatPage from "./ChatsPage";
250 | import Loading from "./Loading";
251 | import { auth } from "@/firebase";
252 | import { User } from "firebase/auth";
253 |
254 | export default function Home() {
255 | const [user, setUser] = useState();
256 | auth.onAuthStateChanged((user) => setUser(user));
257 |
258 | if (user === undefined) {
259 | return ;
260 | } else if (user === null) {
261 | return ;
262 | } else {
263 | return ;
264 | }
265 | }
266 | ```
267 |
268 | ### Enable a Firebase app and create frontend/firebase.ts
269 |
270 | - npm install firebase
271 | - create a .env file and replace with your values
272 |
273 | ```
274 | NEXT_PUBLIC_FIREBASE_API_KEY=AIzaSyDqXgd1AwRdqSCpdrhf_t0-rB1MuE2sd4A
275 | NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=chat-rce.firebaseapp.com
276 | NEXT_PUBLIC_FIREBASE_PROJECT_ID=chat-rce
277 | NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=chat-rce.appspot.com
278 | NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=45443650042
279 | NEXT_PUBLIC_FIREBASE_APP_ID=1:45443650042:web:2598e30783c0e0bd545443
280 | NEXT_PUBLIC_FUNCTIONS_URL=https://us-central1-chat-rce.cloudfunctions.net/v1
281 | NEXT_PUBLIC_CHAT_ENGINE_PROJECT_ID=16b08e85-e4c9-4541-b30e-45e157ec3821
282 | ```
283 |
284 | Make sure `NEXT_PUBLIC_CHAT_ENGINE_PROJECT_ID` is there with yuor project ID.
285 |
286 | - add this code to firebase.ts
287 |
288 | ```
289 | import { initializeApp } from "firebase/app";
290 | import { getAuth } from "firebase/auth";
291 |
292 | const firebaseConfig = {
293 | apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
294 | authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
295 | projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
296 | storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
297 | messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
298 | appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
299 | };
300 |
301 | export const app = initializeApp(firebaseConfig);
302 | export const auth = getAuth(app);
303 | ```
304 |
305 | Now add this code to AuthPage:
306 |
307 | ```
308 | import { auth } from "@/firebase";
309 | import { signInWithRedirect, GoogleAuthProvider } from "firebase/auth";
310 |
311 | export default function AuthPage() {
312 | const onClick = () => {
313 | signInWithRedirect(auth, new GoogleAuthProvider());
314 | };
315 |
316 | return (
317 |
318 |
👋 💬 🤖
319 |
Welcome to ChatRCE
320 |
321 | Log in with your account to continue
322 |
323 |
{" "}
326 |
329 |
330 | );
331 | }
332 | ```
333 |
334 | Finally, let's connect our new user to Chat Engine using [react-chat-engine-pretty](https://www.npmjs.com/package/react-chat-engine-pretty)!
335 |
336 | Modify `pages/ChatsPage.tsx` with the following code:
337 |
338 | ```typescript
339 | import { auth } from "@/firebase";
340 | import { signOut, User } from "firebase/auth";
341 | import { PrettyChatWindow } from "react-chat-engine-pretty";
342 | interface ChatProps {
343 | user: User;
344 | }
345 |
346 | export default function Page(props: ChatProps) {
347 | return (
348 |
349 |
355 |
361 |
362 | );
363 | }
364 | ```
365 |
366 | And we're done!
367 |
--------------------------------------------------------------------------------
/server-nodejs/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "server-node",
3 | "version": "1.0.0",
4 | "lockfileVersion": 2,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "server-node",
9 | "version": "1.0.0",
10 | "license": "ISC",
11 | "dependencies": {
12 | "axios": "^1.2.0",
13 | "cors": "^2.8.5",
14 | "express": "^4.18.2"
15 | },
16 | "devDependencies": {
17 | "nodemon": "^2.0.20"
18 | }
19 | },
20 | "node_modules/abbrev": {
21 | "version": "1.1.1",
22 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
23 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
24 | "dev": true
25 | },
26 | "node_modules/accepts": {
27 | "version": "1.3.8",
28 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
29 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
30 | "dependencies": {
31 | "mime-types": "~2.1.34",
32 | "negotiator": "0.6.3"
33 | },
34 | "engines": {
35 | "node": ">= 0.6"
36 | }
37 | },
38 | "node_modules/anymatch": {
39 | "version": "3.1.3",
40 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
41 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
42 | "dev": true,
43 | "dependencies": {
44 | "normalize-path": "^3.0.0",
45 | "picomatch": "^2.0.4"
46 | },
47 | "engines": {
48 | "node": ">= 8"
49 | }
50 | },
51 | "node_modules/array-flatten": {
52 | "version": "1.1.1",
53 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
54 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
55 | },
56 | "node_modules/asynckit": {
57 | "version": "0.4.0",
58 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
59 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
60 | },
61 | "node_modules/axios": {
62 | "version": "1.2.2",
63 | "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.2.tgz",
64 | "integrity": "sha512-bz/J4gS2S3I7mpN/YZfGFTqhXTYzRho8Ay38w2otuuDR322KzFIWm/4W2K6gIwvWaws5n+mnb7D1lN9uD+QH6Q==",
65 | "dependencies": {
66 | "follow-redirects": "^1.15.0",
67 | "form-data": "^4.0.0",
68 | "proxy-from-env": "^1.1.0"
69 | }
70 | },
71 | "node_modules/balanced-match": {
72 | "version": "1.0.2",
73 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
74 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
75 | "dev": true
76 | },
77 | "node_modules/binary-extensions": {
78 | "version": "2.2.0",
79 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
80 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
81 | "dev": true,
82 | "engines": {
83 | "node": ">=8"
84 | }
85 | },
86 | "node_modules/body-parser": {
87 | "version": "1.20.1",
88 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
89 | "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
90 | "dependencies": {
91 | "bytes": "3.1.2",
92 | "content-type": "~1.0.4",
93 | "debug": "2.6.9",
94 | "depd": "2.0.0",
95 | "destroy": "1.2.0",
96 | "http-errors": "2.0.0",
97 | "iconv-lite": "0.4.24",
98 | "on-finished": "2.4.1",
99 | "qs": "6.11.0",
100 | "raw-body": "2.5.1",
101 | "type-is": "~1.6.18",
102 | "unpipe": "1.0.0"
103 | },
104 | "engines": {
105 | "node": ">= 0.8",
106 | "npm": "1.2.8000 || >= 1.4.16"
107 | }
108 | },
109 | "node_modules/brace-expansion": {
110 | "version": "1.1.11",
111 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
112 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
113 | "dev": true,
114 | "dependencies": {
115 | "balanced-match": "^1.0.0",
116 | "concat-map": "0.0.1"
117 | }
118 | },
119 | "node_modules/braces": {
120 | "version": "3.0.2",
121 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
122 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
123 | "dev": true,
124 | "dependencies": {
125 | "fill-range": "^7.0.1"
126 | },
127 | "engines": {
128 | "node": ">=8"
129 | }
130 | },
131 | "node_modules/bytes": {
132 | "version": "3.1.2",
133 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
134 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
135 | "engines": {
136 | "node": ">= 0.8"
137 | }
138 | },
139 | "node_modules/call-bind": {
140 | "version": "1.0.2",
141 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
142 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
143 | "dependencies": {
144 | "function-bind": "^1.1.1",
145 | "get-intrinsic": "^1.0.2"
146 | },
147 | "funding": {
148 | "url": "https://github.com/sponsors/ljharb"
149 | }
150 | },
151 | "node_modules/chokidar": {
152 | "version": "3.5.3",
153 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
154 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
155 | "dev": true,
156 | "funding": [
157 | {
158 | "type": "individual",
159 | "url": "https://paulmillr.com/funding/"
160 | }
161 | ],
162 | "dependencies": {
163 | "anymatch": "~3.1.2",
164 | "braces": "~3.0.2",
165 | "glob-parent": "~5.1.2",
166 | "is-binary-path": "~2.1.0",
167 | "is-glob": "~4.0.1",
168 | "normalize-path": "~3.0.0",
169 | "readdirp": "~3.6.0"
170 | },
171 | "engines": {
172 | "node": ">= 8.10.0"
173 | },
174 | "optionalDependencies": {
175 | "fsevents": "~2.3.2"
176 | }
177 | },
178 | "node_modules/combined-stream": {
179 | "version": "1.0.8",
180 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
181 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
182 | "dependencies": {
183 | "delayed-stream": "~1.0.0"
184 | },
185 | "engines": {
186 | "node": ">= 0.8"
187 | }
188 | },
189 | "node_modules/concat-map": {
190 | "version": "0.0.1",
191 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
192 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
193 | "dev": true
194 | },
195 | "node_modules/content-disposition": {
196 | "version": "0.5.4",
197 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
198 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
199 | "dependencies": {
200 | "safe-buffer": "5.2.1"
201 | },
202 | "engines": {
203 | "node": ">= 0.6"
204 | }
205 | },
206 | "node_modules/content-type": {
207 | "version": "1.0.4",
208 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
209 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
210 | "engines": {
211 | "node": ">= 0.6"
212 | }
213 | },
214 | "node_modules/cookie": {
215 | "version": "0.5.0",
216 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
217 | "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
218 | "engines": {
219 | "node": ">= 0.6"
220 | }
221 | },
222 | "node_modules/cookie-signature": {
223 | "version": "1.0.6",
224 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
225 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
226 | },
227 | "node_modules/cors": {
228 | "version": "2.8.5",
229 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
230 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
231 | "dependencies": {
232 | "object-assign": "^4",
233 | "vary": "^1"
234 | },
235 | "engines": {
236 | "node": ">= 0.10"
237 | }
238 | },
239 | "node_modules/debug": {
240 | "version": "2.6.9",
241 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
242 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
243 | "dependencies": {
244 | "ms": "2.0.0"
245 | }
246 | },
247 | "node_modules/delayed-stream": {
248 | "version": "1.0.0",
249 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
250 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
251 | "engines": {
252 | "node": ">=0.4.0"
253 | }
254 | },
255 | "node_modules/depd": {
256 | "version": "2.0.0",
257 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
258 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
259 | "engines": {
260 | "node": ">= 0.8"
261 | }
262 | },
263 | "node_modules/destroy": {
264 | "version": "1.2.0",
265 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
266 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
267 | "engines": {
268 | "node": ">= 0.8",
269 | "npm": "1.2.8000 || >= 1.4.16"
270 | }
271 | },
272 | "node_modules/ee-first": {
273 | "version": "1.1.1",
274 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
275 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
276 | },
277 | "node_modules/encodeurl": {
278 | "version": "1.0.2",
279 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
280 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
281 | "engines": {
282 | "node": ">= 0.8"
283 | }
284 | },
285 | "node_modules/escape-html": {
286 | "version": "1.0.3",
287 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
288 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
289 | },
290 | "node_modules/etag": {
291 | "version": "1.8.1",
292 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
293 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
294 | "engines": {
295 | "node": ">= 0.6"
296 | }
297 | },
298 | "node_modules/express": {
299 | "version": "4.18.2",
300 | "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
301 | "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
302 | "dependencies": {
303 | "accepts": "~1.3.8",
304 | "array-flatten": "1.1.1",
305 | "body-parser": "1.20.1",
306 | "content-disposition": "0.5.4",
307 | "content-type": "~1.0.4",
308 | "cookie": "0.5.0",
309 | "cookie-signature": "1.0.6",
310 | "debug": "2.6.9",
311 | "depd": "2.0.0",
312 | "encodeurl": "~1.0.2",
313 | "escape-html": "~1.0.3",
314 | "etag": "~1.8.1",
315 | "finalhandler": "1.2.0",
316 | "fresh": "0.5.2",
317 | "http-errors": "2.0.0",
318 | "merge-descriptors": "1.0.1",
319 | "methods": "~1.1.2",
320 | "on-finished": "2.4.1",
321 | "parseurl": "~1.3.3",
322 | "path-to-regexp": "0.1.7",
323 | "proxy-addr": "~2.0.7",
324 | "qs": "6.11.0",
325 | "range-parser": "~1.2.1",
326 | "safe-buffer": "5.2.1",
327 | "send": "0.18.0",
328 | "serve-static": "1.15.0",
329 | "setprototypeof": "1.2.0",
330 | "statuses": "2.0.1",
331 | "type-is": "~1.6.18",
332 | "utils-merge": "1.0.1",
333 | "vary": "~1.1.2"
334 | },
335 | "engines": {
336 | "node": ">= 0.10.0"
337 | }
338 | },
339 | "node_modules/fill-range": {
340 | "version": "7.0.1",
341 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
342 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
343 | "dev": true,
344 | "dependencies": {
345 | "to-regex-range": "^5.0.1"
346 | },
347 | "engines": {
348 | "node": ">=8"
349 | }
350 | },
351 | "node_modules/finalhandler": {
352 | "version": "1.2.0",
353 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
354 | "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
355 | "dependencies": {
356 | "debug": "2.6.9",
357 | "encodeurl": "~1.0.2",
358 | "escape-html": "~1.0.3",
359 | "on-finished": "2.4.1",
360 | "parseurl": "~1.3.3",
361 | "statuses": "2.0.1",
362 | "unpipe": "~1.0.0"
363 | },
364 | "engines": {
365 | "node": ">= 0.8"
366 | }
367 | },
368 | "node_modules/follow-redirects": {
369 | "version": "1.15.2",
370 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
371 | "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
372 | "funding": [
373 | {
374 | "type": "individual",
375 | "url": "https://github.com/sponsors/RubenVerborgh"
376 | }
377 | ],
378 | "engines": {
379 | "node": ">=4.0"
380 | },
381 | "peerDependenciesMeta": {
382 | "debug": {
383 | "optional": true
384 | }
385 | }
386 | },
387 | "node_modules/form-data": {
388 | "version": "4.0.0",
389 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
390 | "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
391 | "dependencies": {
392 | "asynckit": "^0.4.0",
393 | "combined-stream": "^1.0.8",
394 | "mime-types": "^2.1.12"
395 | },
396 | "engines": {
397 | "node": ">= 6"
398 | }
399 | },
400 | "node_modules/forwarded": {
401 | "version": "0.2.0",
402 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
403 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
404 | "engines": {
405 | "node": ">= 0.6"
406 | }
407 | },
408 | "node_modules/fresh": {
409 | "version": "0.5.2",
410 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
411 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
412 | "engines": {
413 | "node": ">= 0.6"
414 | }
415 | },
416 | "node_modules/fsevents": {
417 | "version": "2.3.2",
418 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
419 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
420 | "dev": true,
421 | "hasInstallScript": true,
422 | "optional": true,
423 | "os": [
424 | "darwin"
425 | ],
426 | "engines": {
427 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
428 | }
429 | },
430 | "node_modules/function-bind": {
431 | "version": "1.1.1",
432 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
433 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
434 | },
435 | "node_modules/get-intrinsic": {
436 | "version": "1.1.3",
437 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
438 | "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==",
439 | "dependencies": {
440 | "function-bind": "^1.1.1",
441 | "has": "^1.0.3",
442 | "has-symbols": "^1.0.3"
443 | },
444 | "funding": {
445 | "url": "https://github.com/sponsors/ljharb"
446 | }
447 | },
448 | "node_modules/glob-parent": {
449 | "version": "5.1.2",
450 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
451 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
452 | "dev": true,
453 | "dependencies": {
454 | "is-glob": "^4.0.1"
455 | },
456 | "engines": {
457 | "node": ">= 6"
458 | }
459 | },
460 | "node_modules/has": {
461 | "version": "1.0.3",
462 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
463 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
464 | "dependencies": {
465 | "function-bind": "^1.1.1"
466 | },
467 | "engines": {
468 | "node": ">= 0.4.0"
469 | }
470 | },
471 | "node_modules/has-flag": {
472 | "version": "3.0.0",
473 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
474 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
475 | "dev": true,
476 | "engines": {
477 | "node": ">=4"
478 | }
479 | },
480 | "node_modules/has-symbols": {
481 | "version": "1.0.3",
482 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
483 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
484 | "engines": {
485 | "node": ">= 0.4"
486 | },
487 | "funding": {
488 | "url": "https://github.com/sponsors/ljharb"
489 | }
490 | },
491 | "node_modules/http-errors": {
492 | "version": "2.0.0",
493 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
494 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
495 | "dependencies": {
496 | "depd": "2.0.0",
497 | "inherits": "2.0.4",
498 | "setprototypeof": "1.2.0",
499 | "statuses": "2.0.1",
500 | "toidentifier": "1.0.1"
501 | },
502 | "engines": {
503 | "node": ">= 0.8"
504 | }
505 | },
506 | "node_modules/iconv-lite": {
507 | "version": "0.4.24",
508 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
509 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
510 | "dependencies": {
511 | "safer-buffer": ">= 2.1.2 < 3"
512 | },
513 | "engines": {
514 | "node": ">=0.10.0"
515 | }
516 | },
517 | "node_modules/ignore-by-default": {
518 | "version": "1.0.1",
519 | "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
520 | "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
521 | "dev": true
522 | },
523 | "node_modules/inherits": {
524 | "version": "2.0.4",
525 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
526 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
527 | },
528 | "node_modules/ipaddr.js": {
529 | "version": "1.9.1",
530 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
531 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
532 | "engines": {
533 | "node": ">= 0.10"
534 | }
535 | },
536 | "node_modules/is-binary-path": {
537 | "version": "2.1.0",
538 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
539 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
540 | "dev": true,
541 | "dependencies": {
542 | "binary-extensions": "^2.0.0"
543 | },
544 | "engines": {
545 | "node": ">=8"
546 | }
547 | },
548 | "node_modules/is-extglob": {
549 | "version": "2.1.1",
550 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
551 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
552 | "dev": true,
553 | "engines": {
554 | "node": ">=0.10.0"
555 | }
556 | },
557 | "node_modules/is-glob": {
558 | "version": "4.0.3",
559 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
560 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
561 | "dev": true,
562 | "dependencies": {
563 | "is-extglob": "^2.1.1"
564 | },
565 | "engines": {
566 | "node": ">=0.10.0"
567 | }
568 | },
569 | "node_modules/is-number": {
570 | "version": "7.0.0",
571 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
572 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
573 | "dev": true,
574 | "engines": {
575 | "node": ">=0.12.0"
576 | }
577 | },
578 | "node_modules/media-typer": {
579 | "version": "0.3.0",
580 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
581 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
582 | "engines": {
583 | "node": ">= 0.6"
584 | }
585 | },
586 | "node_modules/merge-descriptors": {
587 | "version": "1.0.1",
588 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
589 | "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
590 | },
591 | "node_modules/methods": {
592 | "version": "1.1.2",
593 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
594 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
595 | "engines": {
596 | "node": ">= 0.6"
597 | }
598 | },
599 | "node_modules/mime": {
600 | "version": "1.6.0",
601 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
602 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
603 | "bin": {
604 | "mime": "cli.js"
605 | },
606 | "engines": {
607 | "node": ">=4"
608 | }
609 | },
610 | "node_modules/mime-db": {
611 | "version": "1.52.0",
612 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
613 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
614 | "engines": {
615 | "node": ">= 0.6"
616 | }
617 | },
618 | "node_modules/mime-types": {
619 | "version": "2.1.35",
620 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
621 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
622 | "dependencies": {
623 | "mime-db": "1.52.0"
624 | },
625 | "engines": {
626 | "node": ">= 0.6"
627 | }
628 | },
629 | "node_modules/minimatch": {
630 | "version": "3.1.2",
631 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
632 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
633 | "dev": true,
634 | "dependencies": {
635 | "brace-expansion": "^1.1.7"
636 | },
637 | "engines": {
638 | "node": "*"
639 | }
640 | },
641 | "node_modules/ms": {
642 | "version": "2.0.0",
643 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
644 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
645 | },
646 | "node_modules/negotiator": {
647 | "version": "0.6.3",
648 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
649 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
650 | "engines": {
651 | "node": ">= 0.6"
652 | }
653 | },
654 | "node_modules/nodemon": {
655 | "version": "2.0.20",
656 | "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz",
657 | "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==",
658 | "dev": true,
659 | "dependencies": {
660 | "chokidar": "^3.5.2",
661 | "debug": "^3.2.7",
662 | "ignore-by-default": "^1.0.1",
663 | "minimatch": "^3.1.2",
664 | "pstree.remy": "^1.1.8",
665 | "semver": "^5.7.1",
666 | "simple-update-notifier": "^1.0.7",
667 | "supports-color": "^5.5.0",
668 | "touch": "^3.1.0",
669 | "undefsafe": "^2.0.5"
670 | },
671 | "bin": {
672 | "nodemon": "bin/nodemon.js"
673 | },
674 | "engines": {
675 | "node": ">=8.10.0"
676 | },
677 | "funding": {
678 | "type": "opencollective",
679 | "url": "https://opencollective.com/nodemon"
680 | }
681 | },
682 | "node_modules/nodemon/node_modules/debug": {
683 | "version": "3.2.7",
684 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
685 | "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
686 | "dev": true,
687 | "dependencies": {
688 | "ms": "^2.1.1"
689 | }
690 | },
691 | "node_modules/nodemon/node_modules/ms": {
692 | "version": "2.1.3",
693 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
694 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
695 | "dev": true
696 | },
697 | "node_modules/nopt": {
698 | "version": "1.0.10",
699 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
700 | "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==",
701 | "dev": true,
702 | "dependencies": {
703 | "abbrev": "1"
704 | },
705 | "bin": {
706 | "nopt": "bin/nopt.js"
707 | },
708 | "engines": {
709 | "node": "*"
710 | }
711 | },
712 | "node_modules/normalize-path": {
713 | "version": "3.0.0",
714 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
715 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
716 | "dev": true,
717 | "engines": {
718 | "node": ">=0.10.0"
719 | }
720 | },
721 | "node_modules/object-assign": {
722 | "version": "4.1.1",
723 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
724 | "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
725 | "engines": {
726 | "node": ">=0.10.0"
727 | }
728 | },
729 | "node_modules/object-inspect": {
730 | "version": "1.12.3",
731 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
732 | "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
733 | "funding": {
734 | "url": "https://github.com/sponsors/ljharb"
735 | }
736 | },
737 | "node_modules/on-finished": {
738 | "version": "2.4.1",
739 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
740 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
741 | "dependencies": {
742 | "ee-first": "1.1.1"
743 | },
744 | "engines": {
745 | "node": ">= 0.8"
746 | }
747 | },
748 | "node_modules/parseurl": {
749 | "version": "1.3.3",
750 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
751 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
752 | "engines": {
753 | "node": ">= 0.8"
754 | }
755 | },
756 | "node_modules/path-to-regexp": {
757 | "version": "0.1.7",
758 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
759 | "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
760 | },
761 | "node_modules/picomatch": {
762 | "version": "2.3.1",
763 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
764 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
765 | "dev": true,
766 | "engines": {
767 | "node": ">=8.6"
768 | },
769 | "funding": {
770 | "url": "https://github.com/sponsors/jonschlinkert"
771 | }
772 | },
773 | "node_modules/proxy-addr": {
774 | "version": "2.0.7",
775 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
776 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
777 | "dependencies": {
778 | "forwarded": "0.2.0",
779 | "ipaddr.js": "1.9.1"
780 | },
781 | "engines": {
782 | "node": ">= 0.10"
783 | }
784 | },
785 | "node_modules/proxy-from-env": {
786 | "version": "1.1.0",
787 | "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
788 | "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
789 | },
790 | "node_modules/pstree.remy": {
791 | "version": "1.1.8",
792 | "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
793 | "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
794 | "dev": true
795 | },
796 | "node_modules/qs": {
797 | "version": "6.11.0",
798 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
799 | "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
800 | "dependencies": {
801 | "side-channel": "^1.0.4"
802 | },
803 | "engines": {
804 | "node": ">=0.6"
805 | },
806 | "funding": {
807 | "url": "https://github.com/sponsors/ljharb"
808 | }
809 | },
810 | "node_modules/range-parser": {
811 | "version": "1.2.1",
812 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
813 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
814 | "engines": {
815 | "node": ">= 0.6"
816 | }
817 | },
818 | "node_modules/raw-body": {
819 | "version": "2.5.1",
820 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
821 | "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
822 | "dependencies": {
823 | "bytes": "3.1.2",
824 | "http-errors": "2.0.0",
825 | "iconv-lite": "0.4.24",
826 | "unpipe": "1.0.0"
827 | },
828 | "engines": {
829 | "node": ">= 0.8"
830 | }
831 | },
832 | "node_modules/readdirp": {
833 | "version": "3.6.0",
834 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
835 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
836 | "dev": true,
837 | "dependencies": {
838 | "picomatch": "^2.2.1"
839 | },
840 | "engines": {
841 | "node": ">=8.10.0"
842 | }
843 | },
844 | "node_modules/safe-buffer": {
845 | "version": "5.2.1",
846 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
847 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
848 | "funding": [
849 | {
850 | "type": "github",
851 | "url": "https://github.com/sponsors/feross"
852 | },
853 | {
854 | "type": "patreon",
855 | "url": "https://www.patreon.com/feross"
856 | },
857 | {
858 | "type": "consulting",
859 | "url": "https://feross.org/support"
860 | }
861 | ]
862 | },
863 | "node_modules/safer-buffer": {
864 | "version": "2.1.2",
865 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
866 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
867 | },
868 | "node_modules/semver": {
869 | "version": "5.7.1",
870 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
871 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
872 | "dev": true,
873 | "bin": {
874 | "semver": "bin/semver"
875 | }
876 | },
877 | "node_modules/send": {
878 | "version": "0.18.0",
879 | "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
880 | "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
881 | "dependencies": {
882 | "debug": "2.6.9",
883 | "depd": "2.0.0",
884 | "destroy": "1.2.0",
885 | "encodeurl": "~1.0.2",
886 | "escape-html": "~1.0.3",
887 | "etag": "~1.8.1",
888 | "fresh": "0.5.2",
889 | "http-errors": "2.0.0",
890 | "mime": "1.6.0",
891 | "ms": "2.1.3",
892 | "on-finished": "2.4.1",
893 | "range-parser": "~1.2.1",
894 | "statuses": "2.0.1"
895 | },
896 | "engines": {
897 | "node": ">= 0.8.0"
898 | }
899 | },
900 | "node_modules/send/node_modules/ms": {
901 | "version": "2.1.3",
902 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
903 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
904 | },
905 | "node_modules/serve-static": {
906 | "version": "1.15.0",
907 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
908 | "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
909 | "dependencies": {
910 | "encodeurl": "~1.0.2",
911 | "escape-html": "~1.0.3",
912 | "parseurl": "~1.3.3",
913 | "send": "0.18.0"
914 | },
915 | "engines": {
916 | "node": ">= 0.8.0"
917 | }
918 | },
919 | "node_modules/setprototypeof": {
920 | "version": "1.2.0",
921 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
922 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
923 | },
924 | "node_modules/side-channel": {
925 | "version": "1.0.4",
926 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
927 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
928 | "dependencies": {
929 | "call-bind": "^1.0.0",
930 | "get-intrinsic": "^1.0.2",
931 | "object-inspect": "^1.9.0"
932 | },
933 | "funding": {
934 | "url": "https://github.com/sponsors/ljharb"
935 | }
936 | },
937 | "node_modules/simple-update-notifier": {
938 | "version": "1.1.0",
939 | "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz",
940 | "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==",
941 | "dev": true,
942 | "dependencies": {
943 | "semver": "~7.0.0"
944 | },
945 | "engines": {
946 | "node": ">=8.10.0"
947 | }
948 | },
949 | "node_modules/simple-update-notifier/node_modules/semver": {
950 | "version": "7.0.0",
951 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz",
952 | "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==",
953 | "dev": true,
954 | "bin": {
955 | "semver": "bin/semver.js"
956 | }
957 | },
958 | "node_modules/statuses": {
959 | "version": "2.0.1",
960 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
961 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
962 | "engines": {
963 | "node": ">= 0.8"
964 | }
965 | },
966 | "node_modules/supports-color": {
967 | "version": "5.5.0",
968 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
969 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
970 | "dev": true,
971 | "dependencies": {
972 | "has-flag": "^3.0.0"
973 | },
974 | "engines": {
975 | "node": ">=4"
976 | }
977 | },
978 | "node_modules/to-regex-range": {
979 | "version": "5.0.1",
980 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
981 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
982 | "dev": true,
983 | "dependencies": {
984 | "is-number": "^7.0.0"
985 | },
986 | "engines": {
987 | "node": ">=8.0"
988 | }
989 | },
990 | "node_modules/toidentifier": {
991 | "version": "1.0.1",
992 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
993 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
994 | "engines": {
995 | "node": ">=0.6"
996 | }
997 | },
998 | "node_modules/touch": {
999 | "version": "3.1.0",
1000 | "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
1001 | "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==",
1002 | "dev": true,
1003 | "dependencies": {
1004 | "nopt": "~1.0.10"
1005 | },
1006 | "bin": {
1007 | "nodetouch": "bin/nodetouch.js"
1008 | }
1009 | },
1010 | "node_modules/type-is": {
1011 | "version": "1.6.18",
1012 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
1013 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
1014 | "dependencies": {
1015 | "media-typer": "0.3.0",
1016 | "mime-types": "~2.1.24"
1017 | },
1018 | "engines": {
1019 | "node": ">= 0.6"
1020 | }
1021 | },
1022 | "node_modules/undefsafe": {
1023 | "version": "2.0.5",
1024 | "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
1025 | "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
1026 | "dev": true
1027 | },
1028 | "node_modules/unpipe": {
1029 | "version": "1.0.0",
1030 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
1031 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
1032 | "engines": {
1033 | "node": ">= 0.8"
1034 | }
1035 | },
1036 | "node_modules/utils-merge": {
1037 | "version": "1.0.1",
1038 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
1039 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
1040 | "engines": {
1041 | "node": ">= 0.4.0"
1042 | }
1043 | },
1044 | "node_modules/vary": {
1045 | "version": "1.1.2",
1046 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
1047 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
1048 | "engines": {
1049 | "node": ">= 0.8"
1050 | }
1051 | }
1052 | },
1053 | "dependencies": {
1054 | "abbrev": {
1055 | "version": "1.1.1",
1056 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
1057 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
1058 | "dev": true
1059 | },
1060 | "accepts": {
1061 | "version": "1.3.8",
1062 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
1063 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
1064 | "requires": {
1065 | "mime-types": "~2.1.34",
1066 | "negotiator": "0.6.3"
1067 | }
1068 | },
1069 | "anymatch": {
1070 | "version": "3.1.3",
1071 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
1072 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
1073 | "dev": true,
1074 | "requires": {
1075 | "normalize-path": "^3.0.0",
1076 | "picomatch": "^2.0.4"
1077 | }
1078 | },
1079 | "array-flatten": {
1080 | "version": "1.1.1",
1081 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
1082 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
1083 | },
1084 | "asynckit": {
1085 | "version": "0.4.0",
1086 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
1087 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
1088 | },
1089 | "axios": {
1090 | "version": "1.2.2",
1091 | "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.2.tgz",
1092 | "integrity": "sha512-bz/J4gS2S3I7mpN/YZfGFTqhXTYzRho8Ay38w2otuuDR322KzFIWm/4W2K6gIwvWaws5n+mnb7D1lN9uD+QH6Q==",
1093 | "requires": {
1094 | "follow-redirects": "^1.15.0",
1095 | "form-data": "^4.0.0",
1096 | "proxy-from-env": "^1.1.0"
1097 | }
1098 | },
1099 | "balanced-match": {
1100 | "version": "1.0.2",
1101 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
1102 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
1103 | "dev": true
1104 | },
1105 | "binary-extensions": {
1106 | "version": "2.2.0",
1107 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
1108 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
1109 | "dev": true
1110 | },
1111 | "body-parser": {
1112 | "version": "1.20.1",
1113 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
1114 | "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
1115 | "requires": {
1116 | "bytes": "3.1.2",
1117 | "content-type": "~1.0.4",
1118 | "debug": "2.6.9",
1119 | "depd": "2.0.0",
1120 | "destroy": "1.2.0",
1121 | "http-errors": "2.0.0",
1122 | "iconv-lite": "0.4.24",
1123 | "on-finished": "2.4.1",
1124 | "qs": "6.11.0",
1125 | "raw-body": "2.5.1",
1126 | "type-is": "~1.6.18",
1127 | "unpipe": "1.0.0"
1128 | }
1129 | },
1130 | "brace-expansion": {
1131 | "version": "1.1.11",
1132 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
1133 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
1134 | "dev": true,
1135 | "requires": {
1136 | "balanced-match": "^1.0.0",
1137 | "concat-map": "0.0.1"
1138 | }
1139 | },
1140 | "braces": {
1141 | "version": "3.0.2",
1142 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
1143 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
1144 | "dev": true,
1145 | "requires": {
1146 | "fill-range": "^7.0.1"
1147 | }
1148 | },
1149 | "bytes": {
1150 | "version": "3.1.2",
1151 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
1152 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="
1153 | },
1154 | "call-bind": {
1155 | "version": "1.0.2",
1156 | "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
1157 | "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
1158 | "requires": {
1159 | "function-bind": "^1.1.1",
1160 | "get-intrinsic": "^1.0.2"
1161 | }
1162 | },
1163 | "chokidar": {
1164 | "version": "3.5.3",
1165 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
1166 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
1167 | "dev": true,
1168 | "requires": {
1169 | "anymatch": "~3.1.2",
1170 | "braces": "~3.0.2",
1171 | "fsevents": "~2.3.2",
1172 | "glob-parent": "~5.1.2",
1173 | "is-binary-path": "~2.1.0",
1174 | "is-glob": "~4.0.1",
1175 | "normalize-path": "~3.0.0",
1176 | "readdirp": "~3.6.0"
1177 | }
1178 | },
1179 | "combined-stream": {
1180 | "version": "1.0.8",
1181 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
1182 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
1183 | "requires": {
1184 | "delayed-stream": "~1.0.0"
1185 | }
1186 | },
1187 | "concat-map": {
1188 | "version": "0.0.1",
1189 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
1190 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
1191 | "dev": true
1192 | },
1193 | "content-disposition": {
1194 | "version": "0.5.4",
1195 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
1196 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
1197 | "requires": {
1198 | "safe-buffer": "5.2.1"
1199 | }
1200 | },
1201 | "content-type": {
1202 | "version": "1.0.4",
1203 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
1204 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
1205 | },
1206 | "cookie": {
1207 | "version": "0.5.0",
1208 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
1209 | "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw=="
1210 | },
1211 | "cookie-signature": {
1212 | "version": "1.0.6",
1213 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
1214 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
1215 | },
1216 | "cors": {
1217 | "version": "2.8.5",
1218 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
1219 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
1220 | "requires": {
1221 | "object-assign": "^4",
1222 | "vary": "^1"
1223 | }
1224 | },
1225 | "debug": {
1226 | "version": "2.6.9",
1227 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
1228 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
1229 | "requires": {
1230 | "ms": "2.0.0"
1231 | }
1232 | },
1233 | "delayed-stream": {
1234 | "version": "1.0.0",
1235 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
1236 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
1237 | },
1238 | "depd": {
1239 | "version": "2.0.0",
1240 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
1241 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
1242 | },
1243 | "destroy": {
1244 | "version": "1.2.0",
1245 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
1246 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="
1247 | },
1248 | "ee-first": {
1249 | "version": "1.1.1",
1250 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
1251 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
1252 | },
1253 | "encodeurl": {
1254 | "version": "1.0.2",
1255 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
1256 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w=="
1257 | },
1258 | "escape-html": {
1259 | "version": "1.0.3",
1260 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
1261 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
1262 | },
1263 | "etag": {
1264 | "version": "1.8.1",
1265 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
1266 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="
1267 | },
1268 | "express": {
1269 | "version": "4.18.2",
1270 | "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
1271 | "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
1272 | "requires": {
1273 | "accepts": "~1.3.8",
1274 | "array-flatten": "1.1.1",
1275 | "body-parser": "1.20.1",
1276 | "content-disposition": "0.5.4",
1277 | "content-type": "~1.0.4",
1278 | "cookie": "0.5.0",
1279 | "cookie-signature": "1.0.6",
1280 | "debug": "2.6.9",
1281 | "depd": "2.0.0",
1282 | "encodeurl": "~1.0.2",
1283 | "escape-html": "~1.0.3",
1284 | "etag": "~1.8.1",
1285 | "finalhandler": "1.2.0",
1286 | "fresh": "0.5.2",
1287 | "http-errors": "2.0.0",
1288 | "merge-descriptors": "1.0.1",
1289 | "methods": "~1.1.2",
1290 | "on-finished": "2.4.1",
1291 | "parseurl": "~1.3.3",
1292 | "path-to-regexp": "0.1.7",
1293 | "proxy-addr": "~2.0.7",
1294 | "qs": "6.11.0",
1295 | "range-parser": "~1.2.1",
1296 | "safe-buffer": "5.2.1",
1297 | "send": "0.18.0",
1298 | "serve-static": "1.15.0",
1299 | "setprototypeof": "1.2.0",
1300 | "statuses": "2.0.1",
1301 | "type-is": "~1.6.18",
1302 | "utils-merge": "1.0.1",
1303 | "vary": "~1.1.2"
1304 | }
1305 | },
1306 | "fill-range": {
1307 | "version": "7.0.1",
1308 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
1309 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
1310 | "dev": true,
1311 | "requires": {
1312 | "to-regex-range": "^5.0.1"
1313 | }
1314 | },
1315 | "finalhandler": {
1316 | "version": "1.2.0",
1317 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
1318 | "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
1319 | "requires": {
1320 | "debug": "2.6.9",
1321 | "encodeurl": "~1.0.2",
1322 | "escape-html": "~1.0.3",
1323 | "on-finished": "2.4.1",
1324 | "parseurl": "~1.3.3",
1325 | "statuses": "2.0.1",
1326 | "unpipe": "~1.0.0"
1327 | }
1328 | },
1329 | "follow-redirects": {
1330 | "version": "1.15.2",
1331 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
1332 | "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA=="
1333 | },
1334 | "form-data": {
1335 | "version": "4.0.0",
1336 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
1337 | "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
1338 | "requires": {
1339 | "asynckit": "^0.4.0",
1340 | "combined-stream": "^1.0.8",
1341 | "mime-types": "^2.1.12"
1342 | }
1343 | },
1344 | "forwarded": {
1345 | "version": "0.2.0",
1346 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
1347 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
1348 | },
1349 | "fresh": {
1350 | "version": "0.5.2",
1351 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
1352 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="
1353 | },
1354 | "fsevents": {
1355 | "version": "2.3.2",
1356 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
1357 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
1358 | "dev": true,
1359 | "optional": true
1360 | },
1361 | "function-bind": {
1362 | "version": "1.1.1",
1363 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
1364 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
1365 | },
1366 | "get-intrinsic": {
1367 | "version": "1.1.3",
1368 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
1369 | "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==",
1370 | "requires": {
1371 | "function-bind": "^1.1.1",
1372 | "has": "^1.0.3",
1373 | "has-symbols": "^1.0.3"
1374 | }
1375 | },
1376 | "glob-parent": {
1377 | "version": "5.1.2",
1378 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
1379 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
1380 | "dev": true,
1381 | "requires": {
1382 | "is-glob": "^4.0.1"
1383 | }
1384 | },
1385 | "has": {
1386 | "version": "1.0.3",
1387 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
1388 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
1389 | "requires": {
1390 | "function-bind": "^1.1.1"
1391 | }
1392 | },
1393 | "has-flag": {
1394 | "version": "3.0.0",
1395 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
1396 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
1397 | "dev": true
1398 | },
1399 | "has-symbols": {
1400 | "version": "1.0.3",
1401 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
1402 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A=="
1403 | },
1404 | "http-errors": {
1405 | "version": "2.0.0",
1406 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
1407 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
1408 | "requires": {
1409 | "depd": "2.0.0",
1410 | "inherits": "2.0.4",
1411 | "setprototypeof": "1.2.0",
1412 | "statuses": "2.0.1",
1413 | "toidentifier": "1.0.1"
1414 | }
1415 | },
1416 | "iconv-lite": {
1417 | "version": "0.4.24",
1418 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
1419 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
1420 | "requires": {
1421 | "safer-buffer": ">= 2.1.2 < 3"
1422 | }
1423 | },
1424 | "ignore-by-default": {
1425 | "version": "1.0.1",
1426 | "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
1427 | "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
1428 | "dev": true
1429 | },
1430 | "inherits": {
1431 | "version": "2.0.4",
1432 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
1433 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
1434 | },
1435 | "ipaddr.js": {
1436 | "version": "1.9.1",
1437 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
1438 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
1439 | },
1440 | "is-binary-path": {
1441 | "version": "2.1.0",
1442 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
1443 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
1444 | "dev": true,
1445 | "requires": {
1446 | "binary-extensions": "^2.0.0"
1447 | }
1448 | },
1449 | "is-extglob": {
1450 | "version": "2.1.1",
1451 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
1452 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
1453 | "dev": true
1454 | },
1455 | "is-glob": {
1456 | "version": "4.0.3",
1457 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
1458 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
1459 | "dev": true,
1460 | "requires": {
1461 | "is-extglob": "^2.1.1"
1462 | }
1463 | },
1464 | "is-number": {
1465 | "version": "7.0.0",
1466 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
1467 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
1468 | "dev": true
1469 | },
1470 | "media-typer": {
1471 | "version": "0.3.0",
1472 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
1473 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="
1474 | },
1475 | "merge-descriptors": {
1476 | "version": "1.0.1",
1477 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
1478 | "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
1479 | },
1480 | "methods": {
1481 | "version": "1.1.2",
1482 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
1483 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="
1484 | },
1485 | "mime": {
1486 | "version": "1.6.0",
1487 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
1488 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
1489 | },
1490 | "mime-db": {
1491 | "version": "1.52.0",
1492 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
1493 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
1494 | },
1495 | "mime-types": {
1496 | "version": "2.1.35",
1497 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
1498 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
1499 | "requires": {
1500 | "mime-db": "1.52.0"
1501 | }
1502 | },
1503 | "minimatch": {
1504 | "version": "3.1.2",
1505 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
1506 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
1507 | "dev": true,
1508 | "requires": {
1509 | "brace-expansion": "^1.1.7"
1510 | }
1511 | },
1512 | "ms": {
1513 | "version": "2.0.0",
1514 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
1515 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
1516 | },
1517 | "negotiator": {
1518 | "version": "0.6.3",
1519 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
1520 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
1521 | },
1522 | "nodemon": {
1523 | "version": "2.0.20",
1524 | "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz",
1525 | "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==",
1526 | "dev": true,
1527 | "requires": {
1528 | "chokidar": "^3.5.2",
1529 | "debug": "^3.2.7",
1530 | "ignore-by-default": "^1.0.1",
1531 | "minimatch": "^3.1.2",
1532 | "pstree.remy": "^1.1.8",
1533 | "semver": "^5.7.1",
1534 | "simple-update-notifier": "^1.0.7",
1535 | "supports-color": "^5.5.0",
1536 | "touch": "^3.1.0",
1537 | "undefsafe": "^2.0.5"
1538 | },
1539 | "dependencies": {
1540 | "debug": {
1541 | "version": "3.2.7",
1542 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
1543 | "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
1544 | "dev": true,
1545 | "requires": {
1546 | "ms": "^2.1.1"
1547 | }
1548 | },
1549 | "ms": {
1550 | "version": "2.1.3",
1551 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1552 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
1553 | "dev": true
1554 | }
1555 | }
1556 | },
1557 | "nopt": {
1558 | "version": "1.0.10",
1559 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
1560 | "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==",
1561 | "dev": true,
1562 | "requires": {
1563 | "abbrev": "1"
1564 | }
1565 | },
1566 | "normalize-path": {
1567 | "version": "3.0.0",
1568 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
1569 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
1570 | "dev": true
1571 | },
1572 | "object-assign": {
1573 | "version": "4.1.1",
1574 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
1575 | "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
1576 | },
1577 | "object-inspect": {
1578 | "version": "1.12.3",
1579 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
1580 | "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g=="
1581 | },
1582 | "on-finished": {
1583 | "version": "2.4.1",
1584 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
1585 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
1586 | "requires": {
1587 | "ee-first": "1.1.1"
1588 | }
1589 | },
1590 | "parseurl": {
1591 | "version": "1.3.3",
1592 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
1593 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
1594 | },
1595 | "path-to-regexp": {
1596 | "version": "0.1.7",
1597 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
1598 | "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
1599 | },
1600 | "picomatch": {
1601 | "version": "2.3.1",
1602 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
1603 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
1604 | "dev": true
1605 | },
1606 | "proxy-addr": {
1607 | "version": "2.0.7",
1608 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
1609 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
1610 | "requires": {
1611 | "forwarded": "0.2.0",
1612 | "ipaddr.js": "1.9.1"
1613 | }
1614 | },
1615 | "proxy-from-env": {
1616 | "version": "1.1.0",
1617 | "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
1618 | "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
1619 | },
1620 | "pstree.remy": {
1621 | "version": "1.1.8",
1622 | "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
1623 | "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
1624 | "dev": true
1625 | },
1626 | "qs": {
1627 | "version": "6.11.0",
1628 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
1629 | "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
1630 | "requires": {
1631 | "side-channel": "^1.0.4"
1632 | }
1633 | },
1634 | "range-parser": {
1635 | "version": "1.2.1",
1636 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
1637 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
1638 | },
1639 | "raw-body": {
1640 | "version": "2.5.1",
1641 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
1642 | "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
1643 | "requires": {
1644 | "bytes": "3.1.2",
1645 | "http-errors": "2.0.0",
1646 | "iconv-lite": "0.4.24",
1647 | "unpipe": "1.0.0"
1648 | }
1649 | },
1650 | "readdirp": {
1651 | "version": "3.6.0",
1652 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
1653 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
1654 | "dev": true,
1655 | "requires": {
1656 | "picomatch": "^2.2.1"
1657 | }
1658 | },
1659 | "safe-buffer": {
1660 | "version": "5.2.1",
1661 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
1662 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
1663 | },
1664 | "safer-buffer": {
1665 | "version": "2.1.2",
1666 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
1667 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
1668 | },
1669 | "semver": {
1670 | "version": "5.7.1",
1671 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
1672 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
1673 | "dev": true
1674 | },
1675 | "send": {
1676 | "version": "0.18.0",
1677 | "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
1678 | "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
1679 | "requires": {
1680 | "debug": "2.6.9",
1681 | "depd": "2.0.0",
1682 | "destroy": "1.2.0",
1683 | "encodeurl": "~1.0.2",
1684 | "escape-html": "~1.0.3",
1685 | "etag": "~1.8.1",
1686 | "fresh": "0.5.2",
1687 | "http-errors": "2.0.0",
1688 | "mime": "1.6.0",
1689 | "ms": "2.1.3",
1690 | "on-finished": "2.4.1",
1691 | "range-parser": "~1.2.1",
1692 | "statuses": "2.0.1"
1693 | },
1694 | "dependencies": {
1695 | "ms": {
1696 | "version": "2.1.3",
1697 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1698 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
1699 | }
1700 | }
1701 | },
1702 | "serve-static": {
1703 | "version": "1.15.0",
1704 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
1705 | "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
1706 | "requires": {
1707 | "encodeurl": "~1.0.2",
1708 | "escape-html": "~1.0.3",
1709 | "parseurl": "~1.3.3",
1710 | "send": "0.18.0"
1711 | }
1712 | },
1713 | "setprototypeof": {
1714 | "version": "1.2.0",
1715 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
1716 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
1717 | },
1718 | "side-channel": {
1719 | "version": "1.0.4",
1720 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
1721 | "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
1722 | "requires": {
1723 | "call-bind": "^1.0.0",
1724 | "get-intrinsic": "^1.0.2",
1725 | "object-inspect": "^1.9.0"
1726 | }
1727 | },
1728 | "simple-update-notifier": {
1729 | "version": "1.1.0",
1730 | "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz",
1731 | "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==",
1732 | "dev": true,
1733 | "requires": {
1734 | "semver": "~7.0.0"
1735 | },
1736 | "dependencies": {
1737 | "semver": {
1738 | "version": "7.0.0",
1739 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz",
1740 | "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==",
1741 | "dev": true
1742 | }
1743 | }
1744 | },
1745 | "statuses": {
1746 | "version": "2.0.1",
1747 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
1748 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
1749 | },
1750 | "supports-color": {
1751 | "version": "5.5.0",
1752 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
1753 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
1754 | "dev": true,
1755 | "requires": {
1756 | "has-flag": "^3.0.0"
1757 | }
1758 | },
1759 | "to-regex-range": {
1760 | "version": "5.0.1",
1761 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
1762 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
1763 | "dev": true,
1764 | "requires": {
1765 | "is-number": "^7.0.0"
1766 | }
1767 | },
1768 | "toidentifier": {
1769 | "version": "1.0.1",
1770 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
1771 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
1772 | },
1773 | "touch": {
1774 | "version": "3.1.0",
1775 | "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
1776 | "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==",
1777 | "dev": true,
1778 | "requires": {
1779 | "nopt": "~1.0.10"
1780 | }
1781 | },
1782 | "type-is": {
1783 | "version": "1.6.18",
1784 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
1785 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
1786 | "requires": {
1787 | "media-typer": "0.3.0",
1788 | "mime-types": "~2.1.24"
1789 | }
1790 | },
1791 | "undefsafe": {
1792 | "version": "2.0.5",
1793 | "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
1794 | "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
1795 | "dev": true
1796 | },
1797 | "unpipe": {
1798 | "version": "1.0.0",
1799 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
1800 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="
1801 | },
1802 | "utils-merge": {
1803 | "version": "1.0.1",
1804 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
1805 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA=="
1806 | },
1807 | "vary": {
1808 | "version": "1.1.2",
1809 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
1810 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="
1811 | }
1812 | }
1813 | }
1814 |
--------------------------------------------------------------------------------