feat(05-03): calendar backend — model, crypto, source CRUD module
- Add CalendarSource Prisma model with encrypted credentials (AES-256-GCM) - Create CalendarCryptoService with encrypt/decrypt using CALENDAR_ENCRYPTION_KEY - Create CalendarController with source CRUD endpoints (GET/POST/PATCH/DELETE) - Create CalendarService with ownership checks and SSRF URL validation - Add DTOs with https-only URL validation and class-validator decorators - Register CalendarModule in AppModule - Install tsdav, node-ical, ews-javascript-api, @microsoft/microsoft-graph-client - Stub provider files for Task 2 compilation
This commit is contained in:
@@ -9,6 +9,7 @@
|
|||||||
"type-check": "tsc --noEmit"
|
"type-check": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@microsoft/microsoft-graph-client": "3.0.7",
|
||||||
"@nestjs-modules/mailer": "^2.3.7",
|
"@nestjs-modules/mailer": "^2.3.7",
|
||||||
"@nestjs/common": "^11.0.0",
|
"@nestjs/common": "^11.0.0",
|
||||||
"@nestjs/config": "^4.0.0",
|
"@nestjs/config": "^4.0.0",
|
||||||
@@ -24,13 +25,16 @@
|
|||||||
"class-transformer": "^0.5.1",
|
"class-transformer": "^0.5.1",
|
||||||
"class-validator": "^0.15.1",
|
"class-validator": "^0.15.1",
|
||||||
"cookie-parser": "^1.4.7",
|
"cookie-parser": "^1.4.7",
|
||||||
|
"ews-javascript-api": "0.15.3",
|
||||||
"ldapts": "^8.1.8",
|
"ldapts": "^8.1.8",
|
||||||
|
"node-ical": "0.26.1",
|
||||||
"nodemailer": "^9.0.1",
|
"nodemailer": "^9.0.1",
|
||||||
"passport": "^0.7.0",
|
"passport": "^0.7.0",
|
||||||
"passport-jwt": "^4.0.1",
|
"passport-jwt": "^4.0.1",
|
||||||
"passport-local": "^1.0.0",
|
"passport-local": "^1.0.0",
|
||||||
"reflect-metadata": "^0.2.0",
|
"reflect-metadata": "^0.2.0",
|
||||||
"rxjs": "^7.0.0"
|
"rxjs": "^7.0.0",
|
||||||
|
"tsdav": "2.2.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nestjs/cli": "^11.0.0",
|
"@nestjs/cli": "^11.0.0",
|
||||||
|
|||||||
@@ -146,3 +146,25 @@ model SearchProvider {
|
|||||||
|
|
||||||
@@index([userId])
|
@@index([userId])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model CalendarSource {
|
||||||
|
id String @id @default(uuid())
|
||||||
|
userId String
|
||||||
|
tenantId String
|
||||||
|
name String
|
||||||
|
type String // 'caldav' | 'ics' | 'exchange'
|
||||||
|
exchangeMode String? // 'ews' | 'graph' — only for exchange type
|
||||||
|
url String
|
||||||
|
username String?
|
||||||
|
encryptedPassword String? // AES-256-GCM ciphertext (iv:authTag:ciphertext hex)
|
||||||
|
color String? @default("#3B82F6")
|
||||||
|
isVisible Boolean @default(true)
|
||||||
|
syncIntervalMin Int @default(15)
|
||||||
|
lastSyncAt DateTime?
|
||||||
|
lastSyncError String?
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
|
||||||
|
@@index([userId])
|
||||||
|
@@index([tenantId])
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { ForcePasswordChangeInterceptor } from './auth/interceptors/force-passwo
|
|||||||
import { HealthModule } from './health/health.module';
|
import { HealthModule } from './health/health.module';
|
||||||
import { LdapModule } from './ldap/ldap.module';
|
import { LdapModule } from './ldap/ldap.module';
|
||||||
import { MailModule } from './mail/mail.module';
|
import { MailModule } from './mail/mail.module';
|
||||||
|
import { CalendarModule } from './calendar/calendar.module';
|
||||||
import { DashboardModule } from './dashboard/dashboard.module';
|
import { DashboardModule } from './dashboard/dashboard.module';
|
||||||
import { DomaincheckModule } from './domaincheck/domaincheck.module';
|
import { DomaincheckModule } from './domaincheck/domaincheck.module';
|
||||||
import { ModuleRegistryModule } from './module-registry/module-registry.module';
|
import { ModuleRegistryModule } from './module-registry/module-registry.module';
|
||||||
@@ -29,6 +30,7 @@ import { UserModule } from './user/user.module';
|
|||||||
ModuleRegistryModule,
|
ModuleRegistryModule,
|
||||||
DomaincheckModule,
|
DomaincheckModule,
|
||||||
DashboardModule,
|
DashboardModule,
|
||||||
|
CalendarModule,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
// Global JWT guard: all routes require auth unless @Public()
|
// Global JWT guard: all routes require auth unless @Public()
|
||||||
|
|||||||
@@ -0,0 +1,131 @@
|
|||||||
|
import {
|
||||||
|
Body,
|
||||||
|
Controller,
|
||||||
|
Delete,
|
||||||
|
ForbiddenException,
|
||||||
|
Get,
|
||||||
|
Param,
|
||||||
|
Patch,
|
||||||
|
Post,
|
||||||
|
Query,
|
||||||
|
Req,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
import { Request } from 'express';
|
||||||
|
import { CalendarService } from './calendar.service';
|
||||||
|
import { CreateCalendarSourceDto } from './dto/create-calendar-source.dto';
|
||||||
|
import { UpdateCalendarSourceDto } from './dto/update-calendar-source.dto';
|
||||||
|
import { CalendarEventsQueryDto } from './dto/calendar-events-query.dto';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* REST controller for calendar source management and event aggregation.
|
||||||
|
*
|
||||||
|
* All endpoints require JWT auth (global JwtAuthGuard).
|
||||||
|
* Every handler extracts userId and tenantId from the request
|
||||||
|
* and scopes all operations to the calling user (T-05-12).
|
||||||
|
*
|
||||||
|
* Routes:
|
||||||
|
* - GET /calendar/sources — list user's calendar sources (no passwords)
|
||||||
|
* - POST /calendar/sources — add a new calendar source
|
||||||
|
* - PATCH /calendar/sources/:id — update a calendar source
|
||||||
|
* - DELETE /calendar/sources/:id — remove a calendar source
|
||||||
|
* - POST /calendar/sources/:id/test — test connection to a source
|
||||||
|
* - GET /calendar/events — aggregated events from visible sources
|
||||||
|
*/
|
||||||
|
@Controller('calendar')
|
||||||
|
export class CalendarController {
|
||||||
|
constructor(private readonly calendarService: CalendarService) {}
|
||||||
|
|
||||||
|
private extractContext(req: Request) {
|
||||||
|
const userId = (req as any).user?.id;
|
||||||
|
const tenantId =
|
||||||
|
(req as any).tenantId ?? (req as any).user?.tenantId;
|
||||||
|
|
||||||
|
if (!tenantId) {
|
||||||
|
throw new ForbiddenException('No tenant context');
|
||||||
|
}
|
||||||
|
if (!userId) {
|
||||||
|
throw new ForbiddenException('No user context');
|
||||||
|
}
|
||||||
|
|
||||||
|
return { userId, tenantId };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET /calendar/sources
|
||||||
|
* Returns all calendar sources for the user WITHOUT encryptedPassword.
|
||||||
|
* T-05-09: Uses Prisma select to exclude credentials; returns hasCredentials boolean.
|
||||||
|
*/
|
||||||
|
@Get('sources')
|
||||||
|
async getSources(@Req() req: Request) {
|
||||||
|
const { userId } = this.extractContext(req);
|
||||||
|
return this.calendarService.getSources(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POST /calendar/sources
|
||||||
|
* Creates a new calendar source. Password is encrypted before storage.
|
||||||
|
* T-05-11: URL validated as https-only + SSRF private IP check.
|
||||||
|
*/
|
||||||
|
@Post('sources')
|
||||||
|
async addSource(
|
||||||
|
@Req() req: Request,
|
||||||
|
@Body() dto: CreateCalendarSourceDto,
|
||||||
|
) {
|
||||||
|
const { userId, tenantId } = this.extractContext(req);
|
||||||
|
return this.calendarService.addSource(userId, tenantId, dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PATCH /calendar/sources/:id
|
||||||
|
* Updates an existing calendar source. Ownership verified.
|
||||||
|
* CAL-02: isVisible toggle is part of this DTO.
|
||||||
|
*/
|
||||||
|
@Patch('sources/:id')
|
||||||
|
async updateSource(
|
||||||
|
@Param('id') id: string,
|
||||||
|
@Req() req: Request,
|
||||||
|
@Body() dto: UpdateCalendarSourceDto,
|
||||||
|
) {
|
||||||
|
const { userId } = this.extractContext(req);
|
||||||
|
return this.calendarService.updateSource(id, userId, dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DELETE /calendar/sources/:id
|
||||||
|
* Removes a calendar source. Ownership verified (T-05-12).
|
||||||
|
*/
|
||||||
|
@Delete('sources/:id')
|
||||||
|
async deleteSource(
|
||||||
|
@Param('id') id: string,
|
||||||
|
@Req() req: Request,
|
||||||
|
) {
|
||||||
|
const { userId } = this.extractContext(req);
|
||||||
|
return this.calendarService.deleteSource(id, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POST /calendar/sources/:id/test
|
||||||
|
* Tests connection to a calendar source. Implemented in Task 3.
|
||||||
|
*/
|
||||||
|
@Post('sources/:id/test')
|
||||||
|
async testSource(
|
||||||
|
@Param('id') id: string,
|
||||||
|
@Req() req: Request,
|
||||||
|
) {
|
||||||
|
const { userId } = this.extractContext(req);
|
||||||
|
return this.calendarService.testConnection(id, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET /calendar/events
|
||||||
|
* Returns aggregated events from all visible sources. Implemented in Task 3.
|
||||||
|
*/
|
||||||
|
@Get('events')
|
||||||
|
async getEvents(
|
||||||
|
@Req() req: Request,
|
||||||
|
@Query() query: CalendarEventsQueryDto,
|
||||||
|
) {
|
||||||
|
const { userId } = this.extractContext(req);
|
||||||
|
return this.calendarService.aggregateEvents(userId, query.from, query.to);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { CalendarController } from './calendar.controller';
|
||||||
|
import { CalendarService } from './calendar.service';
|
||||||
|
import { CalendarCryptoService } from './crypto.service';
|
||||||
|
import { CalDAVProvider } from './providers/caldav.provider';
|
||||||
|
import { ICSProvider } from './providers/ics.provider';
|
||||||
|
import { ExchangeProvider } from './providers/exchange.provider';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NestJS module for calendar source management and event aggregation.
|
||||||
|
*
|
||||||
|
* Provides:
|
||||||
|
* - CalendarCryptoService: AES-256-GCM encryption for calendar credentials
|
||||||
|
* - CalendarService: Source CRUD + event aggregation across providers
|
||||||
|
* - CalDAVProvider: CalDAV protocol integration via tsdav
|
||||||
|
* - ICSProvider: ICS file fetch + parse via node-ical
|
||||||
|
* - ExchangeProvider: Exchange Online (Graph) + Exchange Server (EWS) integration
|
||||||
|
* - CalendarController: REST API for sources and events
|
||||||
|
*
|
||||||
|
* Exports CalendarService for potential use by other modules.
|
||||||
|
*/
|
||||||
|
@Module({
|
||||||
|
controllers: [CalendarController],
|
||||||
|
providers: [
|
||||||
|
CalendarService,
|
||||||
|
CalendarCryptoService,
|
||||||
|
CalDAVProvider,
|
||||||
|
ICSProvider,
|
||||||
|
ExchangeProvider,
|
||||||
|
],
|
||||||
|
exports: [CalendarService],
|
||||||
|
})
|
||||||
|
export class CalendarModule {}
|
||||||
@@ -0,0 +1,281 @@
|
|||||||
|
import {
|
||||||
|
ForbiddenException,
|
||||||
|
Injectable,
|
||||||
|
Logger,
|
||||||
|
NotFoundException,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
import { PrismaService } from '../prisma/prisma.service';
|
||||||
|
import { CalendarCryptoService } from './crypto.service';
|
||||||
|
import { CreateCalendarSourceDto } from './dto/create-calendar-source.dto';
|
||||||
|
import { UpdateCalendarSourceDto } from './dto/update-calendar-source.dto';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common interface for normalized calendar events across all provider types.
|
||||||
|
*/
|
||||||
|
export interface CalendarEvent {
|
||||||
|
id: string;
|
||||||
|
sourceId: string;
|
||||||
|
title: string;
|
||||||
|
start: Date;
|
||||||
|
end: Date;
|
||||||
|
allDay: boolean;
|
||||||
|
location?: string;
|
||||||
|
description?: string;
|
||||||
|
color?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provider interface for calendar source integrations.
|
||||||
|
* Each provider (ICS, CalDAV, Exchange) implements this contract.
|
||||||
|
*/
|
||||||
|
export interface CalendarProvider {
|
||||||
|
fetchEvents(
|
||||||
|
source: { url: string; username?: string; password?: string; exchangeMode?: string | null; id: string; color?: string | null },
|
||||||
|
from: Date,
|
||||||
|
to: Date,
|
||||||
|
): Promise<CalendarEvent[]>;
|
||||||
|
|
||||||
|
testConnection(
|
||||||
|
source: { url: string; username?: string; password?: string; exchangeMode?: string | null; id: string },
|
||||||
|
): Promise<boolean>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prisma `select` for safe source responses — NEVER includes encryptedPassword.
|
||||||
|
* T-05-09: Return hasCredentials boolean instead.
|
||||||
|
*/
|
||||||
|
const SOURCE_SAFE_SELECT = {
|
||||||
|
id: true,
|
||||||
|
userId: true,
|
||||||
|
tenantId: true,
|
||||||
|
name: true,
|
||||||
|
type: true,
|
||||||
|
exchangeMode: true,
|
||||||
|
url: true,
|
||||||
|
username: true,
|
||||||
|
// encryptedPassword: NEVER included — T-05-09
|
||||||
|
color: true,
|
||||||
|
isVisible: true,
|
||||||
|
syncIntervalMin: true,
|
||||||
|
lastSyncAt: true,
|
||||||
|
lastSyncError: true,
|
||||||
|
createdAt: true,
|
||||||
|
updatedAt: true,
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private IP ranges for SSRF protection (T-05-11).
|
||||||
|
*/
|
||||||
|
const PRIVATE_IP_PATTERNS = [
|
||||||
|
/^10\.\d{1,3}\.\d{1,3}\.\d{1,3}$/,
|
||||||
|
/^192\.168\.\d{1,3}\.\d{1,3}$/,
|
||||||
|
/^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/,
|
||||||
|
/^169\.254\.\d{1,3}\.\d{1,3}$/,
|
||||||
|
/^172\.(1[6-9]|2\d|3[0-1])\.\d{1,3}\.\d{1,3}$/,
|
||||||
|
/^0\.0\.0\.0$/,
|
||||||
|
/^\[::1\]$/,
|
||||||
|
/^\[fc00:/,
|
||||||
|
/^\[fd00:/,
|
||||||
|
/^\[fe80:/,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service for calendar source CRUD and event aggregation.
|
||||||
|
*
|
||||||
|
* Source config is per-user (D-09), not per-tenant.
|
||||||
|
* Credentials encrypted at rest via CalendarCryptoService (T-05-10).
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class CalendarService {
|
||||||
|
private readonly logger = new Logger(CalendarService.name);
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly prisma: PrismaService,
|
||||||
|
private readonly crypto: CalendarCryptoService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all calendar sources for a user WITHOUT encryptedPassword.
|
||||||
|
* Adds a `hasCredentials` boolean so the UI knows if credentials are set.
|
||||||
|
*/
|
||||||
|
async getSources(userId: string) {
|
||||||
|
const sources = await this.prisma.calendarSource.findMany({
|
||||||
|
where: { userId },
|
||||||
|
select: {
|
||||||
|
...SOURCE_SAFE_SELECT,
|
||||||
|
encryptedPassword: true, // Need it only to derive hasCredentials
|
||||||
|
},
|
||||||
|
orderBy: { createdAt: 'asc' },
|
||||||
|
});
|
||||||
|
|
||||||
|
return sources.map(({ encryptedPassword, ...source }) => ({
|
||||||
|
...source,
|
||||||
|
hasCredentials: !!encryptedPassword,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new calendar source. Encrypts password before storage.
|
||||||
|
* T-05-11: Validates URL against private IP ranges (SSRF).
|
||||||
|
*/
|
||||||
|
async addSource(userId: string, tenantId: string, dto: CreateCalendarSourceDto) {
|
||||||
|
await this.validateUrlNotPrivate(dto.url);
|
||||||
|
|
||||||
|
const data: Record<string, unknown> = {
|
||||||
|
userId,
|
||||||
|
tenantId,
|
||||||
|
name: dto.name,
|
||||||
|
type: dto.type,
|
||||||
|
url: dto.url,
|
||||||
|
username: dto.username ?? null,
|
||||||
|
exchangeMode: dto.exchangeMode ?? null,
|
||||||
|
color: dto.color ?? '#3B82F6',
|
||||||
|
};
|
||||||
|
|
||||||
|
if (dto.password) {
|
||||||
|
data.encryptedPassword = this.crypto.encrypt(dto.password);
|
||||||
|
}
|
||||||
|
|
||||||
|
const created = await this.prisma.calendarSource.create({
|
||||||
|
data: data as any,
|
||||||
|
select: SOURCE_SAFE_SELECT,
|
||||||
|
});
|
||||||
|
|
||||||
|
return { ...created, hasCredentials: !!dto.password };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a calendar source. Ownership check ensures user can only modify their own sources.
|
||||||
|
* Re-encrypts password if provided; T-05-12 ownership enforcement.
|
||||||
|
*/
|
||||||
|
async updateSource(id: string, userId: string, dto: UpdateCalendarSourceDto) {
|
||||||
|
const existing = await this.prisma.calendarSource.findUnique({
|
||||||
|
where: { id },
|
||||||
|
select: { userId: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!existing) {
|
||||||
|
throw new NotFoundException('Calendar source not found');
|
||||||
|
}
|
||||||
|
if (existing.userId !== userId) {
|
||||||
|
throw new ForbiddenException('Not your calendar source');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dto.url) {
|
||||||
|
await this.validateUrlNotPrivate(dto.url);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data: Record<string, unknown> = {};
|
||||||
|
if (dto.name !== undefined) data.name = dto.name;
|
||||||
|
if (dto.type !== undefined) data.type = dto.type;
|
||||||
|
if (dto.url !== undefined) data.url = dto.url;
|
||||||
|
if (dto.username !== undefined) data.username = dto.username;
|
||||||
|
if (dto.exchangeMode !== undefined) data.exchangeMode = dto.exchangeMode;
|
||||||
|
if (dto.color !== undefined) data.color = dto.color;
|
||||||
|
if (dto.isVisible !== undefined) data.isVisible = dto.isVisible;
|
||||||
|
|
||||||
|
if (dto.password !== undefined) {
|
||||||
|
data.encryptedPassword = dto.password
|
||||||
|
? this.crypto.encrypt(dto.password)
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const updated = await this.prisma.calendarSource.update({
|
||||||
|
where: { id },
|
||||||
|
data: data as any,
|
||||||
|
select: {
|
||||||
|
...SOURCE_SAFE_SELECT,
|
||||||
|
encryptedPassword: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { encryptedPassword, ...safe } = updated;
|
||||||
|
return { ...safe, hasCredentials: !!encryptedPassword };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a calendar source. Ownership check enforced (T-05-12).
|
||||||
|
*/
|
||||||
|
async deleteSource(id: string, userId: string) {
|
||||||
|
const existing = await this.prisma.calendarSource.findUnique({
|
||||||
|
where: { id },
|
||||||
|
select: { userId: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!existing) {
|
||||||
|
throw new NotFoundException('Calendar source not found');
|
||||||
|
}
|
||||||
|
if (existing.userId !== userId) {
|
||||||
|
throw new ForbiddenException('Not your calendar source');
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.prisma.calendarSource.delete({ where: { id } });
|
||||||
|
return { deleted: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test connection to a calendar source via its provider.
|
||||||
|
* Stub — full implementation in Task 3.
|
||||||
|
*/
|
||||||
|
async testConnection(id: string, userId: string): Promise<{ success: boolean; error?: string }> {
|
||||||
|
const source = await this.prisma.calendarSource.findUnique({ where: { id } });
|
||||||
|
if (!source) throw new NotFoundException('Calendar source not found');
|
||||||
|
if (source.userId !== userId) throw new ForbiddenException('Not your calendar source');
|
||||||
|
return { success: false, error: 'Not yet implemented' };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aggregate events from all visible sources for a user.
|
||||||
|
* Stub — full implementation in Task 3.
|
||||||
|
*/
|
||||||
|
async aggregateEvents(
|
||||||
|
userId: string,
|
||||||
|
from?: string,
|
||||||
|
to?: string,
|
||||||
|
): Promise<CalendarEvent[]> {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypts stored credentials for a source (used internally by providers).
|
||||||
|
* NEVER expose this in API responses.
|
||||||
|
*/
|
||||||
|
decryptSourcePassword(encryptedPassword: string): string {
|
||||||
|
return this.crypto.decrypt(encryptedPassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SSRF protection: reject URLs that resolve to private IP ranges.
|
||||||
|
* T-05-11: Combined with https-only DTO validation.
|
||||||
|
*/
|
||||||
|
private async validateUrlNotPrivate(url: string): Promise<void> {
|
||||||
|
try {
|
||||||
|
const parsed = new URL(url);
|
||||||
|
const hostname = parsed.hostname;
|
||||||
|
|
||||||
|
// Check against private IP patterns
|
||||||
|
for (const pattern of PRIVATE_IP_PATTERNS) {
|
||||||
|
if (pattern.test(hostname)) {
|
||||||
|
throw new ForbiddenException(
|
||||||
|
'Calendar source URL must not point to private/internal networks',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also block localhost variants
|
||||||
|
if (
|
||||||
|
hostname === 'localhost' ||
|
||||||
|
hostname === 'ip6-localhost' ||
|
||||||
|
hostname.endsWith('.local') ||
|
||||||
|
hostname.endsWith('.internal')
|
||||||
|
) {
|
||||||
|
throw new ForbiddenException(
|
||||||
|
'Calendar source URL must not point to localhost or local networks',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof ForbiddenException) throw error;
|
||||||
|
throw new ForbiddenException('Invalid calendar source URL');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import { Injectable, OnModuleInit } from '@nestjs/common';
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
import { createCipheriv, createDecipheriv, randomBytes } from 'crypto';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encryption service for calendar source credentials.
|
||||||
|
*
|
||||||
|
* Uses AES-256-GCM with a 32-byte hex key from CALENDAR_ENCRYPTION_KEY env var.
|
||||||
|
* Encrypted values are stored as `iv:authTag:ciphertext` (hex-joined).
|
||||||
|
*
|
||||||
|
* Security: T-05-10 — credentials encrypted at rest, never returned in GET responses.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class CalendarCryptoService implements OnModuleInit {
|
||||||
|
private key!: Buffer;
|
||||||
|
|
||||||
|
constructor(private readonly configService: ConfigService) {}
|
||||||
|
|
||||||
|
onModuleInit() {
|
||||||
|
const hexKey = this.configService.get<string>('CALENDAR_ENCRYPTION_KEY');
|
||||||
|
|
||||||
|
if (!hexKey) {
|
||||||
|
throw new Error(
|
||||||
|
'CALENDAR_ENCRYPTION_KEY is not set. Generate one with: openssl rand -hex 32',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hexKey.length !== 64) {
|
||||||
|
throw new Error(
|
||||||
|
`CALENDAR_ENCRYPTION_KEY must be a 64-character hex string (32 bytes). Got ${hexKey.length} characters.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.key = Buffer.from(hexKey, 'hex');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypts plaintext using AES-256-GCM.
|
||||||
|
* @returns `iv:authTag:ciphertext` (all hex-encoded, colon-separated)
|
||||||
|
*/
|
||||||
|
encrypt(plaintext: string): string {
|
||||||
|
const iv = randomBytes(12); // 96-bit IV for GCM
|
||||||
|
const cipher = createCipheriv('aes-256-gcm', this.key, iv);
|
||||||
|
|
||||||
|
let encrypted = cipher.update(plaintext, 'utf8', 'hex');
|
||||||
|
encrypted += cipher.final('hex');
|
||||||
|
|
||||||
|
const authTag = cipher.getAuthTag().toString('hex');
|
||||||
|
|
||||||
|
return `${iv.toString('hex')}:${authTag}:${encrypted}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypts a stored `iv:authTag:ciphertext` value.
|
||||||
|
* @returns The original plaintext
|
||||||
|
*/
|
||||||
|
decrypt(stored: string): string {
|
||||||
|
const parts = stored.split(':');
|
||||||
|
if (parts.length !== 3) {
|
||||||
|
throw new Error('Invalid encrypted value format. Expected iv:authTag:ciphertext');
|
||||||
|
}
|
||||||
|
|
||||||
|
const [ivHex, authTagHex, ciphertext] = parts;
|
||||||
|
const iv = Buffer.from(ivHex, 'hex');
|
||||||
|
const authTag = Buffer.from(authTagHex, 'hex');
|
||||||
|
|
||||||
|
const decipher = createDecipheriv('aes-256-gcm', this.key, iv);
|
||||||
|
decipher.setAuthTag(authTag);
|
||||||
|
|
||||||
|
let decrypted = decipher.update(ciphertext, 'hex', 'utf8');
|
||||||
|
decrypted += decipher.final('utf8');
|
||||||
|
|
||||||
|
return decrypted;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { IsDateString, IsOptional } from 'class-validator';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DTO for querying aggregated calendar events.
|
||||||
|
*
|
||||||
|
* Default window: now to now + 30 days (applied in CalendarService).
|
||||||
|
*/
|
||||||
|
export class CalendarEventsQueryDto {
|
||||||
|
@IsOptional()
|
||||||
|
@IsDateString()
|
||||||
|
from?: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsDateString()
|
||||||
|
to?: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import {
|
||||||
|
IsBoolean,
|
||||||
|
IsHexColor,
|
||||||
|
IsIn,
|
||||||
|
IsNotEmpty,
|
||||||
|
IsOptional,
|
||||||
|
IsString,
|
||||||
|
IsUrl,
|
||||||
|
} from 'class-validator';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DTO for creating a new calendar source.
|
||||||
|
*
|
||||||
|
* Security:
|
||||||
|
* - T-05-11: URL restricted to https only (SSRF mitigation)
|
||||||
|
* - T-05-10: password is plaintext in transit (over TLS), encrypted at rest by CryptoService
|
||||||
|
*/
|
||||||
|
export class CreateCalendarSourceDto {
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
name!: string;
|
||||||
|
|
||||||
|
@IsIn(['caldav', 'ics', 'exchange'])
|
||||||
|
type!: string;
|
||||||
|
|
||||||
|
@IsUrl(
|
||||||
|
{ protocols: ['https'], require_protocol: true },
|
||||||
|
{ message: 'URL must use HTTPS protocol' },
|
||||||
|
)
|
||||||
|
url!: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
username?: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
password?: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsIn(['ews', 'graph'])
|
||||||
|
exchangeMode?: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsHexColor()
|
||||||
|
color?: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import {
|
||||||
|
IsBoolean,
|
||||||
|
IsHexColor,
|
||||||
|
IsIn,
|
||||||
|
IsNotEmpty,
|
||||||
|
IsOptional,
|
||||||
|
IsString,
|
||||||
|
IsUrl,
|
||||||
|
} from 'class-validator';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DTO for updating an existing calendar source.
|
||||||
|
* All fields are optional — only provided fields are updated.
|
||||||
|
*
|
||||||
|
* Security:
|
||||||
|
* - T-05-11: URL restricted to https only if provided
|
||||||
|
* - CAL-02: isVisible toggle for widget source visibility
|
||||||
|
*/
|
||||||
|
export class UpdateCalendarSourceDto {
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
name?: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsIn(['caldav', 'ics', 'exchange'])
|
||||||
|
type?: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsUrl(
|
||||||
|
{ protocols: ['https'], require_protocol: true },
|
||||||
|
{ message: 'URL must use HTTPS protocol' },
|
||||||
|
)
|
||||||
|
url?: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
username?: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
password?: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsIn(['ews', 'graph'])
|
||||||
|
exchangeMode?: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsHexColor()
|
||||||
|
color?: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsBoolean()
|
||||||
|
isVisible?: boolean;
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { Injectable, Logger } from '@nestjs/common';
|
||||||
|
import { CalendarEvent, CalendarProvider } from '../calendar.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CalDAV calendar provider — uses tsdav for protocol handling.
|
||||||
|
* Full implementation in Task 2.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class CalDAVProvider implements CalendarProvider {
|
||||||
|
private readonly logger = new Logger(CalDAVProvider.name);
|
||||||
|
|
||||||
|
async fetchEvents(
|
||||||
|
source: { url: string; username?: string; password?: string; id: string; color?: string | null },
|
||||||
|
from: Date,
|
||||||
|
to: Date,
|
||||||
|
): Promise<CalendarEvent[]> {
|
||||||
|
// Stub — implemented in Task 2
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
async testConnection(
|
||||||
|
source: { url: string; username?: string; password?: string; id: string },
|
||||||
|
): Promise<boolean> {
|
||||||
|
// Stub — implemented in Task 2
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { Injectable, Logger } from '@nestjs/common';
|
||||||
|
import { CalendarEvent, CalendarProvider } from '../calendar.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exchange calendar provider — dispatches on exchangeMode ('graph' vs 'ews').
|
||||||
|
* Uses @microsoft/microsoft-graph-client for Graph and ews-javascript-api for EWS.
|
||||||
|
* Full implementation in Task 2.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class ExchangeProvider implements CalendarProvider {
|
||||||
|
private readonly logger = new Logger(ExchangeProvider.name);
|
||||||
|
|
||||||
|
async fetchEvents(
|
||||||
|
source: { url: string; username?: string; password?: string; exchangeMode?: string | null; id: string; color?: string | null },
|
||||||
|
from: Date,
|
||||||
|
to: Date,
|
||||||
|
): Promise<CalendarEvent[]> {
|
||||||
|
// Stub — implemented in Task 2
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
async testConnection(
|
||||||
|
source: { url: string; username?: string; password?: string; exchangeMode?: string | null; id: string },
|
||||||
|
): Promise<boolean> {
|
||||||
|
// Stub — implemented in Task 2
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { Injectable, Logger } from '@nestjs/common';
|
||||||
|
import { CalendarEvent, CalendarProvider } from '../calendar.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ICS calendar provider — fetches and parses .ics files via HTTPS.
|
||||||
|
* Uses node-ical for parsing. Full implementation in Task 2.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class ICSProvider implements CalendarProvider {
|
||||||
|
private readonly logger = new Logger(ICSProvider.name);
|
||||||
|
|
||||||
|
async fetchEvents(
|
||||||
|
source: { url: string; id: string; color?: string | null },
|
||||||
|
from: Date,
|
||||||
|
to: Date,
|
||||||
|
): Promise<CalendarEvent[]> {
|
||||||
|
// Stub — implemented in Task 2
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
async testConnection(
|
||||||
|
source: { url: string; id: string },
|
||||||
|
): Promise<boolean> {
|
||||||
|
// Stub — implemented in Task 2
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+365
-5
@@ -20,6 +20,9 @@ importers:
|
|||||||
|
|
||||||
apps/api:
|
apps/api:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@microsoft/microsoft-graph-client':
|
||||||
|
specifier: 3.0.7
|
||||||
|
version: 3.0.7
|
||||||
'@nestjs-modules/mailer':
|
'@nestjs-modules/mailer':
|
||||||
specifier: ^2.3.7
|
specifier: ^2.3.7
|
||||||
version: 2.3.7(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.27)(chokidar@4.0.3)(nodemailer@9.0.1)(svgo@4.0.1)(terser@5.48.0)(typescript@5.9.3)
|
version: 2.3.7(@nestjs/common@11.1.27(class-transformer@0.5.1)(class-validator@0.15.1)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.27)(chokidar@4.0.3)(nodemailer@9.0.1)(svgo@4.0.1)(terser@5.48.0)(typescript@5.9.3)
|
||||||
@@ -65,9 +68,15 @@ importers:
|
|||||||
cookie-parser:
|
cookie-parser:
|
||||||
specifier: ^1.4.7
|
specifier: ^1.4.7
|
||||||
version: 1.4.7
|
version: 1.4.7
|
||||||
|
ews-javascript-api:
|
||||||
|
specifier: 0.15.3
|
||||||
|
version: 0.15.3
|
||||||
ldapts:
|
ldapts:
|
||||||
specifier: ^8.1.8
|
specifier: ^8.1.8
|
||||||
version: 8.1.8
|
version: 8.1.8
|
||||||
|
node-ical:
|
||||||
|
specifier: 0.26.1
|
||||||
|
version: 0.26.1
|
||||||
nodemailer:
|
nodemailer:
|
||||||
specifier: ^9.0.1
|
specifier: ^9.0.1
|
||||||
version: 9.0.1
|
version: 9.0.1
|
||||||
@@ -86,6 +95,9 @@ importers:
|
|||||||
rxjs:
|
rxjs:
|
||||||
specifier: ^7.0.0
|
specifier: ^7.0.0
|
||||||
version: 7.8.2
|
version: 7.8.2
|
||||||
|
tsdav:
|
||||||
|
specifier: 2.2.2
|
||||||
|
version: 2.2.2
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@nestjs/cli':
|
'@nestjs/cli':
|
||||||
specifier: ^11.0.0
|
specifier: ^11.0.0
|
||||||
@@ -261,6 +273,14 @@ packages:
|
|||||||
'@asamuzakjp/nwsapi@2.3.9':
|
'@asamuzakjp/nwsapi@2.3.9':
|
||||||
resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==}
|
resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==}
|
||||||
|
|
||||||
|
'@azure/msal-common@14.16.1':
|
||||||
|
resolution: {integrity: sha512-nyxsA6NA4SVKh5YyRpbSXiMr7oQbwark7JU9LMeg6tJYTSPyAGkdx61wPT4gyxZfxlSxMMEyAsWaubBlNyIa1w==}
|
||||||
|
engines: {node: '>=0.8.0'}
|
||||||
|
|
||||||
|
'@azure/msal-node@2.16.3':
|
||||||
|
resolution: {integrity: sha512-CO+SE4weOsfJf+C5LM8argzvotrXw252/ZU6SM2Tz63fEblhH1uuVaaO4ISYFuN4Q6BhTo7I3qIdi8ydUQCqhw==}
|
||||||
|
engines: {node: '>=16'}
|
||||||
|
|
||||||
'@babel/code-frame@7.29.7':
|
'@babel/code-frame@7.29.7':
|
||||||
resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==}
|
resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
@@ -474,6 +494,13 @@ packages:
|
|||||||
'@epic-web/invariant@1.0.0':
|
'@epic-web/invariant@1.0.0':
|
||||||
resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==}
|
resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==}
|
||||||
|
|
||||||
|
'@ewsjs/ntlm-client@3.0.1':
|
||||||
|
resolution: {integrity: sha512-eJEyxiR0Eb1kRU0N96ISubBgyhZJ8PXhw+gj5m5My+M5CqDEn8Ae2xPHiSyo0fUWiSj1A2tQ+kk3PZmursR5kQ==}
|
||||||
|
engines: {node: '>=4.0.0'}
|
||||||
|
|
||||||
|
'@ewsjs/xhr@3.1.3':
|
||||||
|
resolution: {integrity: sha512-vUMv1XwUvoGmlhLl0b/zXDB7qIUz4WCQqy70vsdl71RhnWXxnlUA/hIL0VkOBJSLBPEBkhsmERkbhBpnGvpkng==}
|
||||||
|
|
||||||
'@exodus/bytes@1.15.1':
|
'@exodus/bytes@1.15.1':
|
||||||
resolution: {integrity: sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==}
|
resolution: {integrity: sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==}
|
||||||
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
|
engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0}
|
||||||
@@ -802,10 +829,32 @@ packages:
|
|||||||
'@jridgewell/trace-mapping@0.3.31':
|
'@jridgewell/trace-mapping@0.3.31':
|
||||||
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
|
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
|
||||||
|
|
||||||
|
'@js-temporal/polyfill@0.5.1':
|
||||||
|
resolution: {integrity: sha512-hloP58zRVCRSpgDxmqCWJNlizAlUgJFqG2ypq79DCvyv9tHjRYMDOcPFjzfl/A1/YxDvRCZz8wvZvmapQnKwFQ==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
'@lukeed/csprng@1.1.0':
|
'@lukeed/csprng@1.1.0':
|
||||||
resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==}
|
resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
'@microsoft/microsoft-graph-client@3.0.7':
|
||||||
|
resolution: {integrity: sha512-/AazAV/F+HK4LIywF9C+NYHcJo038zEnWkteilcxC1FM/uK/4NVGDKGrxx7nNq1ybspAroRKT4I1FHfxQzxkUw==}
|
||||||
|
engines: {node: '>=12.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
'@azure/identity': '*'
|
||||||
|
'@azure/msal-browser': '*'
|
||||||
|
buffer: '*'
|
||||||
|
stream-browserify: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@azure/identity':
|
||||||
|
optional: true
|
||||||
|
'@azure/msal-browser':
|
||||||
|
optional: true
|
||||||
|
buffer:
|
||||||
|
optional: true
|
||||||
|
stream-browserify:
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@napi-rs/wasm-runtime@1.1.5':
|
'@napi-rs/wasm-runtime@1.1.5':
|
||||||
resolution: {integrity: sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==}
|
resolution: {integrity: sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -1687,6 +1736,10 @@ packages:
|
|||||||
'@webassemblyjs/wast-printer@1.14.1':
|
'@webassemblyjs/wast-printer@1.14.1':
|
||||||
resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==}
|
resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==}
|
||||||
|
|
||||||
|
'@xmldom/xmldom@0.8.13':
|
||||||
|
resolution: {integrity: sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==}
|
||||||
|
engines: {node: '>=10.0.0'}
|
||||||
|
|
||||||
'@xtuc/ieee754@1.2.0':
|
'@xtuc/ieee754@1.2.0':
|
||||||
resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==}
|
resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==}
|
||||||
|
|
||||||
@@ -1723,6 +1776,14 @@ packages:
|
|||||||
engines: {node: '>=0.4.0'}
|
engines: {node: '>=0.4.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
agent-base@6.0.2:
|
||||||
|
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
|
||||||
|
engines: {node: '>= 6.0.0'}
|
||||||
|
|
||||||
|
agent-base@7.1.4:
|
||||||
|
resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==}
|
||||||
|
engines: {node: '>= 14'}
|
||||||
|
|
||||||
ajv-formats@2.1.1:
|
ajv-formats@2.1.1:
|
||||||
resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
|
resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -1820,6 +1881,12 @@ packages:
|
|||||||
resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
|
resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
|
asynckit@0.4.0:
|
||||||
|
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
||||||
|
|
||||||
|
axios@1.18.1:
|
||||||
|
resolution: {integrity: sha512-3nTvFlvpn9Zu/RkHUqtc7/+al4UpRW5az71ap5zccp6e8RAYEzhMTecX8Dz1wWDYrPpUoB1HAQEGEAEvUr7S9g==}
|
||||||
|
|
||||||
babel-walk@3.0.0-canary-5:
|
babel-walk@3.0.0-canary-5:
|
||||||
resolution: {integrity: sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==}
|
resolution: {integrity: sha512-GAwkz0AihzY5bkwIY5QDR+LvsRQgB/B+1foMPvi0FZPMl5fjD7ICiznUiBdLYMH1QYe6vqu4gWYytZOccLouFw==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
@@ -1834,6 +1901,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==}
|
resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==}
|
||||||
engines: {node: 18 || 20 || >=22}
|
engines: {node: 18 || 20 || >=22}
|
||||||
|
|
||||||
|
base-64@1.0.0:
|
||||||
|
resolution: {integrity: sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==}
|
||||||
|
|
||||||
base64-js@1.5.1:
|
base64-js@1.5.1:
|
||||||
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
||||||
|
|
||||||
@@ -2018,6 +2088,10 @@ packages:
|
|||||||
color-name@1.1.4:
|
color-name@1.1.4:
|
||||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||||
|
|
||||||
|
combined-stream@1.0.8:
|
||||||
|
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
comma-separated-tokens@2.0.3:
|
comma-separated-tokens@2.0.3:
|
||||||
resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
|
resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==}
|
||||||
|
|
||||||
@@ -2237,6 +2311,10 @@ packages:
|
|||||||
defu@6.1.7:
|
defu@6.1.7:
|
||||||
resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==}
|
resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==}
|
||||||
|
|
||||||
|
delayed-stream@1.0.0:
|
||||||
|
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
|
||||||
|
engines: {node: '>=0.4.0'}
|
||||||
|
|
||||||
depd@2.0.0:
|
depd@2.0.0:
|
||||||
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
|
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
@@ -2245,6 +2323,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
|
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
des.js@1.1.0:
|
||||||
|
resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==}
|
||||||
|
|
||||||
destr@2.0.5:
|
destr@2.0.5:
|
||||||
resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==}
|
resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==}
|
||||||
|
|
||||||
@@ -2421,6 +2502,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==}
|
resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
es-set-tostringtag@2.1.0:
|
||||||
|
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
|
||||||
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
escalade@3.2.0:
|
escalade@3.2.0:
|
||||||
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
|
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@@ -2484,6 +2569,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
|
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
|
||||||
engines: {node: '>=0.8.x'}
|
engines: {node: '>=0.8.x'}
|
||||||
|
|
||||||
|
ews-javascript-api@0.15.3:
|
||||||
|
resolution: {integrity: sha512-7re0Q/FSHyM9MgcPxjcNZlQuyzHmU7wHOdODRmQYMgxlGU8HB73cZdysyia4rE+CQCFyqhZqV8vMddYJXDwA9Q==}
|
||||||
|
|
||||||
execa@5.1.1:
|
execa@5.1.1:
|
||||||
resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
|
resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@@ -2545,6 +2633,15 @@ packages:
|
|||||||
resolution: {integrity: sha512-5SM1+H2CcuJ3gGEwTiVo/+nd/hYpNj9Ch3iMDOQ58ndY+VGQ2QdvaUTkd3otjZvYnd/8LF/HkJ5cx7PBq0orCQ==}
|
resolution: {integrity: sha512-5SM1+H2CcuJ3gGEwTiVo/+nd/hYpNj9Ch3iMDOQ58ndY+VGQ2QdvaUTkd3otjZvYnd/8LF/HkJ5cx7PBq0orCQ==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
follow-redirects@1.16.0:
|
||||||
|
resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==}
|
||||||
|
engines: {node: '>=4.0'}
|
||||||
|
peerDependencies:
|
||||||
|
debug: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
debug:
|
||||||
|
optional: true
|
||||||
|
|
||||||
foreground-child@3.3.1:
|
foreground-child@3.3.1:
|
||||||
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
|
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
@@ -2556,6 +2653,10 @@ packages:
|
|||||||
typescript: '>3.6.0'
|
typescript: '>3.6.0'
|
||||||
webpack: ^5.11.0
|
webpack: ^5.11.0
|
||||||
|
|
||||||
|
form-data@4.0.6:
|
||||||
|
resolution: {integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==}
|
||||||
|
engines: {node: '>= 6'}
|
||||||
|
|
||||||
forwarded@0.2.0:
|
forwarded@0.2.0:
|
||||||
resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
|
resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
@@ -2754,10 +2855,27 @@ packages:
|
|||||||
htmlparser2@9.1.0:
|
htmlparser2@9.1.0:
|
||||||
resolution: {integrity: sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==}
|
resolution: {integrity: sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==}
|
||||||
|
|
||||||
|
http-cookie-agent@5.0.4:
|
||||||
|
resolution: {integrity: sha512-OtvikW69RvfyP6Lsequ0fN5R49S+8QcS9zwd58k6VSr6r57T8G29BkPdyrBcSwLq6ExLs9V+rBlfxu7gDstJag==}
|
||||||
|
engines: {node: '>=14.18.0 <15.0.0 || >=16.0.0'}
|
||||||
|
peerDependencies:
|
||||||
|
deasync: ^0.1.26
|
||||||
|
tough-cookie: ^4.0.0
|
||||||
|
undici: ^5.11.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
deasync:
|
||||||
|
optional: true
|
||||||
|
undici:
|
||||||
|
optional: true
|
||||||
|
|
||||||
http-errors@2.0.1:
|
http-errors@2.0.1:
|
||||||
resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
|
resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
|
https-proxy-agent@5.0.1:
|
||||||
|
resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
|
||||||
|
engines: {node: '>= 6'}
|
||||||
|
|
||||||
human-signals@2.1.0:
|
human-signals@2.1.0:
|
||||||
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
|
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
|
||||||
engines: {node: '>=10.17.0'}
|
engines: {node: '>=10.17.0'}
|
||||||
@@ -2908,6 +3026,9 @@ packages:
|
|||||||
js-cookie@3.0.8:
|
js-cookie@3.0.8:
|
||||||
resolution: {integrity: sha512-yeJd4aNAdYZQjaon2bpD/Gb0B/omw7HQOsynXXcOiWVCacbBcPlgn8S/d1X6blFSaHao7ozqtW7NZW19xpCtIw==}
|
resolution: {integrity: sha512-yeJd4aNAdYZQjaon2bpD/Gb0B/omw7HQOsynXXcOiWVCacbBcPlgn8S/d1X6blFSaHao7ozqtW7NZW19xpCtIw==}
|
||||||
|
|
||||||
|
js-md4@0.3.2:
|
||||||
|
resolution: {integrity: sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA==}
|
||||||
|
|
||||||
js-stringify@1.0.2:
|
js-stringify@1.0.2:
|
||||||
resolution: {integrity: sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==}
|
resolution: {integrity: sha512-rtS5ATOo2Q5k1G+DADISilDA6lv79zIiwFd6CcjuIxGKLFm5C+RLImRscVap9k55i+MOZwgliw+NejvkLuGD5g==}
|
||||||
|
|
||||||
@@ -2918,6 +3039,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==}
|
resolution: {integrity: sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
jsbi@4.3.2:
|
||||||
|
resolution: {integrity: sha512-9fqMSQbhJykSeii05nxKl4m6Eqn2P6rOlYiS+C5Dr/HPIU/7yZxu5qzbs40tgaFORiw2Amd0mirjxatXYMkIew==}
|
||||||
|
|
||||||
jsdom@29.1.1:
|
jsdom@29.1.1:
|
||||||
resolution: {integrity: sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==}
|
resolution: {integrity: sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==}
|
||||||
engines: {node: ^20.19.0 || ^22.13.0 || >=24.0.0}
|
engines: {node: ^20.19.0 || ^22.13.0 || >=24.0.0}
|
||||||
@@ -3335,6 +3459,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
|
resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
|
||||||
|
minimalistic-assert@1.0.1:
|
||||||
|
resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==}
|
||||||
|
|
||||||
minimatch@10.2.5:
|
minimatch@10.2.5:
|
||||||
resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==}
|
resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==}
|
||||||
engines: {node: 18 || 20 || >=22}
|
engines: {node: 18 || 20 || >=22}
|
||||||
@@ -3448,6 +3575,12 @@ packages:
|
|||||||
resolution: {integrity: sha512-cOrV1zC8SekUpZ2YGT174iWADRnuttYMtrAypQ1UvYXOUCOUc1DvwB8Dx8DH9+51+WyA0fNVOmUDx1Bc8qztqQ==}
|
resolution: {integrity: sha512-cOrV1zC8SekUpZ2YGT174iWADRnuttYMtrAypQ1UvYXOUCOUc1DvwB8Dx8DH9+51+WyA0fNVOmUDx1Bc8qztqQ==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
moment-timezone@0.5.48:
|
||||||
|
resolution: {integrity: sha512-f22b8LV1gbTO2ms2j2z13MuPogNoh5UzxL3nzNAYKGraILnbGc9NEE6dyiiiLv46DGRb8A4kg8UKWLjPthxBHw==}
|
||||||
|
|
||||||
|
moment@2.30.1:
|
||||||
|
resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==}
|
||||||
|
|
||||||
ms@2.1.3:
|
ms@2.1.3:
|
||||||
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||||
|
|
||||||
@@ -3531,6 +3664,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==}
|
resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
node-ical@0.26.1:
|
||||||
|
resolution: {integrity: sha512-KoYLpsz7Ga9lPDpt9vy0iKcgcb/9Ix7ICRZd0csLXMl2lZOSONGj7HrcktJFR7Jid1l44Zu1H4k/1nB04rWPgQ==}
|
||||||
|
engines: {node: '>=20'}
|
||||||
|
|
||||||
node-releases@2.0.48:
|
node-releases@2.0.48:
|
||||||
resolution: {integrity: sha512-1uz8041X6LoI6ZSdZacM9lVY28vuzDlSKitnpbSNK0RfKoIJkX29NBPVEFXhnuSuEOA9Ww0xnPJ+ILWbGAv8DA==}
|
resolution: {integrity: sha512-1uz8041X6LoI6ZSdZacM9lVY28vuzDlSKitnpbSNK0RfKoIJkX29NBPVEFXhnuSuEOA9Ww0xnPJ+ILWbGAv8DA==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -3949,6 +4086,13 @@ packages:
|
|||||||
resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
|
resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
|
||||||
engines: {node: '>= 0.10'}
|
engines: {node: '>= 0.10'}
|
||||||
|
|
||||||
|
proxy-from-env@2.1.0:
|
||||||
|
resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
psl@1.15.0:
|
||||||
|
resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==}
|
||||||
|
|
||||||
pug-attrs@3.0.0:
|
pug-attrs@3.0.0:
|
||||||
resolution: {integrity: sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==}
|
resolution: {integrity: sha512-azINV9dUtzPMFQktvTXciNAfAuVh/L/JCl0vtPCwvOA21uZrC08K/UnmrL+SXGEVc1FwzjW62+xw5S/uaLj6cA==}
|
||||||
|
|
||||||
@@ -4000,6 +4144,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==}
|
resolution: {integrity: sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==}
|
||||||
engines: {node: '>=0.6'}
|
engines: {node: '>=0.6'}
|
||||||
|
|
||||||
|
querystringify@2.2.0:
|
||||||
|
resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
|
||||||
|
|
||||||
range-parser@1.2.1:
|
range-parser@1.2.1:
|
||||||
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
|
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
@@ -4138,6 +4285,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
|
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
requires-port@1.0.0:
|
||||||
|
resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
|
||||||
|
|
||||||
resize-observer-polyfill@1.5.1:
|
resize-observer-polyfill@1.5.1:
|
||||||
resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==}
|
resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==}
|
||||||
|
|
||||||
@@ -4163,6 +4313,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==}
|
resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==}
|
||||||
engines: {node: '>= 18'}
|
engines: {node: '>= 18'}
|
||||||
|
|
||||||
|
rrule-temporal@1.5.3:
|
||||||
|
resolution: {integrity: sha512-qALnXyu4MKNUeykkkO0r6Xxl5or3rM8Cf6ibKIe/29sgmq3tGm1oNq4G1Ddp8Ku3mnKmvC3+3yFAJ3OgOu6OJw==}
|
||||||
|
|
||||||
run-applescript@5.0.0:
|
run-applescript@5.0.0:
|
||||||
resolution: {integrity: sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==}
|
resolution: {integrity: sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
@@ -4391,6 +4544,12 @@ packages:
|
|||||||
resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==}
|
resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
temporal-polyfill@0.3.2:
|
||||||
|
resolution: {integrity: sha512-TzHthD/heRK947GNiSu3Y5gSPpeUDH34+LESnfsq8bqpFhsB79HFBX8+Z834IVX68P3EUyRPZK5bL/1fh437Eg==}
|
||||||
|
|
||||||
|
temporal-spec@0.3.1:
|
||||||
|
resolution: {integrity: sha512-B4TUhezh9knfSIMwt7RVggApDRJZo73uZdj8AacL2mZ8RP5KtLianh2MXxL06GN9ESYiIsiuoLQhgVfwe55Yhw==}
|
||||||
|
|
||||||
terser-webpack-plugin@5.6.1:
|
terser-webpack-plugin@5.6.1:
|
||||||
resolution: {integrity: sha512-201R5j+sJpK8nFWwKVyNfZot8FaJbLZDq5evriVzbV1wDtSXDjRUDRfJzHpAaxFDMEhsZL1QkeqM61wgsS3KaQ==}
|
resolution: {integrity: sha512-201R5j+sJpK8nFWwKVyNfZot8FaJbLZDq5evriVzbV1wDtSXDjRUDRfJzHpAaxFDMEhsZL1QkeqM61wgsS3KaQ==}
|
||||||
engines: {node: '>= 10.13.0'}
|
engines: {node: '>= 10.13.0'}
|
||||||
@@ -4476,6 +4635,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==}
|
resolution: {integrity: sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==}
|
||||||
engines: {node: '>=14.16'}
|
engines: {node: '>=14.16'}
|
||||||
|
|
||||||
|
tough-cookie@4.1.4:
|
||||||
|
resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
tough-cookie@6.0.1:
|
tough-cookie@6.0.1:
|
||||||
resolution: {integrity: sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==}
|
resolution: {integrity: sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
@@ -4498,6 +4661,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==}
|
resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
tsdav@2.2.2:
|
||||||
|
resolution: {integrity: sha512-/uC/RItcdYVxUj8b2gT4CorAkUmDFUuzhgS4XVT+OVzGRE80hH5ldubcWH13dHa2T9rNaXu6UIEWHlQ1UL7H1Q==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
tslib@2.8.1:
|
tslib@2.8.1:
|
||||||
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
||||||
|
|
||||||
@@ -4572,6 +4739,10 @@ packages:
|
|||||||
unist-util-visit@5.1.0:
|
unist-util-visit@5.1.0:
|
||||||
resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==}
|
resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==}
|
||||||
|
|
||||||
|
universalify@0.2.0:
|
||||||
|
resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==}
|
||||||
|
engines: {node: '>= 4.0.0'}
|
||||||
|
|
||||||
universalify@2.0.1:
|
universalify@2.0.1:
|
||||||
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
|
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
@@ -4589,6 +4760,9 @@ packages:
|
|||||||
uri-js@4.4.1:
|
uri-js@4.4.1:
|
||||||
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
||||||
|
|
||||||
|
url-parse@1.5.10:
|
||||||
|
resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
|
||||||
|
|
||||||
use-intl@4.13.0:
|
use-intl@4.13.0:
|
||||||
resolution: {integrity: sha512-fAFDrWaASxlhXOipcOyb5VDD+YONqj6+8O8EcG/J7RBoOUF3A8YahRWLN+mBxYMrlMQB8N6Voqk5X+YC+HSL0A==}
|
resolution: {integrity: sha512-fAFDrWaASxlhXOipcOyb5VDD+YONqj6+8O8EcG/J7RBoOUF3A8YahRWLN+mBxYMrlMQB8N6Voqk5X+YC+HSL0A==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -4601,6 +4775,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
|
resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
|
||||||
engines: {node: '>= 0.4.0'}
|
engines: {node: '>= 0.4.0'}
|
||||||
|
|
||||||
|
uuid@8.3.2:
|
||||||
|
resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
|
||||||
|
deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
uuid@9.0.1:
|
uuid@9.0.1:
|
||||||
resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
|
resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
|
||||||
deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).
|
deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).
|
||||||
@@ -4804,6 +4983,10 @@ packages:
|
|||||||
wrappy@1.0.2:
|
wrappy@1.0.2:
|
||||||
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
|
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
|
||||||
|
|
||||||
|
xml-js@1.6.11:
|
||||||
|
resolution: {integrity: sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
xml-name-validator@5.0.0:
|
xml-name-validator@5.0.0:
|
||||||
resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==}
|
resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
@@ -4931,6 +5114,14 @@ snapshots:
|
|||||||
|
|
||||||
'@asamuzakjp/nwsapi@2.3.9': {}
|
'@asamuzakjp/nwsapi@2.3.9': {}
|
||||||
|
|
||||||
|
'@azure/msal-common@14.16.1': {}
|
||||||
|
|
||||||
|
'@azure/msal-node@2.16.3':
|
||||||
|
dependencies:
|
||||||
|
'@azure/msal-common': 14.16.1
|
||||||
|
jsonwebtoken: 9.0.3
|
||||||
|
uuid: 8.3.2
|
||||||
|
|
||||||
'@babel/code-frame@7.29.7':
|
'@babel/code-frame@7.29.7':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/helper-validator-identifier': 7.29.7
|
'@babel/helper-validator-identifier': 7.29.7
|
||||||
@@ -5096,6 +5287,25 @@ snapshots:
|
|||||||
|
|
||||||
'@epic-web/invariant@1.0.0': {}
|
'@epic-web/invariant@1.0.0': {}
|
||||||
|
|
||||||
|
'@ewsjs/ntlm-client@3.0.1':
|
||||||
|
dependencies:
|
||||||
|
des.js: 1.1.0
|
||||||
|
js-md4: 0.3.2
|
||||||
|
optionalDependencies:
|
||||||
|
extend: 3.0.2
|
||||||
|
|
||||||
|
'@ewsjs/xhr@3.1.3':
|
||||||
|
dependencies:
|
||||||
|
'@ewsjs/ntlm-client': 3.0.1
|
||||||
|
axios: 1.18.1
|
||||||
|
http-cookie-agent: 5.0.4(tough-cookie@4.1.4)
|
||||||
|
tough-cookie: 4.1.4
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- deasync
|
||||||
|
- debug
|
||||||
|
- supports-color
|
||||||
|
- undici
|
||||||
|
|
||||||
'@exodus/bytes@1.15.1': {}
|
'@exodus/bytes@1.15.1': {}
|
||||||
|
|
||||||
'@formatjs/fast-memoize@3.1.6': {}
|
'@formatjs/fast-memoize@3.1.6': {}
|
||||||
@@ -5384,8 +5594,17 @@ snapshots:
|
|||||||
'@jridgewell/resolve-uri': 3.1.2
|
'@jridgewell/resolve-uri': 3.1.2
|
||||||
'@jridgewell/sourcemap-codec': 1.5.5
|
'@jridgewell/sourcemap-codec': 1.5.5
|
||||||
|
|
||||||
|
'@js-temporal/polyfill@0.5.1':
|
||||||
|
dependencies:
|
||||||
|
jsbi: 4.3.2
|
||||||
|
|
||||||
'@lukeed/csprng@1.1.0': {}
|
'@lukeed/csprng@1.1.0': {}
|
||||||
|
|
||||||
|
'@microsoft/microsoft-graph-client@3.0.7':
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.29.7
|
||||||
|
tslib: 2.8.1
|
||||||
|
|
||||||
'@napi-rs/wasm-runtime@1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)':
|
'@napi-rs/wasm-runtime@1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@emnapi/core': 1.10.0
|
'@emnapi/core': 1.10.0
|
||||||
@@ -6252,6 +6471,8 @@ snapshots:
|
|||||||
'@webassemblyjs/ast': 1.14.1
|
'@webassemblyjs/ast': 1.14.1
|
||||||
'@xtuc/long': 4.2.2
|
'@xtuc/long': 4.2.2
|
||||||
|
|
||||||
|
'@xmldom/xmldom@0.8.13': {}
|
||||||
|
|
||||||
'@xtuc/ieee754@1.2.0': {}
|
'@xtuc/ieee754@1.2.0': {}
|
||||||
|
|
||||||
'@xtuc/long@4.2.2': {}
|
'@xtuc/long@4.2.2': {}
|
||||||
@@ -6283,6 +6504,14 @@ snapshots:
|
|||||||
|
|
||||||
acorn@8.17.0: {}
|
acorn@8.17.0: {}
|
||||||
|
|
||||||
|
agent-base@6.0.2:
|
||||||
|
dependencies:
|
||||||
|
debug: 4.4.3
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
agent-base@7.1.4: {}
|
||||||
|
|
||||||
ajv-formats@2.1.1(ajv@8.20.0):
|
ajv-formats@2.1.1(ajv@8.20.0):
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
ajv: 8.20.0
|
ajv: 8.20.0
|
||||||
@@ -6372,6 +6601,18 @@ snapshots:
|
|||||||
|
|
||||||
assertion-error@2.0.1: {}
|
assertion-error@2.0.1: {}
|
||||||
|
|
||||||
|
asynckit@0.4.0: {}
|
||||||
|
|
||||||
|
axios@1.18.1:
|
||||||
|
dependencies:
|
||||||
|
follow-redirects: 1.16.0
|
||||||
|
form-data: 4.0.6
|
||||||
|
https-proxy-agent: 5.0.1
|
||||||
|
proxy-from-env: 2.1.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- debug
|
||||||
|
- supports-color
|
||||||
|
|
||||||
babel-walk@3.0.0-canary-5:
|
babel-walk@3.0.0-canary-5:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/types': 7.29.7
|
'@babel/types': 7.29.7
|
||||||
@@ -6383,6 +6624,8 @@ snapshots:
|
|||||||
|
|
||||||
balanced-match@4.0.4: {}
|
balanced-match@4.0.4: {}
|
||||||
|
|
||||||
|
base-64@1.0.0: {}
|
||||||
|
|
||||||
base64-js@1.5.1: {}
|
base64-js@1.5.1: {}
|
||||||
|
|
||||||
baseline-browser-mapping@2.10.38: {}
|
baseline-browser-mapping@2.10.38: {}
|
||||||
@@ -6600,6 +6843,10 @@ snapshots:
|
|||||||
|
|
||||||
color-name@1.1.4: {}
|
color-name@1.1.4: {}
|
||||||
|
|
||||||
|
combined-stream@1.0.8:
|
||||||
|
dependencies:
|
||||||
|
delayed-stream: 1.0.0
|
||||||
|
|
||||||
comma-separated-tokens@2.0.3: {}
|
comma-separated-tokens@2.0.3: {}
|
||||||
|
|
||||||
commander@10.0.1:
|
commander@10.0.1:
|
||||||
@@ -6838,10 +7085,17 @@ snapshots:
|
|||||||
|
|
||||||
defu@6.1.7: {}
|
defu@6.1.7: {}
|
||||||
|
|
||||||
|
delayed-stream@1.0.0: {}
|
||||||
|
|
||||||
depd@2.0.0: {}
|
depd@2.0.0: {}
|
||||||
|
|
||||||
dequal@2.0.3: {}
|
dequal@2.0.3: {}
|
||||||
|
|
||||||
|
des.js@1.1.0:
|
||||||
|
dependencies:
|
||||||
|
inherits: 2.0.4
|
||||||
|
minimalistic-assert: 1.0.1
|
||||||
|
|
||||||
destr@2.0.5: {}
|
destr@2.0.5: {}
|
||||||
|
|
||||||
detect-indent@6.1.0:
|
detect-indent@6.1.0:
|
||||||
@@ -7017,6 +7271,13 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
|
|
||||||
|
es-set-tostringtag@2.1.0:
|
||||||
|
dependencies:
|
||||||
|
es-errors: 1.3.0
|
||||||
|
get-intrinsic: 1.3.0
|
||||||
|
has-tostringtag: 1.0.2
|
||||||
|
hasown: 2.0.4
|
||||||
|
|
||||||
escalade@3.2.0: {}
|
escalade@3.2.0: {}
|
||||||
|
|
||||||
escape-goat@3.0.0:
|
escape-goat@3.0.0:
|
||||||
@@ -7060,6 +7321,21 @@ snapshots:
|
|||||||
|
|
||||||
events@3.3.0: {}
|
events@3.3.0: {}
|
||||||
|
|
||||||
|
ews-javascript-api@0.15.3:
|
||||||
|
dependencies:
|
||||||
|
'@azure/msal-node': 2.16.3
|
||||||
|
'@ewsjs/xhr': 3.1.3
|
||||||
|
'@xmldom/xmldom': 0.8.13
|
||||||
|
base64-js: 1.5.1
|
||||||
|
moment: 2.30.1
|
||||||
|
moment-timezone: 0.5.48
|
||||||
|
uuid: 9.0.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- deasync
|
||||||
|
- debug
|
||||||
|
- supports-color
|
||||||
|
- undici
|
||||||
|
|
||||||
execa@5.1.1:
|
execa@5.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
cross-spawn: 7.0.6
|
cross-spawn: 7.0.6
|
||||||
@@ -7163,6 +7439,8 @@ snapshots:
|
|||||||
rc: 1.2.8
|
rc: 1.2.8
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
follow-redirects@1.16.0: {}
|
||||||
|
|
||||||
foreground-child@3.3.1:
|
foreground-child@3.3.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
cross-spawn: 7.0.6
|
cross-spawn: 7.0.6
|
||||||
@@ -7186,6 +7464,14 @@ snapshots:
|
|||||||
typescript: 5.9.3
|
typescript: 5.9.3
|
||||||
webpack: 5.106.2(@swc/core@1.15.41)(cssnano@7.1.9(postcss@8.5.15))(postcss@8.5.15)
|
webpack: 5.106.2(@swc/core@1.15.41)(cssnano@7.1.9(postcss@8.5.15))(postcss@8.5.15)
|
||||||
|
|
||||||
|
form-data@4.0.6:
|
||||||
|
dependencies:
|
||||||
|
asynckit: 0.4.0
|
||||||
|
combined-stream: 1.0.8
|
||||||
|
es-set-tostringtag: 2.1.0
|
||||||
|
hasown: 2.0.4
|
||||||
|
mime-types: 2.1.35
|
||||||
|
|
||||||
forwarded@0.2.0: {}
|
forwarded@0.2.0: {}
|
||||||
|
|
||||||
fresh@2.0.0: {}
|
fresh@2.0.0: {}
|
||||||
@@ -7290,7 +7576,6 @@ snapshots:
|
|||||||
has-tostringtag@1.0.2:
|
has-tostringtag@1.0.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
has-symbols: 1.1.0
|
has-symbols: 1.1.0
|
||||||
optional: true
|
|
||||||
|
|
||||||
hasown@2.0.4:
|
hasown@2.0.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -7493,6 +7778,11 @@ snapshots:
|
|||||||
entities: 4.5.0
|
entities: 4.5.0
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
http-cookie-agent@5.0.4(tough-cookie@4.1.4):
|
||||||
|
dependencies:
|
||||||
|
agent-base: 7.1.4
|
||||||
|
tough-cookie: 4.1.4
|
||||||
|
|
||||||
http-errors@2.0.1:
|
http-errors@2.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
depd: 2.0.0
|
depd: 2.0.0
|
||||||
@@ -7501,6 +7791,13 @@ snapshots:
|
|||||||
statuses: 2.0.2
|
statuses: 2.0.2
|
||||||
toidentifier: 1.0.1
|
toidentifier: 1.0.1
|
||||||
|
|
||||||
|
https-proxy-agent@5.0.1:
|
||||||
|
dependencies:
|
||||||
|
agent-base: 6.0.2
|
||||||
|
debug: 4.4.3
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
human-signals@2.1.0:
|
human-signals@2.1.0:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -7645,6 +7942,8 @@ snapshots:
|
|||||||
js-cookie@3.0.8:
|
js-cookie@3.0.8:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
js-md4@0.3.2: {}
|
||||||
|
|
||||||
js-stringify@1.0.2:
|
js-stringify@1.0.2:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
@@ -7654,6 +7953,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
argparse: 2.0.1
|
argparse: 2.0.1
|
||||||
|
|
||||||
|
jsbi@4.3.2: {}
|
||||||
|
|
||||||
jsdom@29.1.1:
|
jsdom@29.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@asamuzakjp/css-color': 5.1.11
|
'@asamuzakjp/css-color': 5.1.11
|
||||||
@@ -8278,6 +8579,8 @@ snapshots:
|
|||||||
|
|
||||||
min-indent@1.0.1: {}
|
min-indent@1.0.1: {}
|
||||||
|
|
||||||
|
minimalistic-assert@1.0.1: {}
|
||||||
|
|
||||||
minimatch@10.2.5:
|
minimatch@10.2.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
brace-expansion: 5.0.6
|
brace-expansion: 5.0.6
|
||||||
@@ -8785,6 +9088,12 @@ snapshots:
|
|||||||
- uncss
|
- uncss
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
moment-timezone@0.5.48:
|
||||||
|
dependencies:
|
||||||
|
moment: 2.30.1
|
||||||
|
|
||||||
|
moment@2.30.1: {}
|
||||||
|
|
||||||
ms@2.1.3: {}
|
ms@2.1.3: {}
|
||||||
|
|
||||||
multer@2.1.1:
|
multer@2.1.1:
|
||||||
@@ -8863,6 +9172,11 @@ snapshots:
|
|||||||
|
|
||||||
node-gyp-build@4.8.4: {}
|
node-gyp-build@4.8.4: {}
|
||||||
|
|
||||||
|
node-ical@0.26.1:
|
||||||
|
dependencies:
|
||||||
|
rrule-temporal: 1.5.3
|
||||||
|
temporal-polyfill: 0.3.2
|
||||||
|
|
||||||
node-releases@2.0.48: {}
|
node-releases@2.0.48: {}
|
||||||
|
|
||||||
nodemailer@8.0.11:
|
nodemailer@8.0.11:
|
||||||
@@ -9337,6 +9651,12 @@ snapshots:
|
|||||||
forwarded: 0.2.0
|
forwarded: 0.2.0
|
||||||
ipaddr.js: 1.9.1
|
ipaddr.js: 1.9.1
|
||||||
|
|
||||||
|
proxy-from-env@2.1.0: {}
|
||||||
|
|
||||||
|
psl@1.15.0:
|
||||||
|
dependencies:
|
||||||
|
punycode: 2.3.1
|
||||||
|
|
||||||
pug-attrs@3.0.0:
|
pug-attrs@3.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
constantinople: 4.0.1
|
constantinople: 4.0.1
|
||||||
@@ -9427,6 +9747,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
side-channel: 1.1.1
|
side-channel: 1.1.1
|
||||||
|
|
||||||
|
querystringify@2.2.0: {}
|
||||||
|
|
||||||
range-parser@1.2.1: {}
|
range-parser@1.2.1: {}
|
||||||
|
|
||||||
raw-body@3.0.2:
|
raw-body@3.0.2:
|
||||||
@@ -9648,6 +9970,8 @@ snapshots:
|
|||||||
|
|
||||||
require-from-string@2.0.2: {}
|
require-from-string@2.0.2: {}
|
||||||
|
|
||||||
|
requires-port@1.0.0: {}
|
||||||
|
|
||||||
resize-observer-polyfill@1.5.1: {}
|
resize-observer-polyfill@1.5.1: {}
|
||||||
|
|
||||||
resolve-from@4.0.0: {}
|
resolve-from@4.0.0: {}
|
||||||
@@ -9696,6 +10020,10 @@ snapshots:
|
|||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
rrule-temporal@1.5.3:
|
||||||
|
dependencies:
|
||||||
|
'@js-temporal/polyfill': 0.5.1
|
||||||
|
|
||||||
run-applescript@5.0.0:
|
run-applescript@5.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
execa: 5.1.1
|
execa: 5.1.1
|
||||||
@@ -9713,8 +10041,7 @@ snapshots:
|
|||||||
|
|
||||||
safer-buffer@2.1.2: {}
|
safer-buffer@2.1.2: {}
|
||||||
|
|
||||||
sax@1.6.0:
|
sax@1.6.0: {}
|
||||||
optional: true
|
|
||||||
|
|
||||||
saxes@6.0.0:
|
saxes@6.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -9964,6 +10291,12 @@ snapshots:
|
|||||||
|
|
||||||
tapable@2.3.3: {}
|
tapable@2.3.3: {}
|
||||||
|
|
||||||
|
temporal-polyfill@0.3.2:
|
||||||
|
dependencies:
|
||||||
|
temporal-spec: 0.3.1
|
||||||
|
|
||||||
|
temporal-spec@0.3.1: {}
|
||||||
|
|
||||||
terser-webpack-plugin@5.6.1(@swc/core@1.15.41)(cssnano@7.1.9(postcss@8.5.15))(postcss@8.5.15)(webpack@5.106.2(@swc/core@1.15.41)(cssnano@7.1.9(postcss@8.5.15))(postcss@8.5.15)):
|
terser-webpack-plugin@5.6.1(@swc/core@1.15.41)(cssnano@7.1.9(postcss@8.5.15))(postcss@8.5.15)(webpack@5.106.2(@swc/core@1.15.41)(cssnano@7.1.9(postcss@8.5.15))(postcss@8.5.15)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/trace-mapping': 0.3.31
|
'@jridgewell/trace-mapping': 0.3.31
|
||||||
@@ -10014,6 +10347,13 @@ snapshots:
|
|||||||
'@tokenizer/token': 0.3.0
|
'@tokenizer/token': 0.3.0
|
||||||
ieee754: 1.2.1
|
ieee754: 1.2.1
|
||||||
|
|
||||||
|
tough-cookie@4.1.4:
|
||||||
|
dependencies:
|
||||||
|
psl: 1.15.0
|
||||||
|
punycode: 2.3.1
|
||||||
|
universalify: 0.2.0
|
||||||
|
url-parse: 1.5.10
|
||||||
|
|
||||||
tough-cookie@6.0.1:
|
tough-cookie@6.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
tldts: 7.4.3
|
tldts: 7.4.3
|
||||||
@@ -10039,6 +10379,14 @@ snapshots:
|
|||||||
minimist: 1.2.8
|
minimist: 1.2.8
|
||||||
strip-bom: 3.0.0
|
strip-bom: 3.0.0
|
||||||
|
|
||||||
|
tsdav@2.2.2:
|
||||||
|
dependencies:
|
||||||
|
base-64: 1.0.0
|
||||||
|
debug: 4.4.3
|
||||||
|
xml-js: 1.6.11
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
tslib@2.8.1: {}
|
tslib@2.8.1: {}
|
||||||
|
|
||||||
turbo@2.9.18:
|
turbo@2.9.18:
|
||||||
@@ -10129,6 +10477,8 @@ snapshots:
|
|||||||
unist-util-is: 6.0.1
|
unist-util-is: 6.0.1
|
||||||
unist-util-visit-parents: 6.0.2
|
unist-util-visit-parents: 6.0.2
|
||||||
|
|
||||||
|
universalify@0.2.0: {}
|
||||||
|
|
||||||
universalify@2.0.1: {}
|
universalify@2.0.1: {}
|
||||||
|
|
||||||
unpipe@1.0.0: {}
|
unpipe@1.0.0: {}
|
||||||
@@ -10143,6 +10493,11 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
punycode: 2.3.1
|
punycode: 2.3.1
|
||||||
|
|
||||||
|
url-parse@1.5.10:
|
||||||
|
dependencies:
|
||||||
|
querystringify: 2.2.0
|
||||||
|
requires-port: 1.0.0
|
||||||
|
|
||||||
use-intl@4.13.0(react@19.2.7):
|
use-intl@4.13.0(react@19.2.7):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@formatjs/fast-memoize': 3.1.6
|
'@formatjs/fast-memoize': 3.1.6
|
||||||
@@ -10155,8 +10510,9 @@ snapshots:
|
|||||||
|
|
||||||
utils-merge@1.0.1: {}
|
utils-merge@1.0.1: {}
|
||||||
|
|
||||||
uuid@9.0.1:
|
uuid@8.3.2: {}
|
||||||
optional: true
|
|
||||||
|
uuid@9.0.1: {}
|
||||||
|
|
||||||
valid-data-url@3.0.1:
|
valid-data-url@3.0.1:
|
||||||
optional: true
|
optional: true
|
||||||
@@ -10353,6 +10709,10 @@ snapshots:
|
|||||||
|
|
||||||
wrappy@1.0.2: {}
|
wrappy@1.0.2: {}
|
||||||
|
|
||||||
|
xml-js@1.6.11:
|
||||||
|
dependencies:
|
||||||
|
sax: 1.6.0
|
||||||
|
|
||||||
xml-name-validator@5.0.0: {}
|
xml-name-validator@5.0.0: {}
|
||||||
|
|
||||||
xmlchars@2.2.0: {}
|
xmlchars@2.2.0: {}
|
||||||
|
|||||||
Reference in New Issue
Block a user