diff --git a/package.json b/package.json index b7c4530..7e1febe 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "license": "MIT", "scripts": { "lint": "eslint src --ext ts,tsx", - "dev:server": "ts-node-dev -r tsconfig-paths/register --inspect --transpile-only --ignore-watch node_modules src/shared/infra/http/server.ts", + "dev:server": "cross-env ts-node-dev -r dotenv/config -r tsconfig-paths/register --inspect --transpile-only --ignore-watch node_modules src/shared/infra/http/server.ts", "build": "babel src --extensions \".js,.ts\" --out-dir dist --copy-files", "docs": "npx insomnia-documenter --output docs" }, @@ -33,6 +33,7 @@ "@typescript-eslint/parser": "^4.15.1", "babel-plugin-module-resolver": "^5.0.0", "babel-plugin-transform-typescript-metadata": "^0.3.1", + "cross-env": "^7.0.3", "eslint": "^7.20.0", "eslint-config-airbnb-base": "^14.2.1", "eslint-import-resolver-typescript": "^2.4.0", diff --git a/src/config/upload.ts b/src/config/upload.ts index d844276..c60fe12 100644 --- a/src/config/upload.ts +++ b/src/config/upload.ts @@ -1,5 +1,3 @@ -/* eslint-disable no-nested-ternary */ -/* eslint-disable no-param-reassign */ import { S3 } from '@aws-sdk/client-s3'; import multer, { FileFilterCallback } from 'multer'; import path from 'path'; @@ -12,6 +10,7 @@ const storageTypes = (type: 'audio' | 'user' | 'music') => ({ local: multer.diskStorage({ destination: tmpFolder, filename(req, file, cb) { + // eslint-disable-next-line no-param-reassign file.key = `${Date.now()}-${file.originalname.replace(/\s/g, '_')}`; return cb(null, file.key); diff --git a/src/modules/events/dtos/IEventsGoogleDTO.ts b/src/modules/events/dtos/IEventsGoogleDTO.ts new file mode 100644 index 0000000..16e54c2 --- /dev/null +++ b/src/modules/events/dtos/IEventsGoogleDTO.ts @@ -0,0 +1,16 @@ +import { calendar_v3 } from 'googleapis'; + +export interface ICustomEventDTO extends calendar_v3.Schema$Event { + accepted?: calendar_v3.Schema$Event[] + declined?: calendar_v3.Schema$Event[] + tentative?:calendar_v3.Schema$Event[] + needsAction?: calendar_v3.Schema$Event[] +} +export interface IEventWithAttendeesStatus { + id?: string; + summary?: string; + accepted: string[]; + declined: string[]; + tentative: string[]; + needsAction: string[]; +} diff --git a/src/modules/invites/infra/http/controller/InvitesController.ts b/src/modules/invites/infra/http/controller/InvitesController.ts index b7680b2..36eee5a 100644 --- a/src/modules/invites/infra/http/controller/InvitesController.ts +++ b/src/modules/invites/infra/http/controller/InvitesController.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ import { Request, Response } from 'express'; import { container } from 'tsyringe'; @@ -9,6 +10,7 @@ import ListEventsByWeekService from '@modules/invites/services/ListEventsByWeekS import UpdateInviteService from '@modules/invites/services/UpdateInviteService'; import OutlookUpdateInviteState from '@modules/invites/services/OutlookUpdateInviteStateService'; import UpdateInviteStateService from '@modules/invites/services/UpdateInviteStateService'; +import AppError from '@shared/errors/AppError'; export default class InviteController { // public async create(req: Request, res: Response): Promise { @@ -43,17 +45,32 @@ export default class InviteController { public async listEventsByUser(req: Request, res: Response): Promise { const list = container.resolve(ListEventsService); const { email } = req.body; - const invites = await list.execute(email); - - return res.status(201).json(invites); + const events = await list.getEventsUser(email); + console.log(`InvitesController 50: Events${JSON.stringify(events)}`); + return res.status(201).json(events); } public async listInvitesByUser(req: Request, res: Response): Promise { - const list = container.resolve(ListInvitesService); + console.log('InvitesController → req.body:', req.body); + console.log('InvitesController → Content-Type:', req.headers['content-type']); const { email } = req.body; - const invites = await list.execute(email); - - return res.status(201).json(invites); + if (!email) { + return res.status(400).json({ message: 'É preciso enviar um email no corpo da requisição.' }); + } + + try { + const invites = await container + .resolve(ListInvitesService) + .getInvites(email); + + return res.status(200).json(invites); + } catch (err) { + if (err instanceof AppError) { + return res.status(err.statusCode).json({ message: err.message }); + } + console.error(err); + return res.status(500).json({ message: 'Erro interno no servidor.' }); + } } public async listEventsInAWeekByUser(req: Request, res: Response): Promise { diff --git a/src/modules/invites/infra/prisma/repositories/InvitesRepository.ts b/src/modules/invites/infra/prisma/repositories/InvitesRepository.ts index 294ff49..edfab2b 100644 --- a/src/modules/invites/infra/prisma/repositories/InvitesRepository.ts +++ b/src/modules/invites/infra/prisma/repositories/InvitesRepository.ts @@ -9,9 +9,9 @@ import ICreateInviteDTO from '@modules/invites/dtos/ICreateInviteDTO'; interface IInviteWithConfirmation { element: Invite; // Replace 'YourElementType' with the actual type of 'element' - yes: {amount: number, ateendees:User[], pseudoAttendes : PseudoUser[]}; - no: {amount: number, ateendees:User[], pseudoAttendes : PseudoUser[]}; - maybe: {amount: number, ateendees:User[], pseudoAttendes : PseudoUser[]}; + yes: { amount: number, ateendees: User[], pseudoAttendes: PseudoUser[] }; + no: { amount: number, ateendees: User[], pseudoAttendes: PseudoUser[] }; + maybe: { amount: number, ateendees: User[], pseudoAttendes: PseudoUser[] }; } export default class InvitesRepository implements IInvitesRepository { private ormRepository: Prisma.InviteDelegate @@ -43,19 +43,19 @@ export default class InvitesRepository implements IInvitesRepository { description, guests: { create: - guests.map((guest) => ({ - Status: 'needsAction', - optional: false, - User: { connect: { email: guest } }, - })), + guests.map((guest) => ({ + Status: 'needsAction', + optional: false, + User: { connect: { email: guest } }, + })), }, pseudoGuests: { create: - pseudoGuests.map((pseudoGuest) => ({ - Status: 'pseudoUser', - optional: false, - pseudoUser: { connect: { id: pseudoGuest } }, - })), + pseudoGuests.map((pseudoGuest) => ({ + Status: 'pseudoUser', + optional: false, + pseudoUser: { connect: { id: pseudoGuest } }, + })), }, address, @@ -184,7 +184,7 @@ export default class InvitesRepository implements IInvitesRepository { inviteId: element.id, }, }); - const yesAteendees1:User[] = []; + const yesAteendees1: User[] = []; yesAttendees.map(async (ateendee) => { const y = await this.ormRepository2.findUnique({ where: { @@ -207,7 +207,7 @@ export default class InvitesRepository implements IInvitesRepository { inviteId: element.id, }, }); - const noAteendees1:User[] = []; + const noAteendees1: User[] = []; noAttendees.map(async (ateendee) => { const n = await this.ormRepository2.findUnique({ where: { @@ -272,7 +272,7 @@ export default class InvitesRepository implements IInvitesRepository { return invitedWithConfirmation; } - public async UpdatedInviteStatusById(id: string, state:string, email:string): Promise { + public async UpdatedInviteStatusById(id: string, state: string, email: string): Promise { const invit = await this.ormRepository.update({ where: { id, @@ -293,7 +293,7 @@ export default class InvitesRepository implements IInvitesRepository { return invit; } - public async UpdatedInviteById(eventId:string, begin:string, end:string, phone:string): Promise { + public async UpdatedInviteById(eventId: string, begin: string, end: string, phone: string): Promise { const inviteUser = await this.ormRepository.findFirst({ where: { id: eventId, @@ -317,7 +317,7 @@ export default class InvitesRepository implements IInvitesRepository { return invit; } - public async listEventsInAWeekByUser(phone: string, beginWeek:string, endWeek:string): Promise { + public async listEventsInAWeekByUser(phone: string, beginWeek: string, endWeek: string): Promise { const events = await this.ormRepository.findMany({ where: { phone, state: 'accepted', begin: { gte: beginWeek }, end: { lte: endWeek }, @@ -414,4 +414,132 @@ export default class InvitesRepository implements IInvitesRepository { return invite; } + private async filterNewInvites(invites: ICreateInviteDTO[]): Promise { + const validInvites = invites.filter((i) => i && typeof i.googleId === 'string' && i.googleId.trim() !== ''); + + const googleIds = invites + .map((i) => i?.googleId) + .filter((id): id is string => !!id); + + const createdInvites = await this.ormRepository.findMany({ + where: { + googleId: { in: googleIds }, + }, + }); + + if (validInvites.length < invites.length) { + console.warn( + '⚠️ Alguns invites estavam inválidos e foram ignorados:', + invites.filter(i => !i || !i.googleId) + ); + } + const existingIds = new Set(createdInvites.map(i => i.googleId)); + return validInvites.filter(i => !existingIds.has(i.googleId)); + } + + private async createInvitesWithoutRelations(invites: ICreateInviteDTO[]): Promise { + const baseData = invites.map((invite) => ({ + name: invite.name, + begin: invite.begin, + end: invite.end, + beginSearch: invite.beginSearch, + endSearch: invite.endSearch, + phone: invite.phone, + description: invite.description, + address: invite.address, + link: invite.link, + state: invite.state, + googleId: invite.googleId, + organizerPhoto: invite.organizerPhoto, + organizerName: invite.organizerName, + })); + + await this.ormRepository.createMany({ data: baseData }); + + return this.ormRepository.findMany({ + where: { + googleId: { in: invites.map((i) => i.googleId) }, + }, + }); + } + private async prepareRelations(invites: ICreateInviteDTO[], createdInvites: Invite[]) { + const inviteUserData: Prisma.InviteUserCreateManyInput[] = []; + const pseudoInviteUserData: Prisma.PseudoInviteUserCreateManyInput[] = []; + + for (const invite of invites) { + const created = createdInvites.find(i => i.googleId === invite.googleId); + if (!created) continue; + + invite.guests.forEach(email => { + inviteUserData.push({ + inviteId: created.id, + userEmail: email, + optional: false, + Status: 'needsAction', + }); + }); + + invite.optionalGuests.forEach(email => { + inviteUserData.push({ + inviteId: created.id, + userEmail: email, + optional: true, + Status: 'needsAction', + }); + }); + + invite.pseudoGuests.forEach(id => { + pseudoInviteUserData.push({ + inviteId: created.id, + pseudoUserId: id, + optional: false, + Status: 'pseudoUser', + }); + }); + + invite.pseudoOptionalGuests.forEach(id => { + pseudoInviteUserData.push({ + inviteId: created.id, + pseudoUserId: id, + optional: true, + Status: 'pseudoUser', + }); + }); + + const organizer = await this.ormRepository2.findUnique({ where: { phone: invite.phone } }); + if (organizer?.email) { + inviteUserData.push({ + inviteId: created.id, + userEmail: organizer.email, + optional: false, + Status: 'accepted', + }); + } + } + + return { inviteUserData, pseudoInviteUserData }; + } + private async createRelations( + inviteUserData: Prisma.InviteUserCreateManyInput[], + pseudoInviteUserData: Prisma.PseudoInviteUserCreateManyInput[] + ) { + if (inviteUserData.length) { + await this.ormRepository3.createMany({ data: inviteUserData, skipDuplicates: true }); + } + + if (pseudoInviteUserData.length) { + await this.ormRepository4.createMany({ data: pseudoInviteUserData, skipDuplicates: true }); + } + } + public async createMany(invites: ICreateInviteDTO[]): Promise { + const newInvites = await this.filterNewInvites(invites); + if (!newInvites.length) return []; + + const createdInvites = await this.createInvitesWithoutRelations(newInvites); + const { inviteUserData, pseudoInviteUserData } = await this.prepareRelations(newInvites, createdInvites); + await this.createRelations(inviteUserData, pseudoInviteUserData); + + return createdInvites; + } + } diff --git a/src/modules/invites/repositories/IInvitesRepository.ts b/src/modules/invites/repositories/IInvitesRepository.ts index ee9ac6d..7a95a40 100644 --- a/src/modules/invites/repositories/IInvitesRepository.ts +++ b/src/modules/invites/repositories/IInvitesRepository.ts @@ -26,6 +26,8 @@ interface IInvitesRepository { connect(user: User, invite: Invite): Promise findInvitesByOrganizerName(eventId:string): Promise<(Invite & { pseudoGuests: PseudoInviteUser[] })[] | null>; delete(id:string): Promise; + createMany(data: ICreateInviteDTO[]): Promise; + } export default IInvitesRepository; diff --git a/src/modules/invites/services/CheckUserAvailabilityService.ts b/src/modules/invites/services/CheckUserAvailabilityService.ts index 47c07a5..368c369 100644 --- a/src/modules/invites/services/CheckUserAvailabilityService.ts +++ b/src/modules/invites/services/CheckUserAvailabilityService.ts @@ -26,7 +26,17 @@ export default class CheckUserAvailabilityService { auth: { clientId: process.env.OUTLOOK_CLIENT_ID as string, clientSecret: process.env.OUTLOOK_CLIENT_SECRET, + authority: 'https://login.microsoftonline.com/common', }, + system: { + loggerOptions: { + loggerCallback(loglevel: any, message: any, containsPii: any) { + console.log(message); + }, + piiLoggingEnabled: false, + logLevel: 3, + } + } }; const cca = new msal.ConfidentialClientApplication(clientConfig); @@ -69,7 +79,7 @@ export default class CheckUserAvailabilityService { return true; } - const oAuth2Client = new google.auth.OAuth2(process.env.GOOGLE_CLIENT_ID, process.env.GOOGLE_CLIENT_SECRET, process.env.GOOGLE_CLIENT_URI); + const oAuth2Client = new google.auth.OAuth2(process.env.GOOGLE_CLIENT_ID, process.env.GOOGLE_CLIENT_SECRET, `${process.env.GOOGLE_CLIENT_URI}`); oAuth2Client.setCredentials({ access_token: user.tokens }); diff --git a/src/modules/invites/services/ListEventsService.ts b/src/modules/invites/services/ListEventsService.ts index f5a59d2..a0c9c1c 100644 --- a/src/modules/invites/services/ListEventsService.ts +++ b/src/modules/invites/services/ListEventsService.ts @@ -1,16 +1,24 @@ -import { inject, injectable } from 'tsyringe'; +/* eslint-disable implicit-arrow-linebreak */ +/* eslint-disable no-console */ +import { inject, injectable, container } from 'tsyringe'; import { Invite, PseudoUser, User } from '@prisma/client'; // import AppError from '@shared/errors/AppError'; import AppError from '@shared/errors/AppError'; +import GetGoogleCalendarEventsService from '@modules/users/services/GetGoogleCalendarEventsService'; +import { calendar_v3 } from 'googleapis'; +import mapGoogleEventToInviteDTO from '@shared/utils/mappers/mapGoogleEventDTO'; import IInvitesRepository from '../repositories/IInvitesRepository'; +import ICreateInviteDTO from '../dtos/ICreateInviteDTO'; +import GetOutlookCalendarEvents from '@modules/users/services/GetOutlookCalendarEventsService'; +import { mapOutlookToGoogle } from '@shared/utils/mappers/mapOutlookToGoogle'; interface IInviteWithConfirmation { element: Invite; // Replace 'YourElementType' with the actual type of 'element' - yes: {amount: number, ateendees:User[], pseudoAttendes : PseudoUser[]}; - no: {amount: number, ateendees:User[], pseudoAttendes : PseudoUser[]}; - maybe: {amount: number, ateendees:User[], pseudoAttendes : PseudoUser[]}; + yes: { amount: number, ateendees: User[], pseudoAttendes: PseudoUser[] }; + no: { amount: number, ateendees: User[], pseudoAttendes: PseudoUser[] }; + maybe: { amount: number, ateendees: User[], pseudoAttendes: PseudoUser[] }; } @injectable() export default class ListEventsService { @@ -20,12 +28,19 @@ export default class ListEventsService { ) { } - public async execute(email:string): Promise { + public async execute(email: string): Promise { + console.log(`ListEventsService email: ${email}`); + const user = await this.invitesRepository.findByEmail(email); - if (!user) throw new AppError('User not found', 400); + console.log(`ListEventsService user: ${JSON.stringify(user)}`); - const invites = await this.invitesRepository.listEventsByUser(email); + if (!user) throw new AppError('User not found', 400); + if (!user.email) { + throw new AppError('User email not found', 400); + } + const invites = await this.invitesRepository.listEventsByUser(user.email); + console.log(`ListEventsService 36: ${invites}`); invites.forEach((invite) => { invite.yes.ateendees.forEach((attendee) => { // eslint-disable-next-line no-param-reassign @@ -43,4 +58,87 @@ export default class ListEventsService { return invites; } + public async getOutlookEvent(email: string): Promise { + const getOutlookCalendarEvents = container.resolve(GetOutlookCalendarEvents); + const events = await getOutlookCalendarEvents.authenticate(email); + // console.log(`ListEventsService 50: Events${JSON.stringify(events)}`); + // const eventsMapped = mapOutlookToGoogle(events); + const mappedEvents: calendar_v3.Schema$Event[] = events?.value.map((event: any) => + mapOutlookToGoogle(event) as calendar_v3.Schema$Event + ); + // console.log(`ListEventsService 53: Events after mapOutlookToGoogle: ${JSON.stringify(mappedEvents)}`); + return mappedEvents; + } + public async getGoogleEvents(email: string) { + const getGoogleCalendarEvents = container.resolve(GetGoogleCalendarEventsService); + const { events, user } = await getGoogleCalendarEvents.authenticate(email); + if (!events) throw new AppError('Events not found', 400); + // this.changeEventsData(events); + // console.log(`ListEventsService 64: events after change: ${JSON.stringify(events)}`); + // console.log(`ListEventsService 69: events after change: ${JSON.stringify(this.addResponseStatusArrays(events))}`); + + const invitesDTO: ICreateInviteDTO[] = events.map((event: calendar_v3.Schema$Event) => { + // console.log(`Event Email organzer : ${JSON.stringify(event.organizer?.displayName)}`) + mapGoogleEventToInviteDTO({ + event, + phone: user.phone, + organizerPhoto: user.photo, + organizerName: event.organizer?.displayName || user.name, + beginSearch: event.start?.dateTime || '', // Replace 'undefined' with actual value if available + endSearch: event.end?.dateTime || '', // Replace 'undefined' with actual value if available + }) + }).filter((invite: any): invite is ICreateInviteDTO => invite !== null);; + try { + const createdInvites = await this.invitesRepository.createMany(invitesDTO); + console.log('✅ Criado com sucesso:', createdInvites); + } catch (error) { + console.error('❌ Erro ao criar múltiplos invites:', error); + } + return events; + } + public async getEventsUser(email: string): Promise { + const userData = await this.invitesRepository.findByEmail(email); + // console.log(`ListEventsService 67 user: ${JSON.stringify(userData?.type)}`); + if (userData?.type === 'OUTLOOK') { + const events = await this.getOutlookEvent(email); + // console.log(`ListEventsService 70: Events after getOutlookEvent: ${JSON.stringify(this.addResponseStatusArrays(events))}`); + return this.addResponseStatusArrays(events); + } + if (userData?.type === 'GOOGLE') { + // console.log(`ListEventsService 72: userData: ${JSON.stringify(userData)}`); + const events = await this.getGoogleEvents(email); + return this.addResponseStatusArrays(events); + } + // Always return an array if no condition matches + return []; + } + + // This method is not implemented in the original code, but you can implement it if needed. + private addResponseStatusArrays(events: calendar_v3.Schema$Event[]): calendar_v3.Schema$Event[] { + return events.map((event) => { + const accepted: calendar_v3.Schema$EventAttendee[] = []; + const declined: calendar_v3.Schema$EventAttendee[] = []; + const tentative: calendar_v3.Schema$EventAttendee[] = []; + const needsAction: calendar_v3.Schema$EventAttendee[] = []; + + event.attendees?.forEach((attendee) => { + // const email = attendee.email || ''; + const status = attendee.responseStatus; + + if (status === 'accepted') accepted.push(attendee); + else if (status === 'declined') declined.push(attendee); + else if (status === 'tentative') tentative.push(attendee); + else if (status === 'needsAction') needsAction.push(attendee); + }); + + // Create a shallow copy before mutating + const eventCopy = { ...event } as any; + eventCopy.accepted = accepted; + eventCopy.declined = declined; + eventCopy.tentative = tentative; + eventCopy.needsAction = needsAction; + + return eventCopy; + }); + } } diff --git a/src/modules/invites/services/ListInvitesService.ts b/src/modules/invites/services/ListInvitesService.ts index b507d90..6013669 100644 --- a/src/modules/invites/services/ListInvitesService.ts +++ b/src/modules/invites/services/ListInvitesService.ts @@ -1,9 +1,12 @@ import { inject, injectable } from 'tsyringe'; +import { container } from 'tsyringe'; import { Invite } from '@prisma/client'; // import AppError from '@shared/errors/AppError'; import IInvitesRepository from '../repositories/IInvitesRepository'; +import ListEventsService from './ListEventsService'; +import { calendar_v3 } from 'googleapis'; @injectable() export default class CreateInviteService { @@ -13,12 +16,19 @@ export default class CreateInviteService { ) { } - public async execute(email:string): Promise { - const invite = await this.invitesRepository.listInvitesByUser(email); - invite.forEach((itens) => { - // eslint-disable-next-line no-param-reassign - itens.status = 0; + public async getInvites(email:string): Promise { + const list = container.resolve(ListEventsService); + const events = await list.getEventsUser(email); + console.log(`ListInvitesService 50: Events${JSON.stringify(events)}`); + // 2. Filtra só os eventos que o usuário raiz NÃO aceitou + const invites = (events as calendar_v3.Schema$Event[]).filter(event => { + // encontra o attendee correspondente ao usuário raiz + const rootAttendee = event.attendees?.find(a => a.email === email); + // se não existir ou não estiver “accepted”, mantemos o evento + return !!rootAttendee && rootAttendee.responseStatus !== 'accepted'; }); - return invite; + + // 3. Retorna só eles + return invites; } } diff --git a/src/modules/invites/services/OutlookUpdateInviteStateService.ts b/src/modules/invites/services/OutlookUpdateInviteStateService.ts index 0757a81..ad8456b 100644 --- a/src/modules/invites/services/OutlookUpdateInviteStateService.ts +++ b/src/modules/invites/services/OutlookUpdateInviteStateService.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ +/* eslint-disable no-console */ import msal from '@azure/msal-node'; import { inject, injectable } from 'tsyringe'; import { InviteUser } from '@prisma/client'; @@ -19,7 +21,7 @@ export default class OutlookUpdateInviteState { public async execute(email: string, idInvite: string, state: string): Promise { const user = await this.invitesRepository.findByEmail(email); - if (!user) throw new AppError('User not found', 400); + if (!user) throw new AppError('User not found user OutlookUptadeInStateServices', 400); const invite = await this.invitesRepository.findInviteById(idInvite); if (!invite) throw new AppError('Invite not found', 400); @@ -30,6 +32,16 @@ export default class OutlookUpdateInviteState { auth: { clientId: process.env.OUTLOOK_CLIENT_ID as string, clientSecret: process.env.OUTLOOK_CLIENT_SECRET, + authority: 'https://login.microsoftonline.com/common', + }, + system: { + loggerOptions: { + loggerCallback(loglevel: any, message: any, containsPii: any) { + console.log(message); + }, + piiLoggingEnabled: false, + logLevel: 3, + }, }, }; diff --git a/src/modules/users/infra/http/controller/PushNotificationController.ts b/src/modules/users/infra/http/controller/PushNotificationController.ts new file mode 100644 index 0000000..d1b11d0 --- /dev/null +++ b/src/modules/users/infra/http/controller/PushNotificationController.ts @@ -0,0 +1,46 @@ +import { Request, Response } from 'express'; +import { PushTokenService } from '@shared/infra/http/middleware/pushNotificationService'; + +const pushTokenService = new PushTokenService(); + +export default class PushNotificationController { + public async pushToken(req:Request, res:Response): Promise { + try { + const { token, platform, deviceId } = req.body; + const userId = req.user?.id; // Do middleware de auth + + if (!userId || !token || !platform) { + return res.status(400).json({ error: 'Dados obrigatórios: token, platform' }); + } + + const success = await pushTokenService.saveToken(userId, token, platform, deviceId); + + if (success) { + return res.json({ message: 'Token salvo com sucesso' }); + } + return res.status(500).json({ error: 'Falha ao salvar token' }); + } catch (error) { + return res.status(500).json({ error: 'Erro interno do servidor' }); + } + } + + public async deleteToken(req: Request, res: Response): Promise { + try { + const { token } = req.body; + const userId = req.user?.id; + + if (!userId || !token) { + return res.status(400).json({ error: 'Token é obrigatório' }); + } + + const success = await pushTokenService.removeToken(userId, token); + + if (success) { + return res.json({ message: 'Token removido com sucesso' }); + } + return res.status(400).json({ error: 'Falha ao remover token' }); + } catch (error) { + return res.status(500).json({ error: 'Erro interno do servidor' }); + } + } +} diff --git a/src/modules/users/infra/http/controller/UsersController.ts b/src/modules/users/infra/http/controller/UsersController.ts index a424c42..c6cdc08 100644 --- a/src/modules/users/infra/http/controller/UsersController.ts +++ b/src/modules/users/infra/http/controller/UsersController.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ import { Request, Response } from 'express'; import { container } from 'tsyringe'; @@ -39,6 +40,7 @@ import ListContactsService from '@modules/users/services/ListContactsService'; import UpdateEventService from '@modules/users/services/UpdateEventService'; import updateAllEventsService from '@modules/users/services/updateAllEventsService'; import SignUpLinkManagerService from '@modules/users/services/SignUpLinkManagerService'; +import { messageConnectionSuccess } from '@shared/utils/messageConnection/messageConnectionSucces'; export default class UserController { public async create(req: Request, res: Response): Promise { @@ -46,13 +48,14 @@ export default class UserController { phone, pseudoUserId, } = req.body; + console.log('UserController 47: Creating user with phone:', phone, 'and pseudoUserId:', pseudoUserId); const createUser = container.resolve(CreateUserService); const user = await createUser.execute({ phone, pseudoUserId, }); - + console.log('UserController 53: User created:', user); return res.status(201).json(user); } @@ -61,6 +64,7 @@ export default class UserController { const { pseudoUserId, link } = req.body; const response = await urlService.execute({ pseudoUserId, link }); + console.log('UserController 66: Sign-up link sent:', response); return res.status(201).json(response); } @@ -76,7 +80,7 @@ export default class UserController { }); user.tokens = 'secured'; - + console.log('UserController 79: User verified:', user); return res.status(201).json(user); } @@ -95,9 +99,11 @@ export default class UserController { photoFile: photo as Express.Multer.File| null, hasPhoto: !!photo, }); - + if (!user) { + throw new AppError('User not found upload', 404); + } user.tokens = 'secured'; - + console.log('UserController 96: User uploaded:', user); return res.status(201).json(user); } @@ -111,7 +117,10 @@ export default class UserController { const user = await updateEmail.execute({ id, email, }); - + if (!user) { + throw new AppError('User not found updateEmail', 404); + } + console.log('UserController 113: User email updated:', user); return res.status(201).json(user); } @@ -125,9 +134,11 @@ export default class UserController { const user = await deleteUser.execute({ phone, }); - + if (!user) { + throw new AppError('User not found deletUser', 404); + } user.tokens = 'secured'; - + console.log('UserController 127: User deleted:', user); return res.status(201).json(user); } @@ -141,7 +152,10 @@ export default class UserController { user.tokens = 'secured'; return user; }); - + if (!users) { + throw new AppError('No users found', 404); + } + console.log('UserController 140: Users listed:', users); return res.status(201).json(users); } @@ -165,39 +179,50 @@ export default class UserController { const urlservice = container.resolve(GoogleAuthUrlService); const { phone } = req.params; + console.log('UserController 182: Getting Google Auth URL for phone:', phone); const Url = await urlservice.authenticate(phone); + console.log('UserController 182 Google Auth URL:', Url); return res.status(201).json(Url); } public async getOutlookAuthUrl(req: Request, res: Response): Promise { const urlservice = container.resolve(OutlookAuthUrlService); const { phone } = req.params; - const Url = await urlservice.authenticate(phone); + console.warn('UserController 192: Outlook Auth URL:', Url); return res.status(201).json(Url); } + + public async getGoogleTokens(req: Request, res: Response): Promise { const { code, state } = req.query; + console.log(`UserController 262: code ${code} status ${state}`); const urlservice = container.resolve(GetGoogleTokensService); + console.log(`UserController 264: urlSerrvice ${urlservice}`); if (!code) throw new AppError('Code not found', 400); if (!state) throw new AppError('state not found', 400); const status = await urlservice.authenticate(code.toString(), state.toString()); - if (status) return res.status(201).json('ok'); + if (status) { + return res.status(200).send(messageConnectionSuccess('Calendario Google')); + } return res.status(201).json('error'); } public async getOutlookTokens(req: Request, res: Response): Promise { const { code, state } = req.query; + console.log(`UserController 207: code ${code} status ${state}`); const urlservice = container.resolve(GetOutlookTokensService); - if (!code) throw new AppError('User not found', 400); - if (!state) throw new AppError('User not found', 400); + if (!code) throw new AppError('User not found Code', 400); + if (!state) throw new AppError('User not found State', 400); const status = await urlservice.authenticate(code.toString(), state.toString()); - - if (status) return res.status(201).json('ok'); + console.log('UserController 210: Outlook tokens status:', status); + if (status) { + return res.status(200).send(messageConnectionSuccess('Calendario Outlook')); + } return res.status(201).json('error'); } @@ -207,9 +232,10 @@ export default class UserController { phone, begin, end, beginSearch, endSearch, attendees, description, address, name, createMeetLink, optionalAttendees, } = req.body; - const Url = await urlservice.authenticate({ + const Url = await urlservice.createGoogleCalendarEvent({ phone, begin, end, beginSearch, endSearch, attendees, description, address, name, createMeetLink, optionalAttendees, }); + console.log('UserController 225: Google event created:', Url); return res.status(201).json(Url); } @@ -232,7 +258,7 @@ export default class UserController { const invite = await urlservice.authenticate({ phone, begin, end, beginSearch, endSearch, attendees, description, address, name, optionalAttendees, createMeetLink, }); - + console.log('UserController 240: Outlook event created:', invite); return res.status(201).json(invite); } @@ -245,6 +271,7 @@ export default class UserController { const Url = await urlservice.updateEventState({ email, state, eventId, }); + console.log('UserController 252: Event state updated:', Url); return res.status(201).json(Url); } @@ -257,6 +284,7 @@ export default class UserController { const Url = await urlservice.authenticate({ phone, begin, end, eventId, }); + console.log('UserController 264: Event updated:', Url); return res.status(201).json(Url); } @@ -269,14 +297,17 @@ export default class UserController { const Url = await urlservice.authenticate({ phone, begin, end, idInvite, }); + console.log('UserController 276: All events updated:', Url); return res.status(201).json(Url); } public async getGoogleEvents(req: Request, res: Response): Promise { + console.log(`UserController 282: Params: ${JSON.stringify(req.params)}`); const urlservice = container.resolve(GetGoogleCalendarEventsService); - const { email } = req.body; - + const { email } = req.params; + console.log('UserController 282: Getting Google events for email:', email); const Url = await urlservice.authenticate(email); + console.log('UserController 286: Google events retrieved:', Url); return res.status(201).json(Url); } @@ -291,18 +322,20 @@ export default class UserController { public async GetUserByPhone(req: Request, res: Response): Promise { const findUser = container.resolve(GetUserByPhoneService); const { phone } = req.params; - const user = await findUser.execute(phone); user.user.tokens = 'secured'; + console.log(`UserControlle 385 GetUserByPhone: ${JSON.stringify(user)}`); + return res.status(201).json(user); } public async GetUserByEmail(req: Request, res: Response): Promise { const findUser = container.resolve(GetUserByEmailService); const { email } = req.params; - const user = await findUser.execute(email); user.user.tokens = 'secured'; + console.log(`UsersController 396: ${user}`); + return res.status(201).json(user); } diff --git a/src/modules/users/infra/http/routes/push.routes.ts b/src/modules/users/infra/http/routes/push.routes.ts new file mode 100644 index 0000000..c66326d --- /dev/null +++ b/src/modules/users/infra/http/routes/push.routes.ts @@ -0,0 +1,10 @@ +// Adicionar nas users.routes.ts +import { Router } from 'express'; +import PushNotificationController from '../controller/PushNotificationController'; + +const router = Router(); +const pushNotificationController = new PushNotificationController(); + +router.post('/push-token', pushNotificationController.pushToken); + +router.delete('/push-token', pushNotificationController.deleteToken); diff --git a/src/modules/users/infra/http/routes/users.routes.ts b/src/modules/users/infra/http/routes/users.routes.ts index 9ac32a6..7b58b45 100644 --- a/src/modules/users/infra/http/routes/users.routes.ts +++ b/src/modules/users/infra/http/routes/users.routes.ts @@ -25,7 +25,7 @@ usersRoutes.post('/resendCode', usersController.resendVerificationCode); usersRoutes.get('/listContacts/:phone', usersController.listContacts); // tokens -usersRoutes.get('/google', usersController.getGoogleTokens); +usersRoutes.get('/google', usersController.getGoogleTokens.bind(usersController)); usersRoutes.get('/outlook', usersController.getOutlookTokens); // urls @@ -39,8 +39,8 @@ usersRoutes.post('/createGoogleEvent', usersController.createGoogleEvent); usersRoutes.post('/createOutlookEvent', usersController.createOutlookEvent); // get events -usersRoutes.get('/getGoogleEvents', usersController.getGoogleEvents); -usersRoutes.get('/getOutlookEvents', usersController.getOutlookEvents); +usersRoutes.get('/getGoogleEvents/:email', usersController.getGoogleEvents); +usersRoutes.get('/getOutlookEvents/:email', usersController.getOutlookEvents); usersRoutes.get('/GetUserByPhone/:phone', usersController.GetUserByPhone); usersRoutes.post('/SendSignUpLink', usersController.SendSignUpLink); diff --git a/src/modules/users/infra/prisma/repositories/UsersRepository.ts b/src/modules/users/infra/prisma/repositories/UsersRepository.ts index 09a398a..5765321 100644 --- a/src/modules/users/infra/prisma/repositories/UsersRepository.ts +++ b/src/modules/users/infra/prisma/repositories/UsersRepository.ts @@ -51,6 +51,8 @@ export default class UsersRepository implements IUsersRepository { } public async findByPhone(phone: string): Promise<(User & { contatos: Contato[] }) | null> { + if (!phone) return null; + const user = await this.ormRepository.findUnique({ where: { phone }, include: { contatos: true }, diff --git a/src/modules/users/services/CreateGoogleEventService.ts b/src/modules/users/services/CreateGoogleEventService.ts index da91f6c..d5f1d15 100644 --- a/src/modules/users/services/CreateGoogleEventService.ts +++ b/src/modules/users/services/CreateGoogleEventService.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ import { google } from 'googleapis'; import { container, inject, injectable } from 'tsyringe'; import AppError from '@shared/errors/AppError'; @@ -26,7 +27,7 @@ export default class CreateGoogleEventService { ) { } - public async authenticate({ + public async createGoogleCalendarEvent({ address, attendees, begin, createMeetLink, description, end, beginSearch, endSearch, phone, name, optionalAttendees, }:IRequest): Promise { // To create the invite we need a valid full-registered-users guest list. @@ -36,14 +37,12 @@ export default class CreateGoogleEventService { const { guests, pseudoGuests, optionalGuests, pseudoOptionalGuests, } = await userManagementService.execute(attendees, optionalAttendees); - - const attendeesEmail = guests; - attendeesEmail.concat(optionalGuests); - - const oAuth2Client = new google.auth.OAuth2(process.env.GOOGLE_CLIENT_ID, process.env.GOOGLE_CLIENT_SECRET, process.env.GOOGLE_CLIENT_URI); - + const attendeesEmail = [...guests, ...optionalGuests,...pseudoGuests, ...pseudoOptionalGuests]; const user = await this.usersRepository.findByPhone(phone); if (!user) throw new AppError('User not found', 400); + // if (user) throw new AppError('User not found', 400); + + const oAuth2Client = new google.auth.OAuth2(process.env.GOOGLE_CLIENT_ID, process.env.GOOGLE_CLIENT_SECRET, `${process.env.GOOGLE_CLIENT_URI}`); oAuth2Client.setCredentials({ access_token: user.tokens }); @@ -54,23 +53,27 @@ export default class CreateGoogleEventService { }); // eslint-disable-next-line no-plusplus - for (let index = 0; index < attendeesEmail.length; index++) { - const element = attendeesEmail[index]; - if (!element.includes('@')) { + const resolvedEmails = await Promise.all( + attendeesEmail.map(async (item) => { + if (item.includes('@')) return item; try { - // eslint-disable-next-line no-await-in-loop - attendeesEmail[index] = await this.usersRepository.findEmailByPhone(element); + return await this.usersRepository.findEmailByPhone(item); } catch (error) { - console.log(error.message); + console.warn(`Erro ao buscar email para ${item}: ${error}`); + return null; } - } - } + }), + ); + + const finalAttendees = resolvedEmails + .filter((email): email is string => Boolean(email)) + .map((email) => ({ email })); const event = { summary: name, description, location: address, - attendees: attendeesEmail.map((email) => ({ email })), + attendees: finalAttendees, start: { dateTime: begin, timeZone: Intl.DateTimeFormat('en-US', { timeZone: 'America/Sao_Paulo' }).resolvedOptions().timeZone, diff --git a/src/modules/users/services/CreateOutlookEventService.ts b/src/modules/users/services/CreateOutlookEventService.ts index 54c0de8..568ad59 100644 --- a/src/modules/users/services/CreateOutlookEventService.ts +++ b/src/modules/users/services/CreateOutlookEventService.ts @@ -1,155 +1,129 @@ -import msal from '@azure/msal-node'; -import { Event } from '@microsoft/microsoft-graph-types'; +/* eslint-disable no-console */ import { Client } from '@microsoft/microsoft-graph-client'; import { container, inject, injectable } from 'tsyringe'; import AppError from '@shared/errors/AppError'; import CreateInviteService from '@modules/invites/services/CreateInviteService'; import UserManagementService from '@modules/users/services/UserManagementService'; import { Invite } from '@prisma/client'; - import IUsersRepository from '../repositories/IUsersRepository'; +import { + buildMsalClient, + getGraphClient, + resolveEmails, + buildEvent, + tryCreateMeetingLink, +} from '@shared/utils/outlookHelpers/outlookHelpers'; +import msal from '@azure/msal-node'; interface IRequest { - phone:string; - begin:string; end:string; - beginSearch:string; endSearch:string; + phone: string; + begin: string; + end: string; + beginSearch: string; + endSearch: string; attendees: string[]; - description:string; - address:string; - createMeetLink:boolean; - name:string; - optionalAttendees:string[]; -} - -interface IMeeting { - url:string; - conferenceId:string; + description: string; + address: string; + createMeetLink: boolean; + name: string; + optionalAttendees: string[]; } @injectable() export default class CreateOutlookCalendarEventService { constructor( @inject('UsersRepository') - private usersRepository: IUsersRepository, - - ) { } + private usersRepository: IUsersRepository + ) {} public async authenticate({ - phone, begin, end, beginSearch, endSearch, attendees, description, address, name, optionalAttendees, createMeetLink, + phone, + begin, + end, + beginSearch, + endSearch, + attendees, + description, + address, + name, + optionalAttendees, + createMeetLink, }: IRequest): Promise { - // To create the invite we need a valid full-registered-users guest list. - // In order to achieve this, we call a service that separates the guests into four lists: + const user = await this.usersRepository.findByPhone(phone); + if (!user) throw new AppError('User not found in CreateOutlookEventService', 400); + // console.log(`CreateOutlookEventService 45: User found: ${JSON.stringify(user.tokens)}`); const userManagementService = container.resolve(UserManagementService); + const optionalAttendeesRefined = optionalAttendees.filter((item): item is NonNullable => item != null); + const attendeesRefined = attendees.filter((item): item is NonNullable => item != null); - // Guests management + console.log(`CreateOutlookEventService 45: ${JSON.stringify(attendees)}, ${JSON.stringify(optionalAttendees)}`); const { - guests, pseudoGuests, optionalGuests, pseudoOptionalGuests, - } = await userManagementService.execute(attendees, optionalAttendees); - - const attendeesEmail = guests; - attendeesEmail.concat(optionalGuests); - - const user = await this.usersRepository.findByPhone(phone); - if (!user) throw new AppError('User not found', 400); + guests, + pseudoGuests, + optionalGuests, + pseudoOptionalGuests, + } = await userManagementService.execute(attendeesRefined, optionalAttendeesRefined); - const tokenCache = JSON.parse(user.tokens!); + const allEmails = [...guests, ...optionalGuests]; + const resolvedEmails = await resolveEmails(allEmails, this.usersRepository.findEmailByPhone.bind(this.usersRepository)); + const tokenCache = JSON.parse(user?.tokens!); const clientConfig = { - auth: { - clientId: process.env.OUTLOOK_CLIENT_ID as string, - clientSecret: process.env.OUTLOOK_CLIENT_SECRET, - }, - }; - + auth: { + clientId: process.env.OUTLOOK_CLIENT_ID!, + clientSecret: process.env.OUTLOOK_CLIENT_SECRET!, + authority: 'https://login.microsoftonline.com/common', + }, + system: { + loggerOptions: { + loggerCallback: (_level: any, message: any) => console.log(message), + piiLoggingEnabled: false, + logLevel: 3, + }, + }, + }; + const cca = new msal.ConfidentialClientApplication(clientConfig); cca.getTokenCache().deserialize(tokenCache); - + + // const cca = buildMsalClient(user.tokens!); + // const graphClient: Client = await getGraphClient(cca); const account = JSON.parse(cca.getTokenCache().serialize()).Account; - const tokenRequest = { - account, - scopes: ['https://graph.microsoft.com/.default'], - }; - - const tokens = await cca.acquireTokenSilent(tokenRequest); - if (!tokens) throw new AppError('Token not found', 400); - - // Graph client configuration - - const authProvider = { - getAccessToken: async () => tokens.accessToken as string, - }; - - const graphClient = Client.initWithMiddleware({ authProvider }); - - // eslint-disable-next-line no-plusplus - for (let index = 0; index < attendeesEmail.length; index++) { - const element = attendeesEmail[index]; - if (!element.includes('@')) { - try { - // eslint-disable-next-line no-await-in-loop - attendeesEmail[index] = await this.usersRepository.findEmailByPhone(element); - } catch (error) { - console.log(error.message); - } - } - } - - const event: Event = { - subject: name, - body: { content: description }, - location: { - displayName: address, - }, - start: { - dateTime: begin, - timeZone: Intl.DateTimeFormat('en-US', { timeZone: 'America/Sao_Paulo' }).resolvedOptions().timeZone, - }, - end: { - dateTime: end, - timeZone: Intl.DateTimeFormat('en-US', { timeZone: 'America/Sao_Paulo' }).resolvedOptions().timeZone, - }, - attendees: attendeesEmail.map((email) => ({ - emailAddress: { - address: email, + const tokenRequest = { + account, + scopes: ['openid','profile', 'offline_access', 'User.Read', 'Calendars.ReadWrite', 'OnlineMeetings.ReadWrite'], + }; + + const tokens = await cca.acquireTokenSilent(tokenRequest); + if (!tokens) throw new Error('❌ AccessToken não encontrado com acquireTokenSilent.'); + + const client = Client.initWithMiddleware({ + authProvider: { + getAccessToken: async () => tokens.accessToken as string, }, - type: 'required', - })), - }; + }); - // Creates an event on the user's calendar and invites the attendees - await graphClient.api('me/events').header('Prefer', 'outlook.timezone="America/Sao_Paulo"').post(event); + const event = buildEvent({ + name, + description, + address, + begin, + end, + attendees: resolvedEmails, + }); - // Tries to create a meeting link for the event - const getMeetLink = async (): Promise => { - if (createMeetLink) { - console.log('creating meeting link'); - try { // will only work with business or school accounts - const meeting = await graphClient.api('/me/onlineMeetings').post({ - startDateTime: begin, - endDateTime: end, - subject: name, - joinMeetingIdSettings: { - isPasscodeRequired: false, - }, - }); - return { - url: meeting.joinWebUrl, - conferenceId: meeting.id, - }; - } catch (error) { - console.log(error.body); - return null; - } - } - return null; - }; + await client + .api('me/events') + .header('Prefer', 'outlook.timezone="America/Sao_Paulo"') + .post(event); - const meeting = await getMeetLink(); + const meeting = createMeetLink + ? await tryCreateMeetingLink(client, { name, begin, end }) + : null; - // Creates the invite on the database const CreateInviteEvent = container.resolve(CreateInviteService); - const state = 'accepted'; + const invite = await CreateInviteEvent.execute({ name, begin, @@ -164,7 +138,7 @@ export default class CreateOutlookCalendarEventService { description, address, link: meeting?.url || null, - state, + state: 'accepted', googleId: meeting?.conferenceId || 'none', organizerPhoto: user.photo, organizerName: user.name || 'organizer', diff --git a/src/modules/users/services/CreateUserService.ts b/src/modules/users/services/CreateUserService.ts index d73a467..9294cee 100644 --- a/src/modules/users/services/CreateUserService.ts +++ b/src/modules/users/services/CreateUserService.ts @@ -1,3 +1,5 @@ +/* eslint-disable import/order */ +/* eslint-disable no-console */ import { container, inject, injectable } from 'tsyringe'; import { User } from '@prisma/client'; @@ -9,7 +11,8 @@ import crypto from 'crypto'; import IUsersRepository from '../repositories/IUsersRepository'; import IPseudoUsersRepository from '../repositories/IPseudoUsersRepository'; import IInvitesRepository from '../../invites/repositories/IInvitesRepository'; -import SmsService from './SmsService'; +// import SmsService from './SmsService'; +import { SMSFallbackProvider } from '@shared/infra/http/middleware/fallbackSMSProvider'; interface IRequest { pseudoUserId?: string; @@ -28,16 +31,30 @@ export default class CreateUserService { @inject('InvitesRepository') private invitesRepository: IInvitesRepository, + @inject('SMSFallbackProvider') // ← ADICIONAR + private smsProviderFallback: SMSFallbackProvider, + ) { } public async execute({ phone, pseudoUserId }: IRequest): Promise { if (phone === '') throw new AppError('Phone is empty', 400); const oldUser = await this.usersRepository.findByPhone(phone); - if (oldUser) { return oldUser; } + console.log('CreateUserService 37: Old user found:', oldUser); + // If user already exists, return the old user + if (oldUser) { + if (oldUser?.code == null) { + throw new AppError('Existing user does not have a code', 400); + } + await this.sendSMS(phone, oldUser.code); + console.log('CreateUserService 40: Returning existing user:', oldUser); + // If the user already exists, we can return it directly + // No need to generate a new code or send SMS again + return oldUser; + } const code = crypto.randomInt(100000, 999999); - + console.log('CreateUserService 42: Generated code:', code); if (pseudoUserId) { const pseudoUser = await this.pseudoUsersRepository.findById(pseudoUserId); if (!pseudoUser) throw new AppError('PseudoUser not found', 400); @@ -49,14 +66,19 @@ export default class CreateUserService { await this.invitesRepository.connect(user, pseudoUserInvite); return user; } + this.sendSMS(phone, code); + const user = await this.usersRepository.create({ phone, code }); + console.log('CreateUserService 54: New user created:', user); + return user; + } + // Método auxiliar para enviar SMS + private async sendSMS(phone: string, code: number): Promise { const message = `Letsapp: Olá seu codigo é ${code}`; - const sendSms = container.resolve(SmsService); - const status = await sendSms.execute({ phone, message }); - if (status === 'Error') throw new AppError('SMS not sent', 400); - - const user = this.usersRepository.create({ phone, code }); - - return user; + // const sendSms = container.resolve(SMSFallbackProvider); + const status = await this.smsProviderFallback.sendSMS(phone, message); + console.log('SMS status:', status); + if (!status) throw new AppError('SMS not sent', 400); + return true; } } diff --git a/src/modules/users/services/GetGoogleCalendarEventsService.ts b/src/modules/users/services/GetGoogleCalendarEventsService.ts index 0c4be2c..cefc1c6 100644 --- a/src/modules/users/services/GetGoogleCalendarEventsService.ts +++ b/src/modules/users/services/GetGoogleCalendarEventsService.ts @@ -1,47 +1,84 @@ import { inject, injectable } from 'tsyringe'; import AppError from '@shared/errors/AppError'; -import { calendar_v3, google } from 'googleapis'; - +import { google, calendar_v3 } from 'googleapis'; import IUsersRepository from '../repositories/IUsersRepository'; +import getWeekRange from '@shared/utils/date/getWeekRange'; @injectable() -export default class GetGoogleCalendarEvents { +export default class GetGoogleCalendarEventsService { constructor( @inject('UsersRepository') private usersRepository: IUsersRepository, - - ) { } - - public async authenticate(email:string): Promise { + ) {} +public async authenticate(email:string): Promise { // const oauth2Client = new google.auth.OAuth2(); const oAuth2Client = new google.auth.OAuth2(process.env.GOOGLE_CLIENT_ID, process.env.GOOGLE_CLIENT_SECRET, process.env.GOOGLE_CLIENT_URI); const user = await this.usersRepository.findByEmail(email); if (!user) throw new AppError('User not found', 400); - + // console.log(`GetGoogleCalendarEventsService 18: user: ${JSON.stringify(user)}`); oAuth2Client.setCredentials({ access_token: user?.tokens }); const calendar = google.calendar({ version: 'v3', auth: oAuth2Client, }); - const now = new Date(); - const end = new Date(); - end.setDate(now.getDate() + 180); + const { startOfWeek, endOfWeek } = getWeekRange(); + + endOfWeek.setDate(startOfWeek.getDate() + 180); const response = await calendar.events.list({ calendarId: 'primary', - timeMin: now.toISOString(), - timeMax: end.toISOString(), + timeMin: startOfWeek.toISOString(), + timeMax: endOfWeek.toISOString(), maxResults: 10000, singleEvents: true, orderBy: 'startTime', }); - const events = response.data.items; + + // console.log(`GetGoogleCalendarEventsService 35: events: ${JSON.stringify(events)}`); if (!events) throw new AppError('Events not found', 400); - return events; + return { events, user }; + } + public async getTimes(email: string): Promise { + const oAuth2Client = new google.auth.OAuth2( + process.env.GOOGLE_CLIENT_ID, + process.env.GOOGLE_CLIENT_SECRET, + process.env.GOOGLE_CLIENT_URI, + ); + + const user = await this.usersRepository.findByEmail(email); + if (!user || !user.tokens) { + throw new AppError('User not found or not authenticated', 400); + } + + oAuth2Client.setCredentials({ access_token: user.tokens }); + + const calendar = google.calendar({ version: 'v3', auth: oAuth2Client }); + + const { startOfWeek, endOfWeek } = getWeekRange(); + endOfWeek.setDate(startOfWeek.getDate() + 180); // Pode ser ajustado + + const response = await calendar.events.list({ + calendarId: 'primary', + timeMin: startOfWeek.toISOString(), + timeMax: endOfWeek.toISOString(), + maxResults: 10000, + singleEvents: true, + orderBy: 'startTime', + }); + + const events = response.data.items ?? []; + + // Filtra apenas os que têm dateTime + const validEvents = events.filter(event => event.start?.dateTime && event.end?.dateTime); + + return validEvents.map(event => ({ + start: { dateTime: event.start!.dateTime! }, + end: { dateTime: event.end!.dateTime! }, + })); } } diff --git a/src/modules/users/services/GetGoogleTokensService.ts b/src/modules/users/services/GetGoogleTokensService.ts index 26653fc..de78c2d 100644 --- a/src/modules/users/services/GetGoogleTokensService.ts +++ b/src/modules/users/services/GetGoogleTokensService.ts @@ -11,7 +11,7 @@ export default class GetTokensService { ) { } public async authenticate(code: string, state: string): Promise { - const oAuth2Client = new google.auth.OAuth2(process.env.GOOGLE_CLIENT_ID, process.env.GOOGLE_CLIENT_SECRET, process.env.GOOGLE_CLIENT_URI); + const oAuth2Client = new google.auth.OAuth2(process.env.GOOGLE_CLIENT_ID, process.env.GOOGLE_CLIENT_SECRET, `${process.env.GOOGLE_CLIENT_URI}`); const { tokens } = await oAuth2Client.getToken(code); oAuth2Client.setCredentials(tokens); diff --git a/src/modules/users/services/GetOutlookCalendarEventsService.ts b/src/modules/users/services/GetOutlookCalendarEventsService.ts index 7bdbc62..18f909d 100644 --- a/src/modules/users/services/GetOutlookCalendarEventsService.ts +++ b/src/modules/users/services/GetOutlookCalendarEventsService.ts @@ -20,6 +20,7 @@ export default class GetOutlookCalendarEvents { end.setDate(now.getDate() - (now.getTimezoneOffset() / 60) + 180); const user = await this.usersRepository.findByEmail(email); + console.log(`GetOutlookCalendarEvents 30: User: ${JSON.stringify(user)}`); if (!user) throw new AppError('User not found', 400); if (!user.tokens) throw new AppError('Token not found', 400); @@ -30,7 +31,17 @@ export default class GetOutlookCalendarEvents { auth: { clientId: process.env.OUTLOOK_CLIENT_ID as string, clientSecret: process.env.OUTLOOK_CLIENT_SECRET, + authority: 'https://login.microsoftonline.com/common', }, + system: { + loggerOptions: { + loggerCallback(loglevel: any, message: any, containsPii: any) { + console.log(message); + }, + piiLoggingEnabled: false, + logLevel: 3, + } + } }; const cca = new msal.ConfidentialClientApplication(clientConfig); @@ -40,12 +51,12 @@ export default class GetOutlookCalendarEvents { const tokenRequest = { account, - scopes: ['https://graph.microsoft.com/.default'], + scopes: ['openid','profile', 'offline_access', 'User.Read', 'Calendars.ReadWrite', 'OnlineMeetings.ReadWrite'], }; const tokens = await cca.acquireTokenSilent(tokenRequest); if (!tokens) throw new AppError('Token not found', 400); - + // console.log(`GetOutlookCalendarEvents 45: tokens: ${JSON.stringify(tokens)}`); const authProvider = { getAccessToken: async () => tokens.accessToken as string, }; @@ -53,7 +64,7 @@ export default class GetOutlookCalendarEvents { const graphClient = Client.initWithMiddleware({ authProvider }); const getEvents = await graphClient.api(`/users/${user.email}/calendar/events`).filter(`(start/dateTime ge '${now.toISOString()}' and end/dateTime le '${end.toISOString()}') or (start/dateTime le '${now.toISOString()}' and end/dateTime ge '${now.toISOString()}')`).header('Prefer', 'outlook.timezone="America/Sao_Paulo"').get(); - + // console.log(`GetOutlookCalendarEvent/s 50: Events${JSON.stringify(getEvents)}`); return getEvents; } } diff --git a/src/modules/users/services/GetOutlookTokensService.ts b/src/modules/users/services/GetOutlookTokensService.ts index 4f032d6..be00206 100644 --- a/src/modules/users/services/GetOutlookTokensService.ts +++ b/src/modules/users/services/GetOutlookTokensService.ts @@ -16,19 +16,29 @@ export default class GetOutlookTokensService { auth: { clientId: process.env.OUTLOOK_CLIENT_ID as string, clientSecret: process.env.OUTLOOK_CLIENT_SECRET, + authority: 'https://login.microsoftonline.com/common', }, + system: { + loggerOptions: { + loggerCallback(loglevel: any, message: any, containsPii: any) { + console.log(message); + }, + piiLoggingEnabled: false, + logLevel: 3, + } + } }; const tokenRequest = { code, redirectUri: process.env.OUTLOOK_CLIENT_URI as string, - scopes: ['https://graph.microsoft.com/.default'], + scopes: ['openid', 'offline_access', 'User.Read', 'Calendars.Read'], }; const cca = new msal.ConfidentialClientApplication(clientConfig); const tokens = await cca.acquireTokenByCode(tokenRequest); if (!tokens.accessToken) throw new AppError('Token not found', 400); - + console.log(`GetOutlookTokensService 45: tokens: ${JSON.stringify(tokens)}`); const tokenCache = JSON.stringify(cca.getTokenCache().serialize()); const authProvider = { @@ -40,7 +50,7 @@ export default class GetOutlookTokensService { try { const user = await this.usersRepository.findByPhone(phone); - if (!user) throw new AppError('User not found', 400); + if (!user) throw new AppError('User not found GetOutlookTokens findByPhone53', 400); await this.usersRepository.updateEmail(user.id, userInfo.mail); this.usersRepository.updateToken(user.id, tokenCache); diff --git a/src/modules/users/services/GetRecommendedTimeService.ts b/src/modules/users/services/GetRecommendedTimeService.ts index fa3cbb9..f6f9dbf 100644 --- a/src/modules/users/services/GetRecommendedTimeService.ts +++ b/src/modules/users/services/GetRecommendedTimeService.ts @@ -1,26 +1,34 @@ -/* eslint-disable no-empty */ -import { container, inject, injectable } from 'tsyringe'; +// src/modules/invites/services/GetRecommendedTimesService.ts +import { inject, injectable, container } from 'tsyringe'; import AppError from '@shared/errors/AppError'; -import moment, { Moment } from 'moment-timezone'; +import moment from 'moment-timezone'; import IUsersRepository from '../repositories/IUsersRepository'; import googleGetRecommendedTimeService from './googleGetRecommendedTimeService'; import outlookGetRecommendedTimeService from './outlookGetRecommendedTimeService'; import UserManagementService from './UserManagementService'; +import { + classifyUsers, + mergeBusyTimes, + buildBusyIntervals, + generateFreeTimes, + validateTimeWindow, +} from '@shared/utils/date/calendarTimeUtils'; interface IFreeTime { - date?: Moment|string |null; - start?: Moment|string|null; - end?: Moment|string|null; + date?: string | null; + start?: string | null; + end?: string | null; } -interface IRequest{ - phone:string, - beginDate:string, - endDate:string, - beginHour:string, - endHour:string, - duration:number, - mandatoryGuests:string[], - optionalGuests:string + +interface IRequest { + phone: string; + beginDate: string; + endDate: string; + beginHour: string; + endHour: string; + duration: number; + mandatoryGuests: string[]; + optionalGuests: string; } interface IMissingAuthentications { @@ -32,298 +40,53 @@ interface IMissingAuthentications { export default class GetRecommendedTimesService { constructor( @inject('UsersRepository') - private usersRepository: IUsersRepository, - - ) { } + private usersRepository: IUsersRepository + ) {} public async authenticate({ - beginDate, beginHour, duration, endDate, endHour, mandatoryGuests, phone, - }:IRequest): Promise<{ freeTimes: IFreeTime[], missingAuthentications: IMissingAuthentications }> { + beginDate, + beginHour, + duration, + endDate, + endHour, + mandatoryGuests, + phone, + }: IRequest): Promise<{ freeTimes: IFreeTime[]; missingAuthentications: IMissingAuthentications }> { moment.tz.setDefault('America/Sao_Paulo'); - const user = await this.usersRepository.findByPhone(phone); - if (!user) throw new AppError('User not found', 400); - const currentTime = moment(); - - const googleGetTime = container.resolve(googleGetRecommendedTimeService); - const outlookGetTime = container.resolve(outlookGetRecommendedTimeService); - const managementService = container.resolve(UserManagementService); - - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion mandatoryGuests.push(user.email!); - - const outlookUsers: string[] = []; - const googleUsers: string[] = []; - + const managementService = container.resolve(UserManagementService); const { guests } = await managementService.execute(mandatoryGuests, []); - // fix - // eslint-disable-next-line no-restricted-syntax - for (const element of guests) { - // eslint-disable-next-line no-await-in-loop - const userType = await this.usersRepository.findTypeByEmail(element); - - if (userType === 'GOOGLE') { - googleUsers.push(element); - } else if (userType === 'OUTLOOK') { - outlookUsers.push(element); - } - } - - const { horariosGoogle, missingGoogleAuthentications } = await googleGetTime.authenticate(googleUsers); - const googleBusyTimes = horariosGoogle; + const { googleUsers, outlookUsers } = await classifyUsers(guests, this.usersRepository); - const { horariosOutlook, missingOutlookAuthentications } = await outlookGetTime.authenticate(outlookUsers); - const outlookBusyTimes = horariosOutlook; + const [googleResult, outlookResult] = await Promise.all([ + container.resolve(googleGetRecommendedTimeService).authenticate(googleUsers), + container.resolve(outlookGetRecommendedTimeService).authenticate(outlookUsers), + ]); - const missingAuthentications = { - google: missingGoogleAuthentications, - outlook: missingOutlookAuthentications, + const missingAuthentications: IMissingAuthentications = { + google: googleResult.missingGoogleAuthentications, + outlook: outlookResult.missingOutlookAuthentications, }; - const roundUp = (start: moment.Moment) => { - if (start.minute() === 0 && start.second() === 0) return start; - if ((start.minute() > 30) || (start.minute() === 30 && start.second() !== 0)) { - const roundUpBegin = start.minute() || start.second() || start.millisecond() ? start.add(1, 'hour').startOf('hour') : start.startOf('hour'); - return roundUpBegin; - } if (start.minute() < 30) { - const roundUpBegin = start.minute() || start.second() || start.millisecond() ? start.add(1, 'minute').startOf('minute') : start.startOf('minute'); - while (roundUpBegin.minute() !== 30) { - roundUpBegin.add(1, 'minute'); - } - return roundUpBegin; - } - return start; - }; - - const roundDown = (end: moment.Moment) => { - if ((end.minute() > 30) || (end.minute() === 30 && end.second() !== 0)) { - const roundDownEnd = end.minute(30).second(0); - return roundDownEnd; - } if (end.minute() < 30) { - const roundDownEnd = end.minute(0).second(0); - return roundDownEnd; - } - return end; - }; - - const getFreeTimes = (start: moment.Moment, end: moment.Moment) => { - const freeTimes: IFreeTime[] = []; - const diff = end.diff(start) / 60000; - - const roundedStart = roundUp(start); - const roundedEnd = roundDown(end); - - if (diff > 0 && roundedStart > moment(beginDate) && roundedEnd < moment(endDate).add(1, 'days') && duration <= diff) { - let eventStart = moment(roundedStart); - const eventEnd = moment(roundedStart); - eventEnd.add(duration, 'minute'); - - const earlyHourLimit = moment(roundedStart); - earlyHourLimit.set('hour', parseInt(beginHour.slice(0, 2), 10)); - earlyHourLimit.set('minute', parseInt(beginHour.slice(3, 5), 10)); - earlyHourLimit.set('seconds', parseInt(beginHour.slice(6, 8), 10)); - - const lateHourLimit = moment(roundedStart); - lateHourLimit.set('hour', parseInt(endHour.slice(0, 2), 10)); - lateHourLimit.set('minute', parseInt(endHour.slice(3, 5), 10)); - lateHourLimit.set('seconds', parseInt(endHour.slice(6, 8), 10)); - - while (eventEnd <= roundedEnd && eventStart >= earlyHourLimit && eventStart <= lateHourLimit && eventEnd <= lateHourLimit && eventEnd >= earlyHourLimit) { - if (eventStart >= currentTime) { - freeTimes.push({ start: eventStart.tz('America/Sao_Paulo').format(), end: eventEnd.tz('America/Sao_Paulo').format() }); - } - eventStart = moment(eventEnd); - eventEnd.add(duration, 'minute'); - } - } - return freeTimes; - }; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const busyTimes: any[] = googleBusyTimes.concat(outlookBusyTimes); - - const freeTimes: IFreeTime[] = []; + const allBusyTimes = mergeBusyTimes(googleResult.horariosGoogle, outlookResult.horariosOutlook); + const busyIntervals = buildBusyIntervals(allBusyTimes); + const { isValid, beginMoment, endMoment } = validateTimeWindow(beginDate, beginHour, endDate, endHour); - // eslint-disable-next-line no-sequences - const simplerS = busyTimes.map((event) => ([moment(event.start?.dateTime), moment(event.end?.dateTime)])); + if (!isValid) return { freeTimes: [], missingAuthentications }; - // if (simplerS === undefined) throw new AppError('Uasdasda', 400); - - const dataAllTimes = simplerS; - - // Custom comparison function - // eslint-disable-next-line @typescript-eslint/no-explicit-any - function compareDates(a:any, b:any) { - const dateTimeA = moment(a[0]); - const dateTimeB = moment(b[0]); - - return dateTimeA.diff(dateTimeB); - } - - const beginSearch = moment(`${beginDate.slice(0, 11)}${beginHour}${beginDate.slice(19, 25)}`); - const endSearch = moment(`${endDate.slice(0, 11)}${endHour}${endDate.slice(19, 25)}`); - - if (beginSearch.isBefore(currentTime) && endSearch.isBefore(currentTime)) return { freeTimes, missingAuthentications }; - - if ((googleBusyTimes.length === 0 && outlookBusyTimes.length === 0)) { - const start = moment(`${beginDate.slice(0, 11)}${beginHour}${beginDate.slice(19, 25)}`); - const end = moment(`${endDate.slice(0, 11)}${endHour}${endDate.slice(19, 25)}`); - - if (start.date() < end.date()) { - if (end.date() - start.date() !== 1) { - const loopTimes = getFreeTimes(start, moment(`${beginDate.slice(0, 11)}${endHour}${beginDate.slice(19, 25)}`).date(start.date())); - loopTimes.map((loopTime) => freeTimes.push(loopTime)); - while (start.date() < end.date() - 1) { - start.add(1, 'days'); - const loopTimes2 = getFreeTimes(moment(`${endDate.slice(0, 11)}${beginHour}${endDate.slice(19, 25)}`).date(start.date()), moment(`${beginDate.slice(0, 11)}${endHour}${beginDate.slice(19, 25)}`).date(start.date())); - loopTimes2.map((loopTime) => freeTimes.push(loopTime)); - } - const loopTimes3 = getFreeTimes(moment(`${endDate.slice(0, 11)}${beginHour}${endDate.slice(19, 25)}`).date(end.date()), end); - loopTimes3.map((loopTime) => freeTimes.push(loopTime)); - } else { - const loopTimes = getFreeTimes(start, moment(`${beginDate.slice(0, 11)}${endHour}${beginDate.slice(19, 25)}`).date(start.date())); - loopTimes.map((loopTime) => freeTimes.push(loopTime)); - const loopTimes2 = getFreeTimes(moment(`${endDate.slice(0, 11)}${beginHour}${endDate.slice(19, 25)}`).date(end.date()), end); - loopTimes2.map((loopTime) => freeTimes.push(loopTime)); - } - } else { - const loopTimes = getFreeTimes(start, end); - loopTimes.map((loopTime) => freeTimes.push(loopTime)); - } - - return { freeTimes, missingAuthentications }; - } - const intervalStart1 = moment(`${beginDate.slice(0, 11)}${beginHour}${beginDate.slice(19, 25)}`); - - const intervalStart = roundUp(intervalStart1); - - const intervalEnd1 = moment(`${endDate.slice(0, 11)}${endHour}${endDate.slice(19, 25)}`); - - const intervalEnd = roundDown(intervalEnd1); - - // Sort the array based on the first datetime of each index - dataAllTimes.sort(compareDates); - - const data: moment.Moment[][] = []; - - // Delete times that are tottaly out of the interval - // eslint-disable-next-line array-callback-return - dataAllTimes.map((event) => { - if ((event[0] <= intervalStart && event[1] > intervalStart) || (event[0] >= intervalStart && event[1] <= intervalEnd) || (event[0] < intervalEnd && event[1] >= intervalEnd)) { - if ((event[0].hour() < intervalStart.hour() && event[1].hour() < intervalStart.hour()) - || (event[0].hour() < intervalStart.hour() && event[1].hour() === intervalStart.hour() && event[1].minute() <= intervalStart.minute()) - || (event[0].hour() > intervalEnd.hour() && event[1].hour() > intervalEnd.hour()) - || (event[0].hour() === intervalEnd.hour() && event[1].hour() > intervalEnd.hour() && event[0].minute() >= intervalEnd.minute())) {} else data.push(event); - } + const freeTimes = generateFreeTimes({ + busyIntervals, + duration, + beginMoment, + endMoment, + beginHour, + endHour, }); - if (data.length === 0) { - const start = moment(`${beginDate.slice(0, 11)}${beginHour}${beginDate.slice(19, 25)}`); - const end = moment(`${endDate.slice(0, 11)}${endHour}${endDate.slice(19, 25)}`); - - if (start.date() < end.date()) { - if (end.date() - start.date() !== 1) { - const loopTimes = getFreeTimes(start, moment(`${beginDate.slice(0, 11)}${endHour}${beginDate.slice(19, 25)}`).date(start.date())); - loopTimes.map((loopTime) => freeTimes.push(loopTime)); - while (start.date() < end.date() - 1) { - start.add(1, 'days'); - const loopTimes2 = getFreeTimes(moment(`${endDate.slice(0, 11)}${beginHour}${endDate.slice(19, 25)}`).date(start.date()), moment(`${beginDate.slice(0, 11)}${endHour}${beginDate.slice(19, 25)}`).date(start.date())); - loopTimes2.map((loopTime) => freeTimes.push(loopTime)); - } - const loopTimes3 = getFreeTimes(moment(`${endDate.slice(0, 11)}${beginHour}${endDate.slice(19, 25)}`).date(end.date()), end); - loopTimes3.map((loopTime) => freeTimes.push(loopTime)); - } else { - const loopTimes = getFreeTimes(start, moment(`${beginDate.slice(0, 11)}${endHour}${beginDate.slice(19, 25)}`).date(start.date())); - loopTimes.map((loopTime) => freeTimes.push(loopTime)); - const loopTimes2 = getFreeTimes(moment(`${endDate.slice(0, 11)}${beginHour}${endDate.slice(19, 25)}`).date(end.date()), end); - loopTimes2.map((loopTime) => freeTimes.push(loopTime)); - } - } else { - const loopTimes = getFreeTimes(start, end); - loopTimes.map((loopTime) => freeTimes.push(loopTime)); - } - return { freeTimes, missingAuthentications }; - } - - const isIntervalBeforeEventStart = intervalEnd.isBefore(data[0][0]); - const isIntervalAfterEventEnd = intervalStart.isAfter(data[data.length - 1][1]); - - if (isIntervalBeforeEventStart || isIntervalAfterEventEnd) { - const start = moment(`${beginDate.slice(0, 11)}${beginHour}${beginDate.slice(19, 25)}`); - const end = moment(`${endDate.slice(0, 11)}${endHour}${endDate.slice(19, 25)}`); - - if (start.date() < end.date()) { - if (end.date() - start.date() !== 1) { - const loopTimes = getFreeTimes(start, moment(`${beginDate.slice(0, 11)}${endHour}${beginDate.slice(19, 25)}`).date(start.date())); - loopTimes.map((loopTime) => freeTimes.push(loopTime)); - while (start.date() < end.date() - 1) { - start.add(1, 'days'); - const loopTimes2 = getFreeTimes(moment(`${endDate.slice(0, 11)}${beginHour}${endDate.slice(19, 25)}`).date(start.date()), moment(`${beginDate.slice(0, 11)}${endHour}${beginDate.slice(19, 25)}`).date(start.date())); - loopTimes2.map((loopTime) => freeTimes.push(loopTime)); - } - const loopTimes3 = getFreeTimes(moment(`${endDate.slice(0, 11)}${beginHour}${endDate.slice(19, 25)}`).date(end.date()), end); - loopTimes3.map((loopTime) => freeTimes.push(loopTime)); - } else { - const loopTimes = getFreeTimes(start, moment(`${beginDate.slice(0, 11)}${endHour}${beginDate.slice(19, 25)}`).date(start.date())); - loopTimes.map((loopTime) => freeTimes.push(loopTime)); - const loopTimes2 = getFreeTimes(moment(`${endDate.slice(0, 11)}${beginHour}${endDate.slice(19, 25)}`).date(end.date()), end); - loopTimes2.map((loopTime) => freeTimes.push(loopTime)); - } - } else { - const loopTimes = getFreeTimes(start, end); - loopTimes.map((loopTime) => freeTimes.push(loopTime)); - } - - return { freeTimes, missingAuthentications }; - } - - let start: moment.Moment; - let end: moment.Moment; - - // eslint-disable-next-line no-plusplus - for (let index = 0; index <= data.length; index++) { - try { - if (index !== 0) { - start = moment(data[index - 1][1]); - } else { - start = moment(`${beginDate.slice(0, 11)}${beginHour}${beginDate.slice(19, 25)}`); - } - if (index === 0) { - end = moment(data[index][0]); - } else if (index > (data.length - 1)) { - end = moment(`${endDate.slice(0, 11)}${endHour}${endDate.slice(19, 25)}`); - } else { - end = moment(data[index][0]); - } - - if (start.date() < end.date()) { - if (end.date() - start.date() !== 1) { - const loopTimes = getFreeTimes(start, moment(`${beginDate.slice(0, 11)}${endHour}${beginDate.slice(19, 25)}`).date(start.date())); - loopTimes.map((loopTime) => freeTimes.push(loopTime)); - while (start.date() < end.date() - 1) { - start.add(1, 'days'); - const loopTimes2 = getFreeTimes(moment(`${endDate.slice(0, 11)}${beginHour}${endDate.slice(19, 25)}`).date(start.date()), moment(`${beginDate.slice(0, 11)}${endHour}${beginDate.slice(19, 25)}`).date(start.date())); - loopTimes2.map((loopTime) => freeTimes.push(loopTime)); - } - const loopTimes3 = getFreeTimes(moment(`${endDate.slice(0, 11)}${beginHour}${endDate.slice(19, 25)}`).date(end.date()), end); - loopTimes3.map((loopTime) => freeTimes.push(loopTime)); - } else { - const loopTimes = getFreeTimes(start, moment(`${beginDate.slice(0, 11)}${endHour}${beginDate.slice(19, 25)}`).date(start.date())); - loopTimes.map((loopTime) => freeTimes.push(loopTime)); - const loopTimes2 = getFreeTimes(moment(`${endDate.slice(0, 11)}${beginHour}${endDate.slice(19, 25)}`).date(end.date()), end); - loopTimes2.map((loopTime) => freeTimes.push(loopTime)); - } - } else { - const loopTimes = getFreeTimes(start, end); - loopTimes.map((loopTime) => freeTimes.push(loopTime)); - } - - // eslint-disable-next-line no-console - } catch (e) { console.log('error', e); } - } return { freeTimes, missingAuthentications }; } } diff --git a/src/modules/users/services/GetUserByPhoneService.ts b/src/modules/users/services/GetUserByPhoneService.ts index a9a5940..f6f76ba 100644 --- a/src/modules/users/services/GetUserByPhoneService.ts +++ b/src/modules/users/services/GetUserByPhoneService.ts @@ -37,7 +37,17 @@ export default class GetUserByPhoneService { auth: { clientId: process.env.OUTLOOK_CLIENT_ID as string, clientSecret: process.env.OUTLOOK_CLIENT_SECRET, + authority: 'https://login.microsoftonline.com/common', }, + system: { + loggerOptions: { + loggerCallback(loglevel: any, message: any, containsPii: any) { + console.log(message); + }, + piiLoggingEnabled: false, + logLevel: 3, + } + } }; const cca = new msal.ConfidentialClientApplication(clientConfig); diff --git a/src/modules/users/services/GoogleAuthUrlService.ts b/src/modules/users/services/GoogleAuthUrlService.ts index 4461de2..e0cc489 100644 --- a/src/modules/users/services/GoogleAuthUrlService.ts +++ b/src/modules/users/services/GoogleAuthUrlService.ts @@ -27,7 +27,7 @@ export default class GoogleAuthUrlService { redirect_uri: process.env.GOOGLE_CLIENT_URI, state: phone, }); - + console.log(`GoogleAuthURLService 26: URL ${process.env.GOOGLE_CLIENT_URI}`); return authUrl; } } diff --git a/src/modules/users/services/OutlookAuthUrlService.ts b/src/modules/users/services/OutlookAuthUrlService.ts index c54ecd8..e1e8cbe 100644 --- a/src/modules/users/services/OutlookAuthUrlService.ts +++ b/src/modules/users/services/OutlookAuthUrlService.ts @@ -1,4 +1,4 @@ -import msal from '@azure/msal-node'; +import msal, { ResponseMode } from '@azure/msal-node'; import { injectable, inject } from 'tsyringe'; import IUsersRepository from '../repositories/IUsersRepository'; @@ -15,15 +15,26 @@ export default class OutlookAuthUrlService { auth: { clientId: process.env.OUTLOOK_CLIENT_ID as string, clientSecret: process.env.OUTLOOK_CLIENT_SECRET, + authority: 'https://login.microsoftonline.com/common', }, + system: { + loggerOptions: { + loggerCallback(loglevel: any, message: any, containsPii: any) { + console.log(`Mesagem after loggin ${message}`); + }, + piiLoggingEnabled: false, + logLevel: 3, + } + } }; const cca = new msal.ConfidentialClientApplication(clientConfig); const authCodeUrlParameters = { - scopes: ['https://graph.microsoft.com/.default'], + scopes: ['openid','profile', 'offline_access', 'User.Read', 'Calendars.ReadWrite', 'OnlineMeetings.ReadWrite'], redirectUri: process.env.OUTLOOK_CLIENT_URI as string, state: phone, + responseMode: ResponseMode.QUERY }; const authCodeUrl = cca.getAuthCodeUrl(authCodeUrlParameters); diff --git a/src/modules/users/services/ResendVerificationCodeService.ts b/src/modules/users/services/ResendVerificationCodeService.ts index b671cff..d6f8cad 100644 --- a/src/modules/users/services/ResendVerificationCodeService.ts +++ b/src/modules/users/services/ResendVerificationCodeService.ts @@ -1,10 +1,11 @@ +/* eslint-disable import/order */ import { container, inject, injectable } from 'tsyringe'; import { User } from '@prisma/client'; import AppError from '@shared/errors/AppError'; import crypto from 'crypto'; import IUsersRepository from '../repositories/IUsersRepository'; -import SmsService from './SmsService'; +import { SMSFallbackProvider } from '@shared/infra/http/middleware/fallbackSMSProvider'; @injectable() export default class resendVerificationCodeService { @@ -12,6 +13,8 @@ export default class resendVerificationCodeService { @inject('UsersRepository') private usersRepository: IUsersRepository, + @inject('SMSFallbackProvider') // ← ADICIONAR + private smsProviderFallback: SMSFallbackProvider, ) { } public async execute(phone: string): Promise { @@ -22,10 +25,10 @@ export default class resendVerificationCodeService { const updatedUser = await this.usersRepository.updateCode(phone, code); - const sendSms = container.resolve(SmsService); + // const sendSms = container.resolve(SMSFallbackProvider); const message = `Letsapp: Olá seu codigo é ${code}`; - const status = await sendSms.execute({ phone, message }); - if (status === 'Error') throw new AppError('SMS not sent', 400); + const status = await this.smsProviderFallback.sendSMS(phone, message); + if (!status) throw new AppError('SMS not sent', 400); return updatedUser; } diff --git a/src/modules/users/services/SmsService.ts b/src/modules/users/services/SmsService.ts index 64f831c..bbf79da 100644 --- a/src/modules/users/services/SmsService.ts +++ b/src/modules/users/services/SmsService.ts @@ -1,21 +1,14 @@ -import { inject, injectable } from 'tsyringe'; +/* eslint-disable no-console */ +import { injectable } from 'tsyringe'; import AWS from 'aws-sdk'; -import IUsersRepository from '../repositories/IUsersRepository'; -interface ISmsService { -phone: string, -message: string; -} +import { ISMSProvider } from '@shared/container/providers/SMSProvider/models/ISMSProvider'; @injectable() -export default class SmsService { - constructor( - @inject('UsersRepository') - private usersRepository: IUsersRepository, - - ) { } +export default class AwsSnsSmsProvider implements ISMSProvider { + // Removido o construtor com UsersRepository, pois não é necessário para o envio de SMS - public async execute({ phone, message }:ISmsService): Promise { + public async sendSMS(to: string, message: string): Promise { AWS.config.update({ region: process.env.AWS_DEFAULT_REGION, accessKeyId: process.env.AWS_ACCESS_KEY_ID, @@ -24,25 +17,24 @@ export default class SmsService { const params = { Message: message, - PhoneNumber: phone, + PhoneNumber: to, }; - const publishTextPromise = new AWS.SNS({ apiVersion: '2010-03-31' }) - .publish(params) - .promise(); - publishTextPromise - .then((data) => { - console.log( - `Message ${params.Message} sent to the topic ${params.PhoneNumber}`, - ); - console.log(`MessageID is ${data.MessageId}`); - }) - .catch((err) => { - console.error(err, err.stack); - - return 'Error'; - }); - - return 'SMS SENDED'; + try { + const publishTextPromise = new AWS.SNS({ apiVersion: '2010-03-31' }) + .publish(params) + .promise(); + const data = await publishTextPromise; + console.log( + `SMS enviado com sucesso via AWS SNS para ${params.PhoneNumber}. MessageID: ${data.MessageId}`, + ); + return true; + } catch (err: any) { + console.error( + `Falha ao enviar SMS via AWS SNS para ${params.PhoneNumber}:`, + err.message || err, + ); + return false; + } } } diff --git a/src/modules/users/services/UserManagementService.ts b/src/modules/users/services/UserManagementService.ts index 378bed6..3411778 100644 --- a/src/modules/users/services/UserManagementService.ts +++ b/src/modules/users/services/UserManagementService.ts @@ -3,10 +3,10 @@ import IUsersRepository from '../repositories/IUsersRepository'; import CreatePseudoUserService from './CreatePseudoUserService'; interface IResponse { - guests: string[]; - pseudoGuests: string[]; - optionalGuests: string[]; - pseudoOptionalGuests: string[]; + guests: string[]; + pseudoGuests: string[]; + optionalGuests: string[]; + pseudoOptionalGuests: string[]; } const urlService = container.resolve(CreatePseudoUserService); @@ -14,88 +14,65 @@ const urlService = container.resolve(CreatePseudoUserService); @injectable() export default class UserManagementService { constructor( - @inject('UsersRepository') - private usersRepository: IUsersRepository, - ) { } + @inject('UsersRepository') + private usersRepository: IUsersRepository + ) {} public async execute(attendees: string[], optionalAttendees: string[]): Promise { const guests: string[] = []; const pseudoGuests: string[] = []; const optionalGuests: string[] = []; const pseudoOptionalGuests: string[] = []; - - let phoneRef; - let emailRef; + console.log(`❌❌UserManagementService 45: attendees: ${JSON.stringify(attendees)}`); + console.log(`❌❌UserManagementService 45: optionalAttendees: ${JSON.stringify(optionalAttendees)}`); + console.log(`😳UserManagementService 45: guesasasast: `); const attendeesPromises = attendees.map(async (guest) => { - if (guest.includes('@')) { - const userAlreadyExists = await this.usersRepository.findByEmail(guest); - if (!userAlreadyExists) { - emailRef = guest; - phoneRef = null; - try { - const pseudoGuest = await urlService.execute({ email: emailRef, phone: phoneRef }); - pseudoGuests.push(pseudoGuest.id); - } catch (error) { - console.log(error.message); - } + if (guest && guest.includes('@')) { + const user = await this.usersRepository.findByEmail(guest); + if (user) { + guests.push(user.email!); } else { - guests.push(userAlreadyExists.email!); + const pseudo = await urlService.execute({ email: guest, phone: null }); + pseudoGuests.push(pseudo.id); } } else { - const userAlreadyExists = await this.usersRepository.findByPhone(guest); - if (!userAlreadyExists) { - emailRef = null; - phoneRef = guest; - try { - const pseudoGuest = await urlService.execute({ email: emailRef, phone: phoneRef }); - pseudoGuests.push(pseudoGuest.id); - } catch (error) { - console.log(error.message); - } + const user = await this.usersRepository.findByPhone(guest); + if (user) { + guests.push(user.email!); } else { - // user could still have not registered email so this could be a problem for a definitive version - guests.push(userAlreadyExists.email!); + const pseudo = await urlService.execute({ email: null, phone: guest }); + pseudoGuests.push(pseudo.id); } } }); - - const optionalAttendeesPromises = optionalAttendees.map(async (optionalGuest) => { - if (optionalGuest.includes('@')) { - const userAlreadyExists = await this.usersRepository.findByEmail(optionalGuest); - if (!userAlreadyExists) { - emailRef = optionalGuest; - phoneRef = null; - try { - const pseudoGuest = await urlService.execute({ email: emailRef, phone: phoneRef }); - pseudoGuests.push(pseudoGuest.id); - } catch (error) { - console.log(error.message); - } + // console.log(`❌❌UserManagementService 51: Attendees promises: ${JSON.stringify(attendeesPromises)}`); + const optionalPromises = optionalAttendees.map(async (optional) => { + if (optional && optional?.includes('@')) { + const user = await this.usersRepository.findByEmail(optional); + if (user) { + optionalGuests.push(user.email!); } else { - guests.push(userAlreadyExists.email!); + const pseudo = await urlService.execute({ email: optional, phone: null }); + pseudoOptionalGuests.push(pseudo.email!); } } else { - const userAlreadyExists = await this.usersRepository.findByPhone(optionalGuest); - if (!userAlreadyExists) { - emailRef = null; - phoneRef = optionalGuest; - try { - const pseudoGuest = await urlService.execute({ email: emailRef, phone: phoneRef }); - pseudoGuests.push(pseudoGuest.id); - } catch (error) { - console.log(error.message); - } + const user = await this.usersRepository.findByPhone(optional); + if (user) { + optionalGuests.push(user.email!); } else { - guests.push(userAlreadyExists.email!); + const pseudo = await urlService.execute({ email: null, phone: optional }); + pseudoOptionalGuests.push(pseudo.id); } } }); - await Promise.all(attendeesPromises.concat(optionalAttendeesPromises)); - + await Promise.all([...attendeesPromises, ...optionalPromises]); return { - guests, pseudoGuests, optionalGuests, pseudoOptionalGuests, + guests, + pseudoGuests, + optionalGuests, + pseudoOptionalGuests, }; } } diff --git a/src/modules/users/services/googleGetRecommendedTimeService.ts b/src/modules/users/services/googleGetRecommendedTimeService.ts index f850f79..b1a06dc 100644 --- a/src/modules/users/services/googleGetRecommendedTimeService.ts +++ b/src/modules/users/services/googleGetRecommendedTimeService.ts @@ -25,7 +25,7 @@ export default class GetCalendarEvents { // For future versions is viable to implement the try-catch block inside the map loop const promises = googleUsers.map(async (user) => { try { - const aux = await urlservice.authenticate(user); + const aux = await urlservice.getTimes(user); for (let index = 0; index < aux.length; index += 1) { horariosGoogle.push(aux[index]); } diff --git a/src/modules/users/services/googleUpdateEventService.ts b/src/modules/users/services/googleUpdateEventService.ts index b14f7d5..72817f8 100644 --- a/src/modules/users/services/googleUpdateEventService.ts +++ b/src/modules/users/services/googleUpdateEventService.ts @@ -22,15 +22,13 @@ export default class UpdateEventService { begin, end, email, eventId, }:IRequest): Promise { // const oauth2Client = new google.auth.OAuth2(); - - const oAuth2Client = new google.auth.OAuth2(process.env.GOOGLE_CLIENT_ID, process.env.GOOGLE_CLIENT_SECRET, process.env.GOOGLE_CLIENT_URI); + const user = await this.usersRepository.findByEmail(email); + if (!user) throw new AppError('User not found', 400); + const oAuth2Client = new google.auth.OAuth2(process.env.GOOGLE_CLIENT_ID, process.env.GOOGLE_CLIENT_SECRET, `${process.env.GOOGLE_CLIENT_URI}`); const inviteFound = await this.usersRepository.findInvite(eventId); if (!inviteFound) throw new AppError('Invite not found', 400); - const user = await this.usersRepository.findByEmail(email); - if (!user) throw new AppError('User not found', 400); - oAuth2Client.setCredentials({ access_token: user.tokens }); const calendar = google.calendar({ diff --git a/src/modules/users/services/outlookUpdateEventService.ts b/src/modules/users/services/outlookUpdateEventService.ts index 40c4cef..4bf95f0 100644 --- a/src/modules/users/services/outlookUpdateEventService.ts +++ b/src/modules/users/services/outlookUpdateEventService.ts @@ -40,7 +40,17 @@ export default class outlookUpdateEvent { auth: { clientId: process.env.OUTLOOK_CLIENT_ID as string, clientSecret: process.env.OUTLOOK_CLIENT_SECRET, + authority: 'https://login.microsoftonline.com/common', }, + system: { + loggerOptions: { + loggerCallback(loglevel: any, message: any, containsPii: any) { + console.log(message); + }, + piiLoggingEnabled: false, + logLevel: 3, + } + } }; const cca = new msal.ConfidentialClientApplication(clientConfig); diff --git a/src/shared/container/index.ts b/src/shared/container/index.ts index 370b085..f16ce64 100644 --- a/src/shared/container/index.ts +++ b/src/shared/container/index.ts @@ -1,7 +1,7 @@ +/* eslint-disable import/extensions */ import { container } from 'tsyringe'; import './providers'; - // Users import IUsersRepository from '@modules/users/repositories/IUsersRepository'; import UsersRepository from '@modules/users/infra/prisma/repositories/UsersRepository'; @@ -11,7 +11,14 @@ import PseudoUsersRepository from '@modules/users/infra/prisma/repositories/Pseu // Invites import IInvitesRepository from '@modules/invites/repositories/IInvitesRepository'; import InvitesRepository from '@modules/invites/infra/prisma/repositories/InvitesRepository'; +import { SMSFallbackProvider } from '@shared/infra/http/middleware/fallbackSMSProvider'; +import ListEventsService from '@modules/invites/services/ListEventsByWeekService'; container.registerSingleton('UsersRepository', UsersRepository); container.registerSingleton('PseudoUsersRepository', PseudoUsersRepository); container.registerSingleton('InvitesRepository', InvitesRepository); +container.registerSingleton( + 'ListEventsService', + ListEventsService, +); +container.registerSingleton('SMSFallbackProvider', SMSFallbackProvider); diff --git a/src/shared/container/providers/SMSProvider/implementations/SMSProvider.ts b/src/shared/container/providers/SMSProvider/implementations/SMSProvider.ts new file mode 100644 index 0000000..ae2a389 --- /dev/null +++ b/src/shared/container/providers/SMSProvider/implementations/SMSProvider.ts @@ -0,0 +1,33 @@ +/* eslint-disable no-console */ +/* eslint-disable no-await-in-loop */ +/* eslint-disable no-restricted-syntax */ +/* eslint-disable import/prefer-default-export */ +import { ISMSProvider } from '../models/ISMSProvider'; + +export class SMSProvider implements ISMSProvider { + private providers: ISMSProvider[]; + + constructor(providers: ISMSProvider[]) { + this.providers = providers; + } + + public async sendSMS(to: string, message: string): Promise { + for (const provider of this.providers) { + try { + const success = await provider.sendSMS(to, message); + if (success) { + console.log(`SMS enviado com sucesso via ${provider.constructor.name}`); + return true; + } + } catch (error: any) { + console.error( + `Falha ao enviar SMS via ${provider.constructor.name}:`, + error.message, + ); + } + } + + console.error('Todos os provedores de SMS falharam.'); + return false; + } +} diff --git a/src/shared/container/providers/SMSProvider/models/ISMSProvider.ts b/src/shared/container/providers/SMSProvider/models/ISMSProvider.ts new file mode 100644 index 0000000..7cf938b --- /dev/null +++ b/src/shared/container/providers/SMSProvider/models/ISMSProvider.ts @@ -0,0 +1,3 @@ +export interface ISMSProvider { + sendSMS(to: string, message: string): Promise; +} diff --git a/src/shared/container/providers/index.ts b/src/shared/container/providers/index.ts index d1a2c4e..a3893e4 100644 --- a/src/shared/container/providers/index.ts +++ b/src/shared/container/providers/index.ts @@ -1,3 +1,42 @@ -import './HashProvider'; -import './MailTemplateProvider'; -import './MailProvider'; +/* eslint-disable import/extensions */ +/* eslint-disable no-console */ +import { container } from 'tsyringe'; + +import AwsSnsSmsProvider from '@modules/users/services/SmsService'; +import { SMSProvider } from './SMSProvider/implementations/SMSProvider'; +import { ISMSProvider } from './SMSProvider/models/ISMSProvider'; + +// Importe seu provedor AWS SNS adaptado (o SmsService.ts modificado) + +// Opcional: Você pode criar um provedor de mock para usar em desenvolvimento +// para não enviar SMS reais. Exemplo: +class MockSmsProvider implements ISMSProvider { + async sendSMS(to: string, message: string): Promise { + console.log(`[MOCK SMS] Simulação de envio para ${to}: ${message}`); + return true; // Sempre sucesso no mock para testes + } +} + +container.register( + 'SMSProvider', // Nome do token de injeção para o serviço de SMS com fallback + { + useFactory: () => { + // Instancie seu provedor AWS SNS + const awsSnsProvider = container.resolve(AwsSnsSmsProvider); + + // Instancie o provedor de mock (opcional, para desenvolvimento) + const mockProvider = new MockSmsProvider(); + + // Crie a instância do SMSProvider (o orquestrador de fallback) + // A ordem aqui define a prioridade: o primeiro da lista é tentado primeiro. + // Se você quiser que o AWS SNS seja o primário e o mock seja o secundário: + return new SMSProvider([awsSnsProvider, mockProvider]); + + // Se você quiser que o mock seja o primário (para desenvolvimento) e o AWS SNS o secundário: + // return new SMSProvider([mockProvider, awsSnsProvider]); + + // Para produção, você pode ter apenas provedores reais, por exemplo: + // return new SMSProvider([awsSnsProvider, new TwilioSmsProvider()]); // Se tiver Twilio + }, + }, +); diff --git a/src/shared/infra/http/middleware/fallbackSMSProvider.ts b/src/shared/infra/http/middleware/fallbackSMSProvider.ts new file mode 100644 index 0000000..dce5a67 --- /dev/null +++ b/src/shared/infra/http/middleware/fallbackSMSProvider.ts @@ -0,0 +1,131 @@ +/* eslint-disable no-var */ +/* eslint-disable no-shadow */ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +/* eslint-disable no-continue */ +/* eslint-disable no-await-in-loop */ +/* eslint-disable no-restricted-syntax */ +/* eslint-disable @typescript-eslint/no-unused-vars */ +/* eslint-disable no-console */ +/* eslint-disable @typescript-eslint/naming-convention */ +/* eslint-disable @typescript-eslint/no-namespace */ +// eslint-disable-next-line max-classes-per-file +import { Request, Response, NextFunction } from 'express'; +import AppError from '@shared/errors/AppError'; +import AWS from 'aws-sdk'; +import IUsersRepository from '@modules/users/repositories/IUsersRepository'; +import { container, inject } from 'tsyringe'; +import { PushNotificationService } from './pushNotificationService'; + +export interface ISMSProvider { + sendMessage(phone: string, message: string): Promise; +} + +class LocalSMSProvider implements ISMSProvider { + async sendMessage(phone: string, message: string): Promise { + // Fallback local para desenvolvimento/teste + console.log(`[LOCAL SMS] Para: ${phone}, Mensagem: ${message}`); + return true; + } +} + +class AWSSSMSProvider implements ISMSProvider { + async sendMessage(phone: string, message: string): Promise { + AWS.config.update({ + region: process.env.AWS_DEFAULT_REGION, + accessKeyId: process.env.AWS_ACCESS_KEY_ID, + secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, + }); + + const params = { + Message: message, + PhoneNumber: phone, + }; + + try { + const publishTextPromise = new AWS.SNS({ apiVersion: '2010-03-31' }) + .publish(params) + .promise(); + const data = await publishTextPromise; + console.log( + `fallbackSMSPROVIDER 49:SMS enviado com sucesso via AWS SNS para ${params.PhoneNumber}. MessageID: ${data.MessageId}`, + ); + return true; + } catch (err: any) { + console.error( + `Falha ao enviar SMS via AWS SNS para ${params.PhoneNumber}:`, + err.message || err, + ); + return false; + } + } +} +class PushNotificationFallback implements ISMSProvider { + constructor( + @inject('UsersRepository') + private usersRepository: IUsersRepository, + ) {} + + async sendMessage(phone: string, message: string): Promise { + try { + // Buscar usuário pelo telefone + const user = await this.usersRepository.findByPhone(phone); + if (user) { + const pushService = new PushNotificationService(); + + return await pushService.sendNotification({ + userId: user.id, + title: 'Código por Push', + body: message, + data: { type: 'sms_fallback', phone }, + }); + } + return false; + } catch (error) { + console.error('Erro no push fallback:', error); + return false; + } + } +} +export class SMSFallbackProvider { + private providers: any[]; + + constructor( + ) { + this.providers = [ + new AWSSSMSProvider(), + new LocalSMSProvider(), + new PushNotificationFallback(container.resolve('UsersRepository')), // ← ADICIONAR AQUI + ]; + } + + async sendSMS(phone: string, message: string): Promise { + for (const provider of this.providers) { + try { + const result = await provider.sendMessage(phone, message); + + if (result) { + return true; + } + } catch (error) { + console.log(`Falha no provedor SMS: ${error}`); + continue; + } + } + throw new AppError('Todos os provedores de SMS falharam', 500); + } +} + +export const smsMiddleware = (req: Request, res: Response, next: NextFunction) => { + req.smsProvider = container.resolve(SMSFallbackProvider); + next(); +}; + +// Extend Express Request interface +declare global { + namespace Express { + interface Request { + smsProvider?: SMSFallbackProvider; + } + } +} +export default SMSFallbackProvider; diff --git a/src/shared/infra/http/middleware/pushNotificationService.ts b/src/shared/infra/http/middleware/pushNotificationService.ts new file mode 100644 index 0000000..673811c --- /dev/null +++ b/src/shared/infra/http/middleware/pushNotificationService.ts @@ -0,0 +1,323 @@ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +/* eslint-disable @typescript-eslint/no-var-requires */ +/* eslint-disable global-require */ +/* eslint-disable no-shadow */ +/* eslint-disable @typescript-eslint/naming-convention */ +/* eslint-disable @typescript-eslint/no-namespace */ +/* eslint-disable no-console */ +/* eslint-disable max-classes-per-file */ +import { Request, Response, NextFunction } from 'express'; + +interface IPushNotificationPayload { + title: string; + body: string; + data?: Record; + userId?: string; + topic?: string; +} + +interface IPushNotificationProvider { + sendNotification(payload: IPushNotificationPayload): Promise; + subscribeToTopic(token: string, topic: string): Promise; + unsubscribeFromTopic(token: string, topic: string): Promise; +} + +class FCMProvider implements IPushNotificationProvider { + private admin: any; + + constructor() { + const admin = require('firebase-admin'); + + // Inicializar Firebase Admin SDK apenas uma vez + if (!admin.apps.length) { + try { + admin.initializeApp({ + credential: admin.credential.cert({ + projectId: process.env.FIREBASE_PROJECT_ID, + clientEmail: process.env.FIREBASE_CLIENT_EMAIL, + privateKey: process.env.FIREBASE_PRIVATE_KEY?.replace(/\\n/g, '\n'), + }), + }); + console.log('[FCM] Firebase Admin SDK inicializado com sucesso'); + } catch (error) { + console.error('[FCM] Erro ao inicializar Firebase Admin SDK:', error); + } + } + + this.admin = admin; + } + + supports(): 'push' { + return 'push'; + } + + private async getUserTokens(userId: string): Promise { + try { + const { getCustomRepository } = require('typeorm'); + // Implementar busca no banco quando a tabela existir + const { database } = require('@shared/infra/typeorm'); + const result = await database.query(` + SELECT push_token + FROM user_push_tokens + WHERE user_id = ? AND is_active = true + `, [userId]); + return result.map((row: any) => row.push_token); + } catch (error) { + console.error('Erro ao buscar tokens do usuário:', error); + return []; + } + } + + async sendNotification(payload: IPushNotificationPayload): Promise { + try { + console.log(`[FCM] Enviando notificação: ${JSON.stringify(payload)}`); + + const message = { + notification: { + title: payload.title, + body: payload.body, + }, + data: payload.data || {}, + android: { + notification: { + icon: 'ic_notification', + color: '#3446E4', + sound: 'default', + }, + }, + apns: { + payload: { + aps: { + sound: 'default', + badge: 1, + }, + }, + }, + }; + + // Se tem userId, busca tokens específicos do usuário + if (payload.userId) { + const tokens = await this.getUserTokens(payload.userId); + if (tokens.length > 0) { + const multicastMessage = { ...message, tokens }; + await this.admin.messaging().sendMulticast(multicastMessage); + console.log(`[FCM] Notificação enviada para ${tokens.length} tokens do usuário ${payload.userId}`); + } else { + console.log(`[FCM] Nenhum token encontrado para usuário ${payload.userId}`); + return false; + } + } else if (payload.topic) { // Se tem tópico, envia para o tópico + const topicMessage = { ...message, topic: payload.topic }; + await this.admin.messaging().send(topicMessage); + console.log(`[FCM] Notificação enviada para tópico: ${payload.topic}`); + } else { + console.log('[FCM] Nem userId nem topic fornecidos'); + return false; + } + + return true; + } catch (error) { + console.error('Erro ao enviar notificação FCM:', error); + return false; + } + } + + async subscribeToTopic(token: string, topic: string): Promise { + try { + console.log(`[FCM] Inscrevendo token ${token} no tópico ${topic}`); + await this.admin.messaging().subscribeToTopic([token], topic); + return true; + } catch (error) { + console.error('Erro ao inscrever no tópico:', error); + return false; + } + } + + async unsubscribeFromTopic(token: string, topic: string): Promise { + try { + console.log(`[FCM] Desinscrevendo token ${token} do tópico ${topic}`); + await this.admin.messaging().unsubscribeFromTopic([token], topic); + return true; + } catch (error) { + console.error('Erro ao desinscrever do tópico:', error); + return false; + } + } +} + +class APNSProvider implements IPushNotificationProvider { + async sendNotification(payload: IPushNotificationPayload): Promise { + try { + // Implementação do Apple Push Notification Service + console.log(`[APNS] Enviando notificação: ${JSON.stringify(payload)}`); + // Aqui seria a implementação real do APNS + // const apn = require('apn'); + // const notification = new apn.Notification(); + // notification.alert = payload.body; + // notification.title = payload.title; + // notification.payload = payload.data; + return true; + } catch (error) { + console.error('Erro ao enviar notificação APNS:', error); + return false; + } + } + + async subscribeToTopic(token: string, topic: string): Promise { + // APNS não tem conceito de tópicos como FCM + console.log(`[APNS] Simulando inscrição no tópico ${topic} para token ${token}`); + return true; + } + + async unsubscribeFromTopic(token: string, topic: string): Promise { + // APNS não tem conceito de tópicos como FCM + console.log(`[APNS] Simulando desinscrição do tópico ${topic} para token ${token}`); + return true; + } +} + +export class PushTokenService { + async saveToken(userId: string, token: string, platform: 'ios' | 'android', deviceId?: string) { + try { + const { database } = require('@shared/infra/typeorm'); + + await database.query(` + INSERT INTO user_push_tokens (user_id, push_token, platform, device_id) + VALUES (?, ?, ?, ?) + ON DUPLICATE KEY UPDATE + is_active = true, + updated_at = CURRENT_TIMESTAMP, + device_id = VALUES(device_id) + `, [userId, token, platform, deviceId]); + + console.log(`[PUSH TOKEN] Token salvo para usuário ${userId}`); + return true; + } catch (error) { + console.error('Erro ao salvar token:', error); + return false; + } + } + + async removeToken(userId: string, token: string) { + try { + const { database } = require('@shared/infra/typeorm'); + + await database.query(` + UPDATE user_push_tokens + SET is_active = false + WHERE user_id = ? AND push_token = ? + `, [userId, token]); + + console.log(`[PUSH TOKEN] Token removido para usuário ${userId}`); + return true; + } catch (error) { + console.error('Erro ao remover token:', error); + return false; + } + } + + async getUserTokens(userId: string): Promise { + try { + const { database } = require('@shared/infra/typeorm'); + const result = await database.query(` + SELECT push_token + FROM user_push_tokens + WHERE user_id = ? AND is_active = true + `, [userId]); + console.log(`[PUSH TOKEN] Tokens recuperados para usuário ${userId}`); + return result.map((row: any) => row.push_token); + } catch (error) { + console.error('Erro ao buscar tokens:', error); + return []; + } + } +} + +export class PushNotificationService { + private providers: IPushNotificationProvider[]; + + constructor() { + this.providers = [ + new FCMProvider(), + new APNSProvider(), + ]; + } + + async sendNotification(payload: IPushNotificationPayload): Promise { + const promises = this.providers.map((provider) => provider.sendNotification(payload)); + + try { + const results: (boolean | { error: any })[] = await Promise.all(promises.map((p) => p.catch((e) => ({ error: e })))); + return results.some((result) => typeof result === 'boolean' && result); + } catch (error) { + console.error('Erro ao enviar notificações:', error); + return false; + } + } + + async subscribeToTopic(token: string, topic: string): Promise { + const promises = this.providers.map((provider) => provider.subscribeToTopic(token, topic)); + + try { + const results = await Promise.all(promises.map((p) => p.catch((e) => ({ error: e })))); + return results.some((result) => (typeof result === 'boolean' && result)); + } catch (error) { + console.error('Erro ao inscrever no tópico:', error); + return false; + } + } + + async unsubscribeFromTopic(token: string, topic: string): Promise { + const promises = this.providers.map((provider) => provider.unsubscribeFromTopic(token, topic)); + + try { + const results = await Promise.all(promises.map((p) => p.catch((e) => ({ error: e })))); + return results.some((result) => (typeof result === 'boolean' && result)); + } catch (error) { + console.error('Erro ao desinscrever do tópico:', error); + return false; + } + } + + // Métodos para eventos específicos do LetsApp + async notifyInviteCreated(userId: string, inviteData: any): Promise { + return this.sendNotification({ + title: 'Novo Convite', + body: `Você foi convidado para: ${inviteData.name}`, + data: { type: 'invite_created', inviteId: inviteData.id }, + userId, + }); + } + + async notifyInviteUpdated(userId: string, inviteData: any): Promise { + return this.sendNotification({ + title: 'Convite Atualizado', + body: `O evento "${inviteData.name}" foi atualizado`, + data: { type: 'invite_updated', inviteId: inviteData.id }, + userId, + }); + } + + async notifyInviteCancelled(userId: string, inviteData: any): Promise { + return this.sendNotification({ + title: 'Convite Cancelado', + body: `O evento "${inviteData.name}" foi cancelado`, + data: { type: 'invite_cancelled', inviteId: inviteData.id }, + userId, + }); + } +} + +export const pushNotificationMiddleware = (req: Request, res: Response, next: NextFunction) => { + req.pushNotificationService = new PushNotificationService(); + next(); +}; + +// Extend Express Request interface +declare global { + namespace Express { + interface Request { + pushNotificationService?: PushNotificationService; + } + } +} diff --git a/src/shared/infra/prisma/migrations/20250716044421_user_push_tokens/migration.sql b/src/shared/infra/prisma/migrations/20250716044421_user_push_tokens/migration.sql new file mode 100644 index 0000000..96e741b --- /dev/null +++ b/src/shared/infra/prisma/migrations/20250716044421_user_push_tokens/migration.sql @@ -0,0 +1,29 @@ +-- CreateEnum +CREATE TYPE "Platform" AS ENUM ('ios', 'android'); + +-- CreateTable +CREATE TABLE "user_push_tokens" ( + "id" SERIAL NOT NULL, + "user_id" TEXT NOT NULL, + "push_token" VARCHAR(500) NOT NULL, + "platform" "Platform" NOT NULL, + "device_id" TEXT, + "device_name" TEXT, + "is_active" BOOLEAN NOT NULL DEFAULT true, + "created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "user_push_tokens_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE INDEX "user_push_tokens_user_id_is_active_idx" ON "user_push_tokens"("user_id", "is_active"); + +-- CreateIndex +CREATE INDEX "user_push_tokens_platform_idx" ON "user_push_tokens"("platform"); + +-- CreateIndex +CREATE INDEX "user_push_tokens_created_at_idx" ON "user_push_tokens"("created_at"); + +-- CreateIndex +CREATE UNIQUE INDEX "user_push_tokens_user_id_push_token_key" ON "user_push_tokens"("user_id", "push_token"); diff --git a/src/shared/infra/prisma/migrations/20250720162246_add_unique_to_googleid/migration.sql b/src/shared/infra/prisma/migrations/20250720162246_add_unique_to_googleid/migration.sql new file mode 100644 index 0000000..d9072cd --- /dev/null +++ b/src/shared/infra/prisma/migrations/20250720162246_add_unique_to_googleid/migration.sql @@ -0,0 +1,8 @@ +/* + Warnings: + + - A unique constraint covering the columns `[googleId]` on the table `invite` will be added. If there are existing duplicate values, this will fail. + +*/ +-- CreateIndex +CREATE UNIQUE INDEX "invite_googleId_key" ON "invite"("googleId"); diff --git a/src/shared/utils/date/calendarTimeUtils.ts b/src/shared/utils/date/calendarTimeUtils.ts new file mode 100644 index 0000000..69bcffb --- /dev/null +++ b/src/shared/utils/date/calendarTimeUtils.ts @@ -0,0 +1,139 @@ +import IUsersRepository from '@modules/users/repositories/IUsersRepository'; +import moment, { Moment } from 'moment-timezone'; + +interface IBusyTime { + start: { dateTime: string }; + end: { dateTime: string }; +} + +interface IFreeTime { + start: string; + end: string; +} + +interface IGenerateFreeTimesInput { + busyIntervals: [Moment, Moment][]; + duration: number; + beginMoment: Moment; + endMoment: Moment; + beginHour: string; + endHour: string; +} + +export async function classifyUsers( + guests: string[], + usersRepository: IUsersRepository +): Promise<{ googleUsers: string[]; outlookUsers: string[] }> { + const googleUsers: string[] = []; + const outlookUsers: string[] = []; + + for (const email of guests) { + const type = await usersRepository.findTypeByEmail(email); + if (type === 'GOOGLE') googleUsers.push(email); + else if (type === 'OUTLOOK') outlookUsers.push(email); + } + + return { googleUsers, outlookUsers }; +} + +export function mergeBusyTimes( + google: IBusyTime[], + outlook: IBusyTime[] +): IBusyTime[] { + const all = [...google, ...outlook]; + // console.log('Building busy intervals from:', all); + + return all.sort((a, b) => moment(a.start.dateTime).diff(moment(b.start.dateTime))); + +} + +export function buildBusyIntervals(busyTimes: IBusyTime[]): [Moment, Moment][] { + const merged: [Moment, Moment][] = []; + console.log('Building busy intervals from:', busyTimes); + for (const event of busyTimes) { + const start = moment(event.start.dateTime); + const end = moment(event.end.dateTime); + + if (!merged.length) { + merged.push([start, end]); + } else { + const last = merged[merged.length - 1]; + if (start.isSameOrBefore(last[1])) { + last[1] = moment.max(last[1], end); + } else { + merged.push([start, end]); + } + } + } + + return merged; +} + +export function validateTimeWindow( + beginDate: string, + beginHour: string, + endDate: string, + endHour: string +): { isValid: boolean; beginMoment: Moment; endMoment: Moment } { + const begin = moment(`${beginDate.slice(0, 11)}${beginHour}${beginDate.slice(19)}`); + const end = moment(`${endDate.slice(0, 11)}${endHour}${endDate.slice(19)}`); + const now = moment(); + + return { + isValid: end.isAfter(now), + beginMoment: begin, + endMoment: end, + }; +} + +export function generateFreeTimes({ + busyIntervals, + duration, + beginMoment, + endMoment, + beginHour, + endHour, +}: IGenerateFreeTimesInput): IFreeTime[] { + const freeTimes: IFreeTime[] = []; + const current = beginMoment.clone().startOf('day'); + + while (current.isSameOrBefore(endMoment, 'day')) { + const dayStart = current.clone().set({ + hour: parseInt(beginHour.slice(0, 2), 10), + minute: parseInt(beginHour.slice(3, 5), 10), + second: 0, + }); + + const dayEnd = current.clone().set({ + hour: parseInt(endHour.slice(0, 2), 10), + minute: parseInt(endHour.slice(3, 5), 10), + second: 0, + }); + + let pointer = dayStart.clone(); + + while (pointer.clone().add(duration, 'minutes').isSameOrBefore(dayEnd)) { + const slotEnd = pointer.clone().add(duration, 'minutes'); + + // Checar se esse bloco conflita com algum intervalo ocupado + const overlaps = busyIntervals.some( + ([busyStart, busyEnd]) => + pointer.isBefore(busyEnd) && slotEnd.isAfter(busyStart) + ); + + if (!overlaps && slotEnd.isSameOrBefore(endMoment)) { + freeTimes.push({ + start: pointer.clone().format(), + end: slotEnd.clone().format(), + }); + } + + pointer.add(duration, 'minutes'); + } + + current.add(1, 'day'); + } + + return freeTimes; +} + diff --git a/src/shared/utils/date/getWeekRange.ts b/src/shared/utils/date/getWeekRange.ts new file mode 100644 index 0000000..a931d94 --- /dev/null +++ b/src/shared/utils/date/getWeekRange.ts @@ -0,0 +1,18 @@ +function getWeekRange(): { startOfWeek: Date; endOfWeek: Date } { + const now = new Date(); + const day = now.getDay(); + const diffToMonday = day === 0 ? -6 : 1 - day; + + const startOfWeek = new Date(now); + startOfWeek.setDate(now.getDate() + diffToMonday); + startOfWeek.setHours(0, 0, 0, 0); + + const endOfWeek = new Date(startOfWeek); + endOfWeek.setDate(startOfWeek.getDate() + 4); + endOfWeek.setHours(23, 59, 59, 999); + + return { startOfWeek, endOfWeek }; +} + +export default getWeekRange; +// This function calculates the start (Monday) and end (Friday) of the current week. diff --git a/src/shared/utils/mappers/mapGoogleEventDTO.ts b/src/shared/utils/mappers/mapGoogleEventDTO.ts new file mode 100644 index 0000000..b661cec --- /dev/null +++ b/src/shared/utils/mappers/mapGoogleEventDTO.ts @@ -0,0 +1,60 @@ +import { calendar_v3 } from 'googleapis'; +import ICreateInviteDTO from '@modules/invites/dtos/ICreateInviteDTO'; + +interface IParams { + event: calendar_v3.Schema$Event; + phone: string; + organizerPhoto: string | null; + organizerName: string; + beginSearch: string; + endSearch: string; +} + +export default function mapGoogleEventToInviteDTO({ + event, + phone, + organizerPhoto, + organizerName, + beginSearch, + endSearch, +}: IParams): ICreateInviteDTO | null { + if (!event.id) { + console.warn('⚠️ Evento do Google sem ID, será ignorado:', event); + return null; + } + + const begin = event.start?.dateTime ?? event.start?.date; + const end = event.end?.dateTime ?? event.end?.date; + + if (!begin || !end) { + console.warn('⚠️ Evento do Google sem data de início/fim:', event); + return null; + } + if (typeof event.id !== 'string' || event.id.trim() === '') { + console.warn('⚠️ Evento do Google com ID inválido:', event); + return null; + } + return { + name: event.summary || 'Evento sem título', + begin, + end, + beginSearch, + endSearch, + phone, + description: event.description || '', + address: event.location || '', + guests: (event.attendees || []) + .filter(a => a.optional !== true && !!a.email) + .map(a => a.email!), + optionalGuests: (event.attendees || []) + .filter(a => a.optional === true && !!a.email) + .map(a => a.email!), + pseudoGuests: [], + pseudoOptionalGuests: [], + link: event.hangoutLink || '', + state: 'accepted', + googleId: event.id, + organizerPhoto, + organizerName, + }; +} diff --git a/src/shared/utils/mappers/mapOutlookToGoogle.ts b/src/shared/utils/mappers/mapOutlookToGoogle.ts new file mode 100644 index 0000000..c1e5a4a --- /dev/null +++ b/src/shared/utils/mappers/mapOutlookToGoogle.ts @@ -0,0 +1,50 @@ +import { calendar_v3 } from 'googleapis'; + +/** + * Converte um evento do Outlook para o formato do Google Calendar (Schema$Event) + */ +export function mapOutlookToGoogle(input: any): calendar_v3.Schema$Event { + const isAllDay = !!input.isAllDay; + + const mapAttendees = (attendees: any[] = []): calendar_v3.Schema$EventAttendee[] => { + return attendees.map((attendee) => { + const responseMap: Record = { + accepted: 'accepted', + declined: 'declined', + tentative: 'tentative', + none: 'needsAction', + }; + + return { + email: attendee.emailAddress?.address || '', + displayName: attendee.emailAddress?.name || '', + responseStatus: responseMap[attendee.status?.response?.toLowerCase()] || 'needsAction', + optional: attendee.type === 'optional', + }; + }); + }; + + const event: calendar_v3.Schema$Event = { + id: input.id, + summary: input.subject || '', // ✅ correto + description: input.bodyPreview || input.body?.content || '', // ✅ correto + location: input.location?.displayName || '', // ✅ correto + start: isAllDay + ? { date: input.start.dateTime.split('T')[0], timeZone: input.start.timeZone } + : { dateTime: input.start.dateTime, timeZone: input.start.timeZone }, + end: isAllDay + ? { date: input.end.dateTime.split('T')[0], timeZone: input.end.timeZone } + : { dateTime: input.end.dateTime, timeZone: input.end.timeZone }, + attendees: mapAttendees(input.attendees), + // Campos extras como undefined + recurrence: undefined, + reminders: undefined, + conferenceData: undefined, + hangoutLink: undefined, + creator: undefined, + organizer: undefined, + status: undefined, + }; + + return event; +} diff --git a/src/shared/utils/messageConnection/messageConnectionSucces.ts b/src/shared/utils/messageConnection/messageConnectionSucces.ts new file mode 100644 index 0000000..0d47bb8 --- /dev/null +++ b/src/shared/utils/messageConnection/messageConnectionSucces.ts @@ -0,0 +1,66 @@ + export function messageConnectionSuccess(title: string): string { + return ` + + + + + + LetsApp - Sucesso + + + +
+
+

${title} Conectado!

+

Sua conta foi vinculada com sucesso ao LetsApp

+

Fechando em 3 segundos...

+
+ + + + + `; + } \ No newline at end of file diff --git a/src/shared/utils/outlookHelpers/outlookHelpers.ts b/src/shared/utils/outlookHelpers/outlookHelpers.ts new file mode 100644 index 0000000..c6f3b7f --- /dev/null +++ b/src/shared/utils/outlookHelpers/outlookHelpers.ts @@ -0,0 +1,114 @@ +import msal from '@azure/msal-node'; +import { Client } from '@microsoft/microsoft-graph-client'; +import { Event } from '@microsoft/microsoft-graph-types'; + +export function buildMsalClient(tokenCache: string) { + const clientConfig = { + auth: { + clientId: process.env.OUTLOOK_CLIENT_ID!, + clientSecret: process.env.OUTLOOK_CLIENT_SECRET!, + authority: 'https://login.microsoftonline.com/common', + }, + system: { + loggerOptions: { + loggerCallback: (_level: any, message: any) => console.log(message), + piiLoggingEnabled: false, + logLevel: 3, + }, + }, + }; + + const cca = new msal.ConfidentialClientApplication(clientConfig); + cca.getTokenCache().deserialize(tokenCache); + + return cca; +} + +export async function getGraphClient(cca: msal.ConfidentialClientApplication) { + +// const accounts = await cca.getTokenCache().getAllAccounts(); + const account = JSON.parse(cca.getTokenCache().serialize()).Account; + + // console.log(`❌❌OutlookHelpers 20: Accounts found: ${JSON.stringify(accounts)}`); + if (!account ) { + throw new Error('❌ Nenhuma conta encontrada no cache MSAL. O usuário precisa se autenticar novamente.'); + } + const tokenRequest = { + account, + scopes: ['openid','profile', 'offline_access', 'User.Read', 'Calendars.ReadWrite', 'OnlineMeetings.ReadWrite'], + }; + + const tokens = await cca.acquireTokenSilent(tokenRequest); + if (!tokens) throw new Error('❌ AccessToken não encontrado com acquireTokenSilent.'); + + return Client.initWithMiddleware({ + authProvider: { + getAccessToken: async () => tokens.accessToken as string, + }, + }); +} + +export async function resolveEmails(emails: string[], lookupFn: (phone: string) => Promise) { + const resolved = []; + for (const item of emails) { + if (item.includes('@')) { + resolved.push(item); + } else { + try { + const email = await lookupFn(item); + resolved.push(email); + } catch (e: any) { + console.log(`Error resolving ${item}:`, e.message); + } + } + } + return resolved; +} + +export function buildEvent({ + name, + description, + address, + begin, + end, + attendees, +}: { + name: string; + description: string; + address: string; + begin: string; + end: string; + attendees: string[]; +}): Event { + const timeZone = Intl.DateTimeFormat('en-US', { timeZone: 'America/Sao_Paulo' }).resolvedOptions().timeZone; + return { + subject: name, + body: { content: description }, + location: { displayName: address }, + start: { dateTime: begin, timeZone }, + end: { dateTime: end, timeZone }, + attendees: attendees.map((email) => ({ + emailAddress: { address: email }, + type: 'required', + })), + }; +} + +export async function tryCreateMeetingLink(graphClient: Client, { name, begin, end }: { name: string; begin: string; end: string; }) { + try { + const meeting = await graphClient.api('/me/onlineMeetings').post({ + startDateTime: begin, + endDateTime: end, + subject: name, + joinMeetingIdSettings: { isPasscodeRequired: false }, + }); + + return { + url: meeting.joinWebUrl, + conferenceId: meeting.id, + }; + } catch (error: any) { + console.log(error?.body || error); + return null; + } +} diff --git a/tmp/uploads/1752596809977-random-file-name b/tmp/uploads/1752596809977-random-file-name new file mode 100644 index 0000000..4dee2e0 Binary files /dev/null and b/tmp/uploads/1752596809977-random-file-name differ diff --git a/yarn.lock b/yarn.lock index 031f399..729b950 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,11 +2,6 @@ # yarn lockfile v1 -"18@^0.0.0": - version "0.0.0" - resolved "https://registry.npmjs.org/18/-/18-0.0.0.tgz" - integrity sha512-2SPMA/ciHy16yY4uVXDrW8q7nLwb2F2Vrt8Qz5OiVo9cyC8Wo8/rwC2hDzbqlTXhIwzt2Y4yJRLem6XMNbT/3A== - "@aws-crypto/crc32@3.0.0": version "3.0.0" resolved "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-3.0.0.tgz" @@ -59,7 +54,7 @@ "@aws-sdk/util-utf8-browser" "^3.0.0" tslib "^1.11.1" -"@aws-crypto/sha256-js@3.0.0", "@aws-crypto/sha256-js@^3.0.0": +"@aws-crypto/sha256-js@^3.0.0", "@aws-crypto/sha256-js@3.0.0": version "3.0.0" resolved "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz" integrity sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ== @@ -539,7 +534,7 @@ "@smithy/util-utf8" "^2.0.0" tslib "^2.5.0" -"@aws-sdk/types@3.398.0", "@aws-sdk/types@^3.222.0": +"@aws-sdk/types@^3.222.0", "@aws-sdk/types@3.398.0": version "3.398.0" resolved "https://registry.npmjs.org/@aws-sdk/types/-/types-3.398.0.tgz" integrity sha512-r44fkS+vsEgKCuEuTV+TIk0t0m5ZlXHNjSDYEUvzLStbbfUFiNus/YG4UCa0wOk9R7VuQI67badsvvPeVPCGDQ== @@ -610,7 +605,7 @@ "@azure/msal-node@^2.1.0": version "2.1.0" - resolved "https://registry.yarnpkg.com/@azure/msal-node/-/msal-node-2.1.0.tgz#1039e27c87a6a4665da94aea8471c3182c5d5f5d" + resolved "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.1.0.tgz" integrity sha512-RiYnw8VdrFJrgTfHAfiAhRehIYN/H8vQ00DGVTYMOtlOkoEbZneK0qs8DV3p2WKVB5GN0cshVSI79N0fVlgbmg== dependencies: "@azure/msal-common" "14.0.3" @@ -634,6 +629,13 @@ "@nicolo-ribaudo/chokidar-2" "^2.1.8" chokidar "^3.4.0" +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13": + version "7.12.13" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz" + integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g== + dependencies: + "@babel/highlight" "^7.12.13" + "@babel/code-frame@7.12.11": version "7.12.11" resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz" @@ -641,26 +643,12 @@ dependencies: "@babel/highlight" "^7.10.4" -"@babel/code-frame@^7.0.0": - version "7.16.7" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz" - integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== - dependencies: - "@babel/highlight" "^7.16.7" - -"@babel/code-frame@^7.12.13": - version "7.12.13" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz" - integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g== - dependencies: - "@babel/highlight" "^7.12.13" - "@babel/compat-data@^7.12.13": version "7.12.13" resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.12.13.tgz" integrity sha512-U/hshG5R+SIoW7HVWIdmy1cB7s3ki+r3FpyEZiCgpi4tFgPnX/vynY80ZGSASOIrUM6O7VxOgCZgdt7h97bUGg== -"@babel/core@^7.12.17": +"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.12.17": version "7.12.17" resolved "https://registry.npmjs.org/@babel/core/-/core-7.12.17.tgz" integrity sha512-V3CuX1aBywbJvV2yzJScRxeiiw0v2KZZYYE3giywxzFJL13RiyPjaaDwhDnxmgFTTS7FgvM2ijr4QmKNIu0AtQ== @@ -850,11 +838,6 @@ resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz" integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== -"@babel/helper-validator-identifier@^7.16.7": - version "7.16.7" - resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz" - integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== - "@babel/helper-validator-option@^7.12.17": version "7.12.17" resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz" @@ -888,15 +871,6 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/highlight@^7.16.7": - version "7.17.9" - resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.9.tgz" - integrity sha512-J9PfEKCbFIv2X5bjTMiZu6Vf341N05QIY+d6FvVKynkG1S7G0j3I0QoRtWIrXhZ+/Nlb5Q0MzqL7TokEJ5BNHg== - dependencies: - "@babel/helper-validator-identifier" "^7.16.7" - chalk "^2.0.0" - js-tokens "^4.0.0" - "@babel/node@^7.12.17": version "7.12.17" resolved "https://registry.npmjs.org/@babel/node/-/node-7.12.17.tgz" @@ -1573,7 +1547,7 @@ "@nodelib/fs.stat" "2.0.4" run-parallel "^1.1.9" -"@nodelib/fs.stat@2.0.4", "@nodelib/fs.stat@^2.0.2": +"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.4": version "2.0.4" resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz" integrity sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q== @@ -2238,17 +2212,7 @@ "@types/qs" "*" "@types/range-parser" "*" -"@types/express@*": - version "4.17.13" - resolved "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz" - integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA== - dependencies: - "@types/body-parser" "*" - "@types/express-serve-static-core" "^4.17.18" - "@types/qs" "*" - "@types/serve-static" "*" - -"@types/express@^4.17.11": +"@types/express@*", "@types/express@^4.17.11": version "4.17.11" resolved "https://registry.npmjs.org/@types/express/-/express-4.17.11.tgz" integrity sha512-no+R6rW60JEc59977wIxreQVsIEOAYwgCqldrA/vkpCnbD7MqTefO97lmoBe4WE0F156bC4uLSP1XHDOySnChg== @@ -2266,7 +2230,7 @@ "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" - integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= + integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== "@types/jsonwebtoken@^8.5.0": version "8.5.0" @@ -2348,7 +2312,7 @@ "@types/strip-bom@^3.0.0": version "3.0.0" resolved "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz" - integrity sha1-FKjsOVbC6B7bdSB5CuzyHCkK69I= + integrity sha1-FKjsOVbC6B7bdSB5CuzyHCkK69I= sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ== "@types/strip-json-comments@0.0.30": version "0.0.30" @@ -2394,7 +2358,7 @@ eslint-scope "^5.0.0" eslint-utils "^2.0.0" -"@typescript-eslint/parser@^4.15.1": +"@typescript-eslint/parser@^4.0.0", "@typescript-eslint/parser@^4.15.1": version "4.15.1" resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.15.1.tgz" integrity sha512-V8eXYxNJ9QmXi5ETDguB7O9diAXlIyS+e3xzLoP/oVE4WCAjssxLIa0mqCLsCGXulYJUfT+GV70Jv1vHsdKwtA== @@ -2438,6 +2402,11 @@ "@typescript-eslint/types" "4.15.1" eslint-visitor-keys "^2.0.0" +"18@^0.0.0": + version "0.0.0" + resolved "https://registry.npmjs.org/18/-/18-0.0.0.tgz" + integrity sha512-2SPMA/ciHy16yY4uVXDrW8q7nLwb2F2Vrt8Qz5OiVo9cyC8Wo8/rwC2hDzbqlTXhIwzt2Y4yJRLem6XMNbT/3A== + accepts@~1.3.8: version "1.3.8" resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz" @@ -2451,7 +2420,7 @@ acorn-jsx@^5.3.1: resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz" integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng== -acorn@^7.4.0: +"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^7.4.0: version "7.4.1" resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== @@ -2506,7 +2475,7 @@ ansi-escapes@^4.2.1: ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA== ansi-regex@^5.0.1: version "5.0.1" @@ -2516,7 +2485,7 @@ ansi-regex@^5.0.1: ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= + integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA== ansi-styles@^3.2.1: version "3.2.1" @@ -2525,7 +2494,14 @@ ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -ansi-styles@^4.0.0, ansi-styles@^4.1.0: +ansi-styles@^4.0.0: + version "4.3.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== @@ -2535,7 +2511,7 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: any-promise@^1.0.0: version "1.3.0" resolved "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz" - integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= + integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== anymatch@^2.0.0: version "2.0.0" @@ -2592,16 +2568,16 @@ archiver@5.3.1: tar-stream "^2.2.0" zip-stream "^4.1.0" -arg@5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/arg/-/arg-5.0.1.tgz" - integrity sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA== - arg@^4.1.0: version "4.1.3" resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== +arg@5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/arg/-/arg-5.0.1.tgz" + integrity sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA== + argparse@^1.0.7: version "1.0.10" resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" @@ -2627,12 +2603,12 @@ arr-union@^3.1.0: array-find-index@^1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz" - integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= + integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw== array-flatten@1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz" - integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== array-includes@^3.1.1: version "3.1.2" @@ -2757,12 +2733,7 @@ babel-plugin-transform-typescript-metadata@^0.3.1: balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= - -base64-js@^1.0.2, base64-js@^1.3.0, base64-js@^1.3.1: - version "1.5.1" - resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= sha512-9Y0g0Q8rmSt+H33DfKv7FOc3v+iRI+o1lbzt8jGcIosYW37IIW/2XVYq5NPdmaD5NQ59Nk26Kl/vZbwW9Fr8vg== base@^0.11.1: version "0.11.2" @@ -2777,10 +2748,15 @@ base@^0.11.1: mixin-deep "^1.2.0" pascalcase "^0.1.1" +base64-js@^1.0.2, base64-js@^1.3.0, base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + bcryptjs@^2.4.3: version "2.4.3" resolved "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz" - integrity sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms= + integrity sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms= sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ== bignumber.js@^9.0.0: version "9.1.2" @@ -2799,7 +2775,7 @@ binary-extensions@^2.0.0: bindings@^1.5.0: version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + resolved "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz" integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== dependencies: file-uri-to-path "1.0.0" @@ -2867,14 +2843,14 @@ braces@^2.3.1, braces@^2.3.2: split-string "^3.0.2" to-regex "^3.0.1" -braces@^3.0.1, braces@^3.0.2, braces@~3.0.2: +braces@^3.0.2, braces@~3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== dependencies: fill-range "^7.0.1" -browserslist@^4.14.5, browserslist@^4.16.3: +browserslist@^4.14.5, browserslist@^4.16.3, "browserslist@>= 4.21.0": version "4.21.4" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz" integrity sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw== @@ -2887,12 +2863,12 @@ browserslist@^4.14.5, browserslist@^4.16.3: buffer-crc32@^0.2.1, buffer-crc32@^0.2.13: version "0.2.13" resolved "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz" - integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= + integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== buffer-equal-constant-time@1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz" - integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= + integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== buffer-from@^1.0.0: version "1.1.1" @@ -2904,6 +2880,14 @@ buffer-writer@2.0.0: resolved "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz" integrity sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw== +buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + buffer@4.9.2: version "4.9.2" resolved "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz" @@ -2921,14 +2905,6 @@ buffer@5.6.0: base64-js "^1.0.2" ieee754 "^1.1.4" -buffer@^5.5.0: - version "5.7.1" - resolved "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz" - integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.1.13" - busboy@^1.0.0: version "1.6.0" resolved "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz" @@ -2972,7 +2948,7 @@ callsites@^3.0.0: camelcase-keys@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz" - integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc= + integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc= sha512-bA/Z/DERHKqoEOrp+qeGKw1QlvEQkGZSc0XaY6VnTxZr+Kv1G5zFwttpjv8qxZ/sBPT4nthwZaAcsAZTJlSKXQ== dependencies: camelcase "^2.0.0" map-obj "^1.0.0" @@ -2980,25 +2956,17 @@ camelcase-keys@^2.0.0: camelcase@^2.0.0: version "2.1.1" resolved "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz" - integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= + integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= sha512-DLIsRzJVBQu72meAKPkWQOLcujdXT32hwdfnkI1frSiSRMK1MofjKHf+MEx0SB6fjEFXL8fBDv1dKymBlOp4Qw== caniuse-lite@^1.0.30001400: version "1.0.30001447" resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001447.tgz" integrity sha512-bdKU1BQDPeEXe9A39xJnGtY0uRq/z5osrnXUw0TcK+EYno45Y+U7QU9HhHEyzvMDffpYadFXi3idnSNkcwLkTw== -chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.0: - version "4.1.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - chalk@^1.1.1: version "1.1.3" resolved "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= + integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A== dependencies: ansi-styles "^2.2.1" escape-string-regexp "^1.0.2" @@ -3015,6 +2983,30 @@ chalk@^2.0.0: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chalk@4.1.2: + version "4.1.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + checkpoint-client@1.1.21: version "1.1.21" resolved "https://registry.npmjs.org/checkpoint-client/-/checkpoint-client-1.1.21.tgz" @@ -3028,6 +3020,21 @@ checkpoint-client@1.1.21: node-fetch "2.6.7" uuid "8.3.2" +chokidar@^3.4.0: + version "3.5.1" + resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz" + integrity sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw== + dependencies: + anymatch "~3.1.1" + braces "~3.0.2" + glob-parent "~5.1.0" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.5.0" + optionalDependencies: + fsevents "~2.3.1" + chokidar@2.1.8: version "2.1.8" resolved "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz" @@ -3047,27 +3054,12 @@ chokidar@2.1.8: optionalDependencies: fsevents "^1.2.7" -chokidar@^3.4.0: - version "3.5.1" - resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz" - integrity sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw== - dependencies: - anymatch "~3.1.1" - braces "~3.0.2" - glob-parent "~5.1.0" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.5.0" - optionalDependencies: - fsevents "~2.3.1" - chownr@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz" integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== -ci-info@3.3.0, ci-info@^3.2.0: +ci-info@^3.2.0, ci-info@3.3.0: version "3.3.0" resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz" integrity sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw== @@ -3131,7 +3123,7 @@ cliui@^7.0.2: clone@^1.0.2: version "1.0.4" resolved "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz" - integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= + integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== collection-visit@^1.0.0: version "1.0.0" @@ -3155,16 +3147,16 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - color-name@~1.1.4: version "1.1.4" resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" @@ -3190,7 +3182,7 @@ commander@^9.2.0: commondir@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz" - integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== component-emitter@^1.2.1: version "1.3.0" @@ -3210,7 +3202,7 @@ compress-commons@^4.1.0: concat-map@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== concat-stream@^1.5.2: version "1.6.2" @@ -3230,7 +3222,7 @@ confusing-browser-globals@^1.0.10: contains-path@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz" - integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= + integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= sha512-OKZnPGeMQy2RPaUIBPFFd71iNf4791H12MCRuVQDnzGRwCYNYmTDy5pdafo2SLAcEMKzTOQnLWG4QdcjeJUMEg== content-disposition@0.5.4: version "0.5.4" @@ -3254,7 +3246,7 @@ convert-source-map@^1.1.0, convert-source-map@^1.7.0: cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz" - integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== cookie@0.5.0: version "0.5.0" @@ -3282,7 +3274,7 @@ core-js@^3.2.1: core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ== cors@^2.8.5: version "2.8.5" @@ -3310,7 +3302,14 @@ create-require@^1.1.0: resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -cross-spawn@7.0.3, cross-spawn@^7.0.2, cross-spawn@^7.0.3: +cross-env@^7.0.3: + version "7.0.3" + resolved "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz" + integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw== + dependencies: + cross-spawn "^7.0.1" + +cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3, cross-spawn@7.0.3: version "7.0.3" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -3332,43 +3331,64 @@ csv-parse@^5.3.3: currently-unhandled@^0.4.1: version "0.4.1" resolved "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz" - integrity sha1-mI3zP+qxke95mmE2nddsF635V+o= + integrity sha1-mI3zP+qxke95mmE2nddsF635V+o= sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng== dependencies: array-find-index "^1.0.1" dateformat@~1.0.4-1.2.3: version "1.0.12" resolved "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz" - integrity sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk= + integrity sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk= sha512-5sFRfAAmbHdIts+eKjR9kYJoF0ViCMVX9yqLu5A7S/v+nd077KgCITOMiirmyCBiZpKLDXbBOkYm6tu7rX/TKg== dependencies: get-stdin "^4.0.1" meow "^3.3.0" -debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: +debug@^2.2.0: version "2.6.9" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" -debug@4, debug@4.3.4, debug@^4.0.1: - version "4.3.4" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== +debug@^2.3.3: + version "2.6.9" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: - ms "2.1.2" + ms "2.0.0" + +debug@^2.6.9: + version "2.6.9" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" -debug@^4.1.0, debug@^4.1.1: +debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@4: version "4.3.1" resolved "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz" integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== dependencies: ms "2.1.2" +debug@2.6.9: + version "2.6.9" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@4.3.4: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + decamelize@^1.1.2: version "1.2.0" resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== decode-uri-component@^0.2.0: version "0.2.2" @@ -3378,12 +3398,12 @@ decode-uri-component@^0.2.0: deep-is@^0.1.3: version "0.1.3" resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= sha512-GtxAN4HvBachZzm4OnWqc45ESpUCMwkYcsjnsPs23FwJbsO+k4t0k9bQCgOmzIlpHO28+WPK/KRbRk0DDHuuDw== defaults@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz" - integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= + integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA== dependencies: clone "^1.0.2" @@ -3457,14 +3477,6 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" -doctrine@1.5.0: - version "1.5.0" - resolved "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz" - integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo= - dependencies: - esutils "^2.0.2" - isarray "^1.0.0" - doctrine@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" @@ -3472,24 +3484,32 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" -dotenv@16.0.1: - version "16.0.1" - resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz" - integrity sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ== +doctrine@1.5.0: + version "1.5.0" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz" + integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo= sha512-lsGyRuYr4/PIB0txi+Fy2xOMI2dGaTguCaotzFGkVZuKR5usKfcRWIFKNM3QNrU7hh/+w2bwTW+ZeXPK5l8uVg== + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" dotenv@^8.2.0: version "8.2.0" resolved "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz" integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== +dotenv@16.0.1: + version "16.0.1" + resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz" + integrity sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ== + dynamic-dedupe@^0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz" - integrity sha1-BuRMIj9eTpTXjvnbI6ZRXOL5YqE= + integrity sha1-BuRMIj9eTpTXjvnbI6ZRXOL5YqE= sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ== dependencies: xtend "^4.0.0" -ecdsa-sig-formatter@1.0.11, ecdsa-sig-formatter@^1.0.11: +ecdsa-sig-formatter@^1.0.11, ecdsa-sig-formatter@1.0.11: version "1.0.11" resolved "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz" integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== @@ -3581,16 +3601,16 @@ escape-html@~1.0.3: resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz" integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + escape-string-regexp@4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - eslint-config-airbnb-base@^14.2.1: version "14.2.1" resolved "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz" @@ -3627,7 +3647,7 @@ eslint-module-utils@^2.6.0: debug "^2.6.9" pkg-dir "^2.0.0" -eslint-plugin-import@2.22.1: +eslint-plugin-import@*, eslint-plugin-import@^2.22.1, eslint-plugin-import@2.22.1: version "2.22.1" resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz" integrity sha512-8K7JjINHOpH64ozkAhpT3sd+FswIZTfMZTjdx052pnWrgRCVfp8op9tbjpAk3DdUeI/Ba4C8OjdC0r90erHEOw== @@ -3661,7 +3681,12 @@ eslint-utils@^2.0.0, eslint-utils@^2.1.0: dependencies: eslint-visitor-keys "^1.1.0" -eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: +eslint-visitor-keys@^1.1.0: + version "1.3.0" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint-visitor-keys@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== @@ -3671,7 +3696,7 @@ eslint-visitor-keys@^2.0.0: resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz" integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== -eslint@^7.20.0: +eslint@*, "eslint@^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0", "eslint@^5.0.0 || ^6.0.0 || ^7.0.0", "eslint@^5.16.0 || ^6.8.0 || ^7.2.0", eslint@^7.20.0: version "7.20.0" resolved "https://registry.npmjs.org/eslint/-/eslint-7.20.0.tgz" integrity sha512-qGi0CTcOGP2OtCQBgWZlQjcTuP0XkIpYFj25XtRTQSHC+umNnp7UMshr2G8SLsRFYDdAPFeHOsiteadmMH02Yw== @@ -3747,7 +3772,12 @@ estraverse@^4.1.1: resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== -estraverse@^5.1.0, estraverse@^5.2.0: +estraverse@^5.1.0: + version "5.2.0" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz" + integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== + +estraverse@^5.2.0: version "5.2.0" resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz" integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== @@ -3765,7 +3795,7 @@ etag@~1.8.1: events@1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/events/-/events-1.1.1.tgz" - integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ= + integrity sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ= sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw== events@3.3.0: version "3.3.0" @@ -3813,7 +3843,7 @@ express-validator@^6.14.2: lodash "^4.17.21" validator "^13.7.0" -express@^4.17.1: +express@^4.16.2, express@^4.17.1, express@>=4.0.0: version "4.18.2" resolved "https://registry.npmjs.org/express/-/express-4.18.2.tgz" integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== @@ -3857,7 +3887,15 @@ extend-shallow@^2.0.1: dependencies: is-extendable "^0.1.0" -extend-shallow@^3.0.0, extend-shallow@^3.0.2: +extend-shallow@^3.0.0: + version "3.0.2" + resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz" + integrity sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q== + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend-shallow@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz" integrity sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q== @@ -3889,18 +3927,6 @@ fast-deep-equal@^3.1.1: resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.1.1: - version "3.2.5" - resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz" - integrity sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.0" - merge2 "^1.3.0" - micromatch "^4.0.2" - picomatch "^2.2.1" - fast-glob@^3.2.9: version "3.2.11" resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz" @@ -3920,7 +3946,7 @@ fast-json-stable-stringify@^2.0.0: fast-levenshtein@^2.0.6: version "2.0.6" resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== fast-text-encoding@^1.0.0: version "1.0.6" @@ -3965,7 +3991,7 @@ file-type@^3.3.0: file-uri-to-path@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + resolved "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz" integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== fill-range@^4.0.0: @@ -4006,15 +4032,6 @@ find-babel-config@^2.0.0: json5 "^2.1.1" path-exists "^4.0.0" -find-cache-dir@3.3.2: - version "3.3.2" - resolved "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz" - integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig== - dependencies: - commondir "^1.0.1" - make-dir "^3.0.2" - pkg-dir "^4.1.0" - find-cache-dir@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz" @@ -4024,18 +4041,19 @@ find-cache-dir@^2.0.0: make-dir "^2.0.0" pkg-dir "^3.0.0" -find-up@5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" - integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== +find-cache-dir@3.3.2: + version "3.3.2" + resolved "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz" + integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig== dependencies: - locate-path "^6.0.0" - path-exists "^4.0.0" + commondir "^1.0.1" + make-dir "^3.0.2" + pkg-dir "^4.1.0" find-up@^1.0.0: version "1.1.2" resolved "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz" - integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= + integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA== dependencies: path-exists "^2.0.0" pinkie-promise "^2.0.0" @@ -4043,7 +4061,7 @@ find-up@^1.0.0: find-up@^2.0.0, find-up@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ== dependencies: locate-path "^2.0.0" @@ -4054,7 +4072,7 @@ find-up@^3.0.0: dependencies: locate-path "^3.0.0" -find-up@^4.0.0, find-up@^4.1.0: +find-up@^4.0.0: version "4.1.0" resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== @@ -4062,13 +4080,29 @@ find-up@^4.0.0, find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" -flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== +find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== dependencies: - flatted "^3.1.0" - rimraf "^3.0.2" + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" flatted@^3.1.0: version "3.1.1" @@ -4151,11 +4185,11 @@ fs-readdir-recursive@^1.1.0: fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== fsevents@^1.2.7: version "1.2.13" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz" integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw== dependencies: bindings "^1.5.0" @@ -4163,7 +4197,7 @@ fsevents@^1.2.7: fsevents@~2.3.1: version "2.3.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== function-bind@^1.1.1: @@ -4174,7 +4208,7 @@ function-bind@^1.1.1: functional-red-black-tree@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== gaxios@^5.0.0, gaxios@^5.0.1: version "5.1.3" @@ -4217,9 +4251,9 @@ get-intrinsic@^1.0.1, get-intrinsic@^1.0.2, get-intrinsic@^1.1.3: get-stdin@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz" - integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4= + integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4= sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw== -get-stream@6.0.1, get-stream@^6.0.0: +get-stream@^6.0.0, get-stream@6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== @@ -4237,7 +4271,7 @@ glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" -glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@~5.1.0: +glob-parent@^5.0.0, glob-parent@~5.1.0: version "5.1.1" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz" integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== @@ -4293,7 +4327,7 @@ globals@^12.1.0: dependencies: type-fest "^0.8.1" -globby@11.1.0: +globby@^11.0.1, globby@11.1.0: version "11.1.0" resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz" integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== @@ -4305,18 +4339,6 @@ globby@11.1.0: merge2 "^1.4.1" slash "^3.0.0" -globby@^11.0.1: - version "11.0.2" - resolved "https://registry.npmjs.org/globby/-/globby-11.0.2.tgz" - integrity sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.1.1" - ignore "^5.1.4" - merge2 "^1.3.0" - slash "^3.0.0" - google-auth-library@^8.0.2, google-auth-library@^8.8.0: version "8.9.0" resolved "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.9.0.tgz" @@ -4366,12 +4388,7 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" -graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.2.4: - version "4.2.6" - resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz" - integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== - -graceful-fs@^4.1.15, graceful-fs@^4.2.0: +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.2.0, graceful-fs@^4.2.4: version "4.2.10" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== @@ -4400,14 +4417,14 @@ handlebars@^4.7.7: has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= + integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg== dependencies: ansi-regex "^2.0.0" has-flag@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== has-flag@^4.0.0: version "4.0.0" @@ -4524,7 +4541,7 @@ http-proxy-agent@5.0.0: agent-base "6" debug "4" -https-proxy-agent@5.0.1, https-proxy-agent@^5.0.0: +https-proxy-agent@^5.0.0, https-proxy-agent@5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz" integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== @@ -4544,26 +4561,16 @@ iconv-lite@0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" -ieee754@1.1.13: +ieee754@^1.1.13, ieee754@^1.1.4, ieee754@1.1.13: version "1.1.13" resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz" integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== -ieee754@^1.1.13, ieee754@^1.1.4: - version "1.2.1" - resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - ignore@^4.0.6: version "4.0.6" resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== -ignore@^5.1.4: - version "5.1.8" - resolved "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz" - integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== - ignore@^5.2.0: version "5.2.0" resolved "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz" @@ -4580,29 +4587,29 @@ import-fresh@^3.0.0, import-fresh@^3.2.1: imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - -indent-string@4.0.0, indent-string@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz" - integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== indent-string@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz" - integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA= + integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA= sha512-aqwDFWSgSgfRaEwao5lg5KEcVd/2a+D1rvoG7NdilmYz0NwRk6StWpWdz/Hpk34MKPpx7s8XxUqimfcQK6gGlg== dependencies: repeating "^2.0.0" +indent-string@^4.0.0, indent-string@4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + inflight@^1.0.4: version "1.0.6" resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== dependencies: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3, inherits@~2.0.4: +inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3, inherits@~2.0.4, inherits@2, inherits@2.0.4: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -4610,7 +4617,7 @@ inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, i inherits@2.0.3: version "2.0.3" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== ini@2.0.0: version "2.0.0" @@ -4647,7 +4654,7 @@ is-arguments@^1.0.4: is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== is-binary-path@^1.0.0: version "1.0.1" @@ -4715,7 +4722,16 @@ is-descriptor@^0.1.0: is-data-descriptor "^0.1.4" kind-of "^5.0.0" -is-descriptor@^1.0.0, is-descriptor@^1.0.2: +is-descriptor@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-descriptor@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz" integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== @@ -4744,7 +4760,7 @@ is-extendable@^1.0.1: is-extglob@^2.1.0, is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== is-finite@^1.0.0: version "1.1.0" @@ -4856,7 +4872,7 @@ is-unicode-supported@^0.1.0: is-utf8@^0.2.0: version "0.2.1" resolved "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz" - integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= + integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q== is-windows@^1.0.2: version "1.0.2" @@ -4870,15 +4886,15 @@ is-wsl@^2.1.1, is-wsl@^2.2.0: dependencies: is-docker "^2.0.0" -isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: +isarray@^1.0.0, isarray@~1.0.0, isarray@1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== isexe@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== isobject@^2.0.0: version "2.1.0" @@ -4918,7 +4934,7 @@ jsesc@^2.5.1: jsesc@~0.5.0: version "0.5.0" resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz" - integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= + integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== json-bigint@^1.0.0: version "1.0.0" @@ -4945,7 +4961,7 @@ json-schema-traverse@^1.0.0: json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== json5@^1.0.1: version "1.0.2" @@ -5003,7 +5019,21 @@ jws@^4.0.0: jwa "^2.0.0" safe-buffer "^5.0.1" -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: +kind-of@^3.0.2: + version "3.2.2" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz" + integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== + dependencies: + is-buffer "^1.1.5" + +kind-of@^3.0.3: + version "3.2.2" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz" + integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== + dependencies: + is-buffer "^1.1.5" + +kind-of@^3.2.0: version "3.2.2" resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz" integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== @@ -5055,7 +5085,7 @@ lines-and-columns@^1.1.6: load-json-file@^1.0.0: version "1.1.0" resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz" - integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= + integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A== dependencies: graceful-fs "^4.1.2" parse-json "^2.2.0" @@ -5066,7 +5096,7 @@ load-json-file@^1.0.0: load-json-file@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz" - integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= + integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= sha512-3p6ZOGNbiX4CdvEd1VcE6yi78UrGNpjHO33noGwHCnT/o2fyllJDepsm8+mFFv/DvtwFHht5HIHSyOy5a+ChVQ== dependencies: graceful-fs "^4.1.2" parse-json "^2.2.0" @@ -5076,7 +5106,7 @@ load-json-file@^2.0.0: locate-path@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA== dependencies: p-locate "^2.0.0" path-exists "^3.0.0" @@ -5106,27 +5136,27 @@ locate-path@^6.0.0: lodash.defaults@^4.2.0: version "4.2.0" resolved "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz" - integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= + integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ== lodash.difference@^4.5.0: version "4.5.0" resolved "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz" - integrity sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw= + integrity sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw= sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA== lodash.flatten@^4.4.0: version "4.4.0" resolved "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz" - integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= + integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g== lodash.isplainobject@^4.0.6: version "4.0.6" resolved "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz" - integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= + integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== lodash.union@^4.6.0: version "4.6.0" resolved "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz" - integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg= + integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg= sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw== lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21: version "4.17.21" @@ -5144,7 +5174,7 @@ log-symbols@^4.1.0: loud-rejection@^1.0.0: version "1.6.0" resolved "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz" - integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8= + integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8= sha512-RPNliZOFkqFumDhvYqOaNY4Uz9oJM2K9tC6JWsJJsNdhuONW4LQHRBpb0qf4pJApVffI5N39SwzWZJuEhfd7eQ== dependencies: currently-unhandled "^0.4.1" signal-exit "^3.0.0" @@ -5156,13 +5186,6 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -make-dir@3.1.0, make-dir@^3.0.0, make-dir@^3.0.2: - version "3.1.0" - resolved "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== - dependencies: - semver "^6.0.0" - make-dir@^2.0.0, make-dir@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz" @@ -5171,6 +5194,20 @@ make-dir@^2.0.0, make-dir@^2.1.0: pify "^4.0.1" semver "^5.6.0" +make-dir@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +make-dir@^3.0.2, make-dir@3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + make-error@^1.1.1: version "1.3.6" resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" @@ -5184,7 +5221,7 @@ map-cache@^0.2.2: map-obj@^1.0.0, map-obj@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz" - integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= + integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg== map-visit@^1.0.0: version "1.0.0" @@ -5196,12 +5233,12 @@ map-visit@^1.0.0: media-typer@0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz" - integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== meow@^3.3.0: version "3.7.0" resolved "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz" - integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs= + integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs= sha512-TNdwZs0skRlpPpCUK25StC4VH+tP5GgeY1HQOOGP+lQ2xtdkN2VtT/5tiX9k3IWpkBPV9b3LsAWXn4GGi/PrSA== dependencies: camelcase-keys "^2.0.0" decamelize "^1.1.2" @@ -5217,7 +5254,7 @@ meow@^3.3.0: merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz" - integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== merge-stream@^2.0.0: version "2.0.0" @@ -5232,7 +5269,7 @@ merge2@^1.3.0, merge2@^1.4.1: methods@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz" - integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== micromatch@^3.1.10, micromatch@^3.1.4: version "3.1.10" @@ -5253,14 +5290,6 @@ micromatch@^3.1.10, micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" -micromatch@^4.0.2: - version "4.0.2" - resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz" - integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== - dependencies: - braces "^3.0.1" - picomatch "^2.0.5" - micromatch@^4.0.4: version "4.0.5" resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz" @@ -5281,16 +5310,16 @@ mime-types@^2.1.12, mime-types@~2.1.24, mime-types@~2.1.34: dependencies: mime-db "1.52.0" -mime@1.6.0: - version "1.6.0" - resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - mime@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz" integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== +mime@1.6.0: + version "1.6.0" + resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" @@ -5350,7 +5379,12 @@ mkdirp@^0.5.4: dependencies: minimist "^1.2.6" -mkdirp@^1.0.3, mkdirp@^1.0.4: +mkdirp@^1.0.3: + version "1.0.4" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +mkdirp@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== @@ -5367,17 +5401,17 @@ moment@^2.29.4: resolved "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz" integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== -ms@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@2.1.2: +ms@^2.1.1, ms@2.1.2: version "2.1.2" resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.1.1: +ms@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.3: version "2.1.3" resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -5416,7 +5450,7 @@ mz@^2.4.0: nan@^2.12.1: version "2.17.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb" + resolved "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz" integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ== nanomatch@^1.2.9: @@ -5439,7 +5473,7 @@ nanomatch@^1.2.9: natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== negotiator@0.6.3: version "0.6.3" @@ -5464,13 +5498,6 @@ node-environment-flags@^1.0.5: object.getownpropertydescriptors "^2.0.3" semver "^5.7.0" -node-fetch@2.6.7: - version "2.6.7" - resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz" - integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== - dependencies: - whatwg-url "^5.0.0" - node-fetch@^2.6.9: version "2.7.0" resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz" @@ -5478,6 +5505,13 @@ node-fetch@^2.6.9: dependencies: whatwg-url "^5.0.0" +node-fetch@2.6.7: + version "2.6.7" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== + dependencies: + whatwg-url "^5.0.0" + node-forge@^1.3.1: version "1.3.1" resolved "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz" @@ -5486,7 +5520,7 @@ node-forge@^1.3.1: node-modules-regexp@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz" - integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= + integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= sha512-JMaRS9L4wSRIR+6PTVEikTrq/lMGEZR43a48ETeilY0Q0iMwVnccMFrUM1k+tNzmYuIU0Vh710bCUqHX+/+ctQ== node-releases@^2.0.6: version "2.0.8" @@ -5530,7 +5564,7 @@ npm-run-path@^4.0.1: object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== object-copy@^0.1.0: version "0.1.0" @@ -5614,7 +5648,7 @@ on-finished@2.4.1: once@^1.3.0, once@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" @@ -5679,7 +5713,14 @@ p-limit@^1.1.0: dependencies: p-try "^1.0.0" -p-limit@^2.0.0, p-limit@^2.2.0: +p-limit@^2.0.0: + version "2.3.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^2.2.0: version "2.3.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== @@ -5696,7 +5737,7 @@ p-limit@^3.0.2: p-locate@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg== dependencies: p-limit "^1.1.0" @@ -5721,18 +5762,18 @@ p-locate@^5.0.0: dependencies: p-limit "^3.0.2" -p-map@4.0.0, p-map@^4.0.0: +p-map@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz" + integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== + +p-map@^4.0.0, p-map@4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz" integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== dependencies: aggregate-error "^3.0.0" -p-map@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz" - integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== - p-retry@4.6.2: version "4.6.2" resolved "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz" @@ -5744,7 +5785,7 @@ p-retry@4.6.2: p-try@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww== p-try@^2.0.0: version "2.2.0" @@ -5766,12 +5807,12 @@ parent-module@^1.0.0: parent-require@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/parent-require/-/parent-require-1.0.0.tgz" - integrity sha1-dGoWdjgIOoYLDu9nMssn7UbDKXc= + integrity sha1-dGoWdjgIOoYLDu9nMssn7UbDKXc= sha512-2MXDNZC4aXdkkap+rBBMv0lUsfJqvX5/2FiYYnfCnorZt3Pk06/IOR5KeaoghgS2w07MLWgjbsnyaq6PdHn2LQ== parse-json@^2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz" - integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= + integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ== dependencies: error-ex "^1.2.0" @@ -5788,7 +5829,7 @@ parse-json@^5.0.0: parse-passwd@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz" - integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY= + integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY= sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q== parse5-htmlparser2-tree-adapter@^6.0.0: version "6.0.1" @@ -5825,14 +5866,14 @@ path-dirname@^1.0.0: path-exists@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz" - integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= + integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ== dependencies: pinkie-promise "^2.0.0" path-exists@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz" - integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ== path-exists@^4.0.0: version "4.0.0" @@ -5842,7 +5883,7 @@ path-exists@^4.0.0: path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" @@ -5857,12 +5898,12 @@ path-parse@^1.0.7: path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz" - integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== path-type@^1.0.0: version "1.1.0" resolved "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz" - integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= + integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg== dependencies: graceful-fs "^4.1.2" pify "^2.0.0" @@ -5871,7 +5912,7 @@ path-type@^1.0.0: path-type@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz" - integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= + integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= sha512-dUnb5dXUf+kzhC/W/F4e5/SkluXIFf5VUHolW1Eg1irn1hGWjPGdsRcvYJ1nD6lhk8Ir7VM0bHJKsYTx8Jx9OQ== dependencies: pify "^2.0.0" @@ -5883,7 +5924,7 @@ path-type@^4.0.0: path@^0.12.7: version "0.12.7" resolved "https://registry.npmjs.org/path/-/path-0.12.7.tgz" - integrity sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8= + integrity sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8= sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q== dependencies: process "^0.11.1" util "^0.10.3" @@ -5919,7 +5960,7 @@ pg-types@^2.1.0: postgres-date "~1.0.4" postgres-interval "^1.1.0" -pg@^8.5.1: +pg@^8.5.1, pg@>=8.0: version "8.5.1" resolved "https://registry.npmjs.org/pg/-/pg-8.5.1.tgz" integrity sha512-9wm3yX9lCfjvA98ybCyw2pADUivyNWT/yIP4ZcDVpMN0og70BUWYEGXPCTAQdGTAqnytfRADb7NERrY1qxhIqw== @@ -5944,12 +5985,7 @@ picocolors@^1.0.0: resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1: - version "2.2.2" - resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz" - integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== - -picomatch@^2.3.1: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -5957,7 +5993,7 @@ picomatch@^2.3.1: pify@^2.0.0: version "2.3.0" resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== pify@^4.0.1: version "4.0.1" @@ -5967,14 +6003,14 @@ pify@^4.0.1: pinkie-promise@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz" - integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= + integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw== dependencies: pinkie "^2.0.0" pinkie@^2.0.0: version "2.0.4" resolved "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz" - integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= + integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg== pirates@^4.0.0: version "4.0.1" @@ -5986,7 +6022,7 @@ pirates@^4.0.0: pkg-dir@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz" - integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= + integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= sha512-ojakdnUgL5pzJYWw2AIDEupaQCX5OPbM688ZevubICjdIX01PRSYKqm33fJoCOJBRseYCTUlQRnBNX+Pchaejw== dependencies: find-up "^2.1.0" @@ -6024,7 +6060,7 @@ postgres-array@~2.0.0: postgres-bytea@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz" - integrity sha1-AntTPAqokOJtFy1Hz5zOzFIazTU= + integrity sha1-AntTPAqokOJtFy1Hz5zOzFIazTU= sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w== postgres-date@~1.0.4: version "1.0.7" @@ -6059,7 +6095,7 @@ prisma-aurora@^1.3.6: glob "^8.0.3" path "^0.12.7" -prisma@^3.14.0: +prisma@*, prisma@^3.14.0: version "3.15.2" resolved "https://registry.npmjs.org/prisma/-/prisma-3.15.2.tgz" integrity sha512-nMNSMZvtwrvoEQ/mui8L/aiCLZRCj5t6L3yujKpcDhIPk7garp8tL4nMx2+oYsN0FWBacevJhazfXAbV1kfBzA== @@ -6074,9 +6110,9 @@ process-nextick-args@~2.0.0: process@^0.11.1: version "0.11.10" resolved "https://registry.npmjs.org/process/-/process-0.11.10.tgz" - integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= + integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== -progress@2.0.3, progress@^2.0.0: +progress@^2.0.0, progress@2.0.3: version "2.0.3" resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== @@ -6102,17 +6138,17 @@ proxy-from-env@^1.1.0: resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz" integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== -punycode@1.3.2: - version "1.3.2" - resolved "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz" - integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= - punycode@^2.1.0: version "2.1.1" resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -qs@6.11.0, qs@^6.7.0: +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz" + integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw== + +qs@^6.7.0, qs@6.11.0: version "6.11.0" resolved "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz" integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== @@ -6122,7 +6158,7 @@ qs@6.11.0, qs@^6.7.0: querystring@0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz" - integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g== queue-microtask@^1.2.2: version "1.2.2" @@ -6144,19 +6180,10 @@ raw-body@2.5.1: iconv-lite "0.4.24" unpipe "1.0.0" -read-pkg-up@7.0.1: - version "7.0.1" - resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz" - integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== - dependencies: - find-up "^4.1.0" - read-pkg "^5.2.0" - type-fest "^0.8.1" - read-pkg-up@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz" - integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= + integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A== dependencies: find-up "^1.0.0" read-pkg "^1.0.0" @@ -6164,15 +6191,24 @@ read-pkg-up@^1.0.1: read-pkg-up@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz" - integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= + integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= sha512-1orxQfbWGUiTn9XsPlChs6rLie/AV9jwZTGmu2NZw/CUDJQchXJFYE0Fq5j7+n558T1JhDWLdhyd1Zj+wLY//w== dependencies: find-up "^2.0.0" read-pkg "^2.0.0" +read-pkg-up@7.0.1: + version "7.0.1" + resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz" + integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== + dependencies: + find-up "^4.1.0" + read-pkg "^5.2.0" + type-fest "^0.8.1" + read-pkg@^1.0.0: version "1.1.0" resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz" - integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= + integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ== dependencies: load-json-file "^1.0.0" normalize-package-data "^2.3.2" @@ -6181,7 +6217,7 @@ read-pkg@^1.0.0: read-pkg@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz" - integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= + integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= sha512-eFIBOPW7FGjzBuk3hdXEuNSiTZS/xEMlH49HxMyzb0hyPfu4EhVjT2DH32K1hSSmVq4sebAWnZuuY5auISUTGA== dependencies: load-json-file "^2.0.0" normalize-package-data "^2.3.2" @@ -6210,7 +6246,43 @@ readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5, readable string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.0.0, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.5.0, readable-stream@^3.6.0: +readable-stream@^3.0.0: + version "3.6.0" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@^3.1.1: + version "3.6.0" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@^3.4.0: + version "3.6.0" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@^3.5.0: + version "3.6.0" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@^3.6.0: version "3.6.0" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -6245,7 +6317,7 @@ readdirp@~3.5.0: redent@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz" - integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94= + integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94= sha512-qtW5hKzGQZqKoh6JNSD+4lfitfPKGz42e6QwiRmPM5mmKtR0N41AbJRYu0xJi7nhOJ4WDgRkKvAk6tw4WIwR4g== dependencies: indent-string "^2.1.0" strip-indent "^1.0.1" @@ -6334,7 +6406,7 @@ repeat-string@^1.6.1: repeating@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz" - integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= + integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= sha512-ZqtSMuVybkISo2OWvqvm7iHSWngvdaW3IpsT9/uP8v4gMi591LY6h35wdOfvQdWCKFWZWm2Y1Opp4kV7vQKT6A== dependencies: is-finite "^1.0.0" @@ -6346,7 +6418,7 @@ replace-string@3.1.0: require-directory@^2.1.1: version "2.1.1" resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== require-from-string@^2.0.2: version "2.0.2" @@ -6368,15 +6440,6 @@ resolve-url@^0.2.1: resolved "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz" integrity sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg== -resolve@1.22.0: - version "1.22.0" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz" - integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== - dependencies: - is-core-module "^2.8.1" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - resolve@^1.0.0, resolve@^1.10.0, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.22.1: version "1.22.1" resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz" @@ -6386,6 +6449,15 @@ resolve@^1.0.0, resolve@^1.10.0, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.22 path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +resolve@1.22.0: + version "1.22.0" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz" + integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== + dependencies: + is-core-module "^2.8.1" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + restore-cursor@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz" @@ -6409,20 +6481,27 @@ reusify@^1.0.4: resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== +rimraf@^2.6.1: + version "2.7.1" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== dependencies: glob "^7.1.3" -rimraf@^2.6.1, rimraf@^2.6.3: +rimraf@^2.6.3: version "2.7.1" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== dependencies: glob "^7.1.3" +rimraf@^3.0.0, rimraf@^3.0.2, rimraf@3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + run-parallel@^1.1.6, run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" @@ -6430,16 +6509,16 @@ run-parallel@^1.1.6, run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -safe-buffer@5.2.1, safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - safe-buffer@^5.0.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +safe-buffer@5.2.1: + version "5.2.1" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + safe-regex@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz" @@ -6452,32 +6531,29 @@ safe-regex@^1.1.0: resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sax@1.2.1: +sax@>=0.6.0, sax@1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz" - integrity sha1-e45lYZCyKOgaZq6nSEgNgozS03o= - -sax@>=0.6.0: - version "1.2.4" - resolved "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + integrity sha1-e45lYZCyKOgaZq6nSEgNgozS03o= sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA== -"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.0: +semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.0, "semver@2 || 3 || 4 || 5": version "5.7.1" resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz" - integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== - semver@^6.0.0: version "6.3.0" resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.2.1, semver@^7.3.2: +semver@^7.2.1: + version "7.3.4" + resolved "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz" + integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw== + dependencies: + lru-cache "^6.0.0" + +semver@^7.3.2: version "7.3.4" resolved "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz" integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw== @@ -6491,6 +6567,11 @@ semver@^7.3.8: dependencies: lru-cache "^6.0.0" +semver@7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz" + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== + send@0.18.0: version "0.18.0" resolved "https://registry.npmjs.org/send/-/send-0.18.0.tgz" @@ -6664,9 +6745,14 @@ source-map-url@^0.4.0: source-map@^0.5.0, source-map@^0.5.6: version "0.5.7" resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== -source-map@^0.6.0, source-map@^0.6.1: +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@^0.6.1: version "0.6.1" resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== @@ -6714,7 +6800,7 @@ split2@^3.1.1: sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== static-extend@^0.1.1: version "0.1.2" @@ -6742,7 +6828,14 @@ streamsearch@^1.1.0: resolved "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz" integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== -string-width@4.2.3: +string_decoder@^1.1.1, string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +string-width@^4.1.0, string-width@^4.2.0, string-width@4.2.3: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -6751,15 +6844,6 @@ string-width@4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^4.1.0, string-width@^4.2.0: - version "4.2.0" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz" - integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" - string.prototype.trimend@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz" @@ -6776,51 +6860,44 @@ string.prototype.trimstart@^1.0.3: call-bind "^1.0.0" define-properties "^1.1.3" -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== +strip-ansi@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg== dependencies: - safe-buffer "~5.1.0" + ansi-regex "^2.0.0" -strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1: +strip-ansi@^6.0.0, strip-ansi@^6.0.1, strip-ansi@6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: ansi-regex "^5.0.1" -strip-ansi@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz" - integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= + integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g== dependencies: is-utf8 "^0.2.0" strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== strip-final-newline@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== +strip-indent@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz" + integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI= sha512-I5iQq6aFMM62fBEAIB/hXzwJD6EEZ0xEGCX2t7oXqaKPIRgt4WruAQ285BISgdkP+HLGWyeGmNJcpIwFeRYRUA== + dependencies: + get-stdin "^4.0.1" + strip-indent@3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz" @@ -6828,17 +6905,10 @@ strip-indent@3.0.0: dependencies: min-indent "^1.0.0" -strip-indent@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz" - integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI= - dependencies: - get-stdin "^4.0.1" - strip-json-comments@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" @@ -6853,7 +6923,7 @@ strnum@^1.0.5: supports-color@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= + integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g== supports-color@^5.3.0: version "5.5.0" @@ -6862,7 +6932,14 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -supports-color@^7.0.0, supports-color@^7.1.0: +supports-color@^7.0.0: + version "7.2.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^7.1.0: version "7.2.0" resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== @@ -6927,15 +7004,15 @@ tar@6.1.11: mkdirp "^1.0.3" yallist "^4.0.0" -temp-dir@2.0.0, temp-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz" - integrity sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg== - temp-dir@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz" - integrity sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0= + integrity sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0= sha512-xZFXEGbG7SNC3itwBzI3RYjq/cEhBkx2hJuKGIUOcEULmkQExXiHat2z/qkISYsuR+IKumhEfKKbV5qXmhICFQ== + +temp-dir@^2.0.0, temp-dir@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz" + integrity sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg== temp-write@4.0.0: version "4.0.0" @@ -6970,12 +7047,12 @@ terminal-link@2.1.1: text-table@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== thenify-all@^1.0.0: version "1.6.0" resolved "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz" - integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY= + integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY= sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== dependencies: thenify ">= 3.1.0 < 4" @@ -6996,7 +7073,7 @@ tmp@0.2.1: to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== to-object-path@^0.3.0: version "0.3.0" @@ -7038,7 +7115,7 @@ toidentifier@1.0.1: tr46@~0.0.3: version "0.0.3" resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" - integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= + integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== tree-kill@^1.2.2: version "1.2.2" @@ -7104,7 +7181,22 @@ tsconfig@^7.0.0: strip-bom "^3.0.0" strip-json-comments "^2.0.0" -tslib@^1.11.1, tslib@^1.13.0, tslib@^1.8.1, tslib@^1.9.3: +tslib@^1.11.1: + version "1.14.1" + resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslib@^1.13.0: + version "1.14.1" + resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslib@^1.9.3: version "1.14.1" resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== @@ -7190,7 +7282,7 @@ typeorm@^0.2.31: yargonaut "^1.1.2" yargs "^16.0.3" -typescript@^4.1.5: +typescript@*, typescript@^4.1.5, typescript@>=2.7, "typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta": version "4.1.5" resolved "https://registry.npmjs.org/typescript/-/typescript-4.1.5.tgz" integrity sha512-6OSu9PTIzmn9TCDiovULTnET6BgXtDYL4Gg4szY+cGsc3JP1dQL8qvE8kShTRx1NIw4Q9IBHlwODjkjWEtMUyA== @@ -7245,7 +7337,7 @@ unique-string@^2.0.0: dependencies: crypto-random-string "^2.0.0" -unpipe@1.0.0, unpipe@~1.0.0: +unpipe@~1.0.0, unpipe@1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== @@ -7291,7 +7383,7 @@ url-template@^2.0.8: url@0.10.3: version "0.10.3" resolved "https://registry.npmjs.org/url/-/url-0.10.3.tgz" - integrity sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ= + integrity sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ= sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ== dependencies: punycode "1.3.2" querystring "0.2.0" @@ -7304,7 +7396,7 @@ use@^3.1.0: util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== util@^0.10.3: version "0.10.4" @@ -7327,28 +7419,28 @@ util@^0.12.4: utils-merge@1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" - integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= - -uuid@8.0.0: - version "8.0.0" - resolved "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz" - integrity sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw== - -uuid@8.3.2, uuid@^8.3.0, uuid@^8.3.2: - version "8.3.2" - resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== uuid@^3.3.2: version "3.4.0" resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== +uuid@^8.3.0, uuid@^8.3.2, uuid@8.3.2: + version "8.3.2" + resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + uuid@^9.0.0: version "9.0.0" resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz" integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== +uuid@8.0.0: + version "8.0.0" + resolved "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz" + integrity sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw== + v8-compile-cache@^2.0.3: version "2.2.0" resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz" @@ -7377,24 +7469,24 @@ validator@^13.7.0: vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" - integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== wcwidth@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz" - integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= + integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg== dependencies: defaults "^1.0.3" webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz" - integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= + integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz" - integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= + integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== dependencies: tr46 "~0.0.3" webidl-conversions "^3.0.0" @@ -7425,7 +7517,7 @@ word-wrap@^1.2.3: wordwrap@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz" - integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= + integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== wrap-ansi@^7.0.0: version "7.0.0" @@ -7439,15 +7531,7 @@ wrap-ansi@^7.0.0: wrappy@1: version "1.0.2" resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -xml2js@0.5.0: - version "0.5.0" - resolved "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz" - integrity sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA== - dependencies: - sax ">=0.6.0" - xmlbuilder "~11.0.0" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== xml2js@^0.4.23: version "0.4.23" @@ -7457,6 +7541,14 @@ xml2js@^0.4.23: sax ">=0.6.0" xmlbuilder "~11.0.0" +xml2js@0.5.0: + version "0.5.0" + resolved "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz" + integrity sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA== + dependencies: + sax ">=0.6.0" + xmlbuilder "~11.0.0" + xmlbuilder@~11.0.0: version "11.0.1" resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz"