forked from sagi/seepur
wip
This commit is contained in:
parent
1eaf0a6176
commit
b02adbdb43
59 changed files with 2617 additions and 341 deletions
5
.babelrc
Normal file
5
.babelrc
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"plugins": [
|
||||
"@babel/plugin-transform-regenerator"
|
||||
]
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
'use strict'
|
||||
const User = use('App/Models/User');
|
||||
const Child = use('App/Models/Child')
|
||||
const Link = use('App/Models/Link')
|
||||
const Child = use('App/Models/Child');
|
||||
const Link = use('App/Models/Link');
|
||||
const IceServer = use('App/Models/IceServer');
|
||||
class AdminApiController {
|
||||
async getUsers({response}) {
|
||||
console.log('API');
|
||||
|
@ -12,6 +13,8 @@ class AdminApiController {
|
|||
// });
|
||||
return users;
|
||||
}
|
||||
async addStunServer({request, response}) {}
|
||||
async addTurnServer({request, response}) {}
|
||||
}
|
||||
|
||||
module.exports = AdminApiController
|
||||
|
|
|
@ -32,8 +32,8 @@ class AuthController {
|
|||
try {
|
||||
const token = await auth.attempt(email, password);
|
||||
const user = auth.user;
|
||||
user.last_logged_in = new Date();
|
||||
await user.save();
|
||||
// user.last_logged_in = new Date();
|
||||
// await user.save();
|
||||
console.log('logged in');
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
|
|
@ -3,44 +3,18 @@ const {validate, rule} = use('Validator');
|
|||
const User = use('App/Models/User');
|
||||
const Child = use('App/Models/Child')
|
||||
const Link = use('App/Models/Link');
|
||||
// import FileUtils from '../../Utils/FileUtils';
|
||||
const Call = use('App/Models/Call');
|
||||
|
||||
const FileUtils = use('App/Utils/FileUtils');
|
||||
const UserChildUtils = use('App/Utils/UserChildUtils');
|
||||
const uuidv4 = require('uuid').v4;
|
||||
|
||||
class ClientApiController {
|
||||
async getConnections({request, auth, response}) {
|
||||
try {
|
||||
const user = auth.user;
|
||||
const userLinks = (await user.links().fetch()).rows;
|
||||
// console.log(userLinks.toJSON());
|
||||
let links = Promise.resolve({});
|
||||
const result = await Promise.all(userLinks.map(async (l) => {
|
||||
const child = await l.child().fetch();
|
||||
const is_parent = !!l.is_parent;
|
||||
const childLinks = (await child.links().fetch())
|
||||
.rows.filter(l => l.user_id != user.id);
|
||||
const linkedUsers = await Promise.all(childLinks.map(async l => {
|
||||
return (await l.user().fetch()).toJSON();
|
||||
}));
|
||||
return {
|
||||
...child.toJSON(), linkedUsers, is_parent
|
||||
}
|
||||
}));
|
||||
return result;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
response.send(err.message);
|
||||
}
|
||||
}
|
||||
|
||||
async getUser({auth}) {
|
||||
const user = auth.user.toJSON();
|
||||
const children = await Promise.all((await auth.user.links().fetch())
|
||||
.rows.filter(l => l.is_parent)
|
||||
.map(async (l) => {
|
||||
return await l.child().fetch();
|
||||
}));
|
||||
const connections = await UserChildUtils.getUserConnections(user.id);
|
||||
return {
|
||||
...user, children
|
||||
...user, connections: {...connections}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,6 +44,145 @@ class ClientApiController {
|
|||
{user_id: auth.user.id, child_id: child.id, is_parent: true});
|
||||
return child;
|
||||
}
|
||||
|
||||
async createCall({auth, request, response}) {
|
||||
try {
|
||||
const user = auth.user;
|
||||
const rules = {
|
||||
connection_id: 'number|required',
|
||||
child_id: 'number|required',
|
||||
};
|
||||
const validation = await validate(request.all(), rules);
|
||||
if (validation.fails()) {
|
||||
response.status(400);
|
||||
response.send(validation.messages());
|
||||
return false;
|
||||
}
|
||||
const body = request.body;
|
||||
if (!(await UserChildUtils.isParentOf(user.id, body.child_id))) {
|
||||
response.status(403);
|
||||
response.send({code: 403, message: 'Unauthorized'});
|
||||
return false;
|
||||
}
|
||||
if (!(await UserChildUtils.isUserConnectedToChild(
|
||||
body.connection_id, body.child_id))) {
|
||||
response.status(403);
|
||||
response.send({code: 403, message: 'Unauthorized'});
|
||||
return false;
|
||||
}
|
||||
const call = await Call.create({
|
||||
state: 'NEW',
|
||||
user_1: user.id,
|
||||
user_2: body.connection_id,
|
||||
child_id: body.child_id
|
||||
});
|
||||
return {
|
||||
code: 0, data: call
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
async getChild({auth, request, response}) {
|
||||
const userId = auth.user.id;
|
||||
const childId = request.params.id;
|
||||
console.log(`${userId} -> ${childId}`);
|
||||
const hasPermission =
|
||||
await UserChildUtils.isUserConnectedToChild(userId, childId);
|
||||
if (!hasPermission) {
|
||||
response.status(403);
|
||||
response.send(
|
||||
{code: 403, message: `You have no permission to connect with child`});
|
||||
return false;
|
||||
}
|
||||
const child = await Child.find(childId);
|
||||
const parents = await UserChildUtils.getChildParents(childId);
|
||||
const connections = await UserChildUtils.getChildConnections(childId);
|
||||
return {
|
||||
code: 0, data: {...child.toJSON(), parents, connections}
|
||||
}
|
||||
}
|
||||
|
||||
async createConnection({request, auth, response}) {
|
||||
try {
|
||||
const user = auth.user;
|
||||
const rules = {
|
||||
email: 'string|email|required',
|
||||
is_parent: 'boolean|required',
|
||||
child_id: 'number|required'
|
||||
};
|
||||
const validation = await validate(request.all(), rules);
|
||||
if (validation.fails()) {
|
||||
response.status(400);
|
||||
response.send(validation.messages());
|
||||
return false;
|
||||
}
|
||||
const body = request.body;
|
||||
if (!await UserChildUtils.isParentOf(user.id, body.child_id)) {
|
||||
response.status(403);
|
||||
response.send({
|
||||
code: 403,
|
||||
message: `You have no permission to add connection to child`
|
||||
});
|
||||
return false;
|
||||
}
|
||||
const usersWithEmail =
|
||||
(await User.query().where({email: body.email}).fetch()).rows;
|
||||
if (!usersWithEmail.length) {
|
||||
return {code: 404, message: 'No user with that Email...'};
|
||||
}
|
||||
const targetUser = usersWithEmail[0];
|
||||
if (await UserChildUtils.isUserConnectedToChild(
|
||||
targetUser.id, body.child_id)) {
|
||||
return {code: 409, message: 'User already connected'};
|
||||
}
|
||||
return {
|
||||
code: 0,
|
||||
data: await UserChildUtils.addConnection(
|
||||
body.child_id, targetUser.id, body.is_parent)
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return error;
|
||||
}
|
||||
//
|
||||
}
|
||||
|
||||
async setChildProfileCover({request, auth, response}) {
|
||||
try {
|
||||
const rules = {
|
||||
profile_cover: [rule('regex', /^(data:image\/\w+;base64).+/)]
|
||||
};
|
||||
const validation = await validate(request.all(), rules);
|
||||
if (validation.fails()) {
|
||||
response.status(400);
|
||||
response.send(validation.messages());
|
||||
return false;
|
||||
}
|
||||
const body = request.body;
|
||||
const userId = auth.user.id;
|
||||
const childId = request.params.id;
|
||||
const isParent = await UserChildUtils.isParentOf(userId, childId);
|
||||
if (!isParent) {
|
||||
response.status(403);
|
||||
response.send(
|
||||
{code: 403, message: `You have no permission to edit this child`});
|
||||
return false;
|
||||
}
|
||||
const child = await Child.find(childId);
|
||||
const file = await FileUtils.saveBase64File(body.profile_cover);
|
||||
console.log(file);
|
||||
child.profile_cover = `/u/images/${file.fileName}`;
|
||||
await child.save();
|
||||
return child.profile_cover;
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ClientApiController
|
||||
|
|
120
app/Controllers/Ws/SignalingController.js
Normal file
120
app/Controllers/Ws/SignalingController.js
Normal file
|
@ -0,0 +1,120 @@
|
|||
'use strict'
|
||||
const User = use('App/Models/User');
|
||||
const UserChildUtils = use('App/Utils/UserChildUtils');
|
||||
const Call = use('App/Models/Call');
|
||||
const IceServer = use('App/Models/IceServer');
|
||||
const calls = {};
|
||||
|
||||
class SignalingController {
|
||||
constructor({socket, request, auth, call}) {
|
||||
this.callId = socket.topic.split(':')[1];
|
||||
this.user = auth.user;
|
||||
this.socket = socket;
|
||||
this.request = request;
|
||||
this.register(call);
|
||||
console.log(`User #${this.user.id} connected to call ${this.callId}`);
|
||||
}
|
||||
register(callModel) {
|
||||
if (!calls[this.callId])
|
||||
calls[this.callId] = new CallSession(callModel);
|
||||
else
|
||||
console.log(`Call #${this.callId} Already Found`);
|
||||
const callSession = calls[this.callId];
|
||||
callSession.registerUser(this.user, this.socket)
|
||||
.then(
|
||||
success => {
|
||||
|
||||
})
|
||||
.catch(
|
||||
error => {
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
onClose() {
|
||||
console.log(`User #${this.user.id} left call ${this.callId}`);
|
||||
}
|
||||
}
|
||||
|
||||
class CallSession {
|
||||
// states: NEW -> STARTED -> IN_PROGRESS -> ENDED
|
||||
constructor(callModel) {
|
||||
this.callId = callModel.id;
|
||||
this.callModel = callModel;
|
||||
this.state = callModel.state;
|
||||
this.user_1 = {id: callModel.user_1, socket: null, userModel: null};
|
||||
this.user_2 = {id: callModel.user_2, socket: null, userModel: null};
|
||||
this.startTime = Date.now();
|
||||
this.heartbeat = setInterval(this.onHeartbeat.bind(this), 5000);
|
||||
}
|
||||
onHeartbeat() {
|
||||
console.log(`We have ${Object.keys(calls).length} ongoing calls. Ids=${
|
||||
Object.keys(calls)}`)
|
||||
console.log(`Heartbeat for call #${this.callId} State: ${this.state}`);
|
||||
}
|
||||
async registerUser(user, socket) {
|
||||
let userIndex = -1;
|
||||
if (this.user_1.id === user.id)
|
||||
userIndex = 1;
|
||||
else if (this.user_2.id === user.id)
|
||||
userIndex = 2;
|
||||
if (userIndex < 0) return false;
|
||||
this[`user_${userIndex}`].userModel = user;
|
||||
this[`user_${userIndex}`].socket = socket;
|
||||
socket.on('wrtc:sdp:offer', this.onSdpOffer.bind(this));
|
||||
socket.on('wrtc:sdp:answer', this.onSdpAnswer.bind(this));
|
||||
socket.on('wrtc:ice', this.onIceCandidate.bind(this));
|
||||
await this.updateState();
|
||||
if (this.state === 'STARTED') await this.sendStandby(socket, userIndex);
|
||||
if (this.state === 'IN_PROGRESS') await this.sendStart(socket, userIndex);
|
||||
return true;
|
||||
}
|
||||
async sendStandby(socket, userIndex) {
|
||||
const iceServers = (await IceServer.all()).rows.map(i => i.toJSON());
|
||||
socket.emit('call:standby', {iceServers, id: userIndex});
|
||||
}
|
||||
async sendStart(socket, userIndex) {
|
||||
const iceServers = (await IceServer.all()).rows.map(i => i.toJSON());
|
||||
socket.emit('call:start', {iceServers, id: userIndex});
|
||||
}
|
||||
async updateState() {
|
||||
console.log(`Call #${this.callId} state=${this.state}`);
|
||||
switch (this.state) {
|
||||
case 'NEW':
|
||||
if (this.areAllPartnersConnected())
|
||||
this.state = 'IN_PROGRESS';
|
||||
else
|
||||
this.state = 'STARTED';
|
||||
case 'STARTED':
|
||||
if (this.areAllPartnersConnected()) this.state = 'IN_PROGRESS';
|
||||
}
|
||||
console.log(`Call #${this.callId} state=${this.state}`);
|
||||
}
|
||||
areAllPartnersConnected() {
|
||||
return !!this.user_1.socket && !!this.user_2.socket;
|
||||
}
|
||||
async onIceCandidate(payload) {
|
||||
const {from = id, ice} = payload;
|
||||
const to = from === 1 ? 2 : 1;
|
||||
this[`user_${to}`].socket.emit('wrtc:ice', {sdp});
|
||||
console.log(`[Signal] [onIceCandidate] ${from} -> ${to}`)
|
||||
return true;
|
||||
}
|
||||
async onSdpOffer(payload) {
|
||||
const {from = payload.id, sdp} = payload;
|
||||
const to = from === 1 ? 2 : 1;
|
||||
this[`user_${to}`].socket.emit('wrtc:sdp:offer', {sdp});
|
||||
console.log(`[Signal] [onSdpOffer] ${from} -> ${to}`)
|
||||
return true;
|
||||
}
|
||||
|
||||
async onSdpAnswer(payload) {
|
||||
const {from = payload.id, sdp} = payload;
|
||||
const to = from === 1 ? 2 : 1;
|
||||
this[`user_${to}`].socket.emit('wrtc:sdp:answer', {sdp});
|
||||
console.log(`[Signal] [onSdpAnswer] ${from} -> ${to}`)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SignalingController
|
73
app/Controllers/Ws/UserChannelController.js
Normal file
73
app/Controllers/Ws/UserChannelController.js
Normal file
|
@ -0,0 +1,73 @@
|
|||
'use strict'
|
||||
const UserChildUtils = use('App/Utils/UserChildUtils');
|
||||
const connectedUsers = {
|
||||
|
||||
};
|
||||
|
||||
class UserChannelController {
|
||||
constructor({socket, request, auth}) {
|
||||
console.log(`User #${auth.user.id} connected`);
|
||||
this.socket = socket;
|
||||
this.request = request;
|
||||
this.user = auth.user;
|
||||
connectedUsers[this.user.id] = this;
|
||||
this.notifyOnConnection(true).catch(console.error);
|
||||
// socket.on('close', this.onClose.bind(this))
|
||||
}
|
||||
onClose() {
|
||||
this.notifyOnConnection(false)
|
||||
.then(_ => {
|
||||
delete connectedUsers[this.user.id];
|
||||
})
|
||||
.catch(console.error);
|
||||
}
|
||||
emit(event, data) {
|
||||
this.socket.emit(event, data);
|
||||
}
|
||||
|
||||
static getUserChannel(userId) {
|
||||
return connectedUsers[userId];
|
||||
}
|
||||
static isUserOnline(userId) {
|
||||
return !!UserChannelController.getUserChannel(userId);
|
||||
}
|
||||
async notifyOnConnection(online) {
|
||||
this.user.last_logged_in = new Date();
|
||||
try {
|
||||
await this.user.save();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
const userConnections =
|
||||
await UserChildUtils.getUserConnections(this.user.id);
|
||||
const notifiedIds = [];
|
||||
for (const child of userConnections.children) {
|
||||
for (const user of child.connections) {
|
||||
const channel = UserChannelController.getUserChannel(user.id);
|
||||
if (channel && notifiedIds.indexOf(user.id) < 0 &&
|
||||
user.id != this.user.id) {
|
||||
/// connection:online
|
||||
channel.emit(
|
||||
`connection:${online ? 'online' : 'offline'}`,
|
||||
this.user.toJSON());
|
||||
notifiedIds.push(user.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const child of userConnections.connections) {
|
||||
for (const user of child.connections) {
|
||||
const channel = UserChannelController.getUserChannel(user.id);
|
||||
if (channel && notifiedIds.indexOf(user.id) < 0 &&
|
||||
user.id != this.user.id) {
|
||||
channel.emit(
|
||||
`connection:${online ? 'online' : 'offline'}`,
|
||||
this.user.toJSON());
|
||||
notifiedIds.push(user.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = UserChannelController
|
32
app/Middleware/WsCallAuth.js
Normal file
32
app/Middleware/WsCallAuth.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
'use strict'
|
||||
/** @typedef {import('@adonisjs/framework/src/Request')} Request */
|
||||
/** @typedef {import('@adonisjs/framework/src/Response')} Response */
|
||||
/** @typedef {import('@adonisjs/framework/src/View')} View */
|
||||
|
||||
const Call = use('App/Models/Call');
|
||||
|
||||
class WsCallAuth {
|
||||
/**
|
||||
* @param {object} ctx
|
||||
* @param {Request} ctx.request
|
||||
* @param {Function} next
|
||||
*/
|
||||
async wsHandle(ctx, next) {
|
||||
const {request, auth, socket} = ctx;
|
||||
const callId = Number(socket.topic.split(':')[1]);
|
||||
const user = auth.user;
|
||||
const call = await Call.find(callId);
|
||||
if (!call) {
|
||||
throw new Error('Call not found');
|
||||
}
|
||||
if (user.id === call.user_1 || user.id === call.user_2) {
|
||||
ctx.call = call;
|
||||
await next()
|
||||
}
|
||||
// call next to advance the request
|
||||
else
|
||||
throw new Error('Not allowed');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = WsCallAuth
|
9
app/Models/Call.js
Normal file
9
app/Models/Call.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
'use strict'
|
||||
|
||||
/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */
|
||||
const Model = use('Model')
|
||||
|
||||
class Call extends Model {
|
||||
}
|
||||
|
||||
module.exports = Call
|
33
app/Models/IceServer.js
Normal file
33
app/Models/IceServer.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
'use strict'
|
||||
|
||||
/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */
|
||||
const Model = use('Model')
|
||||
const uuidv4 = require('uuid').v4;
|
||||
const crypto = require('crypto')
|
||||
|
||||
class IceServer extends Model {
|
||||
toJSON() {
|
||||
const json = {};
|
||||
if (this.type === 'STUN') {
|
||||
json.urls = `stun:${this.url}:${this.port}`;
|
||||
} else {
|
||||
json.urls = '';
|
||||
json.username = `${Math.ceil(Date.now() / 1000)}:${uuidv4()}`
|
||||
json.credential = this.getCredentials(json.username);
|
||||
if (this.protocol === 'UDP') {
|
||||
json.urls = `turn:${this.url}:${this.port}?transport=udp`;
|
||||
} else if (this.protocol === 'TCP') {
|
||||
json.urls = `turn:${this.url}:${this.port}?transport=tcp`;
|
||||
}
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
getCredentials(username) {
|
||||
return crypto.createHmac('sha1', this.secret)
|
||||
.update(username)
|
||||
.digest('base64');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = IceServer
|
69
app/Utils/UserChildUtils.js
Normal file
69
app/Utils/UserChildUtils.js
Normal file
|
@ -0,0 +1,69 @@
|
|||
|
||||
|
||||
const Link = use('App/Models/Link');
|
||||
class UserChildUtils {
|
||||
static async isUserConnectedToChild(user_id, child_id) {
|
||||
const links = await Link.query().where({user_id, child_id}).fetch();
|
||||
return !!links.rows.length;
|
||||
}
|
||||
|
||||
static async isParentOf(user_id, child_id) {
|
||||
const links =
|
||||
await Link.query().where({user_id, child_id, is_parent: true}).fetch();
|
||||
return !!links.rows.length;
|
||||
}
|
||||
|
||||
static async getChildParents(child_id) {
|
||||
const links = await Link.query().where({child_id, is_parent: true}).fetch();
|
||||
const parents = await Promise.all(links.rows.map(async l => {
|
||||
return l.user().fetch();
|
||||
}));
|
||||
return parents;
|
||||
}
|
||||
|
||||
static async getUserConnections(user_id) {
|
||||
const links = await Link.query().where({user_id}).fetch();
|
||||
const connections = await links.rows.reduce(async (_prev, link) => {
|
||||
const prev = await _prev;
|
||||
const is_parent = link.is_parent;
|
||||
const child = await link.child().fetch();
|
||||
if (is_parent) {
|
||||
const parents = await UserChildUtils.getChildParents(child.id);
|
||||
const nonSameUserParents = parents.filter(p => p.id != user_id);
|
||||
prev.children.push({
|
||||
...child.toJSON(),
|
||||
connections: [
|
||||
...await UserChildUtils.getChildConnections(child.id),
|
||||
...nonSameUserParents
|
||||
]
|
||||
})
|
||||
} else {
|
||||
prev.connections.push({
|
||||
...child.toJSON(),
|
||||
connections: [...await UserChildUtils.getChildParents(child.id)]
|
||||
})
|
||||
}
|
||||
return prev;
|
||||
}, Promise.resolve({children: [], connections: []}));
|
||||
return connections;
|
||||
}
|
||||
|
||||
static async getChildConnections(child_id) {
|
||||
const links =
|
||||
await Link.query().where({child_id, is_parent: false}).fetch();
|
||||
const connections = await Promise.all(links.rows.map(async l => {
|
||||
return l.user().fetch();
|
||||
}));
|
||||
return connections;
|
||||
}
|
||||
static async addConnection(child_id, user_id, is_parent = false) {
|
||||
const link = await Link.create({child_id, user_id, is_parent});
|
||||
const user = await link.user().fetch();
|
||||
const child = await link.child().fetch();
|
||||
return {
|
||||
user, child, is_parent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = UserChildUtils;
|
|
@ -20,7 +20,7 @@ module.exports = {
|
|||
| is over 1mb it will not be processed.
|
||||
|
|
||||
*/
|
||||
limit: '1mb',
|
||||
limit: '20mb',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -44,10 +44,8 @@ module.exports = {
|
|||
|
|
||||
*/
|
||||
types: [
|
||||
'application/json',
|
||||
'application/json-patch+json',
|
||||
'application/vnd.api+json',
|
||||
'application/csp-report'
|
||||
'application/json', 'application/json-patch+json',
|
||||
'application/vnd.api+json', 'application/csp-report'
|
||||
]
|
||||
},
|
||||
|
||||
|
@ -59,11 +57,7 @@ module.exports = {
|
|||
|
|
||||
|
|
||||
*/
|
||||
raw: {
|
||||
types: [
|
||||
'text/*'
|
||||
]
|
||||
},
|
||||
raw: {types: ['text/*']},
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -73,11 +67,7 @@ module.exports = {
|
|||
|
|
||||
|
|
||||
*/
|
||||
form: {
|
||||
types: [
|
||||
'application/x-www-form-urlencoded'
|
||||
]
|
||||
},
|
||||
form: {types: ['application/x-www-form-urlencoded']},
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -88,9 +78,7 @@ module.exports = {
|
|||
|
|
||||
*/
|
||||
files: {
|
||||
types: [
|
||||
'multipart/form-data'
|
||||
],
|
||||
types: ['multipart/form-data'],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
66
config/socket.js
Normal file
66
config/socket.js
Normal file
|
@ -0,0 +1,66 @@
|
|||
'use strict'
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Websocket Config
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Used by AdonisJs websocket server
|
||||
|
|
||||
*/
|
||||
module.exports = {
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The base path on which the websocket server will accept connections.
|
||||
|
|
||||
*/
|
||||
path: '/connect',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Server Interval
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This interval is used to create a timer for identifying dead client
|
||||
| connections.
|
||||
|
|
||||
*/
|
||||
serverInterval: 30000,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Server Attempts
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Server attempts are used with serverInterval to identify dead client
|
||||
| connections. A total of `serverAttempts` attmepts after `serverInterval`
|
||||
| will be made before terminating the client connection.
|
||||
|
|
||||
*/
|
||||
serverAttempts: 3,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Client Interval
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This interval is used by client to send ping frames to the server.
|
||||
|
|
||||
*/
|
||||
clientInterval: 25000,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Client Attempts
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Clients attempts are number of times the client will attempt to send the
|
||||
| ping, without receiving a pong from the server. After attempts have
|
||||
| been elapsed, the client will consider server as dead.
|
||||
|
|
||||
*/
|
||||
clientAttempts: 3
|
||||
}
|
|
@ -11,6 +11,7 @@ class UserSchema extends Schema {
|
|||
table.string('name').notNullable();
|
||||
table.string('password', 60).notNullable();
|
||||
table.string('avatar');
|
||||
table.string('profile_cover');
|
||||
table.boolean('is_admin').defaultTo(false).notNullable();
|
||||
table.datetime('last_logged_in').defaultTo(null).nullable();
|
||||
table.timestamps();
|
||||
|
|
|
@ -10,6 +10,7 @@ class ChildSchema extends Schema {
|
|||
table.string('name');
|
||||
table.date('dob');
|
||||
table.string('avatar');
|
||||
table.string('profile_cover');
|
||||
table.timestamps();
|
||||
})
|
||||
}
|
||||
|
|
26
database/migrations/1586374249535_call_schema.js
Normal file
26
database/migrations/1586374249535_call_schema.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
'use strict'
|
||||
|
||||
/** @type {import('@adonisjs/lucid/src/Schema')} */
|
||||
const Schema = use('Schema');
|
||||
|
||||
class CallSchema extends Schema {
|
||||
up() {
|
||||
this.create('calls', (table) => {
|
||||
table.increments();
|
||||
table.string('state').notNullable();
|
||||
table.bigInteger('user_1').notNullable();
|
||||
table.bigInteger('user_2').notNullable();
|
||||
table.bigInteger('child_id').notNullable();
|
||||
table.timestamps();
|
||||
table.index(['child_id']);
|
||||
table.index(['user_1']);
|
||||
table.index(['user_2']);
|
||||
})
|
||||
}
|
||||
|
||||
down() {
|
||||
this.drop('calls');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CallSchema;
|
24
database/migrations/1586612224965_ice_server_schema.js
Normal file
24
database/migrations/1586612224965_ice_server_schema.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
'use strict'
|
||||
|
||||
/** @type {import('@adonisjs/lucid/src/Schema')} */
|
||||
const Schema = use('Schema');
|
||||
|
||||
class IceServerSchema extends Schema {
|
||||
up() {
|
||||
this.create('ice_servers', (table) => {
|
||||
table.increments();
|
||||
table.string('type', 254).notNullable();
|
||||
table.string('url', 254).notNullable();
|
||||
table.integer('port').notNullable();
|
||||
table.string('protocol', 254);
|
||||
table.string('secret', 254);
|
||||
table.timestamps();
|
||||
})
|
||||
}
|
||||
|
||||
down() {
|
||||
this.drop('ice_servers');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = IceServerSchema;
|
|
@ -34,17 +34,26 @@
|
|||
"@adonisjs/session": "^1.0.27",
|
||||
"@adonisjs/shield": "^1.0.8",
|
||||
"@adonisjs/validator": "^5.0.6",
|
||||
"@adonisjs/websocket": "^1.0.12",
|
||||
"@adonisjs/websocket-client": "^1.0.9",
|
||||
"adonis-vue-websocket": "^2.0.2",
|
||||
"animate.css": "^3.7.2",
|
||||
"bulma": "^0.8.0",
|
||||
"fork-awesome": "^1.1.7",
|
||||
"moment": "^2.24.0",
|
||||
"regenerator-runtime": "^0.13.5",
|
||||
"sqlite3": "^4.1.1",
|
||||
"typescript": "^3.7.5",
|
||||
"uuid": "^7.0.3",
|
||||
"vue": "^2.6.11",
|
||||
"vue-router": "^3.1.5",
|
||||
"vuex": "^3.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.8.3",
|
||||
"@babel/plugin-transform-regenerator": "^7.8.7",
|
||||
"@babel/plugin-transform-runtime": "^7.9.0",
|
||||
"@types/node": "^13.11.0",
|
||||
"babel-loader": "^8.0.6",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"babel-preset-stage-2": "^6.24.1",
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><svg width="36px" height="33px" viewBox="0 0 36 33" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g transform="translate(0 .5)" fill="none" fill-rule="evenodd"><path d="M20 2.236L5.618 31h28.764L20 2.236z" stroke="#FFFFFF" stroke-width="2"/><path fill="#FFFFFF" d="M12 2l12 24H0"/></g></svg>
|
Before Width: | Height: | Size: 363 B |
Binary file not shown.
Before Width: | Height: | Size: 111 KiB |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
Before Width: | Height: | Size: 25 KiB |
|
@ -6843,17 +6843,17 @@ label.panel-block {
|
|||
transform: rotate(-90deg);
|
||||
margin: -.8em auto; }
|
||||
|
||||
.columns.is-fullheight {
|
||||
min-height: calc(100vh - ( 3.25rem - .75rem ));
|
||||
max-height: calc(100vh - ( 3.25rem - .75rem ));
|
||||
height: calc(100vh - ( 3.25rem - .75rem ));
|
||||
.is-fullheight {
|
||||
min-height: calc(100vh - ( 3.25rem ));
|
||||
max-height: calc(100vh - ( 3.25rem ));
|
||||
height: calc(100vh - ( 3.25rem ));
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: stretch; }
|
||||
.columns.is-fullheight .column {
|
||||
.is-fullheight .column {
|
||||
overflow-y: auto; }
|
||||
|
||||
.child-avatar-image {
|
||||
.avatar-badge-image {
|
||||
display: table;
|
||||
margin: auto; }
|
||||
|
||||
|
@ -6863,3 +6863,54 @@ label.panel-block {
|
|||
|
||||
.m-auto {
|
||||
margin: auto; }
|
||||
|
||||
.css-loader {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
transform: translate(-50%, -50%);
|
||||
top: 50%;
|
||||
left: 50%; }
|
||||
.css-loader .dot {
|
||||
margin: 5px;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
background: #8A4D76;
|
||||
border-radius: 50%;
|
||||
animation-name: loading-pulse;
|
||||
animation-duration: 2s;
|
||||
animation-iteration-count: infinite;
|
||||
animation-timing-function: ease-in-out; }
|
||||
.css-loader .dot.delay-1 {
|
||||
animation-delay: .3s; }
|
||||
.css-loader .dot.delay-2 {
|
||||
animation-delay: .6s; }
|
||||
|
||||
@keyframes loading-pulse {
|
||||
0% {
|
||||
opacity: .1;
|
||||
transform: scale(0.7); }
|
||||
50% {
|
||||
opacity: 1;
|
||||
transform: scale(1); }
|
||||
100% {
|
||||
opacity: .1;
|
||||
transform: scale(0.7); } }
|
||||
|
||||
.has-pointer {
|
||||
cursor: pointer; }
|
||||
|
||||
.notifications {
|
||||
width: 15vw;
|
||||
z-index: 100;
|
||||
position: fixed;
|
||||
right: 25px;
|
||||
top: calc(25px + ( 3.25rem )); }
|
||||
|
||||
.notification-fade {
|
||||
animation: notification-fade .2s; }
|
||||
|
||||
@keyframes notification-fade {
|
||||
0% {
|
||||
opacity: 0; }
|
||||
100% {
|
||||
opacity: 1; } }
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><svg width="186px" height="31px" viewBox="0 0 186 31" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M20.25 6.106V.1H.72v6.006h5.712v17.388H.72V29.5h19.53v-6.006h-5.712V6.106h5.712zm18.774 7.35v-5.46h-6.846V1.528h-7.182v3.108c0 2.226-1.218 3.36-3.444 3.36h-.084v5.46h3.528v8.904c0 4.578 3.528 7.686 8.82 7.686 1.932 0 3.276-.126 5.208-1.05v-5.964c-2.016.882-2.982.966-3.822.966-1.806 0-3.024-1.008-3.024-2.898v-7.644h6.846zm37.17-5.46l-3.612 13.692L68.76 7.996H63.3l-3.822 13.692-3.654-13.692h-7.308L55.068 29.5h7.266l3.696-12.516L69.684 29.5h7.308l6.552-21.504h-7.35zM95.43 7.45c6.846 0 11.424 4.746 11.424 11.256 0 6.552-4.578 11.34-11.424 11.34-6.888 0-11.466-4.788-11.466-11.34 0-6.51 4.578-11.256 11.466-11.256zm0 5.628c-2.898 0-4.62 2.352-4.62 5.628 0 3.318 1.722 5.712 4.62 5.712 2.856 0 4.578-2.394 4.578-5.712 0-3.276-1.722-5.628-4.578-5.628zm22.092.714V7.996h-7.182V29.5h7.182v-7.518c0-5.376 1.89-7.728 8.946-6.972V7.534c-4.788 0-7.686 1.806-8.946 6.258zM145.158 29.5h8.4l-7.812-11.886 7.14-9.618h-8.316l-4.284 6.552h-3.612V.1h-7.182v29.4h7.182v-8.442h3.612l4.872 8.442zm22.092-14.196h6.384c-.462-5.46-4.326-7.854-9.87-7.854-6.09 0-9.534 2.436-9.534 6.804 0 4.998 4.494 5.586 8.19 6.426 3.822.882 4.704 1.134 4.704 2.478 0 1.512-1.428 1.932-2.982 1.932-2.394 0-3.822-.966-4.074-3.486h-6.384c.336 5.88 4.536 8.442 10.542 8.442 6.132 0 9.66-2.688 9.66-7.14 0-4.998-4.41-5.628-8.736-6.594-3.234-.672-4.326-.882-4.326-2.31 0-1.134 1.176-1.848 2.856-1.848 2.268 0 3.276.882 3.57 3.15zm11.424 4.536h6.258L185.94.1h-8.316l1.05 19.74zm-.63 9.66h7.518v-6.51h-7.518v6.51z" fill="#FFFFFF" fill-rule="evenodd"/></svg>
|
Before Width: | Height: | Size: 1.7 KiB |
|
@ -4,6 +4,7 @@
|
|||
@import './variables.scss';
|
||||
@import './mixins.scss';
|
||||
@import "../../node_modules/bulma/bulma.sass";
|
||||
// @import '../../node_modules/animate.css/source/_base.css';
|
||||
|
||||
.hero-bg-landing01 {
|
||||
background-image: url('/images/landing-hero01.jpg');
|
||||
|
@ -132,11 +133,10 @@ $positions: (
|
|||
margin: -.8em auto;
|
||||
}
|
||||
|
||||
.columns{
|
||||
&.is-fullheight{
|
||||
min-height: calc(100vh - ( #{$navbar-height} - .75rem ) );
|
||||
max-height: calc(100vh - ( #{$navbar-height} - .75rem ) );
|
||||
height: calc(100vh - ( #{$navbar-height} - .75rem ) );
|
||||
.is-fullheight{
|
||||
min-height: calc(100vh - ( #{$navbar-height} ) );
|
||||
max-height: calc(100vh - ( #{$navbar-height} ) );
|
||||
height: calc(100vh - ( #{$navbar-height} ) );
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: stretch;
|
||||
|
@ -144,9 +144,8 @@ $positions: (
|
|||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.child-avatar-image{
|
||||
.avatar-badge-image{
|
||||
display: table;
|
||||
margin: auto;
|
||||
}
|
||||
|
@ -158,3 +157,69 @@ $positions: (
|
|||
.m-auto{
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.css-loader{
|
||||
display: flex;
|
||||
position: absolute;
|
||||
transform: translate(-50%, -50%);
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
.dot{
|
||||
margin: 5px;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
background: $primary;
|
||||
border-radius: 50%;
|
||||
animation-name: loading-pulse;
|
||||
animation-duration: 2s;
|
||||
animation-iteration-count: infinite;
|
||||
animation-timing-function: ease-in-out;
|
||||
&.delay-1{
|
||||
animation-delay:.3s;
|
||||
}
|
||||
&.delay-2{
|
||||
animation-delay:.6s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@keyframes loading-pulse{
|
||||
0%{
|
||||
opacity: .1;
|
||||
transform: scale(.7);
|
||||
}
|
||||
50%{
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
100%{
|
||||
opacity: .1;
|
||||
transform: scale(.7);
|
||||
}
|
||||
}
|
||||
|
||||
.has-pointer{
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.notifications {
|
||||
width: 15vw;
|
||||
z-index: 100;
|
||||
position: fixed;
|
||||
right: 25px;
|
||||
top: calc(25px + ( #{$navbar-height} ) );
|
||||
}
|
||||
|
||||
.notification-fade{
|
||||
animation: notification-fade .2s;
|
||||
}
|
||||
|
||||
@keyframes notification-fade{
|
||||
0%{
|
||||
opacity: 0;
|
||||
}
|
||||
100%{
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<script lang="ts">
|
||||
import "regenerator-runtime/runtime.js";
|
||||
import Vue from "vue";
|
||||
import Vuex from "vuex";
|
||||
import App from "./app.vue";
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
<div class="wrapper">
|
||||
<div class="has-text-centered">
|
||||
<h3 class="title">Settings</h3>
|
||||
<h4 class="subtitle">UserName</h4>
|
||||
</div>
|
||||
<div class="columns">
|
||||
<div class="column is-one-quarter">
|
||||
|
|
|
@ -1,6 +1,18 @@
|
|||
<template>
|
||||
<div class="app">
|
||||
<Header :appName="appName" />
|
||||
<!-- <Header :appName="appName" /> -->
|
||||
<div class="loading" v-if="loading">
|
||||
<Loading />
|
||||
</div>
|
||||
<div class v-else>
|
||||
<div class="notifications">
|
||||
<Notification
|
||||
v-for="notification in notifications"
|
||||
:key="notification.id"
|
||||
:notification="notification"
|
||||
@onClose="onNotificationClose(notification)"
|
||||
/>
|
||||
</div>
|
||||
<div class="columns m-t-xs is-fullheight">
|
||||
<div class="column sidebar">
|
||||
<SideBar :title="appName" :menu="menu" :appName="appName" />
|
||||
|
@ -12,11 +24,16 @@
|
|||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Header from "./components/Header.vue";
|
||||
import Services from "../services/index";
|
||||
import Notification from "../shared/components/Notification.vue";
|
||||
import { mapActions, mapGetters } from "vuex";
|
||||
import Loading from "../shared/components/Loading/Loading.vue";
|
||||
import WebsocketService from "./scripts/websocket.service";
|
||||
// import AppRouter from "./router/router.vue";
|
||||
import {
|
||||
default as SideBar,
|
||||
|
@ -29,12 +46,6 @@ const menu: IMenuItem[] = [
|
|||
isRouterLink: true,
|
||||
icon: "fa fa-home"
|
||||
},
|
||||
{
|
||||
href: "/applications",
|
||||
text: "Applications",
|
||||
isRouterLink: true,
|
||||
icon: "fa fa-puzzle-piece"
|
||||
},
|
||||
{
|
||||
href: "/settings",
|
||||
isRouterLink: true,
|
||||
|
@ -55,13 +66,39 @@ export default {
|
|||
// router: AppRouter,
|
||||
components: {
|
||||
SideBar,
|
||||
Header
|
||||
Header,
|
||||
Notification,
|
||||
Loading
|
||||
},
|
||||
async created() {
|
||||
await this.getUser();
|
||||
this.ws = await WebsocketService.getInstance();
|
||||
this.ws.on(WebsocketService.Events.CONNECTION_ONLINE, user => {
|
||||
console.log(`User Online: ${JSON.stringify(user, null, 2)}`);
|
||||
this.notify({ message: `${user.name} is online!`, level: "success" });
|
||||
});
|
||||
this.ws.on(WebsocketService.Events.CONNECTION_OFFLINE, user => {
|
||||
this.notify({ message: `${user.name} disconnected`, level: "warning" });
|
||||
});
|
||||
this.loading = false;
|
||||
return true;
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
appName: "Seepur",
|
||||
menu
|
||||
menu,
|
||||
loading: true,
|
||||
ws: null
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(["notifications"])
|
||||
},
|
||||
methods: {
|
||||
onNotificationClose(notification) {
|
||||
this.dismissNotification(notification.id);
|
||||
},
|
||||
...mapActions(["dismissNotification", "getUser", "notify"])
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
<template>
|
||||
<Modal
|
||||
:title="`Add Connection to ${childName}`"
|
||||
:isActive="isActive"
|
||||
acceptText="Add"
|
||||
rejectText="Cancel"
|
||||
@accept="addConnection()"
|
||||
@close="close()"
|
||||
>
|
||||
<div class="field">
|
||||
<label class="label">Connection Email</label>
|
||||
<input class="input" type="email" placeholder="name@zmail.com" v-model="email" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>
|
||||
<input class="checkbox" type="checkbox" v-model="isParent" aria-label="isParent" />
|
||||
Is this a parent? {{isParent ? "Yes" : "No"}}
|
||||
</label>
|
||||
</div>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Modal from "../../shared/components/Modal/Modal.vue";
|
||||
import { mapActions } from "vuex";
|
||||
export default {
|
||||
name: "AddConnectionModal",
|
||||
props: ["isActive", "childName"],
|
||||
components: {
|
||||
Modal
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.reset();
|
||||
this.$emit("dismiss");
|
||||
},
|
||||
reset() {
|
||||
this.email = "";
|
||||
this.isParent = false;
|
||||
},
|
||||
addConnection() {
|
||||
// validate email
|
||||
if (!validateEmail(this.email)) {
|
||||
this.notify({
|
||||
message: "Please provide a valid email",
|
||||
level: "warning"
|
||||
});
|
||||
} else {
|
||||
this.$emit("createNewConnection", {
|
||||
email: this.email,
|
||||
is_parent: this.isParent
|
||||
});
|
||||
|
||||
this.reset();
|
||||
}
|
||||
},
|
||||
...mapActions(["notify"])
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
email: "",
|
||||
isParent: false
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
function validateEmail(email) {
|
||||
var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||
return re.test(email);
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,28 @@
|
|||
<template>
|
||||
<div :class="['has-text-centered' ,'p-t-sm', {'has-pointer': !!isLink}]" @click="onClick()">
|
||||
<div class="avatar-badge-image">
|
||||
<figure class="image is-48x48">
|
||||
<img :src="img" alt="Placeholder image" class="is-rounded is-avatar" />
|
||||
</figure>
|
||||
</div>
|
||||
<div class>{{text}}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export interface IChildAvatar {
|
||||
url: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export default {
|
||||
name: "AvatarBadge",
|
||||
props: ["img", "text", "isLink"],
|
||||
created() {},
|
||||
methods: {
|
||||
onClick() {
|
||||
this.$emit("onClick");
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<!-- <div class="card"> -->
|
||||
<div class="card-content">
|
||||
<div class="card-content has-pointer" @click="goToChild(child)">
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<figure class="image is-48x48">
|
||||
|
@ -16,11 +16,16 @@
|
|||
<!-- </div> -->
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import * as Moment from "moment";
|
||||
import Moment from "moment";
|
||||
let childAge;
|
||||
export default {
|
||||
name: "ChildCard",
|
||||
props: ["child"],
|
||||
methods: {
|
||||
goToChild(child) {
|
||||
this.$router.push({ path: `/child/${child.id}` });
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.childAge = Moment().diff(this.child.dob, "years");
|
||||
},
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
<template>
|
||||
<Modal
|
||||
:title="`New Call`"
|
||||
:isActive="isActive"
|
||||
acceptText="Call"
|
||||
rejectText="Cancel"
|
||||
@accept="createCall()"
|
||||
@close="close()"
|
||||
>
|
||||
<div class="columns">
|
||||
<div class="column">
|
||||
Select Child:
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<avatar-badge
|
||||
v-for="child in user.connections.children"
|
||||
:key="child.id"
|
||||
:img="child.avatar"
|
||||
:text="child.name"
|
||||
@onClick="onChildSelected(child)"
|
||||
:isLink="true"
|
||||
:style="child_id===child.id ? `background-color:rgba(56, 181, 187, 0.19); border-radius:15px;` : ''"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
Select Connection:
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<avatar-badge
|
||||
v-for="user in connection_options"
|
||||
:key="user.id"
|
||||
:img="user.avatar"
|
||||
:text="user.name"
|
||||
@onClick="onConnectionSelected(user)"
|
||||
:isLink="true"
|
||||
:style="connection_id===user.id ? `background-color:rgba(56, 181, 187, 0.19); border-radius:15px` : ''"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Modal from "../../shared/components/Modal/Modal.vue";
|
||||
import AvatarBadge from "./AvatarBadge.vue";
|
||||
import { mapActions, mapGetters } from "vuex";
|
||||
export default {
|
||||
name: "ConfigureNewCallModal",
|
||||
props: ["isActive"],
|
||||
components: {
|
||||
Modal,
|
||||
AvatarBadge
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(["user"])
|
||||
},
|
||||
methods: {
|
||||
close() {
|
||||
this.reset();
|
||||
this.$emit("dismiss");
|
||||
},
|
||||
onChildSelected(child) {
|
||||
this.child_id = child.id;
|
||||
this.connection_options = child.connections;
|
||||
},
|
||||
onConnectionSelected(user) {
|
||||
this.connection_id = user.id;
|
||||
},
|
||||
reset() {
|
||||
this.connection_id = "";
|
||||
this.child_id = false;
|
||||
},
|
||||
validate() {
|
||||
if (!this.child_id || !this.connection_id) return false;
|
||||
const children = this.user.connections.children;
|
||||
for (const child of children) {
|
||||
for (const connection of child.connections) {
|
||||
if (connection.id === this.connection_id) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
createCall() {
|
||||
if (!this.validate()) {
|
||||
this.notify({
|
||||
message: "Please select a child and a user",
|
||||
level: "warning"
|
||||
});
|
||||
} else {
|
||||
this.$emit("newCall", {
|
||||
connection_id: this.connection_id,
|
||||
child_id: this.child_id
|
||||
});
|
||||
|
||||
this.reset();
|
||||
}
|
||||
},
|
||||
...mapActions(["notify"])
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
connection_id: null,
|
||||
child_id: null,
|
||||
connection_options: []
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,23 @@
|
|||
<template>
|
||||
<section class="hero is-small p-t-xl p-b-lg" :style="style">
|
||||
<div class="hero-body">
|
||||
<div class="container">
|
||||
<h1 class="title has-text-light">{{title}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "ProfileHeader",
|
||||
props: ["title", "background"],
|
||||
computed: {
|
||||
style() {
|
||||
return `background-image: url('${this.background ||
|
||||
"/images/landing-hero01.jpg"}');
|
||||
background-size: cover;
|
||||
background-position: center;`;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div class="chiled-avatar has-text-centered">
|
||||
<div class="child-avatar-image">
|
||||
<div class="avatar-badge-image">
|
||||
<figure class="image is-48x48">
|
||||
<img :src="child.avatar" alt="Placeholder image" class="is-rounded is-avatar" />
|
||||
</figure>
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
<script lang="ts">
|
||||
import "regenerator-runtime/runtime.js";
|
||||
// import Ws from "@adonisjs/websocket-client";
|
||||
// import WsPlugin from "adonis-vue-websocket";
|
||||
import Vue from "vue";
|
||||
import Vuex from "vuex";
|
||||
import App from "./app.vue";
|
||||
import AppRouter from "./router/router.vue";
|
||||
import store from "./state.vuex";
|
||||
|
||||
// Vue.use(WsPlugin, { adonisWS: Ws });
|
||||
Vue.use(Vuex);
|
||||
const app = new Vue({
|
||||
router: AppRouter,
|
||||
|
|
|
@ -12,7 +12,8 @@ Vue.use(VueRouter);
|
|||
// Views
|
||||
import Home from "../views/home.vue";
|
||||
import Settings from "../views/settings.vue";
|
||||
import Applications from "../views/application.vue";
|
||||
import Call from "../views/call.vue";
|
||||
import ChildProfile from "../views/child_profile.vue";
|
||||
|
||||
const routes: RouteConfig[] = [
|
||||
/** Define Application Routes */
|
||||
|
@ -26,8 +27,12 @@ const routes: RouteConfig[] = [
|
|||
component: Settings
|
||||
},
|
||||
{
|
||||
path: "/applications",
|
||||
component: Applications
|
||||
path: "/call/:id",
|
||||
component: Call
|
||||
},
|
||||
{
|
||||
path: "/child/:id",
|
||||
component: ChildProfile
|
||||
},
|
||||
{
|
||||
path: "*",
|
||||
|
|
165
resources/scripts/applications/home/scripts/call.service.ts
Normal file
165
resources/scripts/applications/home/scripts/call.service.ts
Normal file
|
@ -0,0 +1,165 @@
|
|||
export default class CallService {
|
||||
private callId: string;
|
||||
private inCall: boolean;
|
||||
private peerId: number;
|
||||
private subscription;
|
||||
private localStream: MediaStream;
|
||||
private remoteStream: MediaStream;
|
||||
private needToAddStream: boolean = true;
|
||||
private pc: RTCPeerConnection;
|
||||
constructor(private ws) {
|
||||
this.callId = null;
|
||||
this.inCall = false;
|
||||
this.peerId = -1;
|
||||
this.subscription = null;
|
||||
this.pc = null;
|
||||
this.localStream = null;
|
||||
this.remoteStream = null;
|
||||
this.remoteStream = new MediaStream();
|
||||
}
|
||||
|
||||
async connectToCall(callId: string): Promise<boolean> {
|
||||
if (this.inCall) throw new Error('Already connected to call');
|
||||
this.subscription = this.ws.subscribe(`call:${callId}`);
|
||||
const subscription = this.subscription;
|
||||
const self = this;
|
||||
return new Promise((resolve, reject) => {
|
||||
subscription.on('error', (e) => {
|
||||
console.error(e);
|
||||
resolve(false)
|
||||
});
|
||||
subscription.on('ready', () => {
|
||||
this.callId = callId;
|
||||
this.inCall = true;
|
||||
resolve(true)
|
||||
});
|
||||
subscription.on('close', self.close.bind(this));
|
||||
subscription.on('call:start', self.onCallStart.bind(this));
|
||||
subscription.on('call:standby', self.onCallStandby.bind(this));
|
||||
subscription.on('wrtc:sdp:offer', self.onRemoteOffer.bind(this));
|
||||
subscription.on('wrtc:sdp:answer', self.onRemoteAnswer.bind(this));
|
||||
subscription.on('wrtc:ice', self.onRemoteIce.bind(this));
|
||||
|
||||
});
|
||||
}
|
||||
private send(event: string, payload: { [key: string]: any }) {
|
||||
this.subscription.emit(event, {
|
||||
id: this.peerId,
|
||||
...payload
|
||||
})
|
||||
}
|
||||
async onCallStart(payload: { iceServers: RTCIceServer[], id: number }) {
|
||||
console.log(payload);
|
||||
this.peerId = payload.id;
|
||||
this.pc = new RTCPeerConnection({ iceServers: payload.iceServers });
|
||||
console.log('Created PeerConnection');
|
||||
this.setupPeerConnectionListeners();
|
||||
const sdp = await this.pc.createOffer();
|
||||
await this.pc.setLocalDescription(sdp);
|
||||
console.log('Local description Set');
|
||||
this.send('wrtc:sdp:offer', {
|
||||
sdp
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
async onCallStandby(payload: { iceServers: RTCIceServer[], id: number }) {
|
||||
console.log(payload);
|
||||
this.peerId = payload.id;
|
||||
this.pc = new RTCPeerConnection({ iceServers: payload.iceServers });
|
||||
console.log('Created PeerConnection');
|
||||
this.setupPeerConnectionListeners();
|
||||
return true;
|
||||
}
|
||||
|
||||
setupPeerConnectionListeners() {
|
||||
this.pc.addEventListener("icecandidate", this.onLocalIce.bind(this));
|
||||
this.pc.addEventListener('connectionstatechange', event => {
|
||||
console.log(`PC Connection state: ${this.pc.connectionState}`);
|
||||
// if (this.pc.connectionState === 'connected') {
|
||||
// // Peers connected!
|
||||
// }
|
||||
});
|
||||
|
||||
this.pc.addEventListener('iceconnectionstatechange', event => {
|
||||
console.log('iceconnectionstatechange');
|
||||
console.log(this.pc.iceConnectionState);
|
||||
})
|
||||
|
||||
this.pc.addEventListener('track', async (event) => {
|
||||
console.log('On remote track!');
|
||||
this.remoteStream.addTrack(event.track);
|
||||
});
|
||||
|
||||
this.pc.addEventListener('icegatheringstatechange', event => {
|
||||
console.log('icegatheringstatechange', this.pc.iceGatheringState);
|
||||
});
|
||||
|
||||
if (this.needToAddStream && this.localStream) {
|
||||
this.localStream.getTracks().forEach(t => {
|
||||
console.log('adding track to pc - in the event list');
|
||||
console.log(t);
|
||||
this.pc.addTrack(t, this.localStream);
|
||||
});
|
||||
this.needToAddStream = false;
|
||||
}
|
||||
}
|
||||
|
||||
onLocalIce(event) {
|
||||
if (event.candidate) {
|
||||
console.log('Sending candidate');
|
||||
this.send('wrtc:ice', {
|
||||
ice: event.candidate
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
async onRemoteOffer(payload) {
|
||||
const offer = new RTCSessionDescription(payload.sdp);
|
||||
await this.pc.setRemoteDescription(offer);
|
||||
console.log('Remote offer Set');
|
||||
const sdp = await this.pc.createAnswer();
|
||||
this.send('wrtc:sdp:answer', {
|
||||
sdp
|
||||
});
|
||||
await this.pc.setLocalDescription(sdp);
|
||||
console.log('Local answer Set');
|
||||
return true;
|
||||
}
|
||||
async onRemoteAnswer(payload) {
|
||||
const answer = new RTCSessionDescription(payload.sdp);
|
||||
await this.pc.setRemoteDescription(answer);
|
||||
console.log('Remote answer Set');
|
||||
return true;
|
||||
}
|
||||
async onRemoteIce(payload) {
|
||||
const ice = payload.ice;
|
||||
await this.pc.addIceCandidate(ice);
|
||||
return true;
|
||||
}
|
||||
|
||||
async getUserMedia(constraints: MediaStreamConstraints = { video: false, audio: true }) {
|
||||
if (this.localStream) return this.localStream;
|
||||
this.localStream = await navigator.mediaDevices.getUserMedia(constraints);
|
||||
if (this.pc) {
|
||||
if (this.needToAddStream && this.localStream) {
|
||||
this.localStream.getTracks().forEach(t => {
|
||||
console.log('adding track to pc - in get user media');
|
||||
this.pc.addTrack(t, this.localStream);
|
||||
});
|
||||
this.needToAddStream = false;
|
||||
}
|
||||
}
|
||||
return this.localStream;
|
||||
}
|
||||
|
||||
getRemoteStream() {
|
||||
return this.remoteStream;
|
||||
}
|
||||
|
||||
close() {
|
||||
if (this.subscription) this.subscription.close();
|
||||
this.subscription = null;
|
||||
this.inCall = false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
|
||||
let singleton: UserChannel = null;
|
||||
|
||||
export default class UserChannel {
|
||||
private subscription;
|
||||
private constructor(private ws) {
|
||||
this.subscription = null;
|
||||
}
|
||||
|
||||
async connect(): Promise<boolean> {
|
||||
this.subscription = this.ws.subscribe(`user_channel`);
|
||||
const subscription = this.subscription;
|
||||
const self = this;
|
||||
return new Promise((resolve, reject) => {
|
||||
subscription.on('error', () => { resolve(false) });
|
||||
subscription.on('ready', () => {
|
||||
resolve(true)
|
||||
});
|
||||
subscription.on('close', self.close);
|
||||
});
|
||||
}
|
||||
|
||||
on(event: string, callback: (...args) => void) {
|
||||
if (this.subscription) this.subscription.on(event, callback);
|
||||
}
|
||||
|
||||
static async getInstance(ws) {
|
||||
if (singleton) return singleton;
|
||||
else return new UserChannel(ws);
|
||||
}
|
||||
close() {
|
||||
this.subscription.close();
|
||||
singleton = null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
|
||||
import Ws from "@adonisjs/websocket-client";
|
||||
import CallService from './call.service';
|
||||
import UserChannelService from './user.channel.service';
|
||||
import { EventEmitter } from 'events';
|
||||
let singleton: WebSocketService = null;
|
||||
enum EEvents {
|
||||
NEW_CONNECTION,
|
||||
CONNECTION_ONLINE,
|
||||
CONNECTION_OFFLINE,
|
||||
INCOMING_CALL,
|
||||
SIGNALING_EVENTS,
|
||||
CALL_ACTIONS
|
||||
}
|
||||
export default class WebSocketService {
|
||||
static Events = EEvents;
|
||||
private emitter;
|
||||
private callService: CallService;
|
||||
|
||||
private constructor(private ws, private userChannelService: UserChannelService) {
|
||||
this.emitter = new EventEmitter();
|
||||
this.callService = new CallService(this.ws);
|
||||
this.userChannelService.on('new:connection', this.onUserNewConnection.bind(this));
|
||||
this.userChannelService.on('connection:online', this.onUserConnectionOnline.bind(this));
|
||||
this.userChannelService.on('connection:offline', this.onUserConnectionOffline.bind(this));
|
||||
}
|
||||
|
||||
|
||||
on(event: EEvents, callback: Function) {
|
||||
this.emitter.on(event, callback);
|
||||
}
|
||||
removeListener(event: EEvents, callback) {
|
||||
this.emitter.removeListener(event, callback);
|
||||
}
|
||||
// onPublicChannelMessage(msg) {
|
||||
// this.emitter
|
||||
// }
|
||||
|
||||
private onUserNewConnection(data) {
|
||||
this.emitter.emit(EEvents.NEW_CONNECTION, data);
|
||||
}
|
||||
|
||||
private onUserConnectionOnline(data) {
|
||||
this.emitter.emit(EEvents.CONNECTION_ONLINE, data);
|
||||
}
|
||||
|
||||
private onUserConnectionOffline(data) {
|
||||
this.emitter.emit(EEvents.CONNECTION_OFFLINE, data);
|
||||
}
|
||||
|
||||
async getLocalMedia(constraints: MediaStreamConstraints = null) {
|
||||
return this.callService.getUserMedia(constraints);
|
||||
}
|
||||
|
||||
getRemoteStream() {
|
||||
return this.callService.getRemoteStream();
|
||||
}
|
||||
|
||||
|
||||
static getInstance(): Promise<WebSocketService> {
|
||||
return new Promise((resolve, reject) => {
|
||||
// resolve();
|
||||
// return;
|
||||
if (singleton) return resolve(singleton);
|
||||
|
||||
const ws = Ws('', { path: 'connect' });
|
||||
ws.connect();
|
||||
|
||||
ws.on('open', async () => {
|
||||
const userChannelService = await UserChannelService.getInstance(ws);
|
||||
const success = await userChannelService.connect();
|
||||
console.log('Connected to user socket:', success);
|
||||
singleton = new WebSocketService(ws, userChannelService);
|
||||
resolve(singleton);
|
||||
});
|
||||
ws.on('error', (error) => {
|
||||
console.log(error)
|
||||
reject(new Error('Failed to connect'));
|
||||
})
|
||||
ws.on('close', _ => {
|
||||
console.log('Socket Closed');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async connectToCall(callId: string) {
|
||||
return this.callService.connectToCall(callId);
|
||||
}
|
||||
|
||||
async leaveCall() {
|
||||
this.callService.close();
|
||||
}
|
||||
|
||||
onSignalingMsg(message) {
|
||||
console.log(message);
|
||||
}
|
||||
}
|
|
@ -6,15 +6,30 @@ const store = new Store({
|
|||
strict: true,
|
||||
state: {
|
||||
user: null,
|
||||
notifications: []
|
||||
},
|
||||
getters: {
|
||||
user(state) {
|
||||
return state.user;
|
||||
},
|
||||
notifications(state) {
|
||||
return state.notifications;
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
setUser: (state, user) => {
|
||||
setUser(state, user) {
|
||||
state.user = user;
|
||||
},
|
||||
notify(state, notification) {
|
||||
const id = Math.ceil(Math.random() * 1000);
|
||||
state.notifications.push({ ...notification, id });
|
||||
const dispatch = this.dispatch;
|
||||
setTimeout(() => {
|
||||
dispatch("dismissNotification", id);
|
||||
}, 5000);
|
||||
},
|
||||
dismissNotification(state, noteId: number) {
|
||||
state.notifications = state.notifications.filter(n => n.id != noteId);
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
|
@ -22,6 +37,12 @@ const store = new Store({
|
|||
const user = await Services.ApiService.getUser(userId);
|
||||
ctx.commit('setUser', user);
|
||||
},
|
||||
notify(ctx, notification: { message: string, level?: "info" | "warning" | "success" | "danger" }) {
|
||||
ctx.commit("notify", notification);
|
||||
},
|
||||
dismissNotification(ctx, id: number) {
|
||||
ctx.commit("dismissNotification", id);
|
||||
}
|
||||
}
|
||||
});
|
||||
export default store;
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
<template>
|
||||
<div class="wrapper">
|
||||
<h1 class="is-1">Applications!!!</h1>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "Applications",
|
||||
beforeCreate: () => {
|
||||
console.log("before create home vue");
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
77
resources/scripts/applications/home/views/call.vue
Normal file
77
resources/scripts/applications/home/views/call.vue
Normal file
|
@ -0,0 +1,77 @@
|
|||
<template>
|
||||
<div class="wrapper">
|
||||
<div v-if="loading">
|
||||
<Loading />
|
||||
</div>
|
||||
<div v-else>
|
||||
<video
|
||||
:srcObject="localStream"
|
||||
autoplay="true"
|
||||
controls="false"
|
||||
playsinline="true"
|
||||
muted="true"
|
||||
/>
|
||||
<video :srcObject="remoteStream" autoplay="true" controls="false" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Loading from "../../shared/components/Loading/Loading.vue";
|
||||
import WebsocketService from "../scripts/websocket.service";
|
||||
import Services from "../../services/index";
|
||||
import { mapActions, mapGetters } from "vuex";
|
||||
export default {
|
||||
components: {
|
||||
Loading
|
||||
},
|
||||
name: "Call",
|
||||
async created() {
|
||||
this.loading = true;
|
||||
try {
|
||||
const ws = await WebsocketService.getInstance();
|
||||
const success = await ws.connectToCall(this.$route.params.id);
|
||||
if (!success) {
|
||||
this.notify({ message: "Can find this call...", level: "danger" });
|
||||
this.$router.push({ path: `/` });
|
||||
return false;
|
||||
}
|
||||
this.signalingChannel = this.localStream = await ws.getLocalMedia({
|
||||
video: false,
|
||||
audio: true
|
||||
});
|
||||
this.remoteStream = ws.getRemoteStream();
|
||||
console.log(this.localStream);
|
||||
this.notify({ message: "Connected!", level: "success" });
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
this.notify({ message: e.message, level: "danger" });
|
||||
}
|
||||
|
||||
this.loading = false;
|
||||
},
|
||||
async beforeDestroy() {
|
||||
console.log("destroyed");
|
||||
const ws = await WebsocketService.getInstance();
|
||||
ws.leaveCall();
|
||||
return true;
|
||||
},
|
||||
methods: {
|
||||
...mapActions(["notify"])
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([])
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
call: null,
|
||||
localStream: null,
|
||||
remoteStream: null,
|
||||
signalingChannel: null
|
||||
};
|
||||
},
|
||||
beforeCreate: () => {}
|
||||
};
|
||||
</script>
|
||||
|
258
resources/scripts/applications/home/views/child_profile.vue
Normal file
258
resources/scripts/applications/home/views/child_profile.vue
Normal file
|
@ -0,0 +1,258 @@
|
|||
<template>
|
||||
<div class="wrapper">
|
||||
<div class="loading" v-if="loading">
|
||||
<Loading />
|
||||
</div>
|
||||
<div class v-else>
|
||||
<!-- Profile Cover Modal -->
|
||||
<Modal
|
||||
title="Change Cover"
|
||||
:isActive="showCoverModal"
|
||||
acceptText="Change"
|
||||
rejectText="Cancel"
|
||||
@accept="changeCover()"
|
||||
@close="showCoverModal=false"
|
||||
>
|
||||
<ProfileHeader
|
||||
:title="child.name"
|
||||
:background="childCoverModalImage ? childCoverModalImage : child.profile_cover"
|
||||
/>
|
||||
<file-select v-model="childCoverModalImage" accept="image/*" lable="Select Cover:"></file-select>
|
||||
</Modal>
|
||||
<!-- Add Connection Modal -->
|
||||
<AddConnectionModal
|
||||
@createNewConnection="addConnection($event)"
|
||||
@dismiss="showAddConnectionModal=false"
|
||||
:isActive="showAddConnectionModal"
|
||||
:childName="child.name"
|
||||
/>
|
||||
<!-- Profile -->
|
||||
<ProfileHeader :title="child.name" :background="child.profile_cover" />
|
||||
<div class="columns is-fullheight m-t-md">
|
||||
<div class="column is-3">
|
||||
<div class="card">
|
||||
<div class="card-image">
|
||||
<figure class="image is-4by4 p-md">
|
||||
<img :src="child.avatar" class="is-rounded is-avatar" />
|
||||
</figure>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="content">
|
||||
<p>Hi!</p>
|
||||
<p>Im {{age}}</p>
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
<footer v-if="isParent" class="card-footer">
|
||||
<a
|
||||
class="card-footer-item"
|
||||
@click="togleEditMode()"
|
||||
>{{inEditMode ? 'Cancel' : 'Edit'}}</a>
|
||||
<a class="card-footer-item is-danger" @click="onDeleteClicked()">Delete</a>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<nav class="level">
|
||||
<!-- Left side -->
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<h1 class="subtitle">Parents</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right side -->
|
||||
<div class="level-right">
|
||||
<div class="level-item" v-if="isParent">
|
||||
<button class="button" @click="showAddConnectionModal = true">
|
||||
<i class="fa fa-fw fa-plus"></i> Add Connection
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="parents">
|
||||
<div class="columns">
|
||||
<AvatarBadge
|
||||
class="column"
|
||||
v-for="parent in child.parents"
|
||||
:key="parent.id"
|
||||
:img="parent.avatar"
|
||||
:text="parent.name"
|
||||
:isLink="user.id === parent.id"
|
||||
@onClick="goToUserProfile(parent)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="level">
|
||||
<!-- Left side -->
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<h1 class="subtitle">Connections</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right side -->
|
||||
</nav>
|
||||
<div class="columns">
|
||||
<AvatarBadge
|
||||
class="column"
|
||||
v-for="connection in child.connections"
|
||||
:key="connection.id"
|
||||
:img="connection.avatar"
|
||||
:text="connection.name"
|
||||
:isLink="user.id === connection.id"
|
||||
@onClick="goToUserProfile(connection)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { mapActions, mapGetters } from "vuex";
|
||||
import ChildAvatar, { IChildAvatar } from "../components/child_avatar.vue";
|
||||
import Services from "../../services/index";
|
||||
import Loading from "../../shared/components/Loading/Loading.vue";
|
||||
import ProfileHeader from "../components/ProfileHeader.vue";
|
||||
import AddConnectionModal from "../components/AddConnectionModal.vue";
|
||||
import FileSelect from "../../shared/components/FileSelect/FileSelect.vue";
|
||||
import AvatarBadge from "../components/AvatarBadge.vue";
|
||||
import Moment from "moment";
|
||||
import Modal from "../../shared/components/Modal/Modal.vue";
|
||||
export default {
|
||||
name: "ChildProfile",
|
||||
components: {
|
||||
ChildAvatar,
|
||||
Loading,
|
||||
ProfileHeader,
|
||||
Modal,
|
||||
FileSelect,
|
||||
AvatarBadge,
|
||||
AddConnectionModal
|
||||
},
|
||||
beforeCreate() {},
|
||||
async created() {
|
||||
const response = await Services.ApiService.getChild(this.$route.params.id);
|
||||
this.loading = false;
|
||||
if (response.code === 0) {
|
||||
console.log(response);
|
||||
//Cool
|
||||
this.child = response.data;
|
||||
if (!this.user) await this.getUser();
|
||||
this.isParent = this.child.parents.reduce((isParent, parent) => {
|
||||
if (isParent) return true;
|
||||
return parent.id === this.user.id;
|
||||
}, this.isParent);
|
||||
} else {
|
||||
// notCool
|
||||
this.notify({ message: "Sorry, Child not found!", level: "danger" });
|
||||
this.$router.push({ path: `/` });
|
||||
}
|
||||
return true;
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
child: null,
|
||||
isParent: false,
|
||||
inEditMode: false,
|
||||
showCoverModal: false,
|
||||
showAddConnectionModal: false,
|
||||
childCoverModalImage: null
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onDeleteClicked() {
|
||||
this.notify({ message: "Test" });
|
||||
},
|
||||
goToUserProfile(user) {
|
||||
if (this.user.id === user.id) {
|
||||
this.$router.push({ path: `/` });
|
||||
} else {
|
||||
this.$router.push({ path: `/user/${user.id}` });
|
||||
}
|
||||
},
|
||||
async addConnection(_connection) {
|
||||
try {
|
||||
this.loading = true;
|
||||
const connection = await Services.ApiService.createConnection({
|
||||
..._connection,
|
||||
child_id: this.child.id
|
||||
});
|
||||
if (connection.code === 409) {
|
||||
this.loading = false;
|
||||
this.showAddConnectionModal = false;
|
||||
return this.notify({ message: connection.message, level: "warning" });
|
||||
} else if (connection.code !== 0) {
|
||||
this.loading = false;
|
||||
this.showAddConnectionModal = false;
|
||||
return this.notify({ message: connection.message, level: "danger" });
|
||||
}
|
||||
// debugger;
|
||||
this.notify({
|
||||
message: `Awesome!\n${connection.data.user.name} is connected to ${this.child.name}`,
|
||||
level: "success"
|
||||
});
|
||||
if (connection.data.is_parent) {
|
||||
this.child.parents.push(connection.data.user);
|
||||
} else {
|
||||
this.child.connections.push(connection.data.user);
|
||||
}
|
||||
console.log(connection);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
this.loading = false;
|
||||
this.showAddConnectionModal = false;
|
||||
return true;
|
||||
},
|
||||
async changeCover() {
|
||||
if (this.childCoverModalImage) {
|
||||
this.loading = true;
|
||||
try {
|
||||
this.child.profile_cover = await Services.ApiService.updateChildCover(
|
||||
this.child.id,
|
||||
this.childCoverModalImage
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
this.loading = false;
|
||||
}
|
||||
this.showCoverModal = false;
|
||||
this.this.childCoverModalImage = null;
|
||||
},
|
||||
togleEditMode() {
|
||||
this.inEditMode = !this.inEditMode;
|
||||
if (this.inEditMode) {
|
||||
this.showCoverModal = true;
|
||||
}
|
||||
},
|
||||
...mapActions(["getUser", "getConnections", "notify"])
|
||||
},
|
||||
computed: {
|
||||
age() {
|
||||
const years = Moment().diff(this.child.dob, "years");
|
||||
const months = Moment().diff(this.child.dob, "months") % 12;
|
||||
const isNewBorn = !years && !months;
|
||||
let text = "a new boarn!";
|
||||
if (!isNewBorn) {
|
||||
text = "";
|
||||
if (years) text += `${years} years`;
|
||||
if (years && months) text += ` and`;
|
||||
if (months) text += ` ${months} months`;
|
||||
text += " old";
|
||||
}
|
||||
return `${text}`;
|
||||
},
|
||||
...mapGetters(["user", "connections"])
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
@ -1,45 +1,116 @@
|
|||
<template>
|
||||
<div class="wrapper">
|
||||
<div class="loading" v-if="loading">
|
||||
<Loading />
|
||||
</div>
|
||||
<div class v-else>
|
||||
<!-- Profile Cover Modal -->
|
||||
<Modal
|
||||
title="Change Cover"
|
||||
:isActive="showCoverModal"
|
||||
acceptText="Change"
|
||||
rejectText="Cancel"
|
||||
@accept="changeCover()"
|
||||
@close="showCoverModal=false"
|
||||
>
|
||||
<ProfileHeader
|
||||
:title="user.name"
|
||||
:background="childCoverModalImage ? childCoverModalImage : user.profile_cover"
|
||||
/>
|
||||
<file-select v-model="childCoverModalImage" accept="image/*" lable="Select Cover:"></file-select>
|
||||
</Modal>
|
||||
|
||||
<!-- Create Call Modal -->
|
||||
<ConfigureNewCallModal
|
||||
@newCall="makeCall($event)"
|
||||
@dismiss="showCreateCallModal=false"
|
||||
:isActive="showCreateCallModal"
|
||||
/>
|
||||
<!-- Profile -->
|
||||
<ProfileHeader :title="user.name" :background="user.profile_cover" />
|
||||
<div class="columns is-fullheight m-t-md">
|
||||
<div class="column is-3">
|
||||
<div class="card">
|
||||
<div class="card-image">
|
||||
<figure class="image is-4by4 p-md">
|
||||
<img :src="user.avatar" class="is-rounded is-avatar" />
|
||||
</figure>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div v-if="!![...user.connections.children, ...user.connections.connections].length">
|
||||
<p class="card-header-title">Connections</p>
|
||||
<ChildCard
|
||||
v-for="child in [...user.connections.children, ...user.connections.connections]"
|
||||
:key="child.id"
|
||||
:child="child"
|
||||
></ChildCard>
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="column">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<nav class="level">
|
||||
<!-- Left side -->
|
||||
<div class="level-left">
|
||||
<div class="level-item">
|
||||
<p class="subtitle">
|
||||
<i class="fa fa-users"></i> My Connections
|
||||
</p>
|
||||
<h1 class="title">My Room</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right side -->
|
||||
<div class="level-right">
|
||||
<!-- <div class="level-item">
|
||||
<a href="#" class="button is-success">
|
||||
<i class="fa fa-plus"></i> Add a new Child
|
||||
</a>
|
||||
</div>-->
|
||||
<div class="level-item">
|
||||
<a href="#" class="button is-primary">
|
||||
<i class="fa fa-plug"></i> Connect to a child
|
||||
</a>
|
||||
<button class="button">
|
||||
<i class="fa fa-fw fa-plus"></i> Add
|
||||
</button>
|
||||
<button class="button is-success m-l-md" @click="showCreateCallModal=true">
|
||||
<i class="fa fa-fw fa-phone"></i> Call
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="card m-b-lg">
|
||||
<div v-for="connection in connections" :key="connection.id">
|
||||
<div class="card-content">
|
||||
<div class="media">
|
||||
<div class="media-left">
|
||||
<figure class="image is-48x48">
|
||||
<img :src="connection.avatar" alt="Placeholder image" class="is-rounded is-avatar" />
|
||||
<div class="Games">
|
||||
<h2 class="subtitle">
|
||||
<i class="fa fa-fw fa-puzzle-piece"></i> My Games
|
||||
</h2>
|
||||
<div class="is-flex m-b-md">
|
||||
<div class="game m-l-md" v-for="i of [1, 2, 3, 4]" :key="i">
|
||||
<div class="game-cover">
|
||||
<figure class="image is-2by3 m-a">
|
||||
<img
|
||||
src="https://external-content.duckduckgo.com/iu/?u=http%3A%2F%2Fblog.springshare.com%2Fwp-content%2Fuploads%2F2010%2F02%2Fnc-md.gif&f=1&nofb=1"
|
||||
/>
|
||||
</figure>
|
||||
</div>
|
||||
<div class="media-content">
|
||||
<p class="title is-4">{{connection.name}}</p>
|
||||
<p class="subtitle is-6">@code</p>
|
||||
<div class="game-text">
|
||||
<div>Name</div>
|
||||
<div>Type</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="Books">
|
||||
<h2 class="subtitle">
|
||||
<i class="fa fa-fw fa-book"></i> My Books
|
||||
</h2>
|
||||
<div class="is-flex m-b-md">
|
||||
<div class="book m-l-md" v-for="i of [1, 2, 3, 4]" :key="i">
|
||||
<div class="book-cover">
|
||||
<figure class="image is-2by3 m-a">
|
||||
<img
|
||||
src="https://external-content.duckduckgo.com/iu/?u=http%3A%2F%2Fwww.sylviaday.com%2FWP%2Fwp-content%2Fthemes%2Fsylviaday%2Fimages%2Fcovers%2Ftemp-covers%2Fplaceholder-cover.jpg&f=1&nofb=1"
|
||||
/>
|
||||
</figure>
|
||||
</div>
|
||||
<div class="book-text">
|
||||
<div>book_name</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="columns">
|
||||
<div class="column" v-for="user in connection.linkedUsers" :key="user.id">
|
||||
<ChildAvatar :child="user" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -49,24 +120,103 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import ChildAvatar, { IChildAvatar } from "../components/child_avatar.vue";
|
||||
import { mapActions, mapGetters } from "vuex";
|
||||
import ChildCard from "../components/Child_Card.vue";
|
||||
import Services from "../../services/index";
|
||||
let connections = [];
|
||||
|
||||
import Loading from "../../shared/components/Loading/Loading.vue";
|
||||
import ProfileHeader from "../components/ProfileHeader.vue";
|
||||
import AddConnectionModal from "../components/AddConnectionModal.vue";
|
||||
import ConfigureNewCallModal from "../components/ConfigureNewCallModal.vue";
|
||||
import FileSelect from "../../shared/components/FileSelect/FileSelect.vue";
|
||||
import AvatarBadge from "../components/AvatarBadge.vue";
|
||||
import Moment from "moment";
|
||||
import Modal from "../../shared/components/Modal/Modal.vue";
|
||||
export default {
|
||||
name: "Home",
|
||||
components: {
|
||||
ChildAvatar
|
||||
Loading,
|
||||
ProfileHeader,
|
||||
Modal,
|
||||
FileSelect,
|
||||
AvatarBadge,
|
||||
AddConnectionModal,
|
||||
ConfigureNewCallModal,
|
||||
ChildCard
|
||||
},
|
||||
beforeCreate() {},
|
||||
async created() {
|
||||
this.connections = await Services.ApiService.getConnections();
|
||||
// console.dir(connections);
|
||||
this.loading = false;
|
||||
return true;
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
connections
|
||||
loading: true,
|
||||
child: null,
|
||||
isParent: false,
|
||||
inEditMode: false,
|
||||
showCoverModal: false,
|
||||
showCreateCallModal: false,
|
||||
showAddConnectionModal: false,
|
||||
childCoverModalImage: null
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onDeleteClicked() {
|
||||
this.notify({ message: "Test" });
|
||||
},
|
||||
goChildProfile(connection) {
|
||||
this.$router.push({ path: `/child/${connection.id}` });
|
||||
},
|
||||
async makeCall(event) {
|
||||
try {
|
||||
const response = await Services.ApiService.createCall(event);
|
||||
this.notify({ message: `Connectiong...` });
|
||||
this.$router.push({ path: `/call/${response.data.id}` });
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
async changeCover() {
|
||||
if (this.childCoverModalImage) {
|
||||
this.loading = true;
|
||||
try {
|
||||
this.child.profile_cover = await Services.ApiService.updateChildCover(
|
||||
this.child.id,
|
||||
this.childCoverModalImage
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
this.loading = false;
|
||||
}
|
||||
this.showCoverModal = false;
|
||||
this.this.childCoverModalImage = null;
|
||||
},
|
||||
togleEditMode() {
|
||||
this.inEditMode = !this.inEditMode;
|
||||
if (this.inEditMode) {
|
||||
this.showCoverModal = true;
|
||||
}
|
||||
},
|
||||
...mapActions(["getUser", "notify"])
|
||||
},
|
||||
computed: {
|
||||
age() {
|
||||
const years = Moment().diff(this.child.dob, "years");
|
||||
const months = Moment().diff(this.child.dob, "months") % 12;
|
||||
const isNewBorn = !years && !months;
|
||||
let text = "a new boarn!";
|
||||
if (!isNewBorn) {
|
||||
text = "";
|
||||
if (years) text += `${years} years`;
|
||||
if (years && months) text += ` and`;
|
||||
if (months) text += ` ${months} months`;
|
||||
text += " old";
|
||||
}
|
||||
return `${text}`;
|
||||
},
|
||||
...mapGetters(["user"])
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<template>
|
||||
<div class="wrapper">
|
||||
<div class="loading" v-if="loading">Loading...</div>
|
||||
<div class="loading" v-if="loading">
|
||||
<Loading />
|
||||
</div>
|
||||
<div class v-else>
|
||||
<Modal
|
||||
title="Add A child"
|
||||
|
@ -64,7 +66,7 @@
|
|||
<p class="card-header-title">My Children</p>
|
||||
</header>
|
||||
<div class="card-content">
|
||||
<ChildCard v-for="child in user.children" :key="child.id" :child="child"></ChildCard>
|
||||
<ChildCard v-for="child in user.connections.children" :key="child.id" :child="child"></ChildCard>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<a
|
||||
|
@ -108,11 +110,13 @@ import Modal from "../../shared/components/Modal/Modal.vue";
|
|||
import ChildCard from "../components/Child_Card.vue";
|
||||
import Services from "../../services";
|
||||
import FileSelect from "../../shared/components/FileSelect/FileSelect.vue";
|
||||
import Loading from "../../shared/components/Loading/Loading.vue";
|
||||
export default {
|
||||
components: {
|
||||
Modal,
|
||||
FileSelect,
|
||||
ChildCard
|
||||
ChildCard,
|
||||
Loading
|
||||
},
|
||||
name: "Settings",
|
||||
async beforeCreate() {
|
||||
|
@ -153,10 +157,14 @@ export default {
|
|||
|
||||
this.enableChildModel = false;
|
||||
await this.getUser();
|
||||
this.notify({
|
||||
message: `Yay!, ${child.name} was cretated`,
|
||||
level: "success"
|
||||
});
|
||||
// console.log(child);
|
||||
return true;
|
||||
},
|
||||
...mapActions(["getUser"])
|
||||
...mapActions(["getUser", "notify"])
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(["user"])
|
||||
|
|
127
resources/scripts/applications/services/admin.api.service.ts
Normal file
127
resources/scripts/applications/services/admin.api.service.ts
Normal file
|
@ -0,0 +1,127 @@
|
|||
export default class AdminApiService {
|
||||
|
||||
static async getAllUsers() {
|
||||
return (await fetch('/api/v1/admin/users')).json();
|
||||
}
|
||||
|
||||
static async addStunServer(payload: { port: number, url: string }) {
|
||||
const options = {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
type: 'STUN',
|
||||
...payload
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
try {
|
||||
return (await fetch('/api/v1/admin/ice/stun', options)).json();
|
||||
} catch (error) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
static async addTurnServer(payload: { port: number, url: string, secret: string, protocols: string }) {
|
||||
const options = {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
type: 'TURN',
|
||||
...payload
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
try {
|
||||
return (await fetch('/api/v1/admin/ice/turn', options)).json();
|
||||
} catch (error) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
static async createConnection(payload: { child_id: number, email: string, is_parent: boolean }) {
|
||||
const options = {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(payload),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
try {
|
||||
return (await fetch('/api/v1/client/connections/create', options)).json();
|
||||
} catch (error) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
static async updateChildCover(child_id: number, profile_cover: string) {
|
||||
const options = {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
profile_cover
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
};
|
||||
try {
|
||||
const response = await fetch(`/api/v1/client/child/${child_id}/profile/cover`, options);
|
||||
console.log(response);
|
||||
return response.json();
|
||||
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
static async createCall(payload: { connection_id: number, child_id: number }) {
|
||||
const options = {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(payload),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
};
|
||||
try {
|
||||
const response = await fetch('/api/v1/client/call/create', options);
|
||||
return response.json();
|
||||
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static async createChild(name: string, dob: Date, avatar: string): Promise<any> {
|
||||
|
||||
|
||||
const options = {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
name,
|
||||
dob,
|
||||
avatar
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
};
|
||||
try {
|
||||
const response = await fetch('/api/v1/client/child/', options);
|
||||
console.log(response);
|
||||
return response.json();
|
||||
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface IApiResponse {
|
||||
code: number;
|
||||
data?: any;
|
||||
message?: string;
|
||||
}
|
|
@ -4,13 +4,69 @@ export default class ApiService {
|
|||
return (await fetch('/api/v1/client/user/')).json();
|
||||
}
|
||||
|
||||
static async getConnections() {
|
||||
return (await fetch('/api/v1/client/connections')).json();
|
||||
}
|
||||
|
||||
static async getAllUsers() {
|
||||
return (await fetch('/api/v1/admin/users')).json();
|
||||
}
|
||||
|
||||
static async getChild(id: number): Promise<IApiResponse> {
|
||||
return (await fetch(`/api/v1/client/child/${id}`)).json();
|
||||
}
|
||||
|
||||
static async createConnection(payload: { child_id: number, email: string, is_parent: boolean }) {
|
||||
const options = {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(payload),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}
|
||||
try {
|
||||
return (await fetch('/api/v1/client/connections/create', options)).json();
|
||||
} catch (error) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
static async updateChildCover(child_id: number, profile_cover: string) {
|
||||
const options = {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
profile_cover
|
||||
}),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
};
|
||||
try {
|
||||
const response = await fetch(`/api/v1/client/child/${child_id}/profile/cover`, options);
|
||||
console.log(response);
|
||||
return response.json();
|
||||
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
static async createCall(payload: { connection_id: number, child_id: number }) {
|
||||
const options = {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(payload),
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
};
|
||||
try {
|
||||
const response = await fetch('/api/v1/client/call/create', options);
|
||||
return response.json();
|
||||
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static async createChild(name: string, dob: Date, avatar: string): Promise<any> {
|
||||
|
||||
|
||||
|
@ -36,3 +92,9 @@ export default class ApiService {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface IApiResponse {
|
||||
code: number;
|
||||
data?: any;
|
||||
message?: string;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
<template>
|
||||
<div class="wrapper is-fullheight">
|
||||
<div class="css-loader">
|
||||
<div class="dot"></div>
|
||||
<div class="dot delay-1"></div>
|
||||
<div class="dot delay-2"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from "vue";
|
||||
export default {};
|
||||
</script>
|
|
@ -0,0 +1,20 @@
|
|||
<template>
|
||||
<div
|
||||
:class="['notification','notification-fade' ,'is-light', `is-${notification.level || 'info'}`]"
|
||||
>
|
||||
<button class="delete" @click="close()"></button>
|
||||
{{notification.message}}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: "Notification",
|
||||
props: ["notification"],
|
||||
methods: {
|
||||
close() {
|
||||
this.$emit("onClose");
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -21,5 +21,6 @@ const { Ignitor } = require('@adonisjs/ignitor')
|
|||
|
||||
new Ignitor(require('@adonisjs/fold'))
|
||||
.appRoot(__dirname)
|
||||
.wsServer()
|
||||
.fireHttpServer()
|
||||
.catch(console.error)
|
||||
|
|
|
@ -22,6 +22,7 @@ const providers =
|
|||
'@adonisjs/auth/providers/AuthProvider',
|
||||
'@adonisjs/validator/providers/ValidatorProvider',
|
||||
'@adonisjs/drive/providers/DriveProvider',
|
||||
'@adonisjs/websocket/providers/WsProvider',
|
||||
]
|
||||
|
||||
/*
|
||||
|
|
|
@ -32,9 +32,14 @@ Route.post('/login', 'AuthController.login').validator('Login');
|
|||
|
||||
Route
|
||||
.group(() => {
|
||||
Route.get('connections', 'ClientApiController.getConnections');
|
||||
Route.post('connections/create', 'ClientApiController.createConnection');
|
||||
Route.get('user', 'ClientApiController.getUser');
|
||||
Route.post('child', 'ClientApiController.createChild');
|
||||
Route.get('child/:id', 'ClientApiController.getChild');
|
||||
Route.post(
|
||||
'child/:id/profile/cover',
|
||||
'ClientApiController.setChildProfileCover');
|
||||
Route.post('call/create', 'ClientApiController.createCall');
|
||||
})
|
||||
.prefix('api/v1/client')
|
||||
.middleware(['auth']);
|
||||
|
|
22
start/socket.js
Normal file
22
start/socket.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
'use strict'
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Websocket
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This file is used to register websocket channels and start the Ws server.
|
||||
| Learn more about same in the official documentation.
|
||||
| https://adonisjs.com/docs/websocket
|
||||
|
|
||||
| For middleware, do check `wsKernel.js` file.
|
||||
|
|
||||
*/
|
||||
|
||||
const Ws = use('Ws');
|
||||
// const SignalingController = use('App/Controllers/Ws/SignalingController')
|
||||
|
||||
Ws.channel('call:*', 'SignalingController').middleware([
|
||||
'auth', 'ws_call_auth'
|
||||
]);
|
||||
Ws.channel('user_channel', 'UserChannelController').middleware(['auth']);
|
39
start/wsKernel.js
Normal file
39
start/wsKernel.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
'use strict'
|
||||
|
||||
const Ws = use('Ws');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Global middleware
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Global middleware are executed on each Websocket channel subscription.
|
||||
|
|
||||
*/
|
||||
const globalMiddleware =
|
||||
['Adonis/Middleware/Session', 'Adonis/Middleware/AuthInit'];
|
||||
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Named middleware
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Named middleware are defined as key/value pairs. Later you can use the
|
||||
| keys to run selected middleware on a given channel.
|
||||
|
|
||||
| // define
|
||||
| {
|
||||
| auth: 'Adonis/Middleware/Auth'
|
||||
| }
|
||||
|
|
||||
| // use
|
||||
| Ws.channel('chat', 'ChatController').middleware(['auth'])
|
||||
*/
|
||||
const namedMiddleware = {
|
||||
auth: 'Adonis/Middleware/Auth',
|
||||
ws_call_auth: 'App/Middleware/WsCallAuth',
|
||||
};
|
||||
|
||||
|
||||
Ws.registerGlobal(globalMiddleware).registerNamed(namedMiddleware);
|
|
@ -1,15 +1,30 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"module": "es2015",
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
// "strict": true,
|
||||
"jsx": "preserve",
|
||||
"importHelpers": true,
|
||||
"moduleResolution": "node",
|
||||
"target": "es5",
|
||||
"experimentalDecorators": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"lib": [
|
||||
"dom",
|
||||
"es2015"
|
||||
"baseUrl": ".",
|
||||
"types": [
|
||||
"@types/node"
|
||||
],
|
||||
"experimentalDecorators": true
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
]
|
||||
},
|
||||
"lib": [
|
||||
"esnext",
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"scripthost"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"resources/scripts/main.ts"
|
||||
|
|
|
@ -1,21 +1,14 @@
|
|||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
// const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
// const CleanWebpackPlugin = require('clean-webpack-plugin');
|
||||
// const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||
const {VueLoaderPlugin} = require('vue-loader')
|
||||
const {VueLoaderPlugin} = require('vue-loader');
|
||||
require('babel-loader');
|
||||
require('ts-loader');
|
||||
const resolve = relativePath => path.resolve(__dirname, '..', relativePath);
|
||||
|
||||
module.exports = {
|
||||
mode: 'development',
|
||||
entry: {
|
||||
'components/navbar': './resources/scripts/components/navbar.ts',
|
||||
'views/register': './resources/scripts/views/register.ts',
|
||||
|
||||
// 'applications/story-time':
|
||||
// './resources/scripts/applications/story-time/main.vue',
|
||||
'applications/home': './resources/scripts/applications/home/main.vue',
|
||||
'applications/admin': './resources/scripts/applications/admin/main.vue',
|
||||
},
|
||||
|
@ -75,8 +68,6 @@ module.exports = {
|
|||
plugins: [
|
||||
new webpack.NamedModulesPlugin(),
|
||||
new VueLoaderPlugin(),
|
||||
// Exchanges, adds, or removes modules while an application is running,
|
||||
// without a full reload.
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
],
|
||||
resolve: {
|
||||
|
|
490
yarn.lock
490
yarn.lock
|
@ -206,6 +206,34 @@
|
|||
indicative "^5.0.8"
|
||||
lodash "^4.17.11"
|
||||
|
||||
"@adonisjs/websocket-client@^1.0.9":
|
||||
version "1.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@adonisjs/websocket-client/-/websocket-client-1.0.9.tgz#94f018489e68e05425046b053478d44ed003b827"
|
||||
integrity sha512-GhHmGgyylwYUB+lBMt6KFPEQo1tck4Pn1n/aFs23CydcdChJfy4Yhtn+edqTtIYS+HTpbvXNvqn2z4EiS/xZOg==
|
||||
dependencies:
|
||||
"@adonisjs/websocket-packet" "^1.0.6"
|
||||
emittery "^0.3.0"
|
||||
query-string "^6.0.0"
|
||||
|
||||
"@adonisjs/websocket-packet@^1.0.6":
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/@adonisjs/websocket-packet/-/websocket-packet-1.0.6.tgz#7b310c777fd66793149ff2de94c6b2be46302bdc"
|
||||
integrity sha512-4MlcnwfJ5fy9EGBA0gNDAUThfrK4JeisQzHkRg0Z/Y3WGeciSuzgRB8hdwi2YEFeNOsEFcKme4ubEZXTAF020g==
|
||||
|
||||
"@adonisjs/websocket@^1.0.12":
|
||||
version "1.0.12"
|
||||
resolved "https://registry.yarnpkg.com/@adonisjs/websocket/-/websocket-1.0.12.tgz#ce48276be2dc287c6873d25bad0bfed5d16c35b8"
|
||||
integrity sha512-03Y0KOLs9X+df7XJbVku/Izg3BsjG1tquJzw4fAs9HNjiiLhTKtsBuS6nA3tn6PST12Je9wlddzUeH92xitwZg==
|
||||
dependencies:
|
||||
"@adonisjs/generic-exceptions" "^2.0.1"
|
||||
"@adonisjs/middleware-base" "^1.0.0"
|
||||
"@adonisjs/websocket-packet" "^1.0.6"
|
||||
cuid "^2.1.1"
|
||||
debug "^3.1.0"
|
||||
emittery "^0.4.1"
|
||||
macroable "^1.0.0"
|
||||
ws "^5.2.2"
|
||||
|
||||
"@babel/code-frame@^7.8.3":
|
||||
version "7.8.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e"
|
||||
|
@ -214,44 +242,45 @@
|
|||
"@babel/highlight" "^7.8.3"
|
||||
|
||||
"@babel/core@^7.8.3":
|
||||
version "7.8.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.4.tgz#d496799e5c12195b3602d0fddd77294e3e38e80e"
|
||||
integrity sha512-0LiLrB2PwrVI+a2/IEskBopDYSd8BCb3rOvH7D5tzoWd696TBEduBvuLVm4Nx6rltrLZqvI3MCalB2K2aVzQjA==
|
||||
version "7.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.9.0.tgz#ac977b538b77e132ff706f3b8a4dbad09c03c56e"
|
||||
integrity sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.8.3"
|
||||
"@babel/generator" "^7.8.4"
|
||||
"@babel/helpers" "^7.8.4"
|
||||
"@babel/parser" "^7.8.4"
|
||||
"@babel/template" "^7.8.3"
|
||||
"@babel/traverse" "^7.8.4"
|
||||
"@babel/types" "^7.8.3"
|
||||
"@babel/generator" "^7.9.0"
|
||||
"@babel/helper-module-transforms" "^7.9.0"
|
||||
"@babel/helpers" "^7.9.0"
|
||||
"@babel/parser" "^7.9.0"
|
||||
"@babel/template" "^7.8.6"
|
||||
"@babel/traverse" "^7.9.0"
|
||||
"@babel/types" "^7.9.0"
|
||||
convert-source-map "^1.7.0"
|
||||
debug "^4.1.0"
|
||||
gensync "^1.0.0-beta.1"
|
||||
json5 "^2.1.0"
|
||||
json5 "^2.1.2"
|
||||
lodash "^4.17.13"
|
||||
resolve "^1.3.2"
|
||||
semver "^5.4.1"
|
||||
source-map "^0.5.0"
|
||||
|
||||
"@babel/generator@^7.8.4":
|
||||
version "7.8.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.4.tgz#35bbc74486956fe4251829f9f6c48330e8d0985e"
|
||||
integrity sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA==
|
||||
"@babel/generator@^7.9.0", "@babel/generator@^7.9.5":
|
||||
version "7.9.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.9.5.tgz#27f0917741acc41e6eaaced6d68f96c3fa9afaf9"
|
||||
integrity sha512-GbNIxVB3ZJe3tLeDm1HSn2AhuD/mVcyLDpgtLXa5tplmWrJdF/elxB56XNqCuD6szyNkDi6wuoKXln3QeBmCHQ==
|
||||
dependencies:
|
||||
"@babel/types" "^7.8.3"
|
||||
"@babel/types" "^7.9.5"
|
||||
jsesc "^2.5.1"
|
||||
lodash "^4.17.13"
|
||||
source-map "^0.5.0"
|
||||
|
||||
"@babel/helper-function-name@^7.8.3":
|
||||
version "7.8.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz#eeeb665a01b1f11068e9fb86ad56a1cb1a824cca"
|
||||
integrity sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==
|
||||
"@babel/helper-function-name@^7.9.5":
|
||||
version "7.9.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz#2b53820d35275120e1874a82e5aabe1376920a5c"
|
||||
integrity sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw==
|
||||
dependencies:
|
||||
"@babel/helper-get-function-arity" "^7.8.3"
|
||||
"@babel/template" "^7.8.3"
|
||||
"@babel/types" "^7.8.3"
|
||||
"@babel/types" "^7.9.5"
|
||||
|
||||
"@babel/helper-get-function-arity@^7.8.3":
|
||||
version "7.8.3"
|
||||
|
@ -260,6 +289,63 @@
|
|||
dependencies:
|
||||
"@babel/types" "^7.8.3"
|
||||
|
||||
"@babel/helper-member-expression-to-functions@^7.8.3":
|
||||
version "7.8.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz#659b710498ea6c1d9907e0c73f206eee7dadc24c"
|
||||
integrity sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA==
|
||||
dependencies:
|
||||
"@babel/types" "^7.8.3"
|
||||
|
||||
"@babel/helper-module-imports@^7.8.3":
|
||||
version "7.8.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz#7fe39589b39c016331b6b8c3f441e8f0b1419498"
|
||||
integrity sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg==
|
||||
dependencies:
|
||||
"@babel/types" "^7.8.3"
|
||||
|
||||
"@babel/helper-module-transforms@^7.9.0":
|
||||
version "7.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz#43b34dfe15961918707d247327431388e9fe96e5"
|
||||
integrity sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA==
|
||||
dependencies:
|
||||
"@babel/helper-module-imports" "^7.8.3"
|
||||
"@babel/helper-replace-supers" "^7.8.6"
|
||||
"@babel/helper-simple-access" "^7.8.3"
|
||||
"@babel/helper-split-export-declaration" "^7.8.3"
|
||||
"@babel/template" "^7.8.6"
|
||||
"@babel/types" "^7.9.0"
|
||||
lodash "^4.17.13"
|
||||
|
||||
"@babel/helper-optimise-call-expression@^7.8.3":
|
||||
version "7.8.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9"
|
||||
integrity sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ==
|
||||
dependencies:
|
||||
"@babel/types" "^7.8.3"
|
||||
|
||||
"@babel/helper-plugin-utils@^7.8.3":
|
||||
version "7.8.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz#9ea293be19babc0f52ff8ca88b34c3611b208670"
|
||||
integrity sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==
|
||||
|
||||
"@babel/helper-replace-supers@^7.8.6":
|
||||
version "7.8.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz#5ada744fd5ad73203bf1d67459a27dcba67effc8"
|
||||
integrity sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA==
|
||||
dependencies:
|
||||
"@babel/helper-member-expression-to-functions" "^7.8.3"
|
||||
"@babel/helper-optimise-call-expression" "^7.8.3"
|
||||
"@babel/traverse" "^7.8.6"
|
||||
"@babel/types" "^7.8.6"
|
||||
|
||||
"@babel/helper-simple-access@^7.8.3":
|
||||
version "7.8.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz#7f8109928b4dab4654076986af575231deb639ae"
|
||||
integrity sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw==
|
||||
dependencies:
|
||||
"@babel/template" "^7.8.3"
|
||||
"@babel/types" "^7.8.3"
|
||||
|
||||
"@babel/helper-split-export-declaration@^7.8.3":
|
||||
version "7.8.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9"
|
||||
|
@ -267,59 +353,88 @@
|
|||
dependencies:
|
||||
"@babel/types" "^7.8.3"
|
||||
|
||||
"@babel/helpers@^7.8.4":
|
||||
version "7.8.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.8.4.tgz#754eb3ee727c165e0a240d6c207de7c455f36f73"
|
||||
integrity sha512-VPbe7wcQ4chu4TDQjimHv/5tj73qz88o12EPkO2ValS2QiQS/1F2SsjyIGNnAD0vF/nZS6Cf9i+vW6HIlnaR8w==
|
||||
"@babel/helper-validator-identifier@^7.9.0", "@babel/helper-validator-identifier@^7.9.5":
|
||||
version "7.9.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz#90977a8e6fbf6b431a7dc31752eee233bf052d80"
|
||||
integrity sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==
|
||||
|
||||
"@babel/helpers@^7.9.0":
|
||||
version "7.9.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.9.2.tgz#b42a81a811f1e7313b88cba8adc66b3d9ae6c09f"
|
||||
integrity sha512-JwLvzlXVPjO8eU9c/wF9/zOIN7X6h8DYf7mG4CiFRZRvZNKEF5dQ3H3V+ASkHoIB3mWhatgl5ONhyqHRI6MppA==
|
||||
dependencies:
|
||||
"@babel/template" "^7.8.3"
|
||||
"@babel/traverse" "^7.8.4"
|
||||
"@babel/types" "^7.8.3"
|
||||
"@babel/traverse" "^7.9.0"
|
||||
"@babel/types" "^7.9.0"
|
||||
|
||||
"@babel/highlight@^7.8.3":
|
||||
version "7.8.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.8.3.tgz#28f173d04223eaaa59bc1d439a3836e6d1265797"
|
||||
integrity sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==
|
||||
version "7.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.9.0.tgz#4e9b45ccb82b79607271b2979ad82c7b68163079"
|
||||
integrity sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==
|
||||
dependencies:
|
||||
"@babel/helper-validator-identifier" "^7.9.0"
|
||||
chalk "^2.0.0"
|
||||
esutils "^2.0.2"
|
||||
js-tokens "^4.0.0"
|
||||
|
||||
"@babel/parser@^7.8.3", "@babel/parser@^7.8.4":
|
||||
version "7.8.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.4.tgz#d1dbe64691d60358a974295fa53da074dd2ce8e8"
|
||||
integrity sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw==
|
||||
"@babel/parser@^7.8.6", "@babel/parser@^7.9.0":
|
||||
version "7.9.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.9.4.tgz#68a35e6b0319bbc014465be43828300113f2f2e8"
|
||||
integrity sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA==
|
||||
|
||||
"@babel/template@^7.8.3":
|
||||
version "7.8.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.3.tgz#e02ad04fe262a657809327f578056ca15fd4d1b8"
|
||||
integrity sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ==
|
||||
"@babel/plugin-transform-regenerator@^7.8.7":
|
||||
version "7.8.7"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.7.tgz#5e46a0dca2bee1ad8285eb0527e6abc9c37672f8"
|
||||
integrity sha512-TIg+gAl4Z0a3WmD3mbYSk+J9ZUH6n/Yc57rtKRnlA/7rcCvpekHXe0CMZHP1gYp7/KLe9GHTuIba0vXmls6drA==
|
||||
dependencies:
|
||||
regenerator-transform "^0.14.2"
|
||||
|
||||
"@babel/plugin-transform-runtime@^7.9.0":
|
||||
version "7.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.9.0.tgz#45468c0ae74cc13204e1d3b1f4ce6ee83258af0b"
|
||||
integrity sha512-pUu9VSf3kI1OqbWINQ7MaugnitRss1z533436waNXp+0N3ur3zfut37sXiQMxkuCF4VUjwZucen/quskCh7NHw==
|
||||
dependencies:
|
||||
"@babel/helper-module-imports" "^7.8.3"
|
||||
"@babel/helper-plugin-utils" "^7.8.3"
|
||||
resolve "^1.8.1"
|
||||
semver "^5.5.1"
|
||||
|
||||
"@babel/runtime@^7.8.4":
|
||||
version "7.9.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.2.tgz#d90df0583a3a252f09aaa619665367bae518db06"
|
||||
integrity sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/template@^7.8.3", "@babel/template@^7.8.6":
|
||||
version "7.8.6"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b"
|
||||
integrity sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.8.3"
|
||||
"@babel/parser" "^7.8.3"
|
||||
"@babel/types" "^7.8.3"
|
||||
"@babel/parser" "^7.8.6"
|
||||
"@babel/types" "^7.8.6"
|
||||
|
||||
"@babel/traverse@^7.8.4":
|
||||
version "7.8.4"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.4.tgz#f0845822365f9d5b0e312ed3959d3f827f869e3c"
|
||||
integrity sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg==
|
||||
"@babel/traverse@^7.8.6", "@babel/traverse@^7.9.0":
|
||||
version "7.9.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.9.5.tgz#6e7c56b44e2ac7011a948c21e283ddd9d9db97a2"
|
||||
integrity sha512-c4gH3jsvSuGUezlP6rzSJ6jf8fYjLj3hsMZRx/nX0h+fmHN0w+ekubRrHPqnMec0meycA2nwCsJ7dC8IPem2FQ==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.8.3"
|
||||
"@babel/generator" "^7.8.4"
|
||||
"@babel/helper-function-name" "^7.8.3"
|
||||
"@babel/generator" "^7.9.5"
|
||||
"@babel/helper-function-name" "^7.9.5"
|
||||
"@babel/helper-split-export-declaration" "^7.8.3"
|
||||
"@babel/parser" "^7.8.4"
|
||||
"@babel/types" "^7.8.3"
|
||||
"@babel/parser" "^7.9.0"
|
||||
"@babel/types" "^7.9.5"
|
||||
debug "^4.1.0"
|
||||
globals "^11.1.0"
|
||||
lodash "^4.17.13"
|
||||
|
||||
"@babel/types@^7.8.3":
|
||||
version "7.8.3"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.3.tgz#5a383dffa5416db1b73dedffd311ffd0788fb31c"
|
||||
integrity sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg==
|
||||
"@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.9.0", "@babel/types@^7.9.5":
|
||||
version "7.9.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.5.tgz#89231f82915a8a566a703b3b20133f73da6b9444"
|
||||
integrity sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg==
|
||||
dependencies:
|
||||
esutils "^2.0.2"
|
||||
"@babel/helper-validator-identifier" "^7.9.5"
|
||||
lodash "^4.17.13"
|
||||
to-fast-properties "^2.0.0"
|
||||
|
||||
|
@ -333,6 +448,11 @@
|
|||
node-exceptions "^3.0.0"
|
||||
resetable "^1.0.2"
|
||||
|
||||
"@types/node@^13.11.0":
|
||||
version "13.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.11.0.tgz#390ea202539c61c8fa6ba4428b57e05bc36dc47b"
|
||||
integrity sha512-uM4mnmsIIPK/yeO+42F2RQhGUIs39K2RFmugcJANppXe6J1nvH87PvzPZYpza7Xhhs8Yn9yIAVdLZ84z61+0xQ==
|
||||
|
||||
"@types/tinycolor2@^1.4.0":
|
||||
version "1.4.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/tinycolor2/-/tinycolor2-1.4.2.tgz#721ca5c5d1a2988b4a886e35c2ffc5735b6afbdf"
|
||||
|
@ -537,20 +657,27 @@ acorn-walk@^7.0.0:
|
|||
integrity sha512-wdlPY2tm/9XBr7QkKlq0WQVgiuGTX6YWPyRyBviSoScBuLfTVQhvwg6wJ369GJ/1nPfTLMfnrFIfjqVg6d+jQQ==
|
||||
|
||||
acorn@^6.2.1:
|
||||
version "6.4.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.0.tgz#b659d2ffbafa24baf5db1cdbb2c94a983ecd2784"
|
||||
integrity sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw==
|
||||
version "6.4.1"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474"
|
||||
integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==
|
||||
|
||||
acorn@^7.0.0:
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.0.tgz#949d36f2c292535da602283586c2477c57eb2d6c"
|
||||
integrity sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==
|
||||
version "7.1.1"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.1.tgz#e35668de0b402f359de515c5482a1ab9f89a69bf"
|
||||
integrity sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==
|
||||
|
||||
adonis-await-outside@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/adonis-await-outside/-/adonis-await-outside-1.0.0.tgz#56a11ad529e3bf4018a4ea1e804995c96cebc54c"
|
||||
integrity sha512-YV4eqnlWaq5ptCrb/JTmJU/IZF1R/M8RJnKejT3+KCE8+mAOoHSxQwns8zWJTsJajvo2qcgKsKPQGtzDlENWfA==
|
||||
|
||||
adonis-vue-websocket@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/adonis-vue-websocket/-/adonis-vue-websocket-2.0.2.tgz#1162de981d102d41c77e128b935909fb98b49ecf"
|
||||
integrity sha512-W7VHk+mqCMpOmcfJIzzvOCpeUOIK0Fkuq7YyI+iBmWD3//HVOhZoQRjFM51HWlfofmz1PCYj9lzdVtwyFAjZ4g==
|
||||
dependencies:
|
||||
vue "^2.*"
|
||||
|
||||
ajv-errors@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d"
|
||||
|
@ -561,10 +688,10 @@ ajv-keywords@^3.1.0, ajv-keywords@^3.4.1:
|
|||
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da"
|
||||
integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==
|
||||
|
||||
ajv@^6.1.0, ajv@^6.10.2, ajv@^6.5.5:
|
||||
version "6.11.0"
|
||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.11.0.tgz#c3607cbc8ae392d8a5a536f25b21f8e5f3f87fe9"
|
||||
integrity sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA==
|
||||
ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.0, ajv@^6.5.5:
|
||||
version "6.12.0"
|
||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.0.tgz#06d60b96d87b8454a5adaba86e7854da629db4b7"
|
||||
integrity sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw==
|
||||
dependencies:
|
||||
fast-deep-equal "^3.1.1"
|
||||
fast-json-stable-stringify "^2.0.0"
|
||||
|
@ -576,6 +703,11 @@ amdefine@>=0.0.4:
|
|||
resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
|
||||
integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=
|
||||
|
||||
animate.css@^3.7.2:
|
||||
version "3.7.2"
|
||||
resolved "https://registry.yarnpkg.com/animate.css/-/animate.css-3.7.2.tgz#e73e0d50e92cb1cfef1597d9b38a9481020e08ea"
|
||||
integrity sha512-0bE8zYo7C0KvgOYrSVfrzkbYk6IOTVPNqkiHg2cbyF4Pq/PXzilz4BRWA3hwEUBoMp5VBgrC29lQIZyhRWdBTw==
|
||||
|
||||
ansi-align@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f"
|
||||
|
@ -954,6 +1086,11 @@ async-foreach@^0.1.3:
|
|||
resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542"
|
||||
integrity sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=
|
||||
|
||||
async-limiter@~1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
|
||||
integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
|
||||
|
||||
async@^2.6.1:
|
||||
version "2.6.3"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
|
||||
|
@ -1863,9 +2000,9 @@ camelcase@^5.0.0, camelcase@^5.3.1:
|
|||
integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
|
||||
|
||||
caniuse-lite@^1.0.30000844:
|
||||
version "1.0.30001027"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001027.tgz#283e2ef17d94889cc216a22c6f85303d78ca852d"
|
||||
integrity sha512-7xvKeErvXZFtUItTHgNtLgS9RJpVnwBlWX8jSo/BO8VsF6deszemZSkJJJA1KOKrXuzZH4WALpAJdq5EyfgMLg==
|
||||
version "1.0.30001035"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001035.tgz#2bb53b8aa4716b2ed08e088d4dc816a5fe089a1e"
|
||||
integrity sha512-C1ZxgkuA4/bUEdMbU5WrGY4+UhMFFiXrgNAfxiMIqWgFTWfv/xsZCS2xEHT2LMq7xAZfuAnu6mcqyDl0ZR6wLQ==
|
||||
|
||||
capture-stack-trace@^1.0.0:
|
||||
version "1.0.1"
|
||||
|
@ -2394,6 +2531,11 @@ cssesc@^3.0.0:
|
|||
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
|
||||
integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
|
||||
|
||||
cuid@^2.1.1:
|
||||
version "2.1.8"
|
||||
resolved "https://registry.yarnpkg.com/cuid/-/cuid-2.1.8.tgz#cbb88f954171e0d5747606c0139fb65c5101eac0"
|
||||
integrity sha512-xiEMER6E7TlTPnDxrM4eRiC6TRgjNX9xzEZ5U/Se2YJKr7Mq4pJn/2XEHjl3STcSh96GmkHPcBXLES8M29wyyg==
|
||||
|
||||
currently-unhandled@^0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
|
||||
|
@ -2607,9 +2749,9 @@ ee-first@1.1.1:
|
|||
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
|
||||
|
||||
electron-to-chromium@^1.3.47:
|
||||
version "1.3.353"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.353.tgz#c6f13f27d5212643979867a400c1a5e8a4ef042a"
|
||||
integrity sha512-CkG24biyy9qQTQs8U2vGQaiyWSFDxAXP/UGHBveXZ1TGoWOAw+eYZXryrX0UeIMKnQjcaHx33hzYuydv98kqGQ==
|
||||
version "1.3.377"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.377.tgz#b49d420b36ee6c48b0cd3137bfc7fec75f369b2e"
|
||||
integrity sha512-cm2WzMKf/3dW5+hNANKm8GAW6SwIWOqLTJ6GPCD0Bbw1qJ9Wzm9nmx9M+byzSsgw8CdCv5fb/wzLFqVS5h6QrA==
|
||||
|
||||
elliptic@^6.0.0:
|
||||
version "6.5.2"
|
||||
|
@ -2624,6 +2766,16 @@ elliptic@^6.0.0:
|
|||
minimalistic-assert "^1.0.0"
|
||||
minimalistic-crypto-utils "^1.0.0"
|
||||
|
||||
emittery@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.3.0.tgz#e6dcedabae804b5478c760335ecbbaf159da645c"
|
||||
integrity sha512-Bn/IFhx+BQIjTKn0vq7YWwo/yfTNeBZMqOGufY5FEV07tbwy5heDROFDCkMO2PcO5s7B9FDDXZc+JGgl6KzBOQ==
|
||||
|
||||
emittery@^0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.4.1.tgz#abe9d3297389ba424ac87e53d1c701962ce7433d"
|
||||
integrity sha512-r4eRSeStEGf6M5SKdrQhhLK5bOwOBxQhIE3YSTnZE3GpKiLfnnhE+tPtrJE79+eDJgm39BM6LSoI8SCx4HbwlQ==
|
||||
|
||||
emoji-regex@^7.0.1:
|
||||
version "7.0.3"
|
||||
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
|
||||
|
@ -2634,6 +2786,11 @@ emojis-list@^2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
|
||||
integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k=
|
||||
|
||||
emojis-list@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78"
|
||||
integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==
|
||||
|
||||
enabled@1.0.x:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/enabled/-/enabled-1.0.2.tgz#965f6513d2c2d1c5f4652b64a2e3396467fc2f93"
|
||||
|
@ -3398,9 +3555,9 @@ homedir-polyfill@^1.0.1:
|
|||
parse-passwd "^1.0.0"
|
||||
|
||||
hosted-git-info@^2.1.4:
|
||||
version "2.8.5"
|
||||
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.5.tgz#759cfcf2c4d156ade59b0b2dfabddc42a6b9c70c"
|
||||
integrity sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==
|
||||
version "2.8.8"
|
||||
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488"
|
||||
integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==
|
||||
|
||||
http-errors@1.7.3, http-errors@~1.7.0, http-errors@~1.7.2:
|
||||
version "1.7.3"
|
||||
|
@ -3492,9 +3649,9 @@ imurmurhash@^0.1.4:
|
|||
integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
|
||||
|
||||
in-publish@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51"
|
||||
integrity sha1-4g/146KvwmkDILbcVSaCqcf631E=
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.1.tgz#948b1a535c8030561cea522f73f78f4be357e00c"
|
||||
integrity sha512-oDM0kUSNFC31ShNxHKUyfZKy8ZeXZBWMjMdZHKLOk13uvT27VTL/QzRGfRUcevJhpkZAvlhPYuXkF7eNWrtyxQ==
|
||||
|
||||
indent-string@^2.1.0:
|
||||
version "2.1.0"
|
||||
|
@ -3583,10 +3740,10 @@ invert-kv@^2.0.0:
|
|||
resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02"
|
||||
integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==
|
||||
|
||||
ipaddr.js@1.9.0:
|
||||
version "1.9.0"
|
||||
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65"
|
||||
integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==
|
||||
ipaddr.js@1.9.1:
|
||||
version "1.9.1"
|
||||
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
|
||||
integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
|
||||
|
||||
is-absolute@^1.0.0:
|
||||
version "1.0.0"
|
||||
|
@ -3918,12 +4075,12 @@ json5@^1.0.1:
|
|||
dependencies:
|
||||
minimist "^1.2.0"
|
||||
|
||||
json5@^2.1.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.1.tgz#81b6cb04e9ba496f1c7005d07b4368a2638f90b6"
|
||||
integrity sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==
|
||||
json5@^2.1.2:
|
||||
version "2.1.3"
|
||||
resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43"
|
||||
integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==
|
||||
dependencies:
|
||||
minimist "^1.2.0"
|
||||
minimist "^1.2.5"
|
||||
|
||||
jsonfile@^4.0.0:
|
||||
version "4.0.0"
|
||||
|
@ -4108,7 +4265,7 @@ loader-runner@^2.4.0:
|
|||
resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357"
|
||||
integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==
|
||||
|
||||
loader-utils@1.2.3, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3:
|
||||
loader-utils@1.2.3:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7"
|
||||
integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==
|
||||
|
@ -4117,6 +4274,15 @@ loader-utils@1.2.3, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.
|
|||
emojis-list "^2.0.0"
|
||||
json5 "^1.0.1"
|
||||
|
||||
loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613"
|
||||
integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==
|
||||
dependencies:
|
||||
big.js "^5.2.2"
|
||||
emojis-list "^3.0.0"
|
||||
json5 "^1.0.1"
|
||||
|
||||
locate-path@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
|
||||
|
@ -4441,16 +4607,16 @@ minimatch@^3.0.4, minimatch@~3.0.2:
|
|||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
minimist@0.0.8:
|
||||
version "0.0.8"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
|
||||
integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
|
||||
|
||||
minimist@1.2.0, minimist@^1.1.3, minimist@^1.2.0:
|
||||
minimist@1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
|
||||
integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
|
||||
|
||||
minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5:
|
||||
version "1.2.5"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
||||
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
|
||||
|
||||
minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0:
|
||||
version "2.9.0"
|
||||
resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6"
|
||||
|
@ -4499,11 +4665,11 @@ mixin-object@^2.0.1:
|
|||
is-extendable "^0.1.1"
|
||||
|
||||
"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1:
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
|
||||
integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
|
||||
version "0.5.3"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.3.tgz#5a514b7179259287952881e94410ec5465659f8c"
|
||||
integrity sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg==
|
||||
dependencies:
|
||||
minimist "0.0.8"
|
||||
minimist "^1.2.5"
|
||||
|
||||
moment@^2.22.2, moment@^2.24.0:
|
||||
version "2.24.0"
|
||||
|
@ -4580,9 +4746,9 @@ nanomatch@^1.2.9:
|
|||
to-regex "^3.0.1"
|
||||
|
||||
needle@^2.2.1:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/needle/-/needle-2.3.2.tgz#3342dea100b7160960a450dc8c22160ac712a528"
|
||||
integrity sha512-DUzITvPVDUy6vczKKYTnWc/pBZ0EnjMJnQ3y+Jo5zfKFimJs7S3HFCxCRZYB9FUZcrzUQr3WsmvZgddMEIZv6w==
|
||||
version "2.3.3"
|
||||
resolved "https://registry.yarnpkg.com/needle/-/needle-2.3.3.tgz#a041ad1d04a871b0ebb666f40baaf1fb47867117"
|
||||
integrity sha512-EkY0GeSq87rWp1hoq/sH/wnTWgFVhYlnIkbJ0YJFfRgEFlz2RraCjBpFQ+vrEgEdp0ThfyHADmkChEhcb7PKyw==
|
||||
dependencies:
|
||||
debug "^3.2.6"
|
||||
iconv-lite "^0.4.4"
|
||||
|
@ -4774,9 +4940,9 @@ nodemon@^1.18.7:
|
|||
abbrev "1"
|
||||
|
||||
nopt@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
|
||||
integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48"
|
||||
integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==
|
||||
dependencies:
|
||||
abbrev "1"
|
||||
osenv "^0.1.4"
|
||||
|
@ -5266,14 +5432,14 @@ postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2:
|
|||
uniq "^1.0.1"
|
||||
|
||||
postcss-value-parser@^4.0.0, postcss-value-parser@^4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.0.2.tgz#482282c09a42706d1fc9a069b73f44ec08391dc9"
|
||||
integrity sha512-LmeoohTpp/K4UiyQCwuGWlONxXamGzCMtFxLq4W1nZVGIQLYvMCJx3yAF9qyyuFpflABI9yVdtJAqbihOsCsJQ==
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.0.3.tgz#651ff4593aa9eda8d5d0d66593a2417aeaeb325d"
|
||||
integrity sha512-N7h4pG+Nnu5BEIzyeaaIYWs0LI5XC40OrRh5L60z0QjFsqGWcHcbkBvpe1WYpcIS9yQ8sOi/vIPt1ejQCrMVrg==
|
||||
|
||||
postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.23, postcss@^7.0.5, postcss@^7.0.6:
|
||||
version "7.0.26"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.26.tgz#5ed615cfcab35ba9bbb82414a4fa88ea10429587"
|
||||
integrity sha512-IY4oRjpXWYshuTDFxMVkJDtWIk2LhsTlu8bZnbEJA4+bYT16Lvpo8Qv6EvDumhYRgzjZl489pmsY3qVgJQ08nA==
|
||||
version "7.0.27"
|
||||
resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.27.tgz#cc67cdc6b0daa375105b7c424a85567345fc54d9"
|
||||
integrity sha512-WuQETPMcW9Uf1/22HWUWP9lgsIC+KEHg2kozMflKjbeUtw9ujvFX6QmIfozaErDkmLWS9WEnEdEe6Uo9/BNTdQ==
|
||||
dependencies:
|
||||
chalk "^2.4.2"
|
||||
source-map "^0.6.1"
|
||||
|
@ -5294,7 +5460,7 @@ pretty-hrtime@^1.0.3:
|
|||
resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
|
||||
integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=
|
||||
|
||||
private@^0.1.6:
|
||||
private@^0.1.6, private@^0.1.8:
|
||||
version "0.1.8"
|
||||
resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff"
|
||||
integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==
|
||||
|
@ -5494,12 +5660,12 @@ prompt-rawlist@^2.0.1:
|
|||
prompt-list "^2.0.1"
|
||||
|
||||
proxy-addr@^2.0.4:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34"
|
||||
integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==
|
||||
version "2.0.6"
|
||||
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf"
|
||||
integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==
|
||||
dependencies:
|
||||
forwarded "~0.1.2"
|
||||
ipaddr.js "1.9.0"
|
||||
ipaddr.js "1.9.1"
|
||||
|
||||
prr@~1.0.1:
|
||||
version "1.0.1"
|
||||
|
@ -5583,6 +5749,15 @@ qs@~6.5.2:
|
|||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
|
||||
integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
|
||||
|
||||
query-string@^6.0.0:
|
||||
version "6.12.0"
|
||||
resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.12.0.tgz#fa0fe5b3ddf4d040d1236b80672949ab33d5cf80"
|
||||
integrity sha512-aoiFW9ZU7jP8Itjqfpw80Qe7RoyCIhFrW522sdsp9LG92pat6CCG3d8qNZBaUi71FsEjIfLjx9Ky347FtVoqXA==
|
||||
dependencies:
|
||||
decode-uri-component "^0.2.0"
|
||||
split-on-first "^1.0.0"
|
||||
strict-uri-encode "^2.0.0"
|
||||
|
||||
querystring-es3@^0.2.0:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
|
||||
|
@ -5752,6 +5927,11 @@ regenerator-runtime@^0.11.0:
|
|||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
|
||||
integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
|
||||
|
||||
regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.5:
|
||||
version "0.13.5"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697"
|
||||
integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==
|
||||
|
||||
regenerator-transform@^0.10.0:
|
||||
version "0.10.1"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd"
|
||||
|
@ -5761,6 +5941,14 @@ regenerator-transform@^0.10.0:
|
|||
babel-types "^6.19.0"
|
||||
private "^0.1.6"
|
||||
|
||||
regenerator-transform@^0.14.2:
|
||||
version "0.14.4"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.4.tgz#5266857896518d1616a78a0479337a30ea974cc7"
|
||||
integrity sha512-EaJaKPBI9GvKpvUz2mz4fhx7WPgvwRLY9v3hlNHWmAuJHI13T4nwKnNvm5RWJzEdnI5g5UwtOww+S8IdoUC2bw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.8.4"
|
||||
private "^0.1.8"
|
||||
|
||||
regex-not@^1.0.0, regex-not@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"
|
||||
|
@ -5925,7 +6113,7 @@ resolve-url@^0.2.1:
|
|||
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
|
||||
integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
|
||||
|
||||
resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.3.2:
|
||||
resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.3.2, resolve@^1.8.1:
|
||||
version "1.15.1"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.1.tgz#27bdcdeffeaf2d6244b95bb0f9f4b4653451f3e8"
|
||||
integrity sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==
|
||||
|
@ -6011,11 +6199,11 @@ schema-utils@^1.0.0:
|
|||
ajv-keywords "^3.1.0"
|
||||
|
||||
schema-utils@^2.6.0:
|
||||
version "2.6.4"
|
||||
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.6.4.tgz#a27efbf6e4e78689d91872ee3ccfa57d7bdd0f53"
|
||||
integrity sha512-VNjcaUxVnEeun6B2fiiUDjXXBtD4ZSH7pdbfIu1pOFwgptDPLMo/z9jr4sUfsjFVPqDCEin/F7IYlq7/E6yDbQ==
|
||||
version "2.6.5"
|
||||
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.6.5.tgz#c758f0a7e624263073d396e29cd40aa101152d8a"
|
||||
integrity sha512-5KXuwKziQrTVHh8j/Uxz+QUbxkaLW9X/86NBlx/gnKgtsZA2GIVMUn17qWhRFwF8jdYb3Dig5hRO/W5mZqy6SQ==
|
||||
dependencies:
|
||||
ajv "^6.10.2"
|
||||
ajv "^6.12.0"
|
||||
ajv-keywords "^3.4.1"
|
||||
|
||||
scmp@2.0.0:
|
||||
|
@ -6038,7 +6226,7 @@ semver-diff@^2.0.0:
|
|||
dependencies:
|
||||
semver "^5.0.3"
|
||||
|
||||
"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.1:
|
||||
"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.1:
|
||||
version "5.7.1"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
|
||||
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
|
||||
|
@ -6334,6 +6522,11 @@ spdx-license-ids@^3.0.0:
|
|||
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654"
|
||||
integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==
|
||||
|
||||
split-on-first@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f"
|
||||
integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==
|
||||
|
||||
split-string@^3.0.1, split-string@^3.0.2:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
|
||||
|
@ -6434,6 +6627,11 @@ stream-shift@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d"
|
||||
integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==
|
||||
|
||||
strict-uri-encode@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
|
||||
integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY=
|
||||
|
||||
string-width@^1.0.1, string-width@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
|
||||
|
@ -6619,9 +6817,9 @@ terser-webpack-plugin@^1.4.3:
|
|||
worker-farm "^1.7.0"
|
||||
|
||||
terser@^4.1.2:
|
||||
version "4.6.3"
|
||||
resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.3.tgz#e33aa42461ced5238d352d2df2a67f21921f8d87"
|
||||
integrity sha512-Lw+ieAXmY69d09IIc/yqeBqXpEQIpDGZqT34ui1QWXIUpR2RjbqEkT8X7Lgex19hslSqcWM5iMN2kM11eMsESQ==
|
||||
version "4.6.7"
|
||||
resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.7.tgz#478d7f9394ec1907f0e488c5f6a6a9a2bad55e72"
|
||||
integrity sha512-fmr7M1f7DBly5cX2+rFDvmGBAaaZyPrHYK4mMdHEDAdNTqXSZgSOfqsfGq2HqPGT/1V0foZZuCZFx8CHKgAk3g==
|
||||
dependencies:
|
||||
commander "^2.20.0"
|
||||
source-map "~0.6.1"
|
||||
|
@ -6787,9 +6985,9 @@ ts-loader@^6.2.1:
|
|||
semver "^6.0.0"
|
||||
|
||||
tslib@^1.9.0:
|
||||
version "1.10.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
|
||||
integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==
|
||||
version "1.11.1"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35"
|
||||
integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==
|
||||
|
||||
tsscmp@1.0.6:
|
||||
version "1.0.6"
|
||||
|
@ -6832,9 +7030,9 @@ typedarray@^0.0.6:
|
|||
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
|
||||
|
||||
typescript@^3.7.5:
|
||||
version "3.7.5"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae"
|
||||
integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==
|
||||
version "3.8.3"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061"
|
||||
integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==
|
||||
|
||||
uid-safe@2.1.5:
|
||||
version "2.1.5"
|
||||
|
@ -7006,6 +7204,11 @@ uuid@^3.3.2:
|
|||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
||||
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
||||
|
||||
uuid@^7.0.3:
|
||||
version "7.0.3"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b"
|
||||
integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==
|
||||
|
||||
v8-compile-cache@2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe"
|
||||
|
@ -7062,9 +7265,9 @@ vue-loader@^15.8.3:
|
|||
vue-style-loader "^4.1.0"
|
||||
|
||||
vue-router@^3.1.5:
|
||||
version "3.1.5"
|
||||
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.1.5.tgz#ff29b8a1e1306c526b52d4dc0532109f16c41231"
|
||||
integrity sha512-BszkPvhl7I9h334GjckCh7sVFyjTPMMJFJ4Bsrem/Ik+B/9gt5tgrk8k4gGLO4ZpdvciVdg7O41gW4DisQWurg==
|
||||
version "3.1.6"
|
||||
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.1.6.tgz#45f5a3a3843e31702c061dd829393554e4328f89"
|
||||
integrity sha512-GYhn2ynaZlysZMkFE5oCHRUTqE8BWs/a9YbKpNLi0i7xD6KG1EzDqpHQmv1F5gXjr8kL5iIVS8EOtRaVUEXTqA==
|
||||
|
||||
vue-style-loader@^4.1.0, vue-style-loader@^4.1.2:
|
||||
version "4.1.2"
|
||||
|
@ -7087,15 +7290,15 @@ vue-template-es2015-compiler@^1.9.0:
|
|||
resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825"
|
||||
integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==
|
||||
|
||||
vue@^2.6.11:
|
||||
vue@^2.*, vue@^2.6.11:
|
||||
version "2.6.11"
|
||||
resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.11.tgz#76594d877d4b12234406e84e35275c6d514125c5"
|
||||
integrity sha512-VfPwgcGABbGAue9+sfrD4PuwFar7gPb1yl1UK1MwXoQPAw0BKSqWfoYCT/ThFrdEVWoI51dBuyCoiNU9bZDZxQ==
|
||||
|
||||
vuex@^3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.1.2.tgz#a2863f4005aa73f2587e55c3fadf3f01f69c7d4d"
|
||||
integrity sha512-ha3jNLJqNhhrAemDXcmMJMKf1Zu4sybMPr9KxJIuOpVcsDQlTBYLLladav2U+g1AvdYDG5Gs0xBTb0M5pXXYFQ==
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.1.3.tgz#f2ad73e3fb73691698b38c93f66e58e267947180"
|
||||
integrity sha512-k8vZqNMSNMgKelVZAPYw5MNb2xWSmVgCKtYKAptvm9YtZiOXnRXFWu//Y9zQNORTrm3dNj1n/WaZZI26tIX6Mw==
|
||||
|
||||
warning-symbol@^0.1.0:
|
||||
version "0.1.0"
|
||||
|
@ -7137,9 +7340,9 @@ webpack-sources@^1.4.0, webpack-sources@^1.4.1:
|
|||
source-map "~0.6.1"
|
||||
|
||||
webpack@^4.41.5:
|
||||
version "4.41.6"
|
||||
resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.41.6.tgz#12f2f804bf6542ef166755050d4afbc8f66ba7e1"
|
||||
integrity sha512-yxXfV0Zv9WMGRD+QexkZzmGIh54bsvEs+9aRWxnN8erLWEOehAKUTeNBoUbA6HPEZPlRo7KDi2ZcNveoZgK9MA==
|
||||
version "4.42.0"
|
||||
resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.42.0.tgz#b901635dd6179391d90740a63c93f76f39883eb8"
|
||||
integrity sha512-EzJRHvwQyBiYrYqhyjW9AqM90dE4+s1/XtCfn7uWg6cS72zH+2VPFAlsnW0+W0cDi0XRjNKUMoJtpSi50+Ph6w==
|
||||
dependencies:
|
||||
"@webassemblyjs/ast" "1.8.5"
|
||||
"@webassemblyjs/helper-module-context" "1.8.5"
|
||||
|
@ -7265,6 +7468,13 @@ write-file-atomic@^2.0.0:
|
|||
imurmurhash "^0.1.4"
|
||||
signal-exit "^3.0.2"
|
||||
|
||||
ws@^5.2.2:
|
||||
version "5.2.2"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f"
|
||||
integrity sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==
|
||||
dependencies:
|
||||
async-limiter "~1.0.0"
|
||||
|
||||
xdg-basedir@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4"
|
||||
|
@ -7296,9 +7506,9 @@ yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3:
|
|||
integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
|
||||
|
||||
yargs-parser@^13.1.0:
|
||||
version "13.1.1"
|
||||
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0"
|
||||
integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==
|
||||
version "13.1.2"
|
||||
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38"
|
||||
integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==
|
||||
dependencies:
|
||||
camelcase "^5.0.0"
|
||||
decamelize "^1.2.0"
|
||||
|
|
Loading…
Reference in a new issue