* feat/173: update dependencies
* feat/173: migrate to playback requests to POST
* feat/173: HTTP startById and startByIndex
* feat/173: HTTP loadById and loadByIndex
* feat/173: add tests
* feat/173: OSC API
* feat/173: Websocket API
This commit is contained in:
Carlos Valente
2022-07-13 15:49:59 +02:00
committed by GitHub
parent 91a0d975b3
commit a20909b882
11 changed files with 415 additions and 122 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "ontime",
"version": "1.3.2",
"version": "1.4.0",
"author": "Carlos Valente",
"description": "Time keeping for live events",
"repository": "https://github.com/cpvalente/ontime",
+14
View File
@@ -87,6 +87,11 @@ const oscInEnabled = osc?.enabled !== undefined ? osc.enabled : config.osc.input
const serverPort = data.settings.serverPort || config.server.port;
/**
* @description starts OSC server
* @param overrideConfig
* @return {Promise<void>}
*/
export const startOSCServer = async (overrideConfig = null) => {
if (!oscInEnabled) {
global.timer.info('RX', 'OSC Input Disabled');
@@ -106,6 +111,11 @@ export const startOSCServer = async (overrideConfig = null) => {
// create HTTP server
const server = http.createServer(app);
/**
* @description Starts all necessary services
* @param overrideConfig
* @return {Promise<string>}
*/
export const startServer = async (overrideConfig = null) => {
const port = 4001; // port hardcoded
@@ -126,6 +136,10 @@ export const startServer = async (overrideConfig = null) => {
return returnMessage;
};
/**
* @description clean shutdown app services
* @return {Promise<void>}
*/
export const shutdown = async () => {
console.log('Node service shutdown');
// shutdown express server
+149 -23
View File
@@ -183,79 +183,135 @@ export class EventTimer extends Timer {
/**
* @description Interface for triggering playback actions
* @param {string} action - state to be triggered
* @param {string|number} [payload] - optional action payload
* @returns {boolean} Whether action was called
*/
trigger(action) {
let reply = true;
trigger(action, payload) {
let success = true;
switch (action) {
case 'start':
case 'start': {
if (this.numEvents === 0 || this.numEvents == null) return false;
// Call action and force update
this.info('PLAYBACK', 'Play Mode Start');
this.start();
break;
case 'pause':
}
case 'startById': {
if (this.numEvents === 0 || this.numEvents == null) return false;
const loaded = this.loadEventById(payload);
if (loaded) {
this.info('PLAYBACK', `Loaded event with ID ${payload}`);
this.info('PLAYBACK', 'Play Mode Start');
this.start();
} else {
return false;
}
break;
}
case 'startByIndex': {
if (this.numEvents === 0 || this.numEvents == null) return false;
const loaded = this.loadEventByIndex(payload);
if (loaded) {
this.info('PLAYBACK', `Loaded event with index ${payload}`);
this.info('PLAYBACK', 'Play Mode Start');
this.start();
} else {
return false;
}
break;
}
case 'pause': {
if (this.numEvents === 0 || this.numEvents == null) return false;
// Call action and force update
this.info('PLAYBACK', 'Play Mode Pause');
this.pause();
break;
case 'stop':
}
case 'stop': {
if (this.numEvents === 0 || this.numEvents == null) return false;
// Call action and force update
this.info('PLAYBACK', 'Play Mode Stop');
this.stop();
break;
case 'roll':
}
case 'roll': {
if (this.numEvents === 0 || this.numEvents == null) return false;
// Call action and force update
this.info('PLAYBACK', 'Play Mode Roll');
this.roll();
break;
case 'previous':
}
case 'previous': {
if (this.numEvents === 0 || this.numEvents == null) return false;
// Call action and force update
this.info('PLAYBACK', 'Play Mode Previous');
this.previous();
break;
case 'next':
}
case 'next': {
if (this.numEvents === 0 || this.numEvents == null) return false;
// Call action and force update
this.info('PLAYBACK', 'Play Mode Next');
this.next();
break;
case 'unload':
}
case 'loadById': {
if (this.numEvents === 0 || this.numEvents == null) return false;
const loaded = this.loadEventById(payload);
if (loaded) {
this.info('PLAYBACK', `Loaded event with ID ${payload}`);
} else {
return false;
}
break;
}
case 'loadByIndex': {
if (this.numEvents === 0 || this.numEvents == null) return false;
const loaded = this.loadEventByIndex(payload);
if (loaded) {
this.info('PLAYBACK', `Loaded event with index ${payload}`);
} else {
return false;
}
break;
}
case 'unload': {
if (this.numEvents === 0 || this.numEvents == null) return false;
// Call action and force update
this.info('PLAYBACK', 'Events unloaded');
this.unload();
break;
case 'reload':
}
case 'reload': {
if (this.numEvents === 0 || this.numEvents == null) return false;
// Call action and force update
this.info('PLAYBACK', 'Reloaded event');
this.reload();
break;
case 'onAir':
}
case 'onAir': {
// Call action
this.info('PLAYBACK', 'Going On Air');
this.setonAir(true);
break;
case 'offAir':
}
case 'offAir': {
// Call action and force update
this.info('PLAYBACK', 'Going Off Air');
this.setonAir(false);
break;
default:
}
default: {
// Error, disable flag
this.error('RX', `Unhandled action triggered ${action}`);
reply = false;
success = false;
break;
}
}
// update state
this.runCycle();
return reply;
return success;
}
/**
@@ -553,9 +609,82 @@ export class EventTimer extends Timer {
/***************************************/
/*** TIMER STATE GETTERS / SETTERS ***/
/*** ------- WEBSOCKET API ------- ***/
/*** ----------------------------- ***/
/***************************************/
/*******************************************/
socket.on('ontime-test', () => {
socket.emit('hello');
});
socket.on('set-start', () => {
this.trigger('start');
socket.emit('playstate', this.state);
});
socket.on('set-startid', (data) => {
this.trigger('startById', data);
socket.emit('playstate', this.state);
});
socket.on('set-startindex', (data) => {
const eventIndex = Number(data);
if (isNaN(eventIndex)) {
return;
}
this.trigger('startByIndex', data);
socket.emit('playstate', this.state);
});
socket.on('set-pause', () => {
this.trigger('pause');
socket.emit('playstate', this.state);
});
socket.on('set-stop', () => {
this.trigger('stop');
socket.emit('playstate', this.state);
});
socket.on('set-reload', () => {
this.trigger('reload');
socket.emit('playstate', this.state);
});
socket.on('set-previous', () => {
this.trigger('previous');
socket.emit('playstate', this.state);
});
socket.on('set-next', () => {
this.trigger('next');
socket.emit('playstate', this.state);
});
socket.on('set-roll', () => {
this.trigger('roll');
socket.emit('playstate', this.state);
});
socket.on('set-delay', (data) => {
const delayTime = Number(data);
if (isNaN(delayTime)) {
return;
}
this.increment(delayTime * 1000 * 60);
});
socket.on('set-onAir', (data) => {
try {
const d = JSON.parse(data);
this.onAir = !!d;
this.broadcastThis('onAir', this.onAir);
} catch (error) {
this.error('RX', `Failed to parse message ${data}`);
}
});
/*******************************************/
// general playback state
socket.on('get-state', () => {
@@ -593,11 +722,6 @@ export class EventTimer extends Timer {
socket.emit('playstate', this.state);
});
socket.on('set-onAir', (data) => {
this.onAir = data;
this.broadcastThis('onAir', this.onAir);
});
socket.on('get-onAir', () => {
socket.emit('onAir', this.onAir);
});
@@ -880,11 +1004,12 @@ export class EventTimer extends Timer {
loadEventById(eventId) {
const eventIndex = this._eventlist.findIndex((e) => e.id === eventId);
if (eventIndex === -1) return;
if (eventIndex === -1) return false;
this.pause();
this.loadEvent(eventIndex, 'load');
// run cycle
this.runCycle();
return true;
}
/**
@@ -892,11 +1017,12 @@ export class EventTimer extends Timer {
* @param {number} eventIndex - Index of event in eventlist
*/
loadEventByIndex(eventIndex) {
if (eventIndex === -1 || eventIndex > this.numEvents) return;
if (eventIndex === -1 || eventIndex > this.numEvents) return false;
this.pause();
this.loadEvent(eventIndex, 'load');
// run cycle
this.runCycle();
return true;
}
/**
@@ -905,7 +1031,7 @@ export class EventTimer extends Timer {
* @param {string} [type='load'] - 'load' or 'reload', whether we are keeping running time
*/
loadEvent(eventIndex, type = 'load') {
const e = this._eventlist[eventIndex];
const e = this._eventlist?.[eventIndex];
if (e == null) return;
const start = e.timeStart == null || e.timeStart === '' ? 0 : e.timeStart;
+10 -10
View File
@@ -89,7 +89,7 @@ export class OSCIntegration {
// only specify special cases
switch (payload) {
case 'overtime':
case 'overtime': {
// Whether timer is negative
this.oscClient.send(`${this.ADDRESS}/overtime`, payload, (err) => {
if (err) {
@@ -98,8 +98,8 @@ export class OSCIntegration {
}
});
break;
case 'title':
}
case 'title': {
if (payload != null && payload !== '') {
// Send Title of current event
this.oscClient.send(`${this.ADDRESS}/title`, payload, (err) => {
@@ -113,8 +113,8 @@ export class OSCIntegration {
reply.message = 'Missing message data';
}
break;
case 'eventNumber':
}
case 'eventNumber': {
if (payload != null && payload !== '') {
// Send event number of current event
this.oscClient.send(`${this.ADDRESS}/eventNumber`, payload, (err) => {
@@ -128,8 +128,8 @@ export class OSCIntegration {
reply.message = 'Missing message data';
}
break;
case 'presenter':
}
case 'presenter': {
if (payload != null && payload !== '') {
// Send timer data on current event
this.oscClient.send(`${this.ADDRESS}/presenter`, payload, (err) => {
@@ -143,11 +143,10 @@ export class OSCIntegration {
reply.message = 'Missing message data';
}
break;
default:
}
default: {
// catch all for messages, allows to add new messages
// but should be used with the integrations definition
// eslint-disable-next-line no-case-declarations
const message = new Message(`${this.ADDRESS}/${messageType}`);
if (payload != null) message.append(payload);
this.oscClient.send(message, (err) => {
@@ -157,6 +156,7 @@ export class OSCIntegration {
}
});
break;
}
}
return reply;
}
+49 -13
View File
@@ -42,36 +42,67 @@ export const initiateOSC = (config) => {
// get second part (command)
switch (path.toLowerCase()) {
case 'onair':
case 'onair': {
global.timer.setonAir(true);
break;
case 'offair':
}
case 'offair': {
global.timer.setonAir(false);
break;
case 'start':
case 'play':
}
case 'play': {
global.timer.trigger('start');
break;
case 'pause':
}
case 'start': {
try {
const eventIndex = Number(args);
if (isNaN(eventIndex)) {
global.timer.error('RX', `OSC IN: event index not recognised ${args}`);
return;
}
const success = global.timer.trigger('startByIndex', eventIndex);
if (!success) {
global.timer.error('RX', `OSC IN: event index not recognised ${args}`);
}
} catch (error) {
console.log('error parsing: ', error);
}
break;
}
case 'startid': {
const success = global.timer.trigger('startById', args);
if (!success) {
global.timer.error('RX', `OSC IN: event ID not recognised ${args}`);
}
break;
}
case 'pause': {
global.timer.trigger('pause');
break;
case 'prev':
}
case 'prev': {
global.timer.trigger('previous');
break;
case 'next':
}
case 'next': {
global.timer.trigger('next');
break;
}
case 'unload':
case 'stop':
case 'stop': {
global.timer.trigger('unload');
break;
case 'reload':
}
case 'reload': {
global.timer.trigger('reload');
break;
case 'roll':
}
case 'roll': {
global.timer.trigger('roll');
break;
case 'delay':
}
case 'delay': {
try {
const t = parseInt(args, 10);
if (isNaN(t)) {
@@ -83,7 +114,9 @@ export const initiateOSC = (config) => {
console.log('error parsing: ', error);
}
break;
}
case 'goto':
case 'load': {
try {
const eventIndex = parseInt(args, 10);
if (isNaN(eventIndex) || eventIndex <= 0) {
@@ -97,8 +130,9 @@ export const initiateOSC = (config) => {
global.timer.error('RX', `OSC IN: error calling goto ${error}`);
}
break;
}
case 'gotoid':
console.log('calling gotoid with', args);
case 'loadid': {
if (args == null) {
global.timer.error('RX', `OSC IN: event id not recognised or out of range ${args}}`);
return;
@@ -109,10 +143,12 @@ export const initiateOSC = (config) => {
global.timer.error('RX', `OSC IN: error calling goto ${error}`);
}
break;
}
default:
default: {
global.timer.warning('RX', `OSC IN: unhandled message ${path}`);
break;
}
}
});
};
@@ -46,6 +46,13 @@ async function _insertAt(entry, index) {
await db.write();
}
/**
* @description Inserts an entry after an element with given Id
* @param entry
* @param id
* @return {Promise<void>}
* @private
*/
async function _insertAfterId(entry, id) {
const index = [...data.events].findIndex((event) => event.id === id);
await _insertAt(entry, index + 1);
+39 -1
View File
@@ -19,7 +19,23 @@ export const offAir = async (req, res) => {
// Create controller for GET request to '/playback/start'
// Starts timer object
export const pbStart = async (req, res) => {
global.timer.trigger('start') ? res.sendStatus(200) : res.sendStatus(400);
const { eventId, eventIndex } = req.query;
if (eventId) {
global.timer.trigger('startById', eventId)
? res.sendStatus(200)
: res.status(400).send('Invalid event ID');
} else if (eventIndex) {
const index = Number(eventIndex);
if (!isNaN(index)) {
global.timer.trigger('startByIndex', index - 1)
? res.sendStatus(200)
: res.status(400).send('Invalid event index');
} else {
res.status(400).send('Invalid event index');
}
} else {
global.timer.trigger('start') ? res.sendStatus(200) : res.sendStatus(400);
}
};
// Create controller for GET request to '/playback/pause'
@@ -52,6 +68,28 @@ export const pbNext = async (req, res) => {
global.timer.trigger('next') ? res.sendStatus(200) : res.sendStatus(400);
};
// Create controller for GET request to '/playback/load'
// Load requested event
export const pbLoad = async (req, res) => {
const { eventId, eventIndex } = req.query;
if (eventId) {
global.timer.trigger('loadById', eventId)
? res.sendStatus(200)
: res.status(400).send('Invalid event ID');
} else if (eventIndex) {
const index = Number(eventIndex);
if (!isNaN(index)) {
global.timer.trigger('loadByIndex', index - 1)
? res.sendStatus(200)
: res.status(400).send('Invalid event index');
} else {
res.status(400).send('Invalid event index');
}
} else {
res.status(400).send('No event given');
}
};
// Create controller for GET request to '/playback/unload'
// Unloads any events
export const pbUnload = async (req, res) => {
+5 -6
View File
@@ -1,20 +1,19 @@
{
"name": "ontime-server",
"type": "module",
"version": "1.1.1",
"version": "1.2.0",
"dependencies": {
"body-parser": "^1.20.0",
"dotenv": "^16.0.0",
"express": "^4.18.0",
"express-session": "~1.17.1",
"dotenv": "^16.0.1",
"express": "^4.18.1",
"express-session": "^1.17.3",
"lowdb": "3.0.0",
"multer": "^1.4.4",
"nanoid": "^3.3.3",
"node-osc": "^6.1.16",
"node-xlsx": "^0.21.0",
"passport": "^0.5.2",
"passport": "^0.6.0",
"passport-local": "~1.0.0",
"socket-io": "^1.0.0",
"socket.io": "^4.4.1"
},
"devDependencies": {
@@ -18,100 +18,91 @@ describe('When a GET request request is sent', () => {
});
});
describe('When a GET state change is sent', () => {
test('GET /playback/onAir returns 200', async () => {
describe('When a POST state change is sent', () => {
test('POST /playback/onAir returns 200', async () => {
await supertest(server)
.get('/playback/onAir')
.post('/playback/onAir')
.expect(200)
.then((response) => {
expect(response.text.includes('<!doctype html>')).toBe(false);
});
});
test('GET /playback/offAir returns 200', async () => {
test('POST /playback/offAir returns 200', async () => {
await supertest(server)
.get('/playback/offAir')
.post('/playback/offAir')
.expect(200)
.then((response) => {
expect(response.text.includes('<!doctype html>')).toBe(false);
});
});
test('GET /playback/start returns 200', async () => {
test('POST /playback/start returns 200', async () => {
await supertest(server)
.get('/playback/start')
.post('/playback/start')
.expect(200)
.then((response) => {
expect(response.text.includes('<!doctype html>')).toBe(false);
});
});
test('GET /playback/play returns 200', async () => {
test('POST /playback/pause returns 200', async () => {
await supertest(server)
.get('/playback/play')
.post('/playback/pause')
.expect(200)
.then((response) => {
expect(response.text.includes('<!doctype html>')).toBe(false);
});
});
test('GET /playback/pause returns 200', async () => {
test('POST /playback/stop returns 200', async () => {
await supertest(server)
.get('/playback/pause')
.post('/playback/stop')
.expect(200)
.then((response) => {
expect(response.text.includes('<!doctype html>')).toBe(false);
});
});
test('GET /playback/stop returns 200', async () => {
test('POST /playback/roll returns 200', async () => {
await supertest(server)
.get('/playback/stop')
.post('/playback/roll')
.expect(200)
.then((response) => {
expect(response.text.includes('<!doctype html>')).toBe(false);
});
});
test('GET /playback/roll returns 200', async () => {
test('POST /playback/previous returns 200', async () => {
await supertest(server)
.get('/playback/roll')
.post('/playback/previous')
.expect(200)
.then((response) => {
expect(response.text.includes('<!doctype html>')).toBe(false);
});
});
test('GET /playback/previous returns 200', async () => {
test('POST /playback/next returns 200', async () => {
await supertest(server)
.get('/playback/previous')
.post('/playback/next')
.expect(200)
.then((response) => {
expect(response.text.includes('<!doctype html>')).toBe(false);
});
});
test('GET /playback/next returns 200', async () => {
test('POST /playback/unload returns 200', async () => {
await supertest(server)
.get('/playback/next')
.post('/playback/unload')
.expect(200)
.then((response) => {
expect(response.text.includes('<!doctype html>')).toBe(false);
});
});
test('GET /playback/unload returns 200', async () => {
test('POST /playback/reload returns 200', async () => {
await supertest(server)
.get('/playback/unload')
.expect(200)
.then((response) => {
expect(response.text.includes('<!doctype html>')).toBe(false);
});
});
test('GET /playback/reload returns 200', async () => {
await supertest(server)
.get('/playback/reload')
.post('/playback/reload')
.expect(200)
.then((response) => {
expect(response.text.includes('<!doctype html>')).toBe(false);
@@ -126,4 +117,82 @@ describe('When a GET state change is sent', () => {
expect(response.text.includes('<!doctype html>')).toBe(true);
});
});
test('POST of unknown request returns 404', async () => {
await supertest(server).post('/playback/madeup').expect(404);
});
});
describe('Test POST requests with payload', () => {
describe('Start given event', () => {
test('POST /playback/start with correctly given ID', async () => {
await supertest(server)
.post('/playback/start')
.query({eventId: '5946'})
.expect(200);
});
test('POST /playback/start with correctly given index', async () => {
await supertest(server)
.post('/playback/start')
.query({eventIndex: '2'})
.expect(200);
});
test('POST /playback/start with incorrectly given ID', async () => {
await supertest(server)
.post('/playback/start')
.query({
eventId: 'doesntexist',
})
.expect(400);
});
test('POST /playback/start with incorrectly given index', async () => {
await supertest(server)
.post('/playback/start')
.query({
eventIndex: '25',
})
.expect(400);
});
test('POST /playback/start with incorrectly given index (NaN)', async () => {
await supertest(server)
.post('/playback/start')
.query({
eventIndex: 'notanumber',
})
.expect(400);
});
});
describe('Load given event', () => {
test('POST /playback/load with correctly given ID', async () => {
await supertest(server)
.post('/playback/load')
.query({eventId: '5946'})
.expect(200);
});
test('POST /playback/load with correctly given index', async () => {
await supertest(server)
.post('/playback/load')
.query({eventIndex: '2'})
.expect(200);
});
test('POST /playback/load with incorrectly given ID', async () => {
await supertest(server)
.post('/playback/load')
.query({eventId: 'doesntexist'})
.expect(400);
});
test('POST /playback/load with incorrectly given index', async () => {
await supertest(server)
.post('/playback/load')
.query({eventIndex: '25'})
.expect(400);
});
test('POST /playback/load with incorrectly given index (NaN)', async () => {
await supertest(server)
.post('/playback/load')
.query({ eventIndex: 'notanumber' })
.expect(400);
});
});
});
+14 -11
View File
@@ -12,6 +12,7 @@ import {
pbRoll,
pbPrevious,
pbNext,
pbLoad,
pbUnload,
pbReload,
} from '../controllers/playbackController.js';
@@ -20,32 +21,34 @@ import {
router.get('/', pbGet);
// create route between controller and '/playback/onAir' endpoint
router.get('/onAir', onAir);
router.post('/onAir', onAir);
// create route between controller and '/playback/offAir' endpoint
router.get('/offAir', offAir);
router.post('/offAir', offAir);
// create route between controller and '/playback/start' endpoint
router.get('/start', pbStart);
router.get('/play', pbStart);
router.post('/start', pbStart);
// create route between controller and '/playback/pause' endpoint
router.get('/pause', pbPause);
router.post('/pause', pbPause);
// create route between controller and '/playback/stop' endpoint
router.get('/stop', pbStop);
router.post('/stop', pbStop);
// create route between controller and '/playback/roll' endpoint
router.get('/roll', pbRoll);
router.post('/roll', pbRoll);
// create route between controller and '/playback/previous' endpoint
router.get('/previous', pbPrevious);
router.post('/previous', pbPrevious);
// create route between controller and '/playback/next' endpoint
router.get('/next', pbNext);
router.post('/next', pbNext);
// create route between controller and '/playback/load' endpoint
router.post('/load', pbLoad);
// create route between controller and '/playback/unload' endpoint
router.get('/unload', pbUnload);
router.post('/unload', pbUnload);
// create route between controller and '/playback/reload' endpoint
router.get('/reload', pbReload);
router.post('/reload', pbReload);
+28 -27
View File
@@ -282,16 +282,21 @@ cookie-signature@1.0.6:
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
cookie@0.4.1, cookie@~0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1"
integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==
cookie@0.4.2:
version "0.4.2"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432"
integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==
cookie@0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b"
integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
cookie@~0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1"
integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==
core-util-is@~1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
@@ -373,10 +378,10 @@ doctrine@^3.0.0:
dependencies:
esutils "^2.0.2"
dotenv@^16.0.0:
version "16.0.0"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.0.tgz#c619001253be89ebb638d027b609c75c26e47411"
integrity sha512-qD9WU0MPM4SWLPJy/r2Be+2WgQj8plChsyrCNQzW/0WjvcJQiKQJ9mH3ZgB3fxbUUxgc/11ZJ0Fi5KiimWGz2Q==
dotenv@^16.0.1:
version "16.0.1"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.1.tgz#8f8f9d94876c35dac989876a5d3a82a267fdce1d"
integrity sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==
ee-first@1.1.1:
version "1.1.1"
@@ -540,12 +545,12 @@ exit-on-epipe@~1.0.1:
resolved "https://registry.yarnpkg.com/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz#0bdd92e87d5285d267daa8171d0eb06159689692"
integrity sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==
express-session@~1.17.1:
version "1.17.2"
resolved "https://registry.yarnpkg.com/express-session/-/express-session-1.17.2.tgz#397020374f9bf7997f891b85ea338767b30d0efd"
integrity sha512-mPcYcLA0lvh7D4Oqr5aNJFMtBMKPLl++OKKxkHzZ0U0oDq1rpKBnkR5f5vCHR26VeArlTOEF9td4x5IjICksRQ==
express-session@^1.17.3:
version "1.17.3"
resolved "https://registry.yarnpkg.com/express-session/-/express-session-1.17.3.tgz#14b997a15ed43e5949cb1d073725675dd2777f36"
integrity sha512-4+otWXlShYlG1Ma+2Jnn+xgKUZTMJ5QD3YvfilX3AcocOAbIkVylSWEklzALe/+Pu4qV6TYBj5GwOBFfdKqLBw==
dependencies:
cookie "0.4.1"
cookie "0.4.2"
cookie-signature "1.0.6"
debug "2.6.9"
depd "~2.0.0"
@@ -554,10 +559,10 @@ express-session@~1.17.1:
safe-buffer "5.2.1"
uid-safe "~2.1.5"
express@^4.18.0:
version "4.18.0"
resolved "https://registry.yarnpkg.com/express/-/express-4.18.0.tgz#7a426773325d0dd5406395220614c0db10b6e8e2"
integrity sha512-EJEXxiTQJS3lIPrU1AE2vRuT7X7E+0KBbpm5GSoK524yl0K8X+er8zS2P14E64eqsVNoWbMCT7MpmQ+ErAhgRg==
express@^4.18.1:
version "4.18.1"
resolved "https://registry.yarnpkg.com/express/-/express-4.18.1.tgz#7797de8b9c72c857b9cd0e14a5eea80666267caf"
integrity sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==
dependencies:
accepts "~1.3.8"
array-flatten "1.1.1"
@@ -1051,13 +1056,14 @@ passport-strategy@1.x.x:
resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4"
integrity sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=
passport@^0.5.2:
version "0.5.2"
resolved "https://registry.yarnpkg.com/passport/-/passport-0.5.2.tgz#0cb38dd8a71552c8390dfa6a9a6f7f3909954bcf"
integrity sha512-w9n/Ot5I7orGD4y+7V3EFJCQEznE5RxHamUxcqLT2QoJY0f2JdN8GyHonYFvN0Vz+L6lUJfVhrk2aZz2LbuREw==
passport@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/passport/-/passport-0.6.0.tgz#e869579fab465b5c0b291e841e6cc95c005fac9d"
integrity sha512-0fe+p3ZnrWRW74fe8+SvCyf4a3Pb2/h7gFkQ8yTJpAO50gDzlfjZUZTO1k5Eg9kUct22OxHLqDZoKUWRHOh9ug==
dependencies:
passport-strategy "1.x.x"
pause "0.0.1"
utils-merge "^1.0.1"
path-is-absolute@^1.0.0:
version "1.0.1"
@@ -1266,11 +1272,6 @@ side-channel@^1.0.4:
get-intrinsic "^1.0.2"
object-inspect "^1.9.0"
socket-io@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/socket-io/-/socket-io-1.0.0.tgz#fc566f4d30a6370224d07e65dcef386bd8f5d296"
integrity sha1-/FZvTTCmNwIk0H5l3O84a9j10pY=
socket.io-adapter@~2.3.3:
version "2.3.3"
resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.3.3.tgz#4d6111e4d42e9f7646e365b4f578269821f13486"
@@ -1409,7 +1410,7 @@ util-deprecate@~1.0.1:
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
utils-merge@1.0.1:
utils-merge@1.0.1, utils-merge@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=