diff --git a/.gitignore b/.gitignore
index 6272634..b90905f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,3 @@
-# Local Netlify folder
-.netlify
node_modules
elm-stuff
.cache
diff --git a/app.js b/app.js
new file mode 100644
index 0000000..07fe4f3
--- /dev/null
+++ b/app.js
@@ -0,0 +1,21 @@
+require('dotenv').config();
+const express = require('express');
+const path = require('path');
+const bodyParser = require('body-parser');
+const { routes } = require('./server');
+
+const PORT = process.env.PORT || 8080;
+
+const app = express();
+
+app.use(express.json());
+
+routes.forEach((route) => {
+ route = route.module;
+
+ app[route.method](route.path, route.handler);
+});
+
+app.listen(PORT, () => {
+ console.log(`Server is listening on port ${PORT}`);
+});
diff --git a/functions/login-api.js b/functions/login-api.js
deleted file mode 100644
index b4d3f7d..0000000
--- a/functions/login-api.js
+++ /dev/null
@@ -1,110 +0,0 @@
-// const { createClient } = require('@astrajs/collections');
-const bcrypt = require('bcrypt');
-const jwt = require('jsonwebtoken');
-const { v4: uuid } = require('uuid');
-const { clientPromise } = require('../connect-database');
-
-exports.handler = async function (req) {
- const { body, httpMethod } = req;
- let client;
- let parsedBody;
-
- try {
- client = await clientPromise;
- } catch (err) {
- console.log('Client: ', err);
- client = err.toString();
- }
-
- if (httpMethod !== 'POST')
- return {
- statusCode: 403,
- };
-
- if (!client || typeof client?.execute !== 'function') {
- return {
- statusCode: 500,
- body: `{message: There is no client, payload: ${client}}`,
- };
- }
-
- try {
- parsedBody = JSON.parse(body);
- } catch (error) {
- return {
- statusCode: 500,
- body: error.toString(error),
- };
- }
-
- const { email, password } = parsedBody;
- // const astraClient = await createClient({
- // astraDatabaseId: process.env.ASTRA_DB_ID,
- // astraDatabaseRegion: process.env.ASTRA_DB_REGION,
- // applicationToken: process.env.ASTRA_DB_APPLICATION_TOKEN,
- // });
-
- // const usersCollection = astraClient
- // .namespace(process.env.ASTRA_DB_KEYSPACE)
- // .collection('users');
-
- // const user = await usersCollection.findOne({ email: { $eq: email } });
- const findUser = async (parameters) => {
- const query = `SELECT * FROM ${
- process.env.NODE_ENV === 'development'
- ? process.env.ASTRA_DB_KEYSPACE
- : process.env.ASTRA_DB_KEYSPACE_PROD
- }.users WHERE email = ? ALLOW FILTERING;`;
- try {
- const result = client.execute(query, parameters, { prepare: true });
-
- return result;
- } catch (ex) {
- console.log('Error in finduser', ex.toString());
- }
- };
- const user = await findUser([email]);
-
- if (!user?.rows[0]) {
- return {
- statusCode: 401,
- };
- }
-
- const { id, isverified, passwordhash, salt, firstname, verificationstring, avatarurl } =
- user.rows[0];
- const pepper = process.env.PEPPER_STRING;
-
- const isCorrect = await bcrypt.compare(salt + password + pepper, passwordhash);
-
- if (isCorrect) {
- const token = jwt.sign(
- {
- id,
- isverified,
- email,
- firstname,
- verificationstring,
- profilepicurl: avatarurl || '',
- },
- process.env.JWT_SECRET,
- {
- expiresIn: '2h',
- },
- );
-
- if (!token)
- return {
- statusCode: 403,
- };
-
- return {
- statusCode: 200,
- body: JSON.stringify({ token }),
- };
- } else {
- return {
- statusCode: 401,
- };
- }
-};
diff --git a/functions/profile-put-api.js b/functions/profile-put-api.js
deleted file mode 100644
index 720cdcd..0000000
--- a/functions/profile-put-api.js
+++ /dev/null
@@ -1,186 +0,0 @@
-// const { createClient } = require('@astrajs/collections');
-const bcrypt = require('bcrypt');
-const jwt = require('jsonwebtoken');
-const { v4: uuid } = require('uuid');
-const { clientPromise } = require('../connect-database');
-const querystring = require('querystring').escape;
-const initializeApp = require('firebase/app').initializeApp;
-const {
- getStorage,
- ref,
- uploadBytes,
- getDownloadURL,
- getStream,
- uploadString,
-} = require('firebase/storage');
-
-exports.handler = async function (req) {
- const { body, httpMethod } = req;
- const { authorization } = req.headers;
- const client = await clientPromise;
- let parsedBody;
-
- if (httpMethod !== 'PUT')
- return {
- statusCode: 403,
- };
-
- if (!client)
- return {
- statusCode: 500,
- body: `There is no client: ${client.toString()}`,
- };
-
- try {
- parsedBody = JSON.parse(body);
- } catch (error) {
- return {
- statusCode: 500,
- body: error.toString(error),
- };
- }
-
- // const astraClient = await createClient({
- // astraDatabaseId: process.env.ASTRA_DB_ID,
- // astraDatabaseRegion: process.env.ASTRA_DB_REGION,
- // applicationToken: process.env.ASTRA_DB_APPLICATION_TOKEN,
- // });
-
- // const usersCollection = astraClient
- // .namespace(process.env.ASTRA_DB_KEYSPACE)
- // .collection('users');
-
- if (!authorization) {
- return {
- statusCode: 401,
- body: 'No authorization header sent',
- };
- }
- const { email, firstname, imagefile } = parsedBody;
- const token = authorization.split(' ')[1];
- // const user = await usersCollection.findOne({ email: { $eq: email } });
-
- let decodedToken;
-
- try {
- decodedToken = await jwt.verify(token, process.env.JWT_SECRET);
- } catch (err) {
- return {
- statusCode: 401,
- body: err.toString(),
- };
- }
-
- const firebaseConfig = {
- apiKey: process.env.FIREBASE_API_KEY,
- authDomain: process.env.FIREBASE_AUTH_DOMAIN,
- projectId: process.env.FIREBASE_PROJECT_ID,
- storageBucket: process.env.FIREBASE_STORAGE_BUCKET,
- messagingSenderId: process.env.FIREBASE_MESSAGING_SENDER_ID,
- appId: process.env.FIREBASE_APP_ID,
- measurementId: process.env.FIREBASE_MEASUREMENT_ID,
- };
-
- const app = initializeApp(firebaseConfig);
- const storage = getStorage(app);
-
- const { id } = decodedToken;
-
- let photoUrl = '';
-
- try {
- if (imagefile.length > 0) {
- await uploadString(
- ref(storage, `/images/profile-pic-${id}.jpeg`),
- imagefile,
- 'data_url',
- );
- const downloadUrl = await getDownloadURL(
- ref(storage, `/images/profile-pic-${id}.jpeg`),
- );
- photoUrl =
- downloadUrl.length > 0
- ? `https://firebasestorage.googleapis.com/v0/b/${
- process.env.FIREBASE_STORAGE_BUCKET
- }/o/${querystring(`images/profile-pic-${id}.jpeg`)}?alt=media`
- : '';
- }
- } catch (err) {
- return {
- statusCode: 403,
- };
- }
-
- const updateUser = async (parameters) => {
- const query = `UPDATE ${
- process.env.NODE_ENV === 'development'
- ? process.env.ASTRA_DB_KEYSPACE
- : process.env.ASTRA_DB_KEYSPACE_PROD
- }.users SET firstname = ?, avatarurl = ? WHERE id = ? IF EXISTS;`;
- try {
- const result = await client.execute(query, parameters, { prepare: true });
- // result would be undefined but query would be executed and entery is written in the DB
- return result;
- } catch (ex) {
- console.log('Error in createUser', ex.toString());
- }
- };
-
- const {
- rows: [applied],
- } = await updateUser([firstname, photoUrl, id]);
-
- if (!applied['[applied]']) {
- console.log('Unsuccessfull in updating user');
- return {
- statusCode: 404,
- };
- }
-
- const findUser = async (parameters) => {
- const query = `SELECT * FROM ${
- process.env.NODE_ENV === 'development'
- ? process.env.ASTRA_DB_KEYSPACE
- : process.env.ASTRA_DB_KEYSPACE_PROD
- }.users WHERE email = ? ALLOW FILTERING;`;
- try {
- const result = await client.execute(query, parameters, { prepare: true });
-
- return result;
- } catch (ex) {
- console.log('Error in finduser', ex.toString());
- }
- };
- const user = await findUser([email]);
- const {
- id: decodedId,
- isverified: isVerified,
- email: emailFromUser,
- firstname: firstName,
- verificationstring,
- avatarurl,
- } = user.rows[0];
-
- const newToken = jwt.sign(
- {
- id: decodedId,
- isverified: isVerified,
- email: emailFromUser,
- firstname: firstName,
- verificationstring,
- profilepicurl: avatarurl || '',
- },
- process.env.JWT_SECRET,
- { expiresIn: '2h' },
- );
-
- if (!newToken)
- return {
- statusCode: 403,
- };
-
- return {
- statusCode: 200,
- body: JSON.stringify({ token: newToken }),
- };
-};
diff --git a/functions/signup-api.js b/functions/signup-api.js
deleted file mode 100644
index 9723a28..0000000
--- a/functions/signup-api.js
+++ /dev/null
@@ -1,166 +0,0 @@
-// const { createClient } = require('@astrajs/collections');
-const cassandra = require('cassandra-driver');
-const bcrypt = require('bcrypt');
-const jwt = require('jsonwebtoken');
-const { v4: uuid } = require('uuid');
-const { clientPromise } = require('../connect-database');
-const sendgrid = require('@sendgrid/mail');
-
-sendgrid.setApiKey(process.env.SENDGRID_API_KEY);
-
-const sendEmail = ({ to, from, subject, text, html = '' }) => {
- const msg = { to, from, subject, text, html };
- return sendgrid.send(msg);
-};
-
-exports.handler = async function (req, context) {
- const { body, httpMethod } = req;
- let client;
- let parsedBody;
-
- try {
- client = await clientPromise;
- } catch (err) {
- console.log('Client: ', err);
- client = err.toString();
- }
-
- if (httpMethod !== 'POST')
- return {
- statusCode: 403,
- };
-
- if (!client || typeof client?.execute !== 'function') {
- return {
- statusCode: 500,
- body: `{message: There is no client, payload: ${client}}`,
- };
- }
-
- try {
- parsedBody = JSON.parse(body);
- } catch (error) {
- return {
- statusCode: 500,
- body: error.toString(error),
- };
- }
-
- const { email, password } = parsedBody;
- // const astraClient = await createClient({
- // astraDatabaseId: process.env.ASTRA_DB_ID,
- // astraDatabaseRegion: process.env.ASTRA_DB_REGION,
- // applicationToken: process.env.ASTRA_DB_APPLICATION_TOKEN,
- // });
-
- // const usersCollection = astraClient
- // .namespace(process.env.ASTRA_DB_KEYSPACE)
- // .collection('users');
- const findUser = async (parameters) => {
- const query = `SELECT * FROM ${
- process.env.NODE_ENV === 'development'
- ? process.env.ASTRA_DB_KEYSPACE
- : process.env.ASTRA_DB_KEYSPACE_PROD
- }.users WHERE email = ? ALLOW FILTERING;`;
- try {
- const result = client.execute(query, parameters, { prepare: true });
- return result;
- } catch (ex) {
- console.log('Error in finduser', ex.toString());
- }
- };
-
- const user = await findUser([email]);
-
- if (user?.rows[0]) {
- // conflict error code
- return {
- statusCode: 409,
- };
- }
- const salt = uuid();
- const pepper = process.env.PEPPER_STRING;
- const passwordHash = await bcrypt.hash(salt + password + pepper, 10); // 2 arg is num of iterations to
- const verificationString = uuid();
- const createdId = uuid();
-
- const createUser = async (parameters) => {
- const query = `INSERT INTO ${
- process.env.NODE_ENV === 'development'
- ? process.env.ASTRA_DB_KEYSPACE
- : process.env.ASTRA_DB_KEYSPACE_PROD
- }.users (id, email, firstname, isadmin, isverified, lastname, passwordhash, salt, verificationstring, avatarurl) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);`;
- try {
- const result = await client.execute(query, parameters, { prepare: true });
- // result would be undefined but query would be executed and entery is wirtten in the DB
- return result;
- } catch (ex) {
- console.log('Error in createUser', ex.toString());
- }
- };
-
- const createdUser = await createUser([
- createdId,
- email,
- '',
- false,
- false,
- '',
- passwordHash,
- salt,
- verificationString,
- '',
- ]);
-
- try {
- await sendEmail({
- to: email,
- from: 'dooshanstevanovic@gmail.com',
- subject: 'Please verify your email',
- text: `Thanks for signin up ! To verify your email click here: ${
- process.env.NODE_ENV === 'development'
- ? 'http://localhost:8888'
- : 'https://my-elm-app.netlify.app'
- }/verify-email/${verificationString}`,
- html: `
-
Hello !
-
-
Thanks for signin up !
-
To verify your email click here
-
-
`,
- });
- } catch (err) {
- console.log('Error in signUp', err.response.body.errors);
- return {
- statusCode: 500,
- };
- }
-
- const token = jwt.sign(
- {
- id: createdId,
- isverified: false,
- email,
- firstname: '',
- verificationstring: verificationString,
- profilepicurl: '',
- },
- process.env.JWT_SECRET,
- { expiresIn: '2h' },
- );
-
- if (!token)
- return {
- statusCode: 403,
- };
-
- return {
- statusCode: 200,
- body: JSON.stringify({ token }),
- };
-};
diff --git a/functions/verify-put-api.js b/functions/verify-put-api.js
deleted file mode 100644
index 627b479..0000000
--- a/functions/verify-put-api.js
+++ /dev/null
@@ -1,121 +0,0 @@
-const bcrypt = require('bcrypt');
-const jwt = require('jsonwebtoken');
-const { v4: uuid } = require('uuid');
-const { clientPromise } = require('../connect-database');
-
-exports.handler = async function (req) {
- const { httpMethod } = req;
- const { authorization } = req.headers;
- const client = await clientPromise;
-
- if (httpMethod !== 'PUT')
- return {
- statusCode: 403,
- };
-
- if (!client)
- return {
- statusCode: 500,
- body: `There is no client: ${client.toString()}`,
- };
-
- if (!authorization) {
- return {
- statusCode: 401,
- body: 'No authorization header sent',
- };
- }
-
- const token = authorization.split(' ')[1];
-
- let decodedToken;
-
- try {
- decodedToken = await jwt.verify(token, process.env.JWT_SECRET);
- } catch (err) {
- return {
- statusCode: 401,
- body: err.toString(),
- };
- }
-
- const { id, email, isverified } = decodedToken;
-
- const updateUser = async (parameters) => {
- const query = `UPDATE ${
- process.env.NODE_ENV === 'development'
- ? process.env.ASTRA_DB_KEYSPACE
- : process.env.ASTRA_DB_KEYSPACE_PROD
- }.users SET isverified = True WHERE id = ? IF EXISTS;`;
- try {
- const result = await client.execute(query, parameters, { prepare: true });
- // result would be undefined but query would be executed and entery is wirtten in the DB
- return result;
- } catch (ex) {
- console.log('Error in createUser', ex.toString());
- }
- };
-
- if (isverified) {
- return {
- statusCode: 200,
- body: JSON.stringify({ token }),
- };
- }
-
- const {
- rows: [applied],
- } = await updateUser([id]);
-
- if (!applied['[applied]']) {
- console.log('Unsuccessfull in updating user');
- return {
- statusCode: 404,
- };
- }
-
- const findUser = async (parameters) => {
- const query = `SELECT * FROM ${
- process.env.NODE_ENV === 'development'
- ? process.env.ASTRA_DB_KEYSPACE
- : process.env.ASTRA_DB_KEYSPACE_PROD
- }.users WHERE email = ? ALLOW FILTERING;`;
- try {
- const result = await client.execute(query, parameters, { prepare: true });
-
- return result;
- } catch (ex) {
- console.log('Error in finduser', ex.toString());
- }
- };
- const user = await findUser([email]);
- const {
- id: decodedId,
- isverified: isVerified,
- email: emailFromUser,
- verificationstring,
- } = user.rows[0];
-
- const newToken = jwt.sign(
- {
- id: decodedId,
- isverified: true,
- email: emailFromUser,
- firstname: '',
- verificationstring,
- profilepicurl: '',
- },
- process.env.JWT_SECRET,
- { expiresIn: '2h' },
- );
-
- if (!newToken)
- return {
- statusCode: 403,
- };
-
- return {
- statusCode: 200,
- body: JSON.stringify({ token: newToken }),
- };
-};
diff --git a/index.js b/index.js
index 446c62f..6a361cf 100644
--- a/index.js
+++ b/index.js
@@ -5953,6 +5953,12 @@ var $author$project$Credentials$decodeToSession = F2(
return $author$project$Credentials$Guest;
}
});
+var $author$project$Main$ChatPage = function (a) {
+ return {$: 'ChatPage', a: a};
+};
+var $author$project$Main$GotChatMsg = function (a) {
+ return {$: 'GotChatMsg', a: a};
+};
var $author$project$Main$GotHomeMsg = function (a) {
return {$: 'GotHomeMsg', a: a};
};
@@ -5984,28 +5990,6 @@ var $author$project$Main$SignupPage = function (a) {
var $author$project$Main$VerificationPage = function (a) {
return {$: 'VerificationPage', a: a};
};
-var $author$project$Home$initialModel = {};
-var $elm$core$Platform$Cmd$batch = _Platform_batch;
-var $elm$core$Platform$Cmd$none = $elm$core$Platform$Cmd$batch(_List_Nil);
-var $author$project$Home$init = function (_v0) {
- return _Utils_Tuple2($author$project$Home$initialModel, $elm$core$Platform$Cmd$none);
-};
-var $author$project$Login$initialModel = {
- errors: _List_Nil,
- isLoading: false,
- loginCredentials: {email: '', password: ''}
-};
-var $author$project$Login$init = function (_v0) {
- return _Utils_Tuple2($author$project$Login$initialModel, $elm$core$Platform$Cmd$none);
-};
-var $author$project$Profile$GotTime = function (a) {
- return {$: 'GotTime', a: a};
-};
-var $author$project$Profile$Intruder = {$: 'Intruder'};
-var $author$project$Profile$NotVerified = {$: 'NotVerified'};
-var $author$project$Profile$Verified = function (a) {
- return {$: 'Verified', a: a};
-};
var $simonh1000$elm_jwt$Jwt$TokenDecodeError = function (a) {
return {$: 'TokenDecodeError', a: a};
};
@@ -6668,6 +6652,77 @@ var $author$project$Credentials$fromTokenToString = function (_v0) {
var string = _v0.a;
return string;
};
+var $author$project$Chat$initialModel = {
+ message: '',
+ receivedSocketData: {
+ clientId: '',
+ connectionId: '',
+ data: {message: ''},
+ id: '',
+ name: '',
+ timestamp: 0
+ }
+};
+var $elm$json$Json$Encode$string = _Json_wrap;
+var $author$project$Credentials$initiateSocketChannel = _Platform_outgoingPort('initiateSocketChannel', $elm$json$Json$Encode$string);
+var $elm$core$Platform$Cmd$batch = _Platform_batch;
+var $elm$core$Platform$Cmd$none = $elm$core$Platform$Cmd$batch(_List_Nil);
+var $author$project$Credentials$userIdToString = function (_v0) {
+ var id = _v0.a;
+ return id;
+};
+var $author$project$Chat$init = F2(
+ function (session, maybeSocket) {
+ var _v0 = $author$project$Credentials$fromSessionToToken(session);
+ if (_v0.$ === 'Just') {
+ var token = _v0.a;
+ var _v1 = A2(
+ $simonh1000$elm_jwt$Jwt$decodeToken,
+ $author$project$Credentials$decodeTokenData,
+ $author$project$Credentials$fromTokenToString(token));
+ if (_v1.$ === 'Ok') {
+ var resultTokenRecord = _v1.a;
+ if (maybeSocket.$ === 'Just') {
+ var receivedSocketData = maybeSocket.a;
+ return _Utils_Tuple2(
+ _Utils_update(
+ $author$project$Chat$initialModel,
+ {receivedSocketData: receivedSocketData}),
+ $author$project$Credentials$initiateSocketChannel(
+ $author$project$Credentials$userIdToString(resultTokenRecord.id)));
+ } else {
+ return _Utils_Tuple2(
+ $author$project$Chat$initialModel,
+ $author$project$Credentials$initiateSocketChannel(
+ $author$project$Credentials$userIdToString(resultTokenRecord.id)));
+ }
+ } else {
+ return _Utils_Tuple2($author$project$Chat$initialModel, $elm$core$Platform$Cmd$none);
+ }
+ } else {
+ return _Utils_Tuple2($author$project$Chat$initialModel, $elm$core$Platform$Cmd$none);
+ }
+ });
+var $author$project$Home$initialModel = {};
+var $author$project$Home$init = function (_v0) {
+ return _Utils_Tuple2($author$project$Home$initialModel, $elm$core$Platform$Cmd$none);
+};
+var $author$project$Login$initialModel = {
+ errors: _List_Nil,
+ isLoading: false,
+ loginCredentials: {email: '', password: ''}
+};
+var $author$project$Login$init = function (_v0) {
+ return _Utils_Tuple2($author$project$Login$initialModel, $elm$core$Platform$Cmd$none);
+};
+var $author$project$Profile$GotTime = function (a) {
+ return {$: 'GotTime', a: a};
+};
+var $author$project$Profile$Intruder = {$: 'Intruder'};
+var $author$project$Profile$NotVerified = {$: 'NotVerified'};
+var $author$project$Profile$Verified = function (a) {
+ return {$: 'Verified', a: a};
+};
var $author$project$Credentials$emptyImageString = $author$project$Credentials$ImageString($elm$core$Maybe$Nothing);
var $author$project$Credentials$emptyUserId = $author$project$Credentials$UserId('');
var $author$project$Credentials$emptyVerificationString = $author$project$Credentials$VerificationString('');
@@ -6835,10 +6890,21 @@ var $author$project$Main$initCurrentPage = function (_v0) {
page: $author$project$Main$HomePage(pageModel)
}),
A2($elm$core$Platform$Cmd$map, $author$project$Main$GotHomeMsg, pageCmds));
- case 'VerificationPage':
- var _v5 = A2($author$project$Verification$init, model.session, url.path);
+ case 'ChatPage':
+ var _v5 = A2($author$project$Chat$init, model.session, $elm$core$Maybe$Nothing);
var pageModel = _v5.a;
var pageCmds = _v5.b;
+ return _Utils_Tuple2(
+ _Utils_update(
+ model,
+ {
+ page: $author$project$Main$ChatPage(pageModel)
+ }),
+ A2($elm$core$Platform$Cmd$map, $author$project$Main$GotChatMsg, pageCmds));
+ case 'VerificationPage':
+ var _v6 = A2($author$project$Verification$init, model.session, url.path);
+ var pageModel = _v6.a;
+ var pageCmds = _v6.b;
return _Utils_Tuple2(
_Utils_update(
model,
@@ -6847,9 +6913,9 @@ var $author$project$Main$initCurrentPage = function (_v0) {
}),
A2($elm$core$Platform$Cmd$map, $author$project$Main$GotVerificationMsg, pageCmds));
default:
- var _v6 = $author$project$Profile$init(model.session);
- var pageModel = _v6.a;
- var pageCmds = _v6.b;
+ var _v7 = $author$project$Profile$init(model.session);
+ var pageModel = _v7.a;
+ var pageCmds = _v7.b;
return _Utils_Tuple2(
_Utils_update(
model,
@@ -6859,6 +6925,7 @@ var $author$project$Main$initCurrentPage = function (_v0) {
A2($elm$core$Platform$Cmd$map, $author$project$Main$GotProfileMsg, pageCmds));
}
};
+var $author$project$Main$Chat = {$: 'Chat'};
var $author$project$Main$Home = {$: 'Home'};
var $author$project$Main$Login = {$: 'Login'};
var $author$project$Main$Profile = function (a) {
@@ -7050,6 +7117,10 @@ var $author$project$Main$matchRoute = $elm$url$Url$Parser$oneOf(
$elm$url$Url$Parser$s('signup')),
A2(
$elm$url$Url$Parser$map,
+ $author$project$Main$Chat,
+ $elm$url$Url$Parser$s('chat')),
+ A2(
+ $elm$url$Url$Parser$map,
$author$project$Main$Verification,
A2(
$elm$url$Url$Parser$slash,
@@ -7725,12 +7796,21 @@ var $author$project$Main$urlToPage = F2(
} else {
return $author$project$Main$NotFoundPage;
}
- case 'Home':
+ case 'Chat':
var _v7 = _v0.a;
+ var _v8 = $author$project$Credentials$fromSessionToToken(session);
+ if (_v8.$ === 'Just') {
+ return $author$project$Main$ChatPage(
+ A2($author$project$Chat$init, session, $elm$core$Maybe$Nothing).a);
+ } else {
+ return $author$project$Main$NotFoundPage;
+ }
+ case 'Home':
+ var _v9 = _v0.a;
return $author$project$Main$HomePage(
$author$project$Home$init(_Utils_Tuple0).a);
default:
- var _v8 = _v0.a;
+ var _v10 = _v0.a;
return $author$project$Main$NotFoundPage;
}
} else {
@@ -7752,6 +7832,76 @@ var $author$project$Main$init = F3(
var $author$project$Main$GotSubscriptionChangeMsg = function (a) {
return {$: 'GotSubscriptionChangeMsg', a: a};
};
+var $author$project$Main$GotSubscriptionSocketMsg = function (a) {
+ return {$: 'GotSubscriptionSocketMsg', a: a};
+};
+var $elm$core$Platform$Sub$batch = _Platform_batch;
+var $author$project$Credentials$SocketMessageData = F6(
+ function (name, id, clientId, connectionId, timestamp, data) {
+ return {clientId: clientId, connectionId: connectionId, data: data, id: id, name: name, timestamp: timestamp};
+ });
+var $author$project$Credentials$DataMessage = function (message) {
+ return {message: message};
+};
+var $author$project$Credentials$decodeMessage = A3(
+ $NoRedInk$elm_json_decode_pipeline$Json$Decode$Pipeline$required,
+ 'message',
+ $elm$json$Json$Decode$string,
+ $elm$json$Json$Decode$succeed($author$project$Credentials$DataMessage));
+var $elm$json$Json$Decode$int = _Json_decodeInt;
+var $author$project$Credentials$decodeSocketMessage = A3(
+ $NoRedInk$elm_json_decode_pipeline$Json$Decode$Pipeline$required,
+ 'data',
+ $author$project$Credentials$decodeMessage,
+ A3(
+ $NoRedInk$elm_json_decode_pipeline$Json$Decode$Pipeline$required,
+ 'timestamp',
+ $elm$json$Json$Decode$int,
+ A3(
+ $NoRedInk$elm_json_decode_pipeline$Json$Decode$Pipeline$required,
+ 'connectionId',
+ $elm$json$Json$Decode$string,
+ A3(
+ $NoRedInk$elm_json_decode_pipeline$Json$Decode$Pipeline$required,
+ 'clientId',
+ $elm$json$Json$Decode$string,
+ A3(
+ $NoRedInk$elm_json_decode_pipeline$Json$Decode$Pipeline$required,
+ 'id',
+ $elm$json$Json$Decode$string,
+ A3(
+ $NoRedInk$elm_json_decode_pipeline$Json$Decode$Pipeline$required,
+ 'name',
+ $elm$json$Json$Decode$string,
+ $elm$json$Json$Decode$succeed($author$project$Credentials$SocketMessageData)))))));
+var $elm$core$Debug$toString = _Debug_toString;
+var $author$project$Credentials$decodeToSocket = F2(
+ function (key, value) {
+ var result = A2($elm$json$Json$Decode$decodeValue, $author$project$Credentials$decodeSocketMessage, value);
+ if (result.$ === 'Ok') {
+ var obj = result.a;
+ return obj;
+ } else {
+ var err = result.a;
+ return {
+ clientId: '',
+ connectionId: '',
+ data: {message: ''},
+ id: '',
+ name: $elm$core$Debug$toString(err),
+ timestamp: 0
+ };
+ }
+ });
+var $author$project$Credentials$publishSocketMessage = _Platform_incomingPort('publishSocketMessage', $elm$json$Json$Decode$value);
+var $author$project$Credentials$socketMessageChanges = F2(
+ function (toMsg, key) {
+ return $author$project$Credentials$publishSocketMessage(
+ function (val) {
+ return toMsg(
+ A2($author$project$Credentials$decodeToSocket, key, val));
+ });
+ });
var $author$project$Credentials$onSessionChange = _Platform_incomingPort('onSessionChange', $elm$json$Json$Decode$value);
var $author$project$Credentials$subscriptionChanges = F2(
function (toMsg, key) {
@@ -7762,7 +7912,12 @@ var $author$project$Credentials$subscriptionChanges = F2(
});
});
var $author$project$Main$subscriptions = function (model) {
- return A2($author$project$Credentials$subscriptionChanges, $author$project$Main$GotSubscriptionChangeMsg, model.key);
+ return $elm$core$Platform$Sub$batch(
+ _List_fromArray(
+ [
+ A2($author$project$Credentials$subscriptionChanges, $author$project$Main$GotSubscriptionChangeMsg, model.key),
+ A2($author$project$Credentials$socketMessageChanges, $author$project$Main$GotSubscriptionSocketMsg, model.key)
+ ]));
};
var $elm$browser$Browser$Navigation$load = _Browser_load;
var $elm$core$Maybe$destruct = F3(
@@ -7775,7 +7930,6 @@ var $elm$core$Maybe$destruct = F3(
}
});
var $elm$json$Json$Encode$null = _Json_encodeNull;
-var $elm$json$Json$Encode$string = _Json_wrap;
var $author$project$Credentials$storeSession = _Platform_outgoingPort(
'storeSession',
function ($) {
@@ -7827,6 +7981,24 @@ var $elm$url$Url$toString = function (url) {
_Utils_ap(http, url.host)),
url.path)));
};
+var $author$project$Credentials$sendMessageToSocket = _Platform_outgoingPort('sendMessageToSocket', $elm$json$Json$Encode$string);
+var $author$project$Chat$update = F2(
+ function (msg, model) {
+ if (msg.$ === 'StoreMessage') {
+ var message = msg.a;
+ return _Utils_Tuple2(
+ _Utils_update(
+ model,
+ {message: message}),
+ $elm$core$Platform$Cmd$none);
+ } else {
+ return _Utils_Tuple2(
+ _Utils_update(
+ model,
+ {message: ''}),
+ $author$project$Credentials$sendMessageToSocket(model.message));
+ }
+ });
var $author$project$Home$update = F2(
function (msg, model) {
return _Utils_Tuple2(model, $elm$core$Platform$Cmd$none);
@@ -8162,7 +8334,7 @@ var $author$project$Login$submitLogin = function (credentials) {
body: $elm$http$Http$jsonBody(
$author$project$Login$credentialsEncoder(credentials)),
expect: A2($elm$http$Http$expectJson, $author$project$Login$LoginDone, $author$project$Credentials$tokenDecoder),
- url: '/.netlify/functions/login-api'
+ url: '/api/login'
});
};
var $author$project$Login$BadEmail = function (a) {
@@ -8321,7 +8493,6 @@ var $elm$file$File$Select$file = F2(
_File_uploadOne(mimes));
});
var $elm$json$Json$Decode$float = _Json_decodeFloat;
-var $elm$json$Json$Decode$int = _Json_decodeInt;
var $elm$core$Basics$round = _Basics_round;
var $simonh1000$elm_jwt$Jwt$getTokenExpirationMillis = function (token) {
var decodeExp = $elm$json$Json$Decode$oneOf(
@@ -8414,7 +8585,7 @@ var $author$project$Profile$submitProfile = F2(
method: 'PUT',
timeout: $elm$core$Maybe$Nothing,
tracker: $elm$core$Maybe$Nothing,
- url: '/.netlify/functions/profile-put-api'
+ url: '/api/profile'
});
} else {
return $elm$core$Platform$Cmd$none;
@@ -8623,7 +8794,7 @@ var $author$project$Signup$submitSignup = function (credentials) {
body: $elm$http$Http$jsonBody(
$author$project$Signup$credentialsEncoder(credentials)),
expect: A2($elm$http$Http$expectJson, $author$project$Signup$SignupDone, $author$project$Credentials$tokenDecoder),
- url: '/.netlify/functions/signup-api'
+ url: '/api/signup'
});
};
var $author$project$Signup$BadEmail = function (a) {
@@ -8765,7 +8936,7 @@ var $author$project$Verification$apiCallToVerify = function (session) {
method: 'PUT',
timeout: $elm$core$Maybe$Nothing,
tracker: $elm$core$Maybe$Nothing,
- url: '/.netlify/functions/verify-put-api'
+ url: '/api/verify'
});
} else {
return $elm$core$Platform$Cmd$none;
@@ -8809,10 +8980,6 @@ var $author$project$Verification$update = F2(
A2($elm$json$Json$Encode$encode, 0, tokenValue))));
}
});
-var $author$project$Credentials$userIdToString = function (_v0) {
- var id = _v0.a;
- return id;
-};
var $author$project$Main$update = F2(
function (msg, model) {
switch (msg.$) {
@@ -8896,14 +9063,32 @@ var $author$project$Main$update = F2(
} else {
return _Utils_Tuple2(model, $elm$core$Platform$Cmd$none);
}
+ case 'GotChatMsg':
+ var chatMsg = msg.a;
+ var _v8 = model.page;
+ if (_v8.$ === 'ChatPage') {
+ var chatModel = _v8.a;
+ var _v9 = A2($author$project$Chat$update, chatMsg, chatModel);
+ var chatModelFromChat = _v9.a;
+ var chatMsgFromChat = _v9.b;
+ return _Utils_Tuple2(
+ _Utils_update(
+ model,
+ {
+ page: $author$project$Main$ChatPage(chatModelFromChat)
+ }),
+ A2($elm$core$Platform$Cmd$map, $author$project$Main$GotChatMsg, chatMsgFromChat));
+ } else {
+ return _Utils_Tuple2(model, $elm$core$Platform$Cmd$none);
+ }
case 'GotVerificationMsg':
var verificationMsg = msg.a;
- var _v8 = model.page;
- if (_v8.$ === 'VerificationPage') {
- var verificationModel = _v8.a;
- var _v9 = A2($author$project$Verification$update, verificationMsg, verificationModel);
- var verificationModelFromVerification = _v9.a;
- var verificationMsgFromVerification = _v9.b;
+ var _v10 = model.page;
+ if (_v10.$ === 'VerificationPage') {
+ var verificationModel = _v10.a;
+ var _v11 = A2($author$project$Verification$update, verificationMsg, verificationModel);
+ var verificationModelFromVerification = _v11.a;
+ var verificationMsgFromVerification = _v11.b;
return _Utils_Tuple2(
_Utils_update(
model,
@@ -8916,12 +9101,12 @@ var $author$project$Main$update = F2(
}
case 'GotSignupMsg':
var signupMsg = msg.a;
- var _v10 = model.page;
- if (_v10.$ === 'SignupPage') {
- var signupModel = _v10.a;
- var _v11 = A2($author$project$Signup$update, signupMsg, signupModel);
- var signupModelFromSignup = _v11.a;
- var signupMsgFromSignup = _v11.b;
+ var _v12 = model.page;
+ if (_v12.$ === 'SignupPage') {
+ var signupModel = _v12.a;
+ var _v13 = A2($author$project$Signup$update, signupMsg, signupModel);
+ var signupModelFromSignup = _v13.a;
+ var signupMsgFromSignup = _v13.b;
return _Utils_Tuple2(
_Utils_update(
model,
@@ -8939,15 +9124,15 @@ var $author$project$Main$update = F2(
model,
{session: session}),
function () {
- var _v12 = $author$project$Credentials$fromSessionToToken(session);
- if (_v12.$ === 'Just') {
- var token = _v12.a;
- var _v13 = A2(
+ var _v14 = $author$project$Credentials$fromSessionToToken(session);
+ if (_v14.$ === 'Just') {
+ var token = _v14.a;
+ var _v15 = A2(
$simonh1000$elm_jwt$Jwt$decodeToken,
$author$project$Credentials$decodeTokenData,
$author$project$Credentials$fromTokenToString(token));
- if (_v13.$ === 'Ok') {
- var resultTokenRecord = _v13.a;
+ if (_v15.$ === 'Ok') {
+ var resultTokenRecord = _v15.a;
return A2(
$elm$browser$Browser$Navigation$pushUrl,
model.key,
@@ -8959,8 +9144,25 @@ var $author$project$Main$update = F2(
return A2($elm$browser$Browser$Navigation$pushUrl, model.key, '/login');
}
}());
+ case 'GotSubscriptionSocketMsg':
+ var socketMsgObj = msg.a;
+ var _v16 = A2(
+ $author$project$Chat$init,
+ model.session,
+ $elm$core$Maybe$Just(socketMsgObj));
+ var chatModelFromChat = _v16.a;
+ var chatMsgFromChat = _v16.b;
+ return _Utils_Tuple2(
+ _Utils_update(
+ model,
+ {
+ page: $author$project$Main$ChatPage(chatModelFromChat)
+ }),
+ A2($elm$core$Platform$Cmd$map, $author$project$Main$GotChatMsg, chatMsgFromChat));
case 'GetLogout':
return _Utils_Tuple2(model, $author$project$Credentials$logout);
+ case 'ChatNewMessage':
+ return _Utils_Tuple2(model, $elm$core$Platform$Cmd$none);
default:
return _Utils_Tuple2(
_Utils_update(
@@ -8974,42 +9176,15 @@ var $elm$html$Html$map = $elm$virtual_dom$VirtualDom$map;
var $elm$html$Html$p = _VirtualDom_node('p');
var $elm$virtual_dom$VirtualDom$text = _VirtualDom_text;
var $elm$html$Html$text = $elm$virtual_dom$VirtualDom$text;
-var $elm$html$Html$div = _VirtualDom_node('div');
-var $elm$html$Html$h2 = _VirtualDom_node('h2');
-var $author$project$Home$view = function (model) {
- return A2(
- $elm$html$Html$div,
- _List_Nil,
- _List_fromArray(
- [
- A2(
- $elm$html$Html$h2,
- _List_Nil,
- _List_fromArray(
- [
- $elm$html$Html$text('Hello and welcome to our awesome website !')
- ])),
- A2(
- $elm$html$Html$p,
- _List_Nil,
- _List_fromArray(
- [
- $elm$html$Html$text('which is still under construction')
- ]))
- ]));
-};
-var $author$project$Login$LoginSubmit = function (a) {
- return {$: 'LoginSubmit', a: a};
-};
-var $author$project$Login$StoreEmail = function (a) {
- return {$: 'StoreEmail', a: a};
-};
-var $author$project$Login$StorePassword = function (a) {
- return {$: 'StorePassword', a: a};
+var $author$project$Chat$MessageSubmit = {$: 'MessageSubmit'};
+var $author$project$Chat$StoreMessage = function (a) {
+ return {$: 'StoreMessage', a: a};
};
var $elm$html$Html$br = _VirtualDom_node('br');
var $elm$html$Html$button = _VirtualDom_node('button');
+var $elm$html$Html$div = _VirtualDom_node('div');
var $elm$html$Html$form = _VirtualDom_node('form');
+var $elm$html$Html$h2 = _VirtualDom_node('h2');
var $elm$html$Html$input = _VirtualDom_node('input');
var $elm$virtual_dom$VirtualDom$Normal = function (a) {
return {$: 'Normal', a: a};
@@ -9065,6 +9240,99 @@ var $elm$html$Html$Attributes$stringProperty = F2(
var $elm$html$Html$Attributes$type_ = $elm$html$Html$Attributes$stringProperty('type');
var $elm$html$Html$ul = _VirtualDom_node('ul');
var $elm$html$Html$Attributes$value = $elm$html$Html$Attributes$stringProperty('value');
+var $author$project$Chat$view = function (model) {
+ return A2(
+ $elm$html$Html$div,
+ _List_Nil,
+ _List_fromArray(
+ [
+ A2(
+ $elm$html$Html$h2,
+ _List_Nil,
+ _List_fromArray(
+ [
+ $elm$html$Html$text('Chat')
+ ])),
+ A2(
+ $elm$html$Html$div,
+ _List_Nil,
+ _List_fromArray(
+ [
+ A2(
+ $elm$html$Html$ul,
+ _List_Nil,
+ _List_fromArray(
+ [
+ $elm$html$Html$text(model.receivedSocketData.data.message)
+ ]))
+ ])),
+ A2(
+ $elm$html$Html$form,
+ _List_Nil,
+ _List_fromArray(
+ [
+ A2(
+ $elm$html$Html$div,
+ _List_Nil,
+ _List_fromArray(
+ [
+ $elm$html$Html$text('SomeUser:'),
+ A2($elm$html$Html$br, _List_Nil, _List_Nil),
+ A2(
+ $elm$html$Html$input,
+ _List_fromArray(
+ [
+ $elm$html$Html$Attributes$type_('text'),
+ $elm$html$Html$Events$onInput($author$project$Chat$StoreMessage),
+ $elm$html$Html$Attributes$value(model.message)
+ ]),
+ _List_Nil)
+ ])),
+ A2(
+ $elm$html$Html$button,
+ _List_fromArray(
+ [
+ $elm$html$Html$Attributes$type_('button'),
+ $elm$html$Html$Events$onClick($author$project$Chat$MessageSubmit)
+ ]),
+ _List_fromArray(
+ [
+ $elm$html$Html$text('Send message')
+ ]))
+ ]))
+ ]));
+};
+var $author$project$Home$view = function (model) {
+ return A2(
+ $elm$html$Html$div,
+ _List_Nil,
+ _List_fromArray(
+ [
+ A2(
+ $elm$html$Html$h2,
+ _List_Nil,
+ _List_fromArray(
+ [
+ $elm$html$Html$text('Hello and welcome to our awesome website !')
+ ])),
+ A2(
+ $elm$html$Html$p,
+ _List_Nil,
+ _List_fromArray(
+ [
+ $elm$html$Html$text('which is still under construction')
+ ]))
+ ]));
+};
+var $author$project$Login$LoginSubmit = function (a) {
+ return {$: 'LoginSubmit', a: a};
+};
+var $author$project$Login$StoreEmail = function (a) {
+ return {$: 'StoreEmail', a: a};
+};
+var $author$project$Login$StorePassword = function (a) {
+ return {$: 'StorePassword', a: a};
+};
var $elm$html$Html$li = _VirtualDom_node('li');
var $author$project$Login$viewError = function (checkErrors) {
switch (checkErrors.$) {
@@ -9799,6 +10067,12 @@ var $author$project$Main$content = function (model) {
$elm$html$Html$map,
$author$project$Main$GotHomeMsg,
$author$project$Home$view(homeModel));
+ case 'ChatPage':
+ var chatModel = _v0.a;
+ return A2(
+ $elm$html$Html$map,
+ $author$project$Main$GotChatMsg,
+ $author$project$Chat$view(chatModel));
case 'VerificationPage':
var verificationModel = _v0.a;
return A2(
@@ -9955,6 +10229,14 @@ var $author$project$Main$isActive = function (_v0) {
var _v7 = _v1.a;
return false;
}
+ case 'Chat':
+ if (_v1.b.$ === 'ChatPage') {
+ var _v8 = _v1.a;
+ return true;
+ } else {
+ var _v9 = _v1.a;
+ return false;
+ }
case 'Verification':
if (_v1.b.$ === 'VerificationPage') {
return true;
@@ -9962,13 +10244,12 @@ var $author$project$Main$isActive = function (_v0) {
return false;
}
default:
- var _v8 = _v1.a;
+ var _v10 = _v1.a;
return false;
}
};
var $elm$html$Html$nav = _VirtualDom_node('nav');
var $elm$html$Html$span = _VirtualDom_node('span');
-var $elm$core$Debug$toString = _Debug_toString;
var $elm$html$Html$Attributes$width = function (n) {
return A2(
_VirtualDom_attribute,
@@ -10185,23 +10466,49 @@ var $author$project$Main$viewHeader = function (_v0) {
$elm$core$Debug$toString(err))
]));
}
- }()
- ])),
- A2(
- $elm$html$Html$li,
- _List_Nil,
- _List_fromArray(
- [
+ }(),
A2(
- $elm$html$Html$a,
+ $elm$html$Html$li,
_List_fromArray(
[
- $elm$html$Html$Attributes$href('/'),
- $elm$html$Html$Events$onClick($author$project$Main$GetLogout)
+ $elm$html$Html$Attributes$classList(
+ _List_fromArray(
+ [
+ _Utils_Tuple2(
+ 'active',
+ $author$project$Main$isActive(
+ {link: $author$project$Main$Chat, page: page}))
+ ]))
]),
_List_fromArray(
[
- $elm$html$Html$text('logout')
+ A2(
+ $elm$html$Html$a,
+ _List_fromArray(
+ [
+ $elm$html$Html$Attributes$href('/chat')
+ ]),
+ _List_fromArray(
+ [
+ $elm$html$Html$text('Chat')
+ ]))
+ ])),
+ A2(
+ $elm$html$Html$li,
+ _List_Nil,
+ _List_fromArray(
+ [
+ A2(
+ $elm$html$Html$a,
+ _List_fromArray(
+ [
+ $elm$html$Html$Attributes$href('/'),
+ $elm$html$Html$Events$onClick($author$project$Main$GetLogout)
+ ]),
+ _List_fromArray(
+ [
+ $elm$html$Html$text('logout')
+ ]))
]))
]))
]));
diff --git a/netlify.toml b/netlify.toml
deleted file mode 100755
index fcf3322..0000000
--- a/netlify.toml
+++ /dev/null
@@ -1,16 +0,0 @@
-[functions]
- directory = "functions/"
-
-[[redirects]]
- from = "/*"
- to = "index.html"
- status = 200
-
-[dev]
- targetPort = 8000
-
-[context.production]
- NODE_ENV = "production"
-
-[context.dev.environment]
- NODE_ENV = "development"
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index adfb86f..14c27ae 100755
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,15 +11,22 @@
"dependencies": {
"@sendgrid/mail": "^7.7.0",
"bcrypt": "^5.0.1",
+ "body-parser": "^1.20.1",
"cassandra-driver": "^4.6.4",
+ "dotenv": "^16.0.3",
"elm": "^0.19.1-5",
"elm-hot": "^1.0.1",
"elm-live": "^4.0.2",
+ "express": "^4.18.2",
"firebase": "^9.15.0",
"jsonwebtoken": "^8.5.1",
"netlify-cli": "^12.0.11",
"prettier": "^2.2.1",
+ "socket.io": "^4.5.4",
"uuid": "^8.3.2"
+ },
+ "devDependencies": {
+ "nodemon": "^2.0.20"
}
},
"node_modules/@firebase/analytics": {
@@ -723,6 +730,24 @@
"node": "6.* || 8.* || >=10.*"
}
},
+ "node_modules/@socket.io/component-emitter": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
+ "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
+ },
+ "node_modules/@types/cookie": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
+ "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q=="
+ },
+ "node_modules/@types/cors": {
+ "version": "2.8.13",
+ "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz",
+ "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
"node_modules/@types/long": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz",
@@ -738,6 +763,18 @@
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
},
+ "node_modules/accepts": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+ "dependencies": {
+ "mime-types": "~2.1.34",
+ "negotiator": "0.6.3"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/adm-zip": {
"version": "0.5.9",
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.9.tgz",
@@ -780,6 +817,18 @@
"node": ">=8"
}
},
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
"node_modules/aproba": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz",
@@ -810,6 +859,11 @@
"node": ">= 6"
}
},
+ "node_modules/array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
+ },
"node_modules/asn1": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
@@ -862,6 +916,14 @@
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
+ "node_modules/base64id": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
+ "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
+ "engines": {
+ "node": "^4.5.0 || >= 5.9"
+ }
+ },
"node_modules/bcrypt": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.0.1.tgz",
@@ -888,6 +950,64 @@
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz",
"integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A=="
},
+ "node_modules/binary-extensions": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/body-parser": {
+ "version": "1.20.1",
+ "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
+ "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "on-finished": "2.4.1",
+ "qs": "6.11.0",
+ "raw-body": "2.5.1",
+ "type-is": "~1.6.18",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
+ "node_modules/body-parser/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/body-parser/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
+ "node_modules/body-parser/node_modules/qs": {
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+ "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+ "dependencies": {
+ "side-channel": "^1.0.4"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -897,11 +1017,42 @@
"concat-map": "0.0.1"
}
},
+ "node_modules/braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dependencies": {
+ "fill-range": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/buffer-equal-constant-time": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="
},
+ "node_modules/bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+ "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "get-intrinsic": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
@@ -929,6 +1080,33 @@
"node": "*"
}
},
+ "node_modules/chokidar": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+ "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ ],
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
"node_modules/chownr": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
@@ -976,6 +1154,69 @@
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ=="
},
+ "node_modules/content-disposition": {
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+ "dependencies": {
+ "safe-buffer": "5.2.1"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/content-disposition/node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/content-type": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+ "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
+ "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
+ },
+ "node_modules/cors": {
+ "version": "2.8.5",
+ "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
+ "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
+ "dependencies": {
+ "object-assign": "^4",
+ "vary": "^1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
"node_modules/crocks": {
"version": "0.12.1",
"resolved": "https://registry.npmjs.org/crocks/-/crocks-0.12.1.tgz",
@@ -1064,6 +1305,23 @@
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ=="
},
+ "node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/destroy": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
+ "engines": {
+ "node": ">= 0.8",
+ "npm": "1.2.8000 || >= 1.4.16"
+ }
+ },
"node_modules/detect-libc": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz",
@@ -1072,6 +1330,14 @@
"node": ">=8"
}
},
+ "node_modules/dotenv": {
+ "version": "16.0.3",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz",
+ "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==",
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/ecc-jsbn": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
@@ -1157,37 +1423,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/elm-live/node_modules/anymatch": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
- "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
- "dependencies": {
- "normalize-path": "^3.0.0",
- "picomatch": "^2.0.4"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/elm-live/node_modules/binary-extensions": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
- "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/elm-live/node_modules/braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
- "dependencies": {
- "fill-range": "^7.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/elm-live/node_modules/chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
@@ -1269,45 +1504,10 @@
"resolved": "https://registry.npmjs.org/elm-hot/-/elm-hot-1.1.4.tgz",
"integrity": "sha512-qPDP/o/Fkifriaxaf3E7hHFB5L6Ijihyg8is4A6xna6/h/zebUiNssbQrxywI2oxNUkr6W/leEu/WlIC1tmVnw=="
},
- "node_modules/elm-live/node_modules/fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
- "dependencies": {
- "to-regex-range": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/elm-live/node_modules/fsevents": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
- "hasInstallScript": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
- "node_modules/elm-live/node_modules/glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dependencies": {
- "is-glob": "^4.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/elm-live/node_modules/http-errors": {
- "version": "1.7.3",
- "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz",
- "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==",
+ "node_modules/elm-live/node_modules/http-errors": {
+ "version": "1.7.3",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz",
+ "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==",
"dependencies": {
"depd": "~1.1.2",
"inherits": "2.0.4",
@@ -1319,25 +1519,6 @@
"node": ">= 0.6"
}
},
- "node_modules/elm-live/node_modules/is-binary-path": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
- "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
- "dependencies": {
- "binary-extensions": "^2.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/elm-live/node_modules/is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "engines": {
- "node": ">=0.12.0"
- }
- },
"node_modules/elm-live/node_modules/lru-cache": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
@@ -1374,17 +1555,6 @@
"node": ">= 0.8"
}
},
- "node_modules/elm-live/node_modules/readdirp": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
- "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
- "dependencies": {
- "picomatch": "^2.2.1"
- },
- "engines": {
- "node": ">=8.10.0"
- }
- },
"node_modules/elm-live/node_modules/send": {
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
@@ -1465,17 +1635,6 @@
"node": ">=0.8.0"
}
},
- "node_modules/elm-live/node_modules/to-regex-range": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dependencies": {
- "is-number": "^7.0.0"
- },
- "engines": {
- "node": ">=8.0"
- }
- },
"node_modules/elm-live/node_modules/toidentifier": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
@@ -1518,6 +1677,54 @@
"once": "^1.4.0"
}
},
+ "node_modules/engine.io": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.1.tgz",
+ "integrity": "sha512-ECceEFcAaNRybd3lsGQKas3ZlMVjN3cyWwMP25D2i0zWfyiytVbTpRPa34qrr+FHddtpBVOmq4H/DCv1O0lZRA==",
+ "dependencies": {
+ "@types/cookie": "^0.4.1",
+ "@types/cors": "^2.8.12",
+ "@types/node": ">=10.0.0",
+ "accepts": "~1.3.4",
+ "base64id": "2.0.0",
+ "cookie": "~0.4.1",
+ "cors": "~2.8.5",
+ "debug": "~4.3.1",
+ "engine.io-parser": "~5.0.3",
+ "ws": "~8.2.3"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/engine.io-parser": {
+ "version": "5.0.4",
+ "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz",
+ "integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==",
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/engine.io/node_modules/ws": {
+ "version": "8.2.3",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz",
+ "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": "^5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
"node_modules/es6-promisify": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-6.1.1.tgz",
@@ -1574,6 +1781,118 @@
"node": ">=6"
}
},
+ "node_modules/express": {
+ "version": "4.18.2",
+ "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
+ "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
+ "dependencies": {
+ "accepts": "~1.3.8",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.20.1",
+ "content-disposition": "0.5.4",
+ "content-type": "~1.0.4",
+ "cookie": "0.5.0",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "1.2.0",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.7",
+ "qs": "6.11.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.2.1",
+ "send": "0.18.0",
+ "serve-static": "1.15.0",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/express/node_modules/cookie": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
+ "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/express/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/express/node_modules/finalhandler": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
+ "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
+ "dependencies": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "2.4.1",
+ "parseurl": "~1.3.3",
+ "statuses": "2.0.1",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/express/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
+ "node_modules/express/node_modules/qs": {
+ "version": "6.11.0",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+ "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+ "dependencies": {
+ "side-channel": "^1.0.4"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/express/node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
"node_modules/extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
@@ -1608,6 +1927,17 @@
"node": ">=0.8.0"
}
},
+ "node_modules/fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/finalhandler": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
@@ -1730,6 +2060,14 @@
"node": ">= 0.12"
}
},
+ "node_modules/forwarded": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+ "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
@@ -1754,6 +2092,24 @@
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
},
+ "node_modules/fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+ },
"node_modules/gauge": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz",
@@ -1781,6 +2137,19 @@
"node": "6.* || 8.* || >= 10.*"
}
},
+ "node_modules/get-intrinsic": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
+ "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==",
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/get-stream": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
@@ -1819,6 +2188,17 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
@@ -1840,6 +2220,17 @@
"node": ">=6"
}
},
+ "node_modules/has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "dependencies": {
+ "function-bind": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
"node_modules/has-ansi": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
@@ -1859,11 +2250,46 @@
"node": ">=0.10.0"
}
},
+ "node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/has-unicode": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
"integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ=="
},
+ "node_modules/http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "dependencies": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/http-parser-js": {
"version": "0.5.8",
"resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz",
@@ -1908,11 +2334,28 @@
"node": ">= 6"
}
},
+ "node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/idb": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/idb/-/idb-7.0.1.tgz",
"integrity": "sha512-UUxlE7vGWK5RfB/fDwEGgRf84DY/ieqNha6msMV99UsEMQhJ1RwbCd8AYBj3QMgnE3VZnfQvm4oKVCJTYlqIgg=="
},
+ "node_modules/ignore-by-default": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
+ "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
+ "dev": true
+ },
"node_modules/inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@@ -1955,6 +2398,17 @@
"node": ">= 0.10"
}
},
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/is-buffer": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
@@ -1987,6 +2441,14 @@
"node": ">=0.10.0"
}
},
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
"node_modules/is-stream": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
@@ -2183,6 +2645,38 @@
"is-buffer": "~1.1.6"
}
},
+ "node_modules/media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/merge-descriptors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+ "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
+ },
+ "node_modules/methods": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+ "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
@@ -2241,6 +2735,14 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
+ "node_modules/negotiator": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/netlify-cli": {
"version": "12.0.11",
"resolved": "https://registry.npmjs.org/netlify-cli/-/netlify-cli-12.0.11.tgz",
@@ -25833,6 +26335,43 @@
}
}
},
+ "node_modules/nodemon": {
+ "version": "2.0.20",
+ "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.20.tgz",
+ "integrity": "sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw==",
+ "dev": true,
+ "dependencies": {
+ "chokidar": "^3.5.2",
+ "debug": "^3.2.7",
+ "ignore-by-default": "^1.0.1",
+ "minimatch": "^3.1.2",
+ "pstree.remy": "^1.1.8",
+ "semver": "^5.7.1",
+ "simple-update-notifier": "^1.0.7",
+ "supports-color": "^5.5.0",
+ "touch": "^3.1.0",
+ "undefsafe": "^2.0.5"
+ },
+ "bin": {
+ "nodemon": "bin/nodemon.js"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/nodemon"
+ }
+ },
+ "node_modules/nodemon/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
"node_modules/nopt": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
@@ -25893,6 +26432,25 @@
"node": ">=0.10.0"
}
},
+ "node_modules/object-inspect": {
+ "version": "1.12.2",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
+ "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -25952,6 +26510,11 @@
"node": ">=4"
}
},
+ "node_modules/path-to-regexp": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+ "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
+ },
"node_modules/pem": {
"version": "1.14.2",
"resolved": "https://registry.npmjs.org/pem/-/pem-1.14.2.tgz",
@@ -26024,6 +26587,18 @@
"resolved": "https://registry.npmjs.org/long/-/long-5.2.1.tgz",
"integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A=="
},
+ "node_modules/proxy-addr": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+ "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+ "dependencies": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
"node_modules/pseudomap": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
@@ -26034,6 +26609,12 @@
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
"integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag=="
},
+ "node_modules/pstree.remy": {
+ "version": "1.1.8",
+ "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
+ "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
+ "dev": true
+ },
"node_modules/pump": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
@@ -26067,6 +26648,31 @@
"node": ">= 0.6"
}
},
+ "node_modules/raw-body": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
+ "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
+ "dependencies": {
+ "bytes": "3.1.2",
+ "http-errors": "2.0.0",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
"node_modules/request": {
"version": "2.88.2",
"resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
@@ -26138,11 +26744,71 @@
"semver": "bin/semver"
}
},
+ "node_modules/send": {
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
+ "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
+ "dependencies": {
+ "debug": "2.6.9",
+ "depd": "2.0.0",
+ "destroy": "1.2.0",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "2.0.0",
+ "mime": "1.6.0",
+ "ms": "2.1.3",
+ "on-finished": "2.4.1",
+ "range-parser": "~1.2.1",
+ "statuses": "2.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/send/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/send/node_modules/debug/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
+ "node_modules/send/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ },
+ "node_modules/serve-static": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
+ "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
+ "dependencies": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.18.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
"node_modules/set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
},
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
+ },
"node_modules/shebang-command": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
@@ -26162,11 +26828,78 @@
"node": ">=0.10.0"
}
},
+ "node_modules/side-channel": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+ "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+ "dependencies": {
+ "call-bind": "^1.0.0",
+ "get-intrinsic": "^1.0.2",
+ "object-inspect": "^1.9.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/signal-exit": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
},
+ "node_modules/simple-update-notifier": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz",
+ "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==",
+ "dev": true,
+ "dependencies": {
+ "semver": "~7.0.0"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/simple-update-notifier/node_modules/semver": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz",
+ "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/socket.io": {
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.4.tgz",
+ "integrity": "sha512-m3GC94iK9MfIEeIBfbhJs5BqFibMtkRk8ZpKwG2QwxV0m/eEhPIV4ara6XCF1LWNAus7z58RodiZlAH71U3EhQ==",
+ "dependencies": {
+ "accepts": "~1.3.4",
+ "base64id": "~2.0.0",
+ "debug": "~4.3.2",
+ "engine.io": "~6.2.1",
+ "socket.io-adapter": "~2.4.0",
+ "socket.io-parser": "~4.2.1"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/socket.io-adapter": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz",
+ "integrity": "sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg=="
+ },
+ "node_modules/socket.io-parser": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz",
+ "integrity": "sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==",
+ "dependencies": {
+ "@socket.io/component-emitter": "~3.1.0",
+ "debug": "~4.3.1"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
"node_modules/sshpk": {
"version": "1.17.0",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz",
@@ -26191,6 +26924,14 @@
"node": ">=0.10.0"
}
},
+ "node_modules/statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
@@ -26231,6 +26972,18 @@
"node": ">=0.10.0"
}
},
+ "node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/tar": {
"version": "6.1.11",
"resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz",
@@ -26258,6 +27011,52 @@
"node": ">=10"
}
},
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/touch": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
+ "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==",
+ "dev": true,
+ "dependencies": {
+ "nopt": "~1.0.10"
+ },
+ "bin": {
+ "nodetouch": "bin/nodetouch.js"
+ }
+ },
+ "node_modules/touch/node_modules/nopt": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
+ "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==",
+ "dev": true,
+ "dependencies": {
+ "abbrev": "1"
+ },
+ "bin": {
+ "nopt": "bin/nopt.js"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/tough-cookie": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
@@ -26296,6 +27095,24 @@
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA=="
},
+ "node_modules/type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "dependencies": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/undefsafe": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
+ "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
+ "dev": true
+ },
"node_modules/unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
@@ -26317,6 +27134,14 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
+ "node_modules/utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
"node_modules/uuid": {
"version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
@@ -26325,6 +27150,14 @@
"uuid": "dist/bin/uuid"
}
},
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/verror": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
diff --git a/package.json b/package.json
index c5053df..1556e0e 100755
--- a/package.json
+++ b/package.json
@@ -3,21 +3,28 @@
"version": "0.0.1",
"private": true,
"scripts": {
- "start": "elm-live src/Main.elm --pushstate -- --output=index.js"
+ "start": "NODE_ENV=development nodemon app.js & elm-live src/Main.elm --proxy-prefix=/api --proxy-host=http://localhost:8080/api --pushstate -- --output=index.js"
},
"author": "Dusan Stevanovic",
"license": "ISC",
"dependencies": {
"@sendgrid/mail": "^7.7.0",
"bcrypt": "^5.0.1",
+ "body-parser": "^1.20.1",
"cassandra-driver": "^4.6.4",
+ "dotenv": "^16.0.3",
"elm": "^0.19.1-5",
"elm-hot": "^1.0.1",
"elm-live": "^4.0.2",
+ "express": "^4.18.2",
"firebase": "^9.15.0",
"jsonwebtoken": "^8.5.1",
"netlify-cli": "^12.0.11",
"prettier": "^2.2.1",
+ "socket.io": "^4.5.4",
"uuid": "^8.3.2"
+ },
+ "devDependencies": {
+ "nodemon": "^2.0.20"
}
}
diff --git a/readme.md b/readme.md
index 46e2278..9384497 100755
--- a/readme.md
+++ b/readme.md
@@ -1,8 +1,8 @@
# My Elm app
-## Full authentication flow via serverless functions and Elm
+## Full authentication/authorization flow via Node and Elm
-### Elm / Astra DataStax / Firebase Storage / Netlify
+### Elm / Astra DataStax / Firebase Storage / Express
- Node == v14
-- Run: netlify dev
+- Run: npm run start
diff --git a/server/index.js b/server/index.js
new file mode 100644
index 0000000..e70c974
--- /dev/null
+++ b/server/index.js
@@ -0,0 +1,7 @@
+const loginRoute = require('./login-api');
+const signupRoute = require('./signup-api');
+const profileRoute = require('./profile-put-api');
+const verifyRoute = require('./verify-put-api');
+const socketRoute = require('./socket-api');
+
+exports.routes = [loginRoute, signupRoute, profileRoute, verifyRoute];
diff --git a/server/login-api.js b/server/login-api.js
new file mode 100644
index 0000000..20a6a5d
--- /dev/null
+++ b/server/login-api.js
@@ -0,0 +1,79 @@
+// const { createClient } = require('@astrajs/collections');
+const bcrypt = require('bcrypt');
+const jwt = require('jsonwebtoken');
+const { v4: uuid } = require('uuid');
+const { clientPromise } = require('../connect-database');
+
+exports.module = {
+ path: '/api/login',
+ method: 'post',
+ handler: async (req, res) => {
+ const { body } = req;
+ const { email, password } = body;
+
+ let client;
+
+ try {
+ client = await clientPromise;
+ } catch (err) {
+ console.log('Client: ', err);
+ client = err.toString();
+ }
+
+ if (!client || typeof client?.execute !== 'function') {
+ return res.status(500).json(`{message: There is no client, payload: ${client}}`);
+ }
+
+ const findUser = async (parameters) => {
+ const query = `SELECT * FROM ${
+ process.env.NODE_ENV === 'development'
+ ? process.env.ASTRA_DB_KEYSPACE
+ : process.env.ASTRA_DB_KEYSPACE_PROD
+ }.users WHERE email = ? ALLOW FILTERING;`;
+ try {
+ const result = await client.execute(query, parameters, { prepare: true });
+
+ return result;
+ } catch (ex) {
+ console.log('Error in finduser', ex.toString());
+ }
+ };
+ const user = await findUser([email]);
+
+ if (!user?.rows?.length && !user?.rows[0]) {
+ return res.sendStatus(401);
+ }
+
+ const { id, isverified, passwordhash, salt, firstname, verificationstring, avatarurl } =
+ user.rows[0];
+ const pepper = process.env.PEPPER_STRING;
+
+ const isCorrect = await bcrypt.compare(salt + password + pepper, passwordhash);
+
+ if (isCorrect) {
+ jwt.sign(
+ {
+ id,
+ isverified,
+ email,
+ firstname,
+ verificationstring,
+ profilepicurl: avatarurl || '',
+ },
+ process.env.JWT_SECRET,
+ {
+ expiresIn: '2h',
+ },
+ (err, token) => {
+ if (err) {
+ res.sendStatus(500);
+ }
+
+ res.status(200).json({ token });
+ },
+ );
+ } else {
+ return res.sendStatus(401);
+ }
+ },
+};
diff --git a/server/profile-put-api.js b/server/profile-put-api.js
new file mode 100644
index 0000000..9fea6dd
--- /dev/null
+++ b/server/profile-put-api.js
@@ -0,0 +1,148 @@
+// const { createClient } = require('@astrajs/collections');
+const bcrypt = require('bcrypt');
+const jwt = require('jsonwebtoken');
+const { v4: uuid } = require('uuid');
+const { clientPromise } = require('../connect-database');
+const querystring = require('querystring').escape;
+const initializeApp = require('firebase/app').initializeApp;
+const {
+ getStorage,
+ ref,
+ uploadBytes,
+ getDownloadURL,
+ getStream,
+ uploadString,
+} = require('firebase/storage');
+
+exports.module = {
+ path: '/api/profile',
+ method: 'put',
+ handler: async (req, res) => {
+ const { body } = req;
+ const { email, firstname, imagefile } = body;
+ const { authorization } = req.headers;
+ const client = await clientPromise;
+
+ if (!client)
+ return res.status(500).json(`{message: There is no client, payload: ${client}}`);
+
+ if (!authorization) {
+ return res.status(401).json('No authorization header sent');
+ }
+ const token = authorization.split(' ')[1];
+ // const user = await usersCollection.findOne({ email: { $eq: email } });
+
+ let decodedToken;
+
+ try {
+ decodedToken = await jwt.verify(token, process.env.JWT_SECRET);
+ } catch (err) {
+ return res.sendStatus(401);
+ }
+
+ const firebaseConfig = {
+ apiKey: process.env.FIREBASE_API_KEY,
+ authDomain: process.env.FIREBASE_AUTH_DOMAIN,
+ projectId: process.env.FIREBASE_PROJECT_ID,
+ storageBucket: process.env.FIREBASE_STORAGE_BUCKET,
+ messagingSenderId: process.env.FIREBASE_MESSAGING_SENDER_ID,
+ appId: process.env.FIREBASE_APP_ID,
+ measurementId: process.env.FIREBASE_MEASUREMENT_ID,
+ };
+
+ const app = initializeApp(firebaseConfig);
+ const storage = getStorage(app);
+
+ const { id } = decodedToken;
+
+ let photoUrl = '';
+
+ try {
+ if (imagefile.length > 0) {
+ await uploadString(
+ ref(storage, `/images/profile-pic-${id}.jpeg`),
+ imagefile,
+ 'data_url',
+ );
+ const downloadUrl = await getDownloadURL(
+ ref(storage, `/images/profile-pic-${id}.jpeg`),
+ );
+ photoUrl =
+ downloadUrl.length > 0
+ ? `https://firebasestorage.googleapis.com/v0/b/${
+ process.env.FIREBASE_STORAGE_BUCKET
+ }/o/${querystring(`images/profile-pic-${id}.jpeg`)}?alt=media`
+ : '';
+ }
+ } catch (err) {
+ return res.sendStatus(403);
+ }
+
+ const updateUser = async (parameters) => {
+ const query = `UPDATE ${
+ process.env.NODE_ENV === 'development'
+ ? process.env.ASTRA_DB_KEYSPACE
+ : process.env.ASTRA_DB_KEYSPACE_PROD
+ }.users SET firstname = ?, avatarurl = ? WHERE id = ? IF EXISTS;`;
+ try {
+ const result = await client.execute(query, parameters, { prepare: true });
+ // result would be undefined but query would be executed and entery is written in the DB
+ return result;
+ } catch (ex) {
+ console.log('Error in createUser', ex.toString());
+ }
+ };
+
+ const {
+ rows: [applied],
+ } = await updateUser([firstname, photoUrl, id]);
+
+ if (!applied['[applied]']) {
+ console.log('Unsuccessfull in updating user');
+ return res.sendStatus(404);
+ }
+
+ const findUser = async (parameters) => {
+ const query = `SELECT * FROM ${
+ process.env.NODE_ENV === 'development'
+ ? process.env.ASTRA_DB_KEYSPACE
+ : process.env.ASTRA_DB_KEYSPACE_PROD
+ }.users WHERE email = ? ALLOW FILTERING;`;
+ try {
+ const result = await client.execute(query, parameters, { prepare: true });
+
+ return result;
+ } catch (ex) {
+ console.log('Error in finduser', ex.toString());
+ }
+ };
+ const user = await findUser([email]);
+ const {
+ id: decodedId,
+ isverified: isVerified,
+ email: emailFromUser,
+ firstname: firstName,
+ verificationstring,
+ avatarurl,
+ } = user.rows[0];
+
+ return jwt.sign(
+ {
+ id: decodedId,
+ isverified: isVerified,
+ email: emailFromUser,
+ firstname: firstName,
+ verificationstring,
+ profilepicurl: avatarurl || '',
+ },
+ process.env.JWT_SECRET,
+ { expiresIn: '2h' },
+ (err, token) => {
+ if (err) {
+ return res.status(200).json(err);
+ }
+ res.status(200).json({ token });
+ },
+ );
+ },
+};
diff --git a/server/signup-api.js b/server/signup-api.js
new file mode 100644
index 0000000..383fe26
--- /dev/null
+++ b/server/signup-api.js
@@ -0,0 +1,138 @@
+// const { createClient } = require('@astrajs/collections');
+const cassandra = require('cassandra-driver');
+const bcrypt = require('bcrypt');
+const jwt = require('jsonwebtoken');
+const { v4: uuid } = require('uuid');
+const { clientPromise } = require('../connect-database');
+const sendgrid = require('@sendgrid/mail');
+
+sendgrid.setApiKey(process.env.SENDGRID_API_KEY);
+
+const sendEmail = ({ to, from, subject, text, html = '' }) => {
+ const msg = { to, from, subject, text, html };
+ return sendgrid.send(msg);
+};
+
+exports.module = {
+ path: '/api/signup',
+ method: 'post',
+ handler: async (req, res) => {
+ const { body } = req;
+ const { email, password } = body;
+ let client;
+
+ try {
+ client = await clientPromise;
+ } catch (err) {
+ console.log('Client: ', err);
+ client = err.toString();
+ }
+
+ if (!client || typeof client?.execute !== 'function') {
+ return res.status(500).json(`{message: There is no client, payload: ${client}}`);
+ }
+
+ const findUser = async (parameters) => {
+ const query = `SELECT * FROM ${
+ process.env.NODE_ENV === 'development'
+ ? process.env.ASTRA_DB_KEYSPACE
+ : process.env.ASTRA_DB_KEYSPACE_PROD
+ }.users WHERE email = ? ALLOW FILTERING;`;
+ try {
+ const result = client.execute(query, parameters, { prepare: true });
+ return result;
+ } catch (ex) {
+ console.log('Error in finduser', ex.toString());
+ }
+ };
+
+ const user = await findUser([email]);
+
+ if (user?.rows[0]) {
+ // conflict error code
+ return res.sendStatus(401);
+ }
+ const salt = uuid();
+ const pepper = process.env.PEPPER_STRING;
+ const passwordHash = await bcrypt.hash(salt + password + pepper, 10); // 2 arg is num of iterations to
+ const verificationString = uuid();
+ const createdId = uuid();
+
+ const createUser = async (parameters) => {
+ const query = `INSERT INTO ${
+ process.env.NODE_ENV === 'development'
+ ? process.env.ASTRA_DB_KEYSPACE
+ : process.env.ASTRA_DB_KEYSPACE_PROD
+ }.users (id, email, firstname, isadmin, isverified, lastname, passwordhash, salt, verificationstring, avatarurl) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);`;
+ try {
+ const result = await client.execute(query, parameters, { prepare: true });
+ // result would be undefined but query would be executed and entery is wirtten in the DB
+ return result;
+ } catch (ex) {
+ console.log('Error in createUser', ex.toString());
+ }
+ };
+
+ const createdUser = await createUser([
+ createdId,
+ email,
+ '',
+ false,
+ false,
+ '',
+ passwordHash,
+ salt,
+ verificationString,
+ '',
+ ]);
+
+ try {
+ await sendEmail({
+ to: email,
+ from: 'dooshanstevanovic@gmail.com',
+ subject: 'Please verify your email',
+ text: `Thanks for signin up ! To verify your email click here: ${
+ process.env.NODE_ENV === 'development'
+ ? 'http://localhost:8000'
+ : 'https://my-elm-app.netlify.app'
+ }/verify-email/${verificationString}`,
+ html: `
+
Hello !
+
+
Thanks for signin up !
+
To verify your email click here
+
+
`,
+ });
+ } catch (err) {
+ console.log('Error in sendEmail', err.toString());
+ return {
+ statusCode: 500,
+ };
+ }
+
+ return jwt.sign(
+ {
+ id: createdId,
+ isverified: false,
+ email,
+ firstname: '',
+ verificationstring: verificationString,
+ profilepicurl: '',
+ },
+ process.env.JWT_SECRET,
+ { expiresIn: '2h' },
+ (err, token) => {
+ if (err) {
+ res.sendStatus(500);
+ }
+
+ res.status(200).json({ token });
+ },
+ );
+ },
+};
diff --git a/server/socket-api.js b/server/socket-api.js
new file mode 100644
index 0000000..a8c0641
--- /dev/null
+++ b/server/socket-api.js
@@ -0,0 +1,9 @@
+exports.handler = async function (req) {
+ const clientId = req.queryStringParameters['clientId'] || 'NO_CLIENT_ID';
+
+ return {
+ statusCode: 200,
+ headers: { 'content-type': 'application/json' },
+ body: JSON.stringify('123'),
+ };
+};
diff --git a/functions/tournament-api.js b/server/tournament-api.js
similarity index 100%
rename from functions/tournament-api.js
rename to server/tournament-api.js
diff --git a/server/verify-put-api.js b/server/verify-put-api.js
new file mode 100644
index 0000000..7bd02aa
--- /dev/null
+++ b/server/verify-put-api.js
@@ -0,0 +1,101 @@
+const bcrypt = require('bcrypt');
+const jwt = require('jsonwebtoken');
+const { v4: uuid } = require('uuid');
+const { clientPromise } = require('../connect-database');
+
+exports.module = {
+ path: '/api/verify',
+ method: 'put',
+ handler: async (req, res) => {
+ const { authorization } = req.headers;
+ const client = await clientPromise;
+
+ if (!client)
+ return res.status(500).json(`{message: There is no client, payload: ${client}}`);
+
+ if (!authorization) {
+ return res.status(401).json('No authorization header sent');
+ }
+
+ const token = authorization.split(' ')[1];
+
+ let decodedToken;
+
+ try {
+ decodedToken = await jwt.verify(token, process.env.JWT_SECRET);
+ } catch (err) {
+ return res.sendStatus(401);
+ }
+
+ const { id, email, isverified } = decodedToken;
+
+ const updateUser = async (parameters) => {
+ const query = `UPDATE ${
+ process.env.NODE_ENV === 'development'
+ ? process.env.ASTRA_DB_KEYSPACE
+ : process.env.ASTRA_DB_KEYSPACE_PROD
+ }.users SET isverified = True WHERE id = ? IF EXISTS;`;
+ try {
+ const result = await client.execute(query, parameters, { prepare: true });
+ // result would be undefined but query would be executed and entery is wirtten in the DB
+ return result;
+ } catch (ex) {
+ console.log('Error in createUser', ex.toString());
+ }
+ };
+
+ if (isverified) {
+ return res.status(200).json(token);
+ }
+
+ const {
+ rows: [applied],
+ } = await updateUser([id]);
+
+ if (!applied['[applied]']) {
+ console.log('Unsuccessfull in updating user');
+ return res.sendStatus(404);
+ }
+
+ const findUser = async (parameters) => {
+ const query = `SELECT * FROM ${
+ process.env.NODE_ENV === 'development'
+ ? process.env.ASTRA_DB_KEYSPACE
+ : process.env.ASTRA_DB_KEYSPACE_PROD
+ }.users WHERE email = ? ALLOW FILTERING;`;
+ try {
+ const result = await client.execute(query, parameters, { prepare: true });
+
+ return result;
+ } catch (ex) {
+ console.log('Error in finduser', ex.toString());
+ }
+ };
+ const user = await findUser([email]);
+ const {
+ id: decodedId,
+ isverified: isVerified,
+ email: emailFromUser,
+ verificationstring,
+ } = user.rows[0];
+
+ return jwt.sign(
+ {
+ id: decodedId,
+ isverified: true,
+ email: emailFromUser,
+ firstname: '',
+ verificationstring,
+ profilepicurl: '',
+ },
+ process.env.JWT_SECRET,
+ { expiresIn: '2h' },
+ (err, token) => {
+ if (err) {
+ return res.status(200).json(err);
+ }
+ res.status(200).json({ token });
+ },
+ );
+ },
+};
diff --git a/src/Chat.elm b/src/Chat.elm
new file mode 100644
index 0000000..9719ce7
--- /dev/null
+++ b/src/Chat.elm
@@ -0,0 +1,107 @@
+module Chat exposing (..)
+
+import Credentials exposing (Session, SocketMessageData, decodeTokenData, fromSessionToToken, fromTokenToString, initiateSocketChannel, sendMessageToSocket, userIdToString)
+import Html exposing (..)
+import Html.Attributes exposing (..)
+import Html.Events exposing (..)
+import Jwt
+
+
+type alias Model =
+ { message : String, receivedSocketData : SocketMessageData }
+
+
+type CheckErrors
+ = BadInput String
+ | BadRequest String
+
+
+type Msg
+ = StoreMessage String
+ | MessageSubmit
+
+
+initialModel : Model
+initialModel =
+ { message = ""
+ , receivedSocketData =
+ { name = ""
+ , id = ""
+ , clientId = ""
+ , connectionId = ""
+ , timestamp = 0
+ , data =
+ { message = ""
+ }
+ }
+ }
+
+
+update : Msg -> Model -> ( Model, Cmd Msg )
+update msg model =
+ case msg of
+ StoreMessage message ->
+ ( { model | message = message }, Cmd.none )
+
+ MessageSubmit ->
+ ( { model | message = "" }, sendMessageToSocket model.message )
+
+
+init : Session -> Maybe SocketMessageData -> ( Model, Cmd Msg )
+init session maybeSocket =
+ case fromSessionToToken session of
+ Just token ->
+ case Jwt.decodeToken decodeTokenData <| fromTokenToString token of
+ Ok resultTokenRecord ->
+ case maybeSocket of
+ Just receivedSocketData ->
+ ( { initialModel | receivedSocketData = receivedSocketData }, initiateSocketChannel <| userIdToString resultTokenRecord.id )
+
+ Nothing ->
+ ( initialModel, initiateSocketChannel <| userIdToString resultTokenRecord.id )
+
+ Err _ ->
+ ( initialModel, Cmd.none )
+
+ Nothing ->
+ ( initialModel, Cmd.none )
+
+
+
+-- Just receivedSocketData )
+-- { initialModel | receivedSocketData = receivedSocketData }
+-- ( Nothing, Nothing ) ->
+-- ( initialModel, Cmd.none )
+-- ( Just _, Nothing ) ->
+-- ( initialModel, Cmd.none )
+-- ( Nothing, Just _ ) ->
+-- ( initialModel, Cmd.none )
+
+
+view : Model -> Html Msg
+view model =
+ div
+ []
+ [ h2 []
+ [ text "Chat" ]
+ , div []
+ [ ul [] [ text model.receivedSocketData.data.message ]
+ ]
+ , Html.form []
+ [ div []
+ [ text "SomeUser:"
+ , br [] []
+ , input
+ [ type_ "text"
+ , onInput StoreMessage
+ , value model.message
+ ]
+ []
+ ]
+ , button
+ [ type_ "button"
+ , onClick MessageSubmit
+ ]
+ [ text "Send message" ]
+ ]
+ ]
diff --git a/src/Credentials.elm b/src/Credentials.elm
index a544e0f..2d9438e 100644
--- a/src/Credentials.elm
+++ b/src/Credentials.elm
@@ -1,6 +1,7 @@
port module Credentials exposing
( ImageString
, Session
+ , SocketMessageData
, Token
, UnwrappedTokenData
, UserId
@@ -17,8 +18,11 @@ port module Credentials exposing
, fromTokenToString
, guest
, imageStringToMaybeString
+ , initiateSocketChannel
, logout
, onSessionChange
+ , sendMessageToSocket
+ , socketMessageChanges
, storeSession
, stringToImageString
, subscriptionChanges
@@ -31,8 +35,8 @@ port module Credentials exposing
import Browser.Navigation as Nav
import Http exposing (Header, header)
-import Json.Decode as Decode exposing (Decoder, Value, at, bool, map6, string)
-import Json.Decode.Pipeline exposing (required)
+import Json.Decode as Decode exposing (Decoder, Value, at, bool, int, map6, string)
+import Json.Decode.Pipeline exposing (required, requiredAt)
import Json.Encode as Encode exposing (Value)
import Url.Parser exposing (Parser, custom)
@@ -54,6 +58,43 @@ type UserId
= UserId String
+type alias SocketMessageData =
+ { name : String
+ , id : String
+ , clientId : String
+ , connectionId : String
+ , timestamp : Int
+ , data : DataMessage
+ }
+
+
+type alias DataMessage =
+ { message : String
+ }
+
+
+
+-- t{ name = Debug.toString err
+-- , id = ""
+-- , clientId = ""
+-- , connectionId = ""
+-- , timestamp = 0
+-- , data =
+-- { message = ""
+-- }
+-- }
+-- {
+-- name: 'hello-world-message',
+-- id: 'W46cHmYS-f:5:0',
+-- clientId: '123',
+-- connectionId: 'W46cHmYS-f',
+-- encoding: null,
+-- data: {
+-- message: '{msgType: hello-there-guys, msgText: Hello from Elm Side !}',
+-- },
+-- };
+
+
userIdToString : UserId -> String
userIdToString (UserId id) =
id
@@ -201,14 +242,23 @@ encodeToken (Token token) =
port storeSession : Maybe String -> Cmd msg
+port onSessionChange : (Value -> msg) -> Sub msg
+
+
+port publishSocketMessage : (Value -> msg) -> Sub msg
+
+
+port initiateSocketChannel : String -> Cmd msg
+
+
+port sendMessageToSocket : String -> Cmd msg
+
+
logout : Cmd msg
logout =
storeSession Nothing
-port onSessionChange : (Value -> msg) -> Sub msg
-
-
decodeTokenData : Decoder UnwrappedTokenData
decodeTokenData =
map6 UnwrappedTokenData
@@ -242,11 +292,83 @@ decodeToSession key value =
Guest
+decodeSocketMessage : Decoder SocketMessageData
+decodeSocketMessage =
+ Decode.succeed SocketMessageData
+ |> required "name" string
+ |> required "id" string
+ |> required "clientId" string
+ |> required "connectionId" string
+ |> required "timestamp" int
+ |> required "data" decodeMessage
+
+
+decodeMessage : Decoder DataMessage
+decodeMessage =
+ Decode.succeed DataMessage
+ |> required "message" string
+
+
+
+-- { name = String
+-- , id = String
+-- , clientId = String
+-- , connectionId = String
+-- , encoding = String
+-- , data =
+-- { message = String
+-- }
+-- }
+
+
+decodeToSocket : Nav.Key -> Value -> SocketMessageData
+decodeToSocket key value =
+ let
+ result =
+ Decode.decodeValue
+ decodeSocketMessage
+ value
+
+ -- |> Result.toMaybe
+ in
+ case result of
+ Ok obj ->
+ obj
+
+ Err err ->
+ { name = Debug.toString err
+ , id = ""
+ , clientId = ""
+ , connectionId = ""
+ , timestamp = 0
+ , data =
+ { message = ""
+ }
+ }
+
+
+
+-- decodeTokenData : Decoder UnwrappedTokenData
+-- decodeTokenData =
+-- map6 UnwrappedTokenData
+-- (at [ "id" ] idDecoder)
+-- (at [ "isverified" ] bool)
+-- (at [ "email" ] string)
+-- (at [ "firstname" ] string)
+-- (at [ "verificationstring" ] verifyStringDecoder)
+-- (at [ "profilepicurl" ] imageStringDecoder)
+
+
subscriptionChanges : (Session -> msg) -> Nav.Key -> Sub msg
subscriptionChanges toMsg key =
onSessionChange (\val -> toMsg (decodeToSession key val))
+socketMessageChanges : (SocketMessageData -> msg) -> Nav.Key -> Sub msg
+socketMessageChanges toMsg key =
+ publishSocketMessage (\val -> toMsg (decodeToSocket key val))
+
+
addHeader : Token -> Header
addHeader (Token tokenString) =
header "authorization" ("Token " ++ tokenString)
diff --git a/src/Login.elm b/src/Login.elm
index a01fd9b..a2a29b9 100755
--- a/src/Login.elm
+++ b/src/Login.elm
@@ -123,7 +123,7 @@ sumOfErrors model =
submitLogin : Credentials -> Cmd Msg
submitLogin credentials =
Http.post
- { url = "/.netlify/functions/login-api"
+ { url = "/api/login"
, body = Http.jsonBody (credentialsEncoder credentials)
, expect = Http.expectJson LoginDone tokenDecoder
}
diff --git a/src/Main.elm b/src/Main.elm
index cf58e3b..2cbe583 100755
--- a/src/Main.elm
+++ b/src/Main.elm
@@ -2,9 +2,11 @@ module Main exposing (..)
import Browser exposing (Document)
import Browser.Navigation as Nav
+import Chat
import Credentials
exposing
( Session
+ , SocketMessageData
, UserId
, VerificationString
, decodeToSession
@@ -13,6 +15,7 @@ import Credentials
, fromTokenToString
, imageStringToMaybeString
, logout
+ , socketMessageChanges
, subscriptionChanges
, userIdParser
, userIdToString
@@ -29,6 +32,8 @@ import Login
import Minidenticons exposing (identicon)
import Profile
import Signup
+import Task
+import Time
import Url exposing (Url)
import Url.Parser as Parser exposing ((>), Parser, s)
import Verification
@@ -47,6 +52,7 @@ type Page
| SignupPage Signup.Model
| ProfilePage Profile.Model
| HomePage Home.Model
+ | ChatPage Chat.Model
| VerificationPage Verification.Model
| NotFoundPage
@@ -56,6 +62,7 @@ type Route
| Signup
| Profile UserId
| Home
+ | Chat
| Verification VerificationString
| NotFound
@@ -67,10 +74,13 @@ type Msg
| GotLoginMsg Login.Msg
| GotProfileMsg Profile.Msg
| GotHomeMsg Home.Msg
+ | GotChatMsg Chat.Msg
| GotVerificationMsg Verification.Msg
| GotSubscriptionChangeMsg Session
+ | GotSubscriptionSocketMsg SocketMessageData
| GetLogout
| OpenDropdown
+ | ChatNewMessage
content : Model -> Html Msg
@@ -92,6 +102,10 @@ content model =
Home.view homeModel
|> Html.map GotHomeMsg
+ ChatPage chatModel ->
+ Chat.view chatModel
+ |> Html.map GotChatMsg
+
VerificationPage verificationModel ->
Verification.view verificationModel
|> Html.map GotVerificationMsg
@@ -183,10 +197,18 @@ viewHeader { page, session, openDropdown, key } =
Err err ->
li [] [ text (Debug.toString err) ]
+ , li
+ [ classList
+ [ ( "active"
+ , isActive { link = Chat, page = page }
+ )
+ ]
+ ]
+ [ a [ href "/chat" ] [ text "Chat" ] ]
+ , li
+ []
+ [ a [ href "/", onClick GetLogout ] [ text "logout" ] ]
]
- , li
- []
- [ a [ href "/", onClick GetLogout ] [ text "logout" ] ]
]
Nothing ->
@@ -248,6 +270,12 @@ isActive { link, page } =
( Home, _ ) ->
False
+ ( Chat, ChatPage _ ) ->
+ True
+
+ ( Chat, _ ) ->
+ False
+
( Verification _, VerificationPage _ ) ->
True
@@ -312,6 +340,18 @@ update msg model =
_ ->
( model, Cmd.none )
+ GotChatMsg chatMsg ->
+ case model.page of
+ ChatPage chatModel ->
+ let
+ ( chatModelFromChat, chatMsgFromChat ) =
+ Chat.update chatMsg chatModel
+ in
+ ( { model | page = ChatPage chatModelFromChat }, Cmd.map GotChatMsg chatMsgFromChat )
+
+ _ ->
+ ( model, Cmd.none )
+
GotVerificationMsg verificationMsg ->
case model.page of
VerificationPage verificationModel ->
@@ -351,9 +391,31 @@ update msg model =
Nav.pushUrl model.key "/login"
)
+ GotSubscriptionSocketMsg socketMsgObj ->
+ let
+ ( chatModelFromChat, chatMsgFromChat ) =
+ Chat.init model.session <| Just socketMsgObj
+ in
+ ( { model | page = ChatPage chatModelFromChat }, Cmd.map GotChatMsg chatMsgFromChat )
+
+ -- case model.page of
+ -- ChatPage chatModel ->
+ -- let
+ -- ( chatModelFromChat, chatMsgFromChat ) =
+ -- Chat.update msgToChatMsg chatModel
+ -- in
+ -- ( { model | page = ChatPage chatModelFromChat }, Cmd.map GotChatMsg chatMsgFromChat )
+ -- _ ->
+ -- ( model, Cmd.none )
+ -- (model, GotSubscriptionSocketMsg)
+ -- in
+ -- ( model, Cmd.none )
GetLogout ->
( model, logout )
+ ChatNewMessage ->
+ ( model, Cmd.none )
+
OpenDropdown ->
( { model | openDropdown = not model.openDropdown }, Cmd.none )
@@ -365,6 +427,7 @@ matchRoute =
, Parser.map Login (s "login")
, Parser.map Profile (s "profile" > userIdParser)
, Parser.map Signup (s "signup")
+ , Parser.map Chat (s "chat")
, Parser.map Verification (s "verify-email" > verifictionStringParser)
]
@@ -404,6 +467,14 @@ urlToPage url session =
Nothing ->
NotFoundPage
+ Just Chat ->
+ case fromSessionToToken session of
+ Just _ ->
+ ChatPage (Tuple.first (Chat.init session Nothing))
+
+ Nothing ->
+ NotFoundPage
+
Just Home ->
HomePage (Tuple.first (Home.init ()))
@@ -461,6 +532,13 @@ initCurrentPage ( url, model, existingCmds ) =
in
( { model | page = HomePage pageModel }, Cmd.map GotHomeMsg pageCmds )
+ ChatPage _ ->
+ let
+ ( pageModel, pageCmds ) =
+ Chat.init model.session Nothing
+ in
+ ( { model | page = ChatPage pageModel }, Cmd.map GotChatMsg pageCmds )
+
VerificationPage _ ->
let
( pageModel, pageCmds ) =
@@ -490,7 +568,10 @@ init flags url key =
subscriptions : Model -> Sub Msg
subscriptions model =
- subscriptionChanges GotSubscriptionChangeMsg model.key
+ Sub.batch
+ [ subscriptionChanges GotSubscriptionChangeMsg model.key
+ , socketMessageChanges GotSubscriptionSocketMsg model.key
+ ]
main : Program Value Model Msg
diff --git a/src/Profile.elm b/src/Profile.elm
index 9702f7a..a461975 100644
--- a/src/Profile.elm
+++ b/src/Profile.elm
@@ -396,7 +396,7 @@ submitProfile session data =
Http.request
{ method = "PUT"
, headers = [ addHeader token ]
- , url = "/.netlify/functions/profile-put-api"
+ , url = "/api/profile"
, body = Http.jsonBody (profileSubmitDataEncoder data)
, expect = Http.expectJson ProfileDone tokenDecoder
, timeout = Nothing
diff --git a/src/Signup.elm b/src/Signup.elm
index 56cc5e6..66c2cd8 100755
--- a/src/Signup.elm
+++ b/src/Signup.elm
@@ -162,7 +162,7 @@ sumOfErrors model =
submitSignup : Credentials -> Cmd Msg
submitSignup credentials =
Http.post
- { url = "/.netlify/functions/signup-api"
+ { url = "/api/signup"
, body = Http.jsonBody (credentialsEncoder credentials)
, expect = Http.expectJson SignupDone tokenDecoder
}
diff --git a/src/Verification.elm b/src/Verification.elm
index 6117685..e85e438 100644
--- a/src/Verification.elm
+++ b/src/Verification.elm
@@ -96,7 +96,7 @@ apiCallToVerify session =
Http.request
{ method = "PUT"
, headers = [ addHeader token ]
- , url = "/.netlify/functions/verify-put-api"
+ , url = "/api/verify"
, expect = Http.expectJson VerifyDone tokenDecoder
, body = Http.emptyBody
, timeout = Nothing