diff --git a/packages/api/.env.development b/packages/api/.env.development deleted file mode 100644 index 95d58c9..0000000 --- a/packages/api/.env.development +++ /dev/null @@ -1,3 +0,0 @@ -MONGO_CONNECTION_STRING=mongodb+srv://default:M9iZXokJlZpN4KLX@cluster0.mkuqa.mongodb.net/default?retryWrites=true&w=majority - -JWT_TOKEN_SECRET=afajdslfwk1@lkkasdfl21ASDF!2 \ No newline at end of file diff --git a/packages/new_api_model/.eslintrc.json b/packages/api/.eslintrc.json similarity index 100% rename from packages/new_api_model/.eslintrc.json rename to packages/api/.eslintrc.json diff --git a/packages/new_api_model/.gcloudignore b/packages/api/.gcloudignore similarity index 100% rename from packages/new_api_model/.gcloudignore rename to packages/api/.gcloudignore diff --git a/packages/new_api_model/app.yaml b/packages/api/app.yaml similarity index 100% rename from packages/new_api_model/app.yaml rename to packages/api/app.yaml diff --git a/packages/api/config.ts b/packages/api/config/config.ts similarity index 100% rename from packages/api/config.ts rename to packages/api/config/config.ts diff --git a/packages/api/index.ts b/packages/api/index.ts index 275c1fb..966bbf6 100644 --- a/packages/api/index.ts +++ b/packages/api/index.ts @@ -1,48 +1,43 @@ -import express, { Application, Request, Response } from "express"; +import './repository/db'; -import GetAllSocketClients from "@nirvana/core/sockets/getAllActiveSocketClients"; -import InitializeWs from "./sockets"; -import { NextFunction } from "express"; -import NirvanaResponse from "@nirvana/core/responses/nirvanaResponse"; -import ReceiveSignal from "../core/sockets/receiveSignal"; -import SendSignal from "@nirvana/core/sockets/sendSignal"; -import SocketChannels from "@nirvana/core/sockets/channels"; -import { UserService } from "./services/user.service"; -import { UserStatus } from "@nirvana/core/models"; -import cors from "cors"; -import getLineRoutes from "./routes/line"; -import getSearchRoutes from "./routes/search"; -import getUserRoutes from "./routes/user"; +import * as Sentry from '@sentry/node'; +import * as Tracing from '@sentry/tracing'; + +/* eslint-disable @typescript-eslint/no-var-requires */ +import express, { Application, NextFunction, Request, Response } from 'express'; + +import InitializeWs from './services/SocketService'; +import cors from 'cors'; +import morgan from 'morgan'; const app = express(); +app.use(morgan('combined')); app.use(cors()); app.use(express.json()); - app.use((req: Request, res: Response, next: NextFunction) => { - console.log("Time: ", new Date()); + console.log('Time: ', new Date()); next(); }); - -app.get("/", (req: Request, res: Response) => { - res.send("hello world."); +app.get('/', (req: Request, res: Response) => { + res.send('hello world.'); +}); +app.use('/api/status', (req: Request, res: Response) => { + res.json({ message: 'wohoo, server is healthy' }); }); -app.use("/api/status", (req: Request, res: Response) => { - res.json(new NirvanaResponse("wohoo, server is healthy")); -}); +const PORT = process.env.PORT || 8080; +const server = app.listen(PORT, () => + console.log(`express running on port | ${PORT} in host machine`), +); -app.use("/api/user", getUserRoutes()); -app.use("/api/search", getSearchRoutes()); -app.use("/api/lines", getLineRoutes()); +// won't catch any errors here and we don't want it to +console.log(); -const PORT = 5000; -const server = app.listen(PORT, () => console.log("express running")); - -const io = require("socket.io")(server, { +const io = require('socket.io')(server, { // todo: add authentication cors: { - origin: "*", + origin: '*', }, }); diff --git a/packages/api/middleware/auth.ts b/packages/api/middleware/auth.ts deleted file mode 100644 index f0bccc4..0000000 --- a/packages/api/middleware/auth.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { NextFunction, Request, Response } from "express"; - -import { loadConfig } from "../config"; - -const jwt = require("jsonwebtoken"); - -const config = loadConfig(); - -// used by specific routes that need to authentication -export const authCheck = async ( - req: Request, - res: Response, - next: NextFunction -) => { - try { - const { authorization } = req.headers; - - if (!authorization) { - throw Error("No provided header"); - } - - // verify jwt token with our api secret - var decoded: JwtClaims = jwt.verify(authorization, config.JWT_TOKEN_SECRET); - - res.locals.userInfo = decoded; - - next(); - } catch (error) { - res.status(401).send("unauthorized"); - } -}; - -export interface JwtClaims { - userId: string; - googleUserId: string; - picture: string; - email: string; - name: string; -} diff --git a/packages/api/nodemon.json b/packages/api/nodemon.json index 4d05214..c9cfbe1 100644 --- a/packages/api/nodemon.json +++ b/packages/api/nodemon.json @@ -1,6 +1,6 @@ { "ignore": ["**/*.test.ts", "**/*.spec.ts", "node_modules"], - "watch": ["./"], - "exec": "npm start", + "watch": ["./", "../common"], + "exec": "npm run start:dev", "ext": "ts" } diff --git a/packages/api/package.json b/packages/api/package.json index 3a7b71b..c50621d 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -1,32 +1,40 @@ { - "name": "@nirvana/api", + "name": "@nirvana/new_api_model", "version": "1.0.0", "main": "index.ts", "license": "MIT", - "dependencies": { - "@nirvana/core": "*", - "axios": "^0.26.1", - "cors": "^2.8.5", - "dotenv": "^16.0.0", - "express": "^4.17.3", - "google-auth-library": "^7.14.0", - "jsonwebtoken": "^8.5.1", - "mongodb": "^4.4.1", - "socket.io": "^4.4.1" - }, "scripts": { - "dev": "NODE_ENV=development nodemon", - "start": "ts-node index.ts", - "production": "NODE_ENV=production nodemon" + "core": "rm -rf ./core && cp -r ../core/src ./core/", + "dev": "NODE_ENV=development && yarn core && nodemon", + "start:dev": "ts-node index.ts", + "lint": "eslint --ext .ts,.tsx .", + "build": "npm run lint && tsc -p .", + "start": "node dist/index.js", + "gcp-build": "npm run build" }, "devDependencies": { "@types/express": "^4.17.13", + "@types/morgan": "^1.9.3", "@types/node": "^17.0.21", + "@typescript-eslint/eslint-plugin": "^5.0.0", + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^8.0.1", + "eslint-plugin-import": "^2.25.0", "nodemon": "^2.0.15", - "ts-node": "^10.7.0", "typescript": "^4.6.2" }, - "workspaces": [ - "packages/*" - ] + "dependencies": { + "@sentry/node": "^7.0.0", + "@sentry/tracing": "^7.0.0", + "axios": "^0.26.1", + "cors": "^2.8.5", + "express": "^4.17.3", + "firebase": "^9.8.2", + "google-auth-library": "^7.14.0", + "jsonwebtoken": "^8.5.1", + "mongodb": "^4.4.1", + "morgan": "^1.10.0", + "socket.io": "^4.4.1", + "ts-node": "^10.7.0" + } } diff --git a/packages/api/services/database.service.ts b/packages/api/repository/db.ts similarity index 73% rename from packages/api/services/database.service.ts rename to packages/api/repository/db.ts index 2962896..3e0e226 100644 --- a/packages/api/services/database.service.ts +++ b/packages/api/repository/db.ts @@ -1,7 +1,7 @@ // External Dependencies import * as mongoDB from 'mongodb'; -import environmentVariables from '../config'; +import environmentVariables from '../config/config'; // Global Variables export const collections: { @@ -11,9 +11,9 @@ export const collections: { } = {}; // Initialize Connection -export const client: mongoDB.MongoClient = new mongoDB.MongoClient( - environmentVariables.MONGO_CONNECTION_STRING, -); +const config = environmentVariables; + +export const client: mongoDB.MongoClient = new mongoDB.MongoClient(config.MONGO_CONNECTION_STRING); client.connect(); @@ -27,7 +27,4 @@ collections.users = usersCollection; collections.lines = lineCollection; collections.lineMembers = lineMembersCollection; -console.log( - `Successfully connected to database: ${db.databaseName} and collections: `, - Object.keys(collections).forEach((coll) => console.log(coll)), -); +console.log(`Successfully connected to database: ${db.databaseName} and collections`); diff --git a/packages/new_api_model/routes.ts b/packages/api/routes.ts similarity index 69% rename from packages/new_api_model/routes.ts rename to packages/api/routes.ts index c8b3500..5b338a4 100644 --- a/packages/new_api_model/routes.ts +++ b/packages/api/routes.ts @@ -4,4 +4,4 @@ const router = express.Router(); router.use(express.json()); -router.post('/login', loginOrCreate); +// router.post('/login', loginOrCreate); diff --git a/packages/api/routes/line.ts b/packages/api/routes/line.ts deleted file mode 100644 index 1236511..0000000 --- a/packages/api/routes/line.ts +++ /dev/null @@ -1,216 +0,0 @@ -import { JwtClaims, authCheck } from '../middleware/auth'; -import { Line, LineMember, LineMemberState } from '@nirvana/core/models/line.model'; -import express, { Application, Request, Response } from 'express'; - -import Content from '@nirvana/core/models/content.model'; -import CreateLineRequest from '@nirvana/core/requests/createLine.request'; -import GetConversationDetailsResponse from '@nirvana/core/responses/getConversationDetails.response'; -import GetDmConversationByOtherUserIdResponse from '@nirvana/core/responses/getDmConversationByOtherUserId.response'; -import GetUserLinesResponse from '@nirvana/core/responses/getUserLines.response'; -import { LineService } from '../services/line.service'; -import MasterLineData from '@nirvana/core/models/masterLineData.model'; -import NirvanaResponse from '@nirvana/core/responses/nirvanaResponse'; -import { ObjectId } from 'mongodb'; -import Relationship from '@nirvana/core/models/relationship.model'; -import { User } from '@nirvana/core/models/user.model'; -import { UserService } from '../services/user.service'; -import { collections } from '../services/database.service'; -import UpdateLineMemberState from '@nirvana/core/requests/updateLineMemberState.request'; - -export default function getLineRoutes() { - const router = express.Router(); - - router.use(express.json()); - - // get data for a one on one conversation - // router.get("/:otherUserGoogleUserId", authCheck, getConversationDetails); - - // create a line - router.post('/', authCheck, createLine); - - // get all of user's lines - router.get('/', authCheck, getUserLines); - - // toggle tune into a line - router.post('/:lineId/state', authCheck, updateLineMemberState); - - // get conversation between user and other user - router.get('/dm/:otherUserId', authCheck, getDmByOtherUserId); - - return router; -} - -async function getDmByOtherUserId(req: Request, res: Response) { - try { - const { otherUserId } = req.params; - const userInfo = res.locals.userInfo as JwtClaims; - - console.log(otherUserId); - - // check db for lines between me and this other person - // if there is one, then return it with 200 status - // else return it with custom status that frontend will read - - res.status(200).json(); - return; - - res.status(205).json('no such conversation between you two'); - } catch (error) { - res.status(500).json(error); - } -} - -async function createLine(req: Request, res: Response) { - try { - const reqObj: CreateLineRequest = req.body as CreateLineRequest; - console.log(req.body); - - if (!reqObj?.otherMemberIds.length) { - res.status(400).json('must provide member Ids'); - return; - } - - const userInfo = res.locals.userInfo as JwtClaims; - - const newLine = new Line( - new ObjectId(userInfo.userId), - reqObj.lineName ?? undefined, - new Date(), - new Date(), - new ObjectId(), - ); - - // TODO: validate that users exists before creating line members - const lineMembers: LineMember[] = - reqObj.otherMemberIds.map((memId) => { - const newLineMember = new LineMember( - newLine._id!, - new ObjectId(memId), - LineMemberState.INBOX, - ); - - return newLineMember; - }) ?? []; - - lineMembers.push( - new LineMember(newLine._id!, new ObjectId(userInfo.userId), LineMemberState.INBOX), - ); - - const transactionResult = await LineService.createLine(newLine, lineMembers); - - transactionResult - ? res.status(200).json(new NirvanaResponse(newLine)) - : res.status(400).json(new NirvanaResponse(undefined, new Error('unable to create line'))); - } catch (error) { - console.log(error); - res.status(500).json(error); - } -} - -async function updateLineMemberState(req: Request, res: Response) { - try { - const userInfo = res.locals.userInfo as JwtClaims; - const { lineId } = req.params; - const request = req.body as UpdateLineMemberState; - - // TODO: validation to check if user is actually a member of the line - - const result = await LineService.updateLineMemberState( - lineId, - userInfo.userId, - request.newState, - ); - - return result?.ok - ? res.status(200).json(new NirvanaResponse("successfully updated line member's state")) - : res - .status(400) - .json(new NirvanaResponse(undefined, new Error('not updated...something went wrong'))); - } catch (error) { - res.status(500).json(new NirvanaResponse(undefined, error as Error)); - } -} - -async function getUserLines(req: Request, res: Response) { - try { - const userInfo = res.locals.userInfo as JwtClaims; - - // get all of user's lineMember entries - const userLineMembers = await LineService.getLineMembersByUserId(userInfo.userId); - - if (!userLineMembers?.length) { - const resObj = new GetUserLinesResponse([]); - - res.json(new NirvanaResponse(resObj, undefined, 'this user is not in any lines')); - - return; - } - - const lineIds = userLineMembers?.map((lineMember) => lineMember.lineId) ?? []; - - // this will include the current user lineMember association to the line - const allLineMembers = await LineService.getLineMembersInLines(lineIds); - - const allLinesUsersIds: ObjectId[] = []; - allLineMembers?.map((currentLineMember) => { - if (currentLineMember?.userId) allLinesUsersIds.push(currentLineMember.userId); - }) ?? []; - - // get all users relevant here - const allRelevantUsers = await UserService.getUsersByIds(allLinesUsersIds); - - // get all lines from the list of relevant lines - const lines = (await LineService.getLinesByIds(lineIds)) ?? []; - - const masterLines: MasterLineData[] = []; - - // TODO: get the latest audio blocks for this line...maybe like today and yesterday or by block count - - lines.map((currentLine) => { - let associatedLineMembersForLine: LineMember[] = []; - - // get all of the line members for this Line - // make sure that we don't add line member if it's the current user - allLineMembers?.map((lineMember) => { - if (currentLine._id) { - if (lineMember.lineId.equals(currentLine._id)) - associatedLineMembersForLine.push(lineMember); - } - }) ?? []; - - // get the user lineMember assoc out of the list of the lineMembers for this line - const userLineMember = associatedLineMembersForLine?.find( - (currentLineMemberForLine) => - currentLineMemberForLine.userId.toString() === userInfo.userId, - ); - - if (userLineMember) { - // take out the current user from the "other" line members list now - - associatedLineMembersForLine = associatedLineMembersForLine.filter( - (currentLineMember) => currentLineMember.userId.toString() !== userInfo.userId, - ); - - // get the user objects for all of the other members - const otherUsers: User[] = []; - associatedLineMembersForLine.forEach((currentLineMember) => { - const foundUserObject = allRelevantUsers?.find((currentUser) => - currentUser._id?.equals(currentLineMember.userId), - ); - - if (foundUserObject) otherUsers.push(foundUserObject); - }); - - masterLines.push( - new MasterLineData(currentLine, userLineMember, associatedLineMembersForLine, otherUsers), - ); - } - }); - - const resObj = new GetUserLinesResponse(masterLines); - - res.json(new NirvanaResponse(resObj)); - } catch (error) { - res.status(500).json(error); - } -} diff --git a/packages/api/routes/search.ts b/packages/api/routes/search.ts deleted file mode 100644 index 63d75fc..0000000 --- a/packages/api/routes/search.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { JwtClaims, authCheck } from "../middleware/auth"; -import express, { Application, Request, Response } from "express"; - -import { User } from "@nirvana/core/models"; -import UserSearchResponse from "../../core/responses/userSearch.response"; -import { UserService } from "../services/user.service"; - -export default function getSearchRoutes() { - const router = express.Router(); - - router.use(express.json()); - - // get user details based on id token - router.get("/users", authCheck, handleUserSearch); - - return router; -} - -async function handleUserSearch(req: Request, res: Response) { - try { - const userInfo = res.locals.userInfo as JwtClaims; - - const { query } = req.query; - - if (!query) { - res.status(400).send("No search query provided!"); - return; - } - - // text search on users - const users: User[] | null = await UserService.getUsersLikeEmailAndName( - query as string - ); - - const filteredUsers = users?.filter( - (currUser) => currUser._id?.toString() !== userInfo.userId - ); - - const resObj = new UserSearchResponse(filteredUsers ?? []); - - res.send(resObj); - } catch (error) { - console.log(error); - res.status(500).send(`something went wrong`); - } -} diff --git a/packages/api/routes/user.ts b/packages/api/routes/user.ts deleted file mode 100644 index ab4d7ac..0000000 --- a/packages/api/routes/user.ts +++ /dev/null @@ -1,149 +0,0 @@ -import { GoogleUserInfo, User } from '@nirvana/core/models'; -import { JwtClaims, authCheck } from '../middleware/auth'; -import express, { Application, Request, Response } from 'express'; - -import LoginResponse from '../../core/responses/login.response'; -import { OAuth2Client } from 'google-auth-library'; -import { ObjectID } from 'bson'; -import { ObjectId } from 'mongodb'; -import UserDetailsResponse from '../../core/responses/userDetails.response'; -import { UserService } from '../services/user.service'; -import { UserStatus } from '../../core/models/user.model'; -import { collections } from '../services/database.service'; -import { loadConfig } from '../config'; - -const jwt = require('jsonwebtoken'); - -const config = loadConfig(); - -const client = new OAuth2Client(config.GOOGLE_AUTH_CLIENT_ID); - -export default function getUserRoutes() { - const router = express.Router(); - - router.use(express.json()); - - // get user details based on id token - router.get('/', authCheck, getUserDetails); - - router.get('/login', login); - - router.get('/authcheck', authCheck, handleAuthCheck); - - return router; -} - -async function handleAuthCheck(req: Request, res: Response) { - try { - res.status(200).json('You are good to go!'); - } catch (error) { - res.status(401).json('Unauthorized'); - } -} - -async function getUserDetails(req: Request, res: Response) { - try { - const userInfo = res.locals.userInfo as JwtClaims; - - const user = await UserService.getUserById(userInfo.userId); - - user - ? res.status(200).json(new UserDetailsResponse(user)) - : res.status(404).json('No such user'); - } catch (error) { - console.log(error); - res.status(500).json(`Problem with signing user up or logging in`); - } -} - -/** Create user if doesn't exist - * Returns jwt token for client and user details - */ -async function login(req: Request, res: Response) { - // passed in accesstoken no matter what - const { access_token, id_token } = req.query; - - try { - const ticket = await client.verifyIdToken({ - idToken: (id_token as string) ?? '', - audience: config.GOOGLE_AUTH_CLIENT_ID, // Specify the CLIENT_ID of the app that accesses the backend - }); - const googleUserId = ticket.getPayload()?.sub as string; - const email = ticket.getPayload()?.email as string; - - if (!googleUserId || !email) { - res.status(401).json('no google account found'); - return; - } - - // return user details if it passed auth middleware - let user = await UserService.getUserByEmail(email); - - // if no user found, then go ahead and create user - if (!user) { - if (!access_token) { - res.status(400).json('No access token provided'); - return; - } - - // get google user info from access token - const userInfo: GoogleUserInfo = await UserService.getGoogleUserInfoWithAccessToken( - access_token as string, - ); - - // create initial user model object - - const newUser = new User( - googleUserId, - userInfo.email, - userInfo.name, - userInfo.given_name, - userInfo.family_name, - new Date(), - userInfo.picture, - userInfo.verifiedEmail, - userInfo.locale, - ); - - // create user if not exists - const insertResult = await UserService.createUserIfNotExists(newUser); - - newUser._id = insertResult?.insertedId; - - // create jwt token with new user info - const jwtToken = jwt.sign( - { - userId: newUser._id, - googleUserId: newUser.googleId, - picture: newUser.picture, - email: newUser.email, - name: newUser.name, - }, - config.JWT_TOKEN_SECRET, - ); - - insertResult - ? res.status(200).json(new LoginResponse(jwtToken, newUser)) - : res.status(500).json('Failed to create account, already exists'); - - return; - } - - // create jwt token with existing user info - const existingUserJwtToken = jwt.sign( - { - userId: user._id, - googleUserId: user.googleId, - picture: user.picture, - email: user.email, - name: user.name, - }, - config.JWT_TOKEN_SECRET, - ); - - res.status(200).json(new LoginResponse(existingUserJwtToken, user)); - } catch (error) { - console.log(error); - res.status(500).json(`Problem with signing user up or logging in`); - } -} diff --git a/packages/new_api_model/src/socket.ts b/packages/api/services/SocketService.ts similarity index 100% rename from packages/new_api_model/src/socket.ts rename to packages/api/services/SocketService.ts diff --git a/packages/new_api_model/services/UserService.ts b/packages/api/services/UserService.ts similarity index 100% rename from packages/new_api_model/services/UserService.ts rename to packages/api/services/UserService.ts diff --git a/packages/api/services/line.service.ts b/packages/api/services/line.service.ts deleted file mode 100644 index bcfa195..0000000 --- a/packages/api/services/line.service.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { - Line, - LineMember, - LineMemberState, -} from "@nirvana/core/models/line.model"; -import { client, collections } from "./database.service"; - -import NirvanaResponse from "@nirvana/core/responses/nirvanaResponse"; -import { ObjectId } from "mongodb"; - -export class LineService { - static async getLineByOtherUserId(otherUserId: ObjectId) { - // get all of the conversations for this user that have exactly two conversation members - // get all of the conversationMembers for this user - // get all of the conversations for this user - // get all of the conversations - // const query = { googleId: userId }; - // const res = await collections.users?.findOne(query); - // // exists - // if (res?._id) { - // return res as User; - // } - // return null; - } - - static async getLinesByIds(convoIds: ObjectId[]) { - const query = { _id: { $in: convoIds } }; - - const convosRes = await collections.lines?.find(query).toArray(); - - // exists - if (convosRes?.length) { - return convosRes as Line[]; - } - - return null; - } - - static async getLineMembersByUserId(userId: string) { - const query = { userId: new ObjectId(userId) }; - - const convoMembersRes = await collections.lineMembers - ?.find(query) - .toArray(); - - // exists - if (convoMembersRes?.length) { - return convoMembersRes as LineMember[]; - } - - return null; - } - - /** Get all of the members associated to the given list of lines */ - static async getLineMembersInLines(lineIds: ObjectId[]) { - const query = { lineId: { $in: lineIds } }; - - const lineMembersRes = await collections.lineMembers?.find(query).toArray(); - - // exists - if (lineMembersRes?.length) { - return lineMembersRes as LineMember[]; - } - - return null; - } - - static async createLine(line: Line, lineMembers: LineMember[]) { - const session = client.startSession(); - try { - const transactionResults = await session.withTransaction(async () => { - // todo: check if convoMembers userId's actually exist - - const insertLineRes = await collections.lines?.insertOne(line); - if (!insertLineRes?.insertedId) { - await session.abortTransaction(); - console.error("failed to create line"); - - return; - } - - const insertConvoMembersRes = await collections.lineMembers?.insertMany( - lineMembers - ); - if (!insertConvoMembersRes?.insertedCount) { - await session.abortTransaction(); - console.error("failed to create line members"); - - return; - } - - console.log("success"); - return insertConvoMembersRes; - }); - - console.log(transactionResults); - - return "success"; - - // if (transactionResults) { - // console.log("The convo was successfully created."); - // return transactionResults; - // } else { - // console.log("The convo was intentionally aborted."); - // return null; - // } - } catch (e) { - console.log( - "The transaction was aborted due to an unexpected error: " + e - ); - } finally { - await session.endSession(); - } - - return null; - } - - static async updateLineMemberState( - lineId: string, - userId: string, - newState: LineMemberState - ) { - const query = { - lineId: new ObjectId(lineId), - userId: new ObjectId(userId), - }; - const updateSet = { $set: { state: newState, lastVisitDate: new Date() } }; - - const updateRes = await collections.lineMembers?.findOneAndUpdate( - query, - updateSet - ); - - return updateRes; - } - - static async updateLineMemberVisitDate(lineId: string, userId: string) { - const query = { lineId, userId: new ObjectId(userId) }; - const updateSet = { $set: { lastVisitDate: new Date() } }; - - const updateRes = await collections.lineMembers?.findOneAndUpdate( - query, - updateSet - ); - - return updateRes; - } -} diff --git a/packages/api/services/user.service.ts b/packages/api/services/user.service.ts deleted file mode 100644 index 443ba9a..0000000 --- a/packages/api/services/user.service.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { GoogleUserInfo, User } from "@nirvana/core/models"; - -import { ObjectId } from "mongodb"; -import { UserStatus } from "../../core/models/user.model"; -import axios from "axios"; -import { collections } from "./database.service"; - -export class UserService { - static async getUserById(userId: string) { - const query = { _id: new ObjectId(userId) }; - - const res = await collections.users?.findOne(query); - - // exists - if (res?._id) { - return res as User; - } - - return null; - } - - static async getUsersByIds(userIds: ObjectId[]) { - const query = { _id: { $in: userIds } }; - - const res = await collections.users?.find(query).toArray(); - - // exists - if (res?.length) { - return res as User[]; - } - - return undefined; - } - - static async getUserByGoogleId(googleUserId: string) { - const query = { googleId: googleUserId }; - - const res = await collections.users?.findOne(query); - - // exists - if (res?._id) { - return res as User; - } - - return null; - } - - static async getUserByEmail(email: string) { - const query = { email }; - - const res = await collections.users?.findOne(query); - - // exists - if (res?._id) { - return res as User; - } - - return null; - } - - static async getUsersLikeEmailAndName(searchQuery: string) { - // based on index defined in Mongo atlas - const query = { - $search: { - index: "basic user search", - text: { - query: searchQuery, - path: { - wildcard: "*", - }, - }, - }, - }; - - // const res = await collections.users?.find(query).toArray(); - - const res = await collections.users?.aggregate([query]).toArray(); - - // exists - if (res?.length) { - return res as User[]; - } - - return null; - } - - static async createUserIfNotExists(newUser: User) { - const getUser = await this.getUserByEmail(newUser.email); - - if (!getUser) { - return await collections.users?.insertOne(newUser); - } - - // user with email exists already, don't create - return null; - } - - static async getGoogleUserInfoWithAccessToken( - accessToken: string - ): Promise { - return ( - await axios.get( - `https://www.googleapis.com/oauth2/v1/userinfo?access_token=${accessToken}` - ) - ).data; - } - - static async updateUserStatus(userGoogleId: string, newStatus: UserStatus) { - const query = { googleId: userGoogleId }; - const updateDoc = { - $set: { status: newStatus, lastUpdatedDate: new Date() }, - }; - - const resultUpdate = await collections.users?.updateOne(query, updateDoc); - - return resultUpdate; - } -} diff --git a/packages/api/sockets/index.ts b/packages/api/sockets/index.ts deleted file mode 100644 index 9075add..0000000 --- a/packages/api/sockets/index.ts +++ /dev/null @@ -1,215 +0,0 @@ -import { - ConnectToLineRequest, - RtcAnswerSomeoneRequest, - RtcCallRequest, - RtcNewUserJoinedResponse, - RtcReceiveAnswerResponse, - ServerRequestChannels, - ServerResponseChannels, - SomeoneConnectedResponse, - SomeoneDisconnectedResponse, - SomeoneTunedResponse, - SomeoneUntunedFromLineResponse, - StartBroadcastingRequest, - StopBroadcastingRequest, - TuneToLineRequest, - UntuneFromLineRequest, - UserStartedBroadcastingResponse, - UserStoppedBroadcastingResponse, -} from '@nirvana/core/sockets/channels'; - -import GetAllSocketClients from '@nirvana/core/sockets/getAllActiveSocketClients'; -import { JwtClaims } from '../middleware/auth'; -import { LineMemberState } from '@nirvana/core/models/line.model'; -import { LineService } from '../services/line.service'; -import ReceiveSignal from '@nirvana/core/sockets/receiveSignal'; -import SendSignal from '@nirvana/core/sockets/sendSignal'; -import { UserService } from '../services/user.service'; -import { UserStatus } from '@nirvana/core/models/user.model'; -import { client } from '../services/database.service'; -import { loadConfig } from '../config'; - -const jwt = require('jsonwebtoken'); - -const config = loadConfig(); - -// NOTE: client socket connections should never have to deal with socketIds -const socketIdsToUserIds: { - [socketId: string]: string; -} = {}; -const userIdsToSocketIds: { - [userId: string]: string; -} = {}; - -export default function InitializeWs(io: any) { - console.log('initializing web sockets'); - - return io - .use(function (socket: any, next: any) { - console.log('authenticating user...'); - - try { - const { token } = socket.handshake.query; - console.log(token); - - // verify jwt token with our api secret - var decoded: JwtClaims = jwt.verify(token, config.JWT_TOKEN_SECRET); - - socket.userInfo = decoded; - - next(); - } catch (error) { - console.error(error); - next(new Error('WS Authentication Error')); - } - }) - .on('connection', function (socket: any) { - const userInfo: JwtClaims = socket.userInfo; - - socketIdsToUserIds[socket.id] = userInfo.userId.toString(); - userIdsToSocketIds[userInfo.userId.toString()] = socket.id; - - console.log(`a user connected | user Id: ${userInfo.userId} and name: ${userInfo.name}`); - - socket.on('test', () => { - console.log('asdf'); - }); - - // ?verification that user is in a particular line to be tuned into it or just generally in it? - - /** CONNECT | User wants to subscribe to live emissions of a line */ - socket.on(ServerRequestChannels.CONNECT_TO_LINE, (req: ConnectToLineRequest) => { - // add this user to the room - console.log(`${socket.id} user CONNECTED room for line ${Object.keys(socket.rooms)}`); - - const roomName = `connectedLine:${req.lineId}`; - socket.join(roomName); - - const clientUserIdsInRoom = [...(io.sockets.adapter.rooms.get(roomName) ?? [])].map( - (otherUserSocketId: string) => socketIdsToUserIds[otherUserSocketId], - ); - - io.in(roomName).emit( - ServerResponseChannels.SOMEONE_CONNECTED_TO_LINE, - new SomeoneConnectedResponse(req.lineId, userInfo.userId, clientUserIdsInRoom), - ); - }); - - /** TUNE | User tunes into the line either temporarily or toggled in */ - socket.on(ServerRequestChannels.TUNE_INTO_LINE, async (req: TuneToLineRequest) => { - console.log(`${socket.id} user TUNED into room for line ${req.lineId}`); - - const roomName = `tunedLine:${req.lineId}`; - socket.join(roomName); - - const clientUserIdsInRoom = [...(io.sockets.adapter.rooms.get(roomName) ?? [])].map( - (otherUserSocketId: string) => socketIdsToUserIds[otherUserSocketId], - ); - - // we want to notify everyone connected to the line even if they are not tuned in - const connectedLineRoomName = `connectedLine:${req.lineId}`; - - io.in(connectedLineRoomName).emit( - ServerResponseChannels.SOMEONE_TUNED_INTO_LINE, - new SomeoneTunedResponse(req.lineId, userInfo.userId, clientUserIdsInRoom), - ); - }); - - /** - * Notify all connected users when someone UNTUNES from a room - */ - socket.on(ServerRequestChannels.UNTUNE_FROM_LINE, async (req: UntuneFromLineRequest) => { - const roomName = `tunedLine:${req.lineId}`; - socket.leave(roomName); - - console.log(`${userInfo.userId} left room: ${roomName}`); - - // we want to notify everyone connected to the line even if they are not tuned in - const connectedLineRoomName = `connectedLine:${req.lineId}`; - - io.in(connectedLineRoomName).emit( - ServerResponseChannels.SOMEONE_UNTUNED_FROM_LINE, - new SomeoneUntunedFromLineResponse(req.lineId, userInfo.userId), - ); - }); - - // TODO: use same pattern as tuning and untuning and send updated fresh list of current broadcasters but using another namespace/room for broadcasters in a line - /** BROADCAST UPDATE | tell all connected, not just tuned into, that there is an update to someone broadcasting */ - socket.on(ServerRequestChannels.BROADCAST_TO_LINE, (req: StartBroadcastingRequest) => { - const roomName = `connectedLine:${req.lineId}`; - - io.in(roomName).emit( - ServerResponseChannels.SOMEONE_STARTED_BROADCASTING, - new UserStartedBroadcastingResponse(req.lineId, userInfo.userId), - ); - }); - - socket.on(ServerRequestChannels.STOP_BROADCAST_TO_LINE, (req: StopBroadcastingRequest) => { - const roomName = `connectedLine:${req.lineId}`; - - io.in(roomName).emit( - ServerResponseChannels.SOMEONE_STOPPED_BROADCASTING, - new UserStoppedBroadcastingResponse(req.lineId, userInfo.userId), - ); - }); - - socket.on(ServerRequestChannels.RTC_CALL_SOMEONE_FOR_LINE, (req: RtcCallRequest) => { - console.log('slave calling a master'); - - const userSocketId = userIdsToSocketIds[req.userToCall]; - - io.to(userSocketId).emit( - ServerResponseChannels.RTC_NEW_USER_JOINED, - new RtcNewUserJoinedResponse(userInfo.userId, req.lineId, req.simplePeerSignal), - ); - }); - - socket.on( - ServerRequestChannels.RTC_ANSWER_SOMEONE_FOR_LINE, - (req: RtcAnswerSomeoneRequest) => { - console.log('master answering slave'); - - const userSocketId = userIdsToSocketIds[req.newbieUserId]; - - io.to(userSocketId).emit( - ServerResponseChannels.RTC_RECEIVING_MASTER_ANSWER, - new RtcReceiveAnswerResponse(userInfo.userId, req.lineId, req.simplePeerSignal), - ); - }, - ); - - // tell everyone in the channel to - // socket.on(ServerRequestChannels.CREATED_CHANNEL, (req: CreatedLineRequest) => { - - // }) - - // tell all people in all my lines that I am disconnecting or untuning - // tell the tuned in folks the new list of - socket.on('disconnecting', (reason: any) => { - console.log(`someone disconnecting: ${reason}`); - - console.log(socket.rooms); - - for (const roomName of socket.rooms) { - if (roomName !== socket.id) { - const lineId = roomName.split(':')[1]; - - const roomToTell = roomName.includes('tunedLine') - ? `connectedLine:${lineId}` - : roomName; - - io.in(roomToTell).emit( - ServerResponseChannels.SOMEONE_DISCONNECTED_FROM_LINE, - new SomeoneDisconnectedResponse(lineId, userInfo.userId), - ); - } - } - }); - - // ==== DISCONNECT ==== - socket.on('disconnect', () => { - delete socketIdsToUserIds[socket.id]; - delete userIdsToSocketIds[userInfo.userId]; - }); - }); -} diff --git a/packages/api/tsconfig.json b/packages/api/tsconfig.json index 5679481..cb943b0 100644 --- a/packages/api/tsconfig.json +++ b/packages/api/tsconfig.json @@ -11,7 +11,7 @@ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ /* Language and Environment */ - "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "jsx": "preserve", /* Specify what JSX code is generated. */ // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ @@ -24,7 +24,7 @@ // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ /* Modules */ - "module": "commonjs", /* Specify what module code is generated. */ + "module": "commonjs" /* Specify what module code is generated. */, // "rootDir": "./", /* Specify the root folder within your source files. */ // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ @@ -47,7 +47,7 @@ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ - // "outDir": "./", /* Specify an output folder for all emitted files. */ + "outDir": "dist" /* Specify an output folder for all emitted files. */, // "removeComments": true, /* Disable emitting comments. */ // "noEmit": true, /* Disable emitting files from a compilation. */ // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ @@ -69,12 +69,12 @@ /* Interop Constraints */ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */, // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, /* Type Checking */ - "strict": true, /* Enable all strict type-checking options. */ + "strict": true /* Enable all strict type-checking options. */, // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ @@ -96,6 +96,6 @@ /* Completeness */ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ } } diff --git a/packages/common/package.json b/packages/common/package.json deleted file mode 100644 index 5bd0970..0000000 --- a/packages/common/package.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "@nirvana/common", - "version": "1.0.0", - "main": "index.js", - "license": "MIT" -} diff --git a/packages/common/src/models/content.model.ts b/packages/common/src/models/content.model.ts deleted file mode 100644 index ba59f4c..0000000 --- a/packages/common/src/models/content.model.ts +++ /dev/null @@ -1,35 +0,0 @@ -export interface IContent { - id: string; - creatorUserId: string; - contentUrl: string; // remote resource of file/media - createdDate: Date; - - // visitCount -} - -// ? persist length of clip for easier viewing for others... -// ?they have to load it anyway and will get metadata anyway? -export class ContentBlock implements IContent { - constructor( - public id: string, - public creatorUserId: string, - public contentUrl: string, - - public contentType: ContentType, - public blobType: string, - - public createdDate: Date, - ) {} -} - -export enum ContentType { - audio = 'audio', - - link = 'link', - - image = 'image', -} - -export function isUrlImage(url: string) { - return url.match(/\.(jpeg|jpg|gif|png)$/) != null; -} diff --git a/packages/common/src/models/conversation.model.ts b/packages/common/src/models/conversation.model.ts deleted file mode 100644 index 3ed04d4..0000000 --- a/packages/common/src/models/conversation.model.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { User } from './user.model'; -export default class Conversation { - constructor( - public id: string, - public createdByUserId: string, - - public memberIdsList: string[], - - public members: MemberMap, - - public userCache: User[], - - public name: string | null = null, - - public lastUpdatedDate: Date, - - public createdDate: Date, - - public membersInRoom: string[] = [], - ) {} -} - -export type MemberMap = { - [memberId: string]: ConversationMember; -}; - -export class ConversationMember { - constructor( - public userId: string, // NOTE: serves as the user ID - - public role: MemberRole, - - public memberState: MemberState, - public isActive: boolean = true, - public lastActiveDate: Date, - public joinedDate = Date, - ) {} -} - -export enum MemberRole { - admin = 'admin', - regular = 'regular', -} -export enum MemberState { - priority = 'priority', - inbox = 'inbox', - // deleted = "deleted" -} diff --git a/packages/common/src/models/user.model.ts b/packages/common/src/models/user.model.ts deleted file mode 100644 index 6fa5b16..0000000 --- a/packages/common/src/models/user.model.ts +++ /dev/null @@ -1,16 +0,0 @@ -export class User { - lastUpdatedDate?: Date; - - priorityConversations?: string[]; // id of all priority convos - - constructor( - public id: string, - public uid: string, - public providerId: string, - public email: string, - public displayName?: string, - public photoUrl?: string, - public phoneNumber?: string, - public createdDate: Date = new Date(), - ) {} -} diff --git a/packages/common/src/sockets.ts b/packages/common/src/sockets.ts deleted file mode 100644 index 29f2031..0000000 --- a/packages/common/src/sockets.ts +++ /dev/null @@ -1,13 +0,0 @@ -type SocketEvents = { - request: object - response: object -} - -export const SOCKET_EVENTS: SocketEvents = { - request: { - - } - response : { - - } -} \ No newline at end of file diff --git a/packages/common/src/index.ts b/packages/core/index.ts similarity index 100% rename from packages/common/src/index.ts rename to packages/core/index.ts diff --git a/packages/core/src/models/content.model.ts b/packages/core/models/content.model.ts similarity index 100% rename from packages/core/src/models/content.model.ts rename to packages/core/models/content.model.ts diff --git a/packages/core/src/models/conversation.model.ts b/packages/core/models/conversation.model.ts similarity index 100% rename from packages/core/src/models/conversation.model.ts rename to packages/core/models/conversation.model.ts diff --git a/packages/core/src/models/user.model.ts b/packages/core/models/user.model.ts similarity index 100% rename from packages/core/src/models/user.model.ts rename to packages/core/models/user.model.ts diff --git a/packages/core/package.json b/packages/core/package.json index c2b7707..2744b33 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -2,8 +2,5 @@ "name": "@nirvana/core", "version": "1.0.0", "main": "index.js", - "license": "MIT", - "dependencies": { - "firebase": "^9.8.2" - } + "license": "MIT" } diff --git a/packages/core/responses/nirvanaResponse.ts b/packages/core/responses/nirvanaResponse.ts new file mode 100644 index 0000000..7317d42 --- /dev/null +++ b/packages/core/responses/nirvanaResponse.ts @@ -0,0 +1,20 @@ +// TODO: enforce this or the other sort of thing for the class +// type INirvanaResponse = +// | { +// data: T; +// error?: Error; +// } +// | { data?: T; error: Error }; + +export default class NirvanaResponse { + data?: T; + error?: Error; + message?: string; + + constructor(_data: T, _error?: Error, _message?: string) { + this.data = _data; + this.error = _error; + + this.message = _message; + } +} diff --git a/packages/core/sockets/channels.ts b/packages/core/sockets/channels.ts new file mode 100644 index 0000000..732ca6e --- /dev/null +++ b/packages/core/sockets/channels.ts @@ -0,0 +1,129 @@ +// ! NOTE: these are legacy and too much thinking in the developers head to understand the flow +enum SocketChannels { + SEND_AUDIO_CLIP = 'SEND_AUDIO_CLIP', + SEND_USER_STATUS_UPDATE = 'SEND_USER_STATUS_UPDATE', + + SEND_STARTED_SPEAKING = 'SEND_STARTED_SPEAKING', + SEND_STOPPED_SPEAKING = 'SEND_STOPPED_SPEAKING', + + JOIN_LIVE_ROOM = 'JOIN_LIVE_ROOM', + GET_ALL_ACTIVE_SOCKET_IDS = 'GET_ALL_ACTIVE_SOCKET_IDS', + + SEND_SIGNAL = 'SEND_SIGNAL', + + RECEIVE_SIGNAL = 'RECEIVE_SIGNAL', + + // v3 + + /** + * when someone connects to a line, whether tuned in or not + */ + CONNECT_TO_LINE = 'CONNECT_TO_LINE', + SOMEONE_CONNECTED_TO_LINE = 'SOMEONE_CONNECTED_TO_LINE', + + TUNE_TO_LINE = 'TUNE_TO_LINE', + SOMEONE_TUNED_TO_LINE = 'SOMEONE_TUNED_TO_LINE', + + SOMEONE_UNTUNED_FROM_LINE = 'SOMEONE_UNTUNED_FROM_LINE', + + USER_BROADCAST_PUSH_PULL = 'USER_BROADCAST_PUSH_PULL', +} + +// ! MAKE SURE THAT THE ENUMS BETWEEN REQUEST AND RESPONSE DON'T OVERLAP??? +// ?maybe won't matter since it's different for server and client? +export enum ServerRequestChannels { + CONNECT_TO_LINE = 'CONNECT_TO_LINE', + + DISCONNECT_FROM_LINE = 'DISCONNECT_FROM_LINE', // TODO: not implementing now + + TUNE_INTO_LINE = 'TUNE_INTO_LINE', // pass in if user wants to toggle/persist? or is this just temporary? + UNTUNE_FROM_LINE = 'UNTUNE_FROM_LINE', + + BROADCAST_TO_LINE = 'BROADCAST_TO_LINE', + STOP_BROADCAST_TO_LINE = 'STOP_BROADCAST_TO_LINE', + + RTC_CALL_SOMEONE_FOR_LINE = 'RTC_CALL_SOMEONE_FOR_LINE', + RTC_ANSWER_SOMEONE_FOR_LINE = 'RTC_ANSWER_SOMEONE_FOR_LINE', + + GOING_INTO_FLOW_STATE = 'GOING_INTO_FLOW_STATE', +} + +export enum ServerResponseChannels { + SOMEONE_CONNECTED_TO_LINE = 'SOMEONE_CONNECTED_TO_LINE', + SOMEONE_DISCONNECTED_FROM_LINE = 'SOMEONE_DISCONNECTED_FROM_LINE', + + SOMEONE_TUNED_INTO_LINE = 'SOMEONE_TUNED_INTO_LINE', // allows all current tuned in folks to create peer objects + SOMEONE_UNTUNED_FROM_LINE = 'SOMEONE_UNTUNED_FROM_LINE', // discard peer + + SOMEONE_STARTED_BROADCASTING = 'SOMEONE_STARTED_BROADCASTING', //show their stream tracks + SOMEONE_STOPPED_BROADCASTING = 'SOMEONE_STOPPED_BROADCASTING', // stop showing their stream tracks + + RTC_NEW_USER_JOINED = 'RTC_NEW_USER_JOINED', + RTC_RECEIVING_MASTER_ANSWER = 'RTC_RECEIVING_MASTER_ANSWER', + + SOMEONE_GOING_INTO_FLOW_STATE = 'SOMEONE_GOING_INTO_FLOW_STATE', +} + +export default SocketChannels; + +export class ConnectToLineRequest { + constructor(public lineId: string) {} +} +export class SomeoneConnectedResponse { + constructor(public lineId: string, public userId: string, public allUsers: string[]) {} +} + +export class SomeoneDisconnectedResponse { + constructor(public lineId: string, public userId: string) {} +} +export class TuneToLineRequest { + constructor(public lineId: string) {} +} +export class SomeoneTunedResponse { + constructor(public lineId: string, public userId: string, public allUsers: string[]) {} +} +export class UntuneFromLineRequest { + constructor(public lineId: string) {} +} +export class SomeoneUntunedFromLineResponse { + constructor(public lineId: string, public userId: string) {} +} + +export class StartBroadcastingRequest { + constructor(public lineId: string) {} +} +export class UserStartedBroadcastingResponse { + constructor(public lineId: string, public userId: string) {} +} + +export class StopBroadcastingRequest { + constructor(public lineId: string) {} +} +export class UserStoppedBroadcastingResponse { + constructor(public lineId: string, public userId: string) {} +} + +// ?another approach to use switch statements, but it just requires same mess, just less methods with socket but who cares right now +export class SocketEmitter { + constructor(public channel: SocketChannels, data: T) {} +} + +export class RtcCallRequest { + constructor(public userToCall: string, public lineId: string, public simplePeerSignal: any) {} +} + +export class RtcNewUserJoinedResponse { + constructor(public userWhoCalled: string, public lineId: string, public simplePeerSignal: any) {} +} + +export class RtcAnswerSomeoneRequest { + constructor(public newbieUserId: string, public lineId: string, public simplePeerSignal: any) {} +} + +export class RtcReceiveAnswerResponse { + constructor(public masterUserId: string, public lineId: string, public simplePeerSignal: any) {} +} + +export class FlowStateRequest { + constructor() {} +} diff --git a/packages/core/src/functions/request/GetTwilioAccessToken.request.ts b/packages/core/src/functions/request/GetTwilioAccessToken.request.ts deleted file mode 100644 index f2353c6..0000000 --- a/packages/core/src/functions/request/GetTwilioAccessToken.request.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default class GetTwilioAccessTokenRequest { - constructor(public roomName: string, public roomType: 'webrtc-go' | 'p2p-group' | 'group-room') {} -} diff --git a/packages/core/src/functions/response/TwilioAccessToken.response.ts b/packages/core/src/functions/response/TwilioAccessToken.response.ts deleted file mode 100644 index 3c9d81c..0000000 --- a/packages/core/src/functions/response/TwilioAccessToken.response.ts +++ /dev/null @@ -1,3 +0,0 @@ -export default class TwilioAccessToken { - constructor(public token: string) {} -} diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts deleted file mode 100644 index 76f132f..0000000 --- a/packages/core/src/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const connectCore = () => { - console.log('CONNECTED COREEEE'); -}; diff --git a/packages/new_api_model/.gitignore b/packages/new_api_model/.gitignore deleted file mode 100644 index 6a7d6d8..0000000 --- a/packages/new_api_model/.gitignore +++ /dev/null @@ -1,130 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* -.pnpm-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# Snowpack dependency directory (https://snowpack.dev/) -web_modules/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional stylelint cache -.stylelintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variable files -.env -.env.development.local -.env.test.local -.env.production.local -.env.local - -# parcel-bundler cache (https://parceljs.org/) -.cache -.parcel-cache - -# Next.js build output -.next -out - -# Nuxt.js build / generate output -.nuxt -dist - -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and not Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# vuepress v2.x temp and cache directory -.temp -.cache - -# Docusaurus cache and generated files -.docusaurus - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TernJS port file -.tern-port - -# Stores VSCode versions used for testing VSCode extensions -.vscode-test - -# yarn v2 -.yarn/cache -.yarn/unplugged -.yarn/build-state.yml -.yarn/install-state.gz -.pnp.* \ No newline at end of file diff --git a/packages/new_api_model/common/index.ts b/packages/new_api_model/common/index.ts deleted file mode 100644 index 76f132f..0000000 --- a/packages/new_api_model/common/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const connectCore = () => { - console.log('CONNECTED COREEEE'); -}; diff --git a/packages/new_api_model/common/models/content.model.ts b/packages/new_api_model/common/models/content.model.ts deleted file mode 100644 index ba59f4c..0000000 --- a/packages/new_api_model/common/models/content.model.ts +++ /dev/null @@ -1,35 +0,0 @@ -export interface IContent { - id: string; - creatorUserId: string; - contentUrl: string; // remote resource of file/media - createdDate: Date; - - // visitCount -} - -// ? persist length of clip for easier viewing for others... -// ?they have to load it anyway and will get metadata anyway? -export class ContentBlock implements IContent { - constructor( - public id: string, - public creatorUserId: string, - public contentUrl: string, - - public contentType: ContentType, - public blobType: string, - - public createdDate: Date, - ) {} -} - -export enum ContentType { - audio = 'audio', - - link = 'link', - - image = 'image', -} - -export function isUrlImage(url: string) { - return url.match(/\.(jpeg|jpg|gif|png)$/) != null; -} diff --git a/packages/new_api_model/common/models/conversation.model.ts b/packages/new_api_model/common/models/conversation.model.ts deleted file mode 100644 index 3ed04d4..0000000 --- a/packages/new_api_model/common/models/conversation.model.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { User } from './user.model'; -export default class Conversation { - constructor( - public id: string, - public createdByUserId: string, - - public memberIdsList: string[], - - public members: MemberMap, - - public userCache: User[], - - public name: string | null = null, - - public lastUpdatedDate: Date, - - public createdDate: Date, - - public membersInRoom: string[] = [], - ) {} -} - -export type MemberMap = { - [memberId: string]: ConversationMember; -}; - -export class ConversationMember { - constructor( - public userId: string, // NOTE: serves as the user ID - - public role: MemberRole, - - public memberState: MemberState, - public isActive: boolean = true, - public lastActiveDate: Date, - public joinedDate = Date, - ) {} -} - -export enum MemberRole { - admin = 'admin', - regular = 'regular', -} -export enum MemberState { - priority = 'priority', - inbox = 'inbox', - // deleted = "deleted" -} diff --git a/packages/new_api_model/common/models/user.model.ts b/packages/new_api_model/common/models/user.model.ts deleted file mode 100644 index 6fa5b16..0000000 --- a/packages/new_api_model/common/models/user.model.ts +++ /dev/null @@ -1,16 +0,0 @@ -export class User { - lastUpdatedDate?: Date; - - priorityConversations?: string[]; // id of all priority convos - - constructor( - public id: string, - public uid: string, - public providerId: string, - public email: string, - public displayName?: string, - public photoUrl?: string, - public phoneNumber?: string, - public createdDate: Date = new Date(), - ) {} -} diff --git a/packages/new_api_model/index.ts b/packages/new_api_model/index.ts deleted file mode 100644 index 22e6615..0000000 --- a/packages/new_api_model/index.ts +++ /dev/null @@ -1,42 +0,0 @@ -import * as Sentry from '@sentry/node'; -import * as Tracing from '@sentry/tracing'; - -/* eslint-disable @typescript-eslint/no-var-requires */ -import express, { Application, NextFunction, Request, Response } from 'express'; - -import InitializeWs from './src/socket'; -import cors from 'cors'; -import morgan from 'morgan'; - -const app = express(); - -app.use(morgan('combined')); -app.use(cors()); -app.use(express.json()); -app.use((req: Request, res: Response, next: NextFunction) => { - console.log('Time: ', new Date()); - next(); -}); -app.get('/', (req: Request, res: Response) => { - res.send('hello world.'); -}); -app.use('/api/status', (req: Request, res: Response) => { - res.json({ message: 'wohoo, server is healthy' }); -}); - -const PORT = process.env.PORT || 8080; -const server = app.listen(PORT, () => - console.log(`express running on port | ${PORT} in host machine`), -); - -// won't catch any errors here and we don't want it to -console.log(); - -const io = require('socket.io')(server, { - // todo: add authentication - cors: { - origin: '*', - }, -}); - -InitializeWs(io); diff --git a/packages/new_api_model/nodemon.json b/packages/new_api_model/nodemon.json deleted file mode 100644 index c9cfbe1..0000000 --- a/packages/new_api_model/nodemon.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "ignore": ["**/*.test.ts", "**/*.spec.ts", "node_modules"], - "watch": ["./", "../common"], - "exec": "npm run start:dev", - "ext": "ts" -} diff --git a/packages/new_api_model/package.json b/packages/new_api_model/package.json deleted file mode 100644 index a682b6c..0000000 --- a/packages/new_api_model/package.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "name": "@nirvana/new_api_model", - "version": "1.0.0", - "main": "index.ts", - "license": "MIT", - "scripts": { - "common": "rm -rf ./common && cp -r ../common/src ./common/", - "dev": "NODE_ENV=development && yarn common && nodemon", - "start:dev": "ts-node index.ts", - "lint": "eslint --ext .ts,.tsx .", - "build": "npm run lint && tsc -p .", - "start": "node dist/index.js", - "gcp-build": "npm run build" - }, - "devDependencies": { - "@types/express": "^4.17.13", - "@types/morgan": "^1.9.3", - "@types/node": "^17.0.21", - "@typescript-eslint/eslint-plugin": "^5.0.0", - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^8.0.1", - "eslint-plugin-import": "^2.25.0", - "nodemon": "^2.0.15", - "typescript": "^4.6.2" - }, - "dependencies": { - "@sentry/node": "^7.0.0", - "@sentry/tracing": "^7.0.0", - "axios": "^0.26.1", - "cors": "^2.8.5", - "express": "^4.17.3", - "firebase": "^9.8.2", - "google-auth-library": "^7.14.0", - "jsonwebtoken": "^8.5.1", - "mongodb": "^4.4.1", - "morgan": "^1.10.0", - "socket.io": "^4.4.1", - "ts-node": "^10.7.0" - } -} diff --git a/packages/new_api_model/tsconfig.json b/packages/new_api_model/tsconfig.json deleted file mode 100644 index cb943b0..0000000 --- a/packages/new_api_model/tsconfig.json +++ /dev/null @@ -1,101 +0,0 @@ -{ - "compilerOptions": { - /* Visit https://aka.ms/tsconfig.json to read more about this file */ - - /* Projects */ - // "incremental": true, /* Enable incremental compilation */ - // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ - // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ - // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ - // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ - // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - - /* Language and Environment */ - "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, - // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ - // "jsx": "preserve", /* Specify what JSX code is generated. */ - // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ - // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ - // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ - // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ - // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ - // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ - // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ - - /* Modules */ - "module": "commonjs" /* Specify what module code is generated. */, - // "rootDir": "./", /* Specify the root folder within your source files. */ - // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ - // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ - // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ - // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ - // "types": [], /* Specify type package names to be included without being referenced in a source file. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - // "resolveJsonModule": true, /* Enable importing .json files */ - // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ - - /* JavaScript Support */ - // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ - // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ - // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ - - /* Emit */ - // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - // "declarationMap": true, /* Create sourcemaps for d.ts files. */ - // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ - // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ - "outDir": "dist" /* Specify an output folder for all emitted files. */, - // "removeComments": true, /* Disable emitting comments. */ - // "noEmit": true, /* Disable emitting files from a compilation. */ - // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ - // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ - // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ - // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ - // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ - // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ - // "newLine": "crlf", /* Set the newline character for emitting files. */ - // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ - // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ - // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ - // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ - // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ - - /* Interop Constraints */ - // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ - // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */, - // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, - - /* Type Checking */ - "strict": true /* Enable all strict type-checking options. */, - // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ - // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ - // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ - // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ - // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ - // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ - // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ - // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ - // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ - // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ - // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ - // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ - // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ - // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ - // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ - // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ - // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ - // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - - /* Completeness */ - // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ - } -}