diff --git a/backend/mail-plugin/app.js b/backend/mail-plugin/app.js new file mode 100644 index 00000000..1bda7715 --- /dev/null +++ b/backend/mail-plugin/app.js @@ -0,0 +1,2 @@ +#!/usr/bin/env node +import './lib/cli.js'; diff --git a/backend/mail-plugin/package.json b/backend/mail-plugin/package.json new file mode 100644 index 00000000..2f791373 --- /dev/null +++ b/backend/mail-plugin/package.json @@ -0,0 +1,68 @@ +{ + "name": "@openstapps/mail-plugin", + "description": "Mail Plugin", + "version": "3.2.0", + "private": true, + "type": "module", + "license": "GPL-3.0-only", + "author": "Thea Schöbl", + "bin": "app.js", + "files": [ + "app.js", + "lib", + "README.md", + "CHANGELOG.md", + "Dockerfile" + ], + "scripts": { + "build": "tsup-node --dts", + "dev": "tsup-node --watch --onSuccess \"pnpm run start\"", + "start": "node app.js", + "deploy": "pnpm --prod --filter=@openstapps/minimal-plugin deploy ../../.deploy/minimal-plugin", + "format": "prettier . -c --ignore-path ../../.gitignore", + "format:fix": "prettier --write . --ignore-path ../../.gitignore", + "lint": "eslint --ext .ts src/", + "lint:fix": "eslint --fix --ext .ts src/" + }, + "dependencies": { + "@openstapps/core": "workspace:*", + "@openstapps/core-tools": "workspace:*", + "@openstapps/logger": "workspace:*", + "commander": "10.0.0", + "dotenv": "16.4.5", + "express": "4.18.2", + "imapflow": "1.0.162", + "mailparser": "3.7.1", + "node-forge": "1.3.1", + "nodemailer": "6.9.14", + "ts-node": "10.9.2" + }, + "devDependencies": { + "@openstapps/eslint-config": "workspace:*", + "@openstapps/prettier-config": "workspace:*", + "@openstapps/tsconfig": "workspace:*", + "@types/express": "4.17.17", + "@types/imapflow": "1.0.18", + "@types/mailparser": "3.4.4", + "@types/node": "18.15.3", + "@types/node-forge": "1.3.11", + "@types/nodemailer": "6.4.15", + "tsup": "6.7.0", + "typescript": "5.4.2" + }, + "tsup": { + "entry": [ + "src/cli.ts" + ], + "sourcemap": true, + "clean": true, + "format": "esm", + "outDir": "lib" + }, + "prettier": "@openstapps/prettier-config", + "eslintConfig": { + "extends": [ + "@openstapps" + ] + } +} diff --git a/backend/mail-plugin/src/cli.ts b/backend/mail-plugin/src/cli.ts new file mode 100644 index 00000000..59f23b58 --- /dev/null +++ b/backend/mail-plugin/src/cli.ts @@ -0,0 +1,104 @@ +import {config} from 'dotenv'; +import {ImapFlow} from 'imapflow'; +import express from 'express'; + +config({path: '.env.local'}); + +const app = express(); +const port = process.env.PORT || 4000; + +if (!process.env.IMAP_USER || !process.env.IMAP_PASSWORD) { + throw new Error('Provide IMAP user'); +} + +app.use((_request, response, next) => { + const client = new ImapFlow({ + host: 'imap.server.uni-frankfurt.de', + port: 993, + secure: true, + emitLogs: false, + auth: { + user: process.env.IMAP_USER!, + pass: process.env.IMAP_PASSWORD!, + }, + }); + response.locals.client = client; + next(); +}); + +app.get('/', async (request, response) => { + const client = response.locals.client as ImapFlow; + await client.connect(); + const lock = await client.getMailboxLock('INBOX'); + try { + const messages = []; + for await (const message of client.fetch('1:*', { + envelope: true, + labels: true, + bodyStructure: true, + flags: true, + })) { + messages.push({ + bodyStructure: message.bodyStructure, + labels: [...(message.labels ?? [])], + flags: [...(message.flags ?? [])], + envelope: message.envelope, + seq: message.seq, + }); + } + response.json(messages); + } finally { + lock.release(); + } + await client.logout(); +}); + +app.get('/:id', async (request, response) => { + const client = response.locals.client as ImapFlow; + await client.connect(); + const lock = await client.getMailboxLock('INBOX'); + try { + const message = await client.fetchOne(request.params.id, { + envelope: true, + labels: true, + flags: true, + bodyStructure: true, + }); + response.json({ + bodyStructure: message.bodyStructure, + labels: [...(message.labels ?? [])], + flags: [...(message.flags ?? [])], + envelope: message.envelope, + seq: message.seq, + }); + } finally { + lock.release(); + } + await client.logout(); +}); + +app.get('/:id/attachment/:attachment', async (request, response) => { + const client = response.locals.client as ImapFlow; + await client.connect(); + const lock = await client.getMailboxLock('INBOX'); + try { + const message = await client.download(request.params.id, request.params.attachment); + const body = await new Promise(resolve => { + let body = ''; + message.content.on('data', chunk => { + body += chunk.toString(); + }); + message.content.on('end', () => { + resolve(body); + }); + }); + response.send(body); + } finally { + lock.release(); + } + await client.logout(); +}); + +app.listen(port, () => { + console.log(`Server is running on http://localhost:${port}`); +}); diff --git a/backend/mail-plugin/tsconfig.json b/backend/mail-plugin/tsconfig.json new file mode 100644 index 00000000..988e304d --- /dev/null +++ b/backend/mail-plugin/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "@openstapps/tsconfig", + "exclude": ["lib", "app.js"] +} diff --git a/frontend/app/package.json b/frontend/app/package.json index f2190b6a..c357d8be 100644 --- a/frontend/app/package.json +++ b/frontend/app/package.json @@ -106,7 +106,9 @@ "ngx-markdown": "17.1.1", "ngx-moment": "6.0.2", "opening_hours": "3.8.0", + "pkijs": "3.1.0", "pmtiles": "3.0.3", + "postal-mime": "2.2.5", "rxjs": "7.8.1", "semver": "7.6.0", "swiper": "8.4.5", @@ -139,6 +141,7 @@ "@ionic/cli": "7.2.0", "@openstapps/prettier-config": "workspace:*", "@openstapps/tsconfig": "workspace:*", + "@types/dompurify": "^3.0.5", "@types/fontkit": "2.0.7", "@types/geojson": "1.0.6", "@types/glob": "8.1.0", @@ -154,6 +157,7 @@ "@typescript-eslint/parser": "7.2.0", "cordova-res": "0.15.4", "cypress": "13.7.0", + "dompurify": "^3.1.6", "eslint": "8.57.0", "eslint-plugin-jsdoc": "48.2.1", "eslint-plugin-prettier": "5.1.3", diff --git a/frontend/app/src/app/app.module.ts b/frontend/app/src/app/app.module.ts index 80c0fcd6..194370ec 100644 --- a/frontend/app/src/app/app.module.ts +++ b/frontend/app/src/app/app.module.ts @@ -71,6 +71,7 @@ import {Capacitor} from '@capacitor/core'; import {SplashScreen} from '@capacitor/splash-screen'; import maplibregl from 'maplibre-gl'; import {Protocol} from 'pmtiles'; +import {MailModule} from './modules/mail/mail.module'; registerLocaleData(localeDe); @@ -165,6 +166,7 @@ export function createTranslateLoader(http: HttpClient) { ProfilePageModule, FeedbackModule, MapModule, + MailModule, MenuModule, NavigationModule, NewsModule, diff --git a/frontend/app/src/app/modules/auth/mail-auth.service.ts b/frontend/app/src/app/modules/auth/mail-auth.service.ts new file mode 100644 index 00000000..82b08101 --- /dev/null +++ b/frontend/app/src/app/modules/auth/mail-auth.service.ts @@ -0,0 +1,10 @@ +import {Injectable} from '@angular/core'; + +@Injectable({providedIn: 'root'}) +export class MailAuthService { + login(username: string, password: string) { + navigator.credentials.store(new PasswordCredential({})) + } + + logout() {} +} diff --git a/frontend/app/src/app/modules/mail/mail-detail.component.ts b/frontend/app/src/app/modules/mail/mail-detail.component.ts new file mode 100644 index 00000000..11f62da9 --- /dev/null +++ b/frontend/app/src/app/modules/mail/mail-detail.component.ts @@ -0,0 +1,51 @@ +import {ChangeDetectionStrategy, Component, signal} from '@angular/core'; +import {MailService} from './mail.service'; +import {AsyncPipe} from '@angular/common'; +import {IonicModule} from '@ionic/angular'; +import {DataModule} from '../data/data.module'; +import {IonIconModule} from 'src/app/util/ion-icon/ion-icon.module'; +import {UtilModule} from 'src/app/util/util.module'; +import {FormatPurePipeModule, ParseIsoPipeModule} from 'ngx-date-fns'; +import {ActivatedRoute, RouterModule} from '@angular/router'; +import {mergeMap, tap} from 'rxjs'; +import {DomSanitizer} from '@angular/platform-browser'; +import {MailPartComponent} from './parts/mail-part.component'; +import {MailMetaComponent} from './mail-meta.component'; + +@Component({ + selector: 'stapps-mail-detail', + templateUrl: 'mail-detail.html', + styleUrl: 'mail-detail.scss', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [ + AsyncPipe, + IonicModule, + DataModule, + IonIconModule, + UtilModule, + FormatPurePipeModule, + ParseIsoPipeModule, + RouterModule, + MailPartComponent, + MailMetaComponent, + ], +}) +export class MailDetailComponent { + mail = this.activatedRoute.params.pipe( + mergeMap(parameters => this.mailService.getMail(parameters.id)), + tap(console.log), + ); + + collapse = signal(false); + + constructor( + readonly mailService: MailService, + readonly activatedRoute: ActivatedRoute, + readonly sanitizer: DomSanitizer, + ) {} + + todo() { + alert('TODO'); + } +} diff --git a/frontend/app/src/app/modules/mail/mail-detail.html b/frontend/app/src/app/modules/mail/mail-detail.html new file mode 100644 index 00000000..17035338 --- /dev/null +++ b/frontend/app/src/app/modules/mail/mail-detail.html @@ -0,0 +1,65 @@ + + + + + + + @if (mail | async; as mail) { + {{ mail.envelope.subject }} + } @else { + + } + + + + + + + + + + + + + +

+ @if (mail | async; as mail) { + {{ mail.envelope.subject }} + } @else { + + } +

+
+ @if (mail | async; as mail) { + +
+ @if (mail.envelope.from[0]; as from) { +
+ {{ (from.name || from.address).charAt(0).toUpperCase() }} +
+ } +
+ + @for (from of mail.envelope.from; track from) { +

{{ from.name || from.address }}

+ } +

+ to + @for (to of mail.envelope.to; track to) { + {{ to.name || to.address }} + } +

+
+
+ + } @else { + + } +
+ @if (mail | async; as mail) { + + } +
diff --git a/frontend/app/src/app/modules/mail/mail-detail.scss b/frontend/app/src/app/modules/mail/mail-detail.scss new file mode 100644 index 00000000..2344f68c --- /dev/null +++ b/frontend/app/src/app/modules/mail/mail-detail.scss @@ -0,0 +1,53 @@ +@import '../../../theme/util/mixins'; + +.body { + @include border-radius-in-parallax(var(--border-radius-default)); + + margin: var(--spacing-md); + padding: var(--spacing-md); + background: var(--ion-item-background); +} + +ion-item { + margin-block-end: var(--spacing-xl); +} + +ion-title { + transition: + opacity 0.2s ease, + translate 0.2s ease; +} + +h1 { + margin: var(--spacing-sm) var(--spacing-md); + font-weight: var(--font-weight-bold); + color: var(--ion-color-primary-contrast); +} + +pre { + word-wrap: break-word; + white-space: pre-wrap; +} + +stapps-mail-meta { + // css hack to make the element stick to the bottom of the scroll container even + // when the content is not filling it + position: sticky; + top: 100vh; +} + +ion-accordion { + background: none; +} + +.attachment { + display: flex; + align-items: center; + justify-content: space-between; + + margin: var(--spacing-md) 0; + padding: var(--spacing-md); + + border: 1px solid var(--ion-border-color); + border-radius: var(--border-radius-default); +} diff --git a/frontend/app/src/app/modules/mail/mail-meta.component.ts b/frontend/app/src/app/modules/mail/mail-meta.component.ts new file mode 100644 index 00000000..be181c58 --- /dev/null +++ b/frontend/app/src/app/modules/mail/mail-meta.component.ts @@ -0,0 +1,17 @@ +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; +import {FormatPurePipeModule, ParseIsoPipeModule} from 'ngx-date-fns'; +import {EmailData} from './types'; +import {TranslateModule} from '@ngx-translate/core'; +import {TitleCasePipe} from '@angular/common'; + +@Component({ + selector: 'stapps-mail-meta', + templateUrl: 'mail-meta.html', + styleUrl: 'mail-meta.scss', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [ParseIsoPipeModule, FormatPurePipeModule, TranslateModule, TitleCasePipe], +}) +export class MailMetaComponent { + @Input({required: true}) mail: EmailData; +} diff --git a/frontend/app/src/app/modules/mail/mail-meta.html b/frontend/app/src/app/modules/mail/mail-meta.html new file mode 100644 index 00000000..8a38fcf5 --- /dev/null +++ b/frontend/app/src/app/modules/mail/mail-meta.html @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + +
{{ 'mail.FROM' | translate | titlecase }} +
    + @for (from of mail.envelope.from; track from) { +
  • + @if (from.name) { + {{ from.name }} + } + {{ from.address }} +
  • + } +
+
{{ 'mail.SENDER' | translate | titlecase }} +
    + @for (sender of mail.envelope.sender; track sender) { +
  • + @if (sender.name) { + {{ sender.name }} + } + {{ sender.address }} +
  • + } +
+
{{ 'mail.TO' | translate | titlecase }} +
    + @for (to of mail.envelope.to; track to) { +
  • + @if (to.name) { + {{ to.name }} + } + {{ to.address }} +
  • + } +
+
{{ 'mail.DATE' | translate | titlecase }}{{ mail.envelope.date | dfnsParseIso | dfnsFormatPure: 'PPp' }}
diff --git a/frontend/app/src/app/modules/mail/mail-meta.scss b/frontend/app/src/app/modules/mail/mail-meta.scss new file mode 100644 index 00000000..6e1f6d69 --- /dev/null +++ b/frontend/app/src/app/modules/mail/mail-meta.scss @@ -0,0 +1,35 @@ +ul { + margin: 0; + padding: 0; + list-style: none; +} + +code { + font-weight: 400; + font-style: italic; + color: var(--ion-color-dark); +} + +span + code::before { + content: ' • '; +} + +th, +td { + font-size: 0.8em; +} + +th { + padding-inline-end: var(--spacing-md); + text-align: left; + vertical-align: top; +} + +td { + vertical-align: top; +} + +table { + margin: var(--spacing-lg); + opacity: 0.8; +} diff --git a/frontend/app/src/app/modules/mail/mail-page.component.ts b/frontend/app/src/app/modules/mail/mail-page.component.ts new file mode 100644 index 00000000..9b155d31 --- /dev/null +++ b/frontend/app/src/app/modules/mail/mail-page.component.ts @@ -0,0 +1,32 @@ +import {ChangeDetectionStrategy, Component} from '@angular/core'; +import {MailService} from './mail.service'; +import {AsyncPipe} from '@angular/common'; +import {IonicModule} from '@ionic/angular'; +import {DataModule} from '../data/data.module'; +import {IonIconModule} from 'src/app/util/ion-icon/ion-icon.module'; +import {UtilModule} from 'src/app/util/util.module'; +import {FormatPurePipeModule, ParseIsoPipeModule} from 'ngx-date-fns'; +import {RouterModule} from '@angular/router'; + +@Component({ + selector: 'stapps-mail-page', + templateUrl: 'mail-page.html', + styleUrl: 'mail-page.scss', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [ + AsyncPipe, + IonicModule, + DataModule, + IonIconModule, + UtilModule, + FormatPurePipeModule, + ParseIsoPipeModule, + RouterModule, + ], +}) +export class MailPageComponent { + mails = this.mailService.list(); + + constructor(readonly mailService: MailService) {} +} diff --git a/frontend/app/src/app/modules/mail/mail-page.html b/frontend/app/src/app/modules/mail/mail-page.html new file mode 100644 index 00000000..ea43cb5e --- /dev/null +++ b/frontend/app/src/app/modules/mail/mail-page.html @@ -0,0 +1,34 @@ + + + Mail + + + + +

Inbox

+ + @if (mails | async; as mails) { + + @for (mail of mails; track mail) { + +
+ @if (mail.envelope.from[0]; as from) { +
+ {{ (from.name || from.address).charAt(0).toUpperCase() }} +
+ } +
+ + @for (from of mail.envelope.from; track from) { +

{{ from.name || from.address }}

+ } +

{{ mail.envelope.subject }}

+
+ {{ mail.envelope.date | dfnsParseIso | dfnsFormatPure: 'PPp' }} +
+ } +
+ } @else { +
Loading...
+ } +
diff --git a/frontend/app/src/app/modules/mail/mail-page.scss b/frontend/app/src/app/modules/mail/mail-page.scss new file mode 100644 index 00000000..c484561d --- /dev/null +++ b/frontend/app/src/app/modules/mail/mail-page.scss @@ -0,0 +1,33 @@ +.avatar { + display: flex; + align-items: center; + justify-content: center; + + width: 2em; + height: 2em; + + color: var(--ion-color-light-contrast); + + background: var(--ion-color-light); + border-radius: 50%; +} + +h1 { + margin-inline: var(--spacing-md); + color: var(--ion-color-primary-contrast); +} + +ion-item.unread h2 { + font-weight: bold; +} + +ion-item p { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +ion-list { + margin: var(--spacing-md); + border-radius: var(--border-radius-default); +} diff --git a/frontend/app/src/app/modules/mail/mail.module.ts b/frontend/app/src/app/modules/mail/mail.module.ts new file mode 100644 index 00000000..849604a9 --- /dev/null +++ b/frontend/app/src/app/modules/mail/mail.module.ts @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2024 StApps + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ +import {RouterModule} from '@angular/router'; +import {NgModule} from '@angular/core'; +import {MailPageComponent} from './mail-page.component'; +import {MailDetailComponent} from './mail-detail.component'; + +@NgModule({ + imports: [ + RouterModule.forChild([ + {path: 'mail', component: MailPageComponent}, + {path: 'mail/:id', component: MailDetailComponent}, + ]), + ], +}) +export class MailModule {} diff --git a/frontend/app/src/app/modules/mail/mail.service.ts b/frontend/app/src/app/modules/mail/mail.service.ts new file mode 100644 index 00000000..8d3383e5 --- /dev/null +++ b/frontend/app/src/app/modules/mail/mail.service.ts @@ -0,0 +1,26 @@ +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {Observable, map, tap} from 'rxjs'; +import {EmailData} from './types'; + +@Injectable({providedIn: 'root'}) +export class MailService { + constructor(private httpClient: HttpClient) {} + + list(): Observable { + return this.httpClient.get('http://localhost:4000/', {responseType: 'json'}).pipe( + tap(console.log), + map(it => it.sort((a: EmailData, b: EmailData) => b.envelope.date.localeCompare(a.envelope.date))), + ); + } + + getAttachment(id: string, attachment?: string): Observable { + return this.httpClient.get(`http://localhost:4000/${id}/attachment/${attachment ?? 'TEXT'}`, { + responseType: 'arraybuffer', + }); + } + + getMail(id: string): Observable { + return this.httpClient.get(`http://localhost:4000/${id}`, {responseType: 'json'}); + } +} diff --git a/frontend/app/src/app/modules/mail/parts/mail-attachment-text.pipe.ts b/frontend/app/src/app/modules/mail/parts/mail-attachment-text.pipe.ts new file mode 100644 index 00000000..1760c0df --- /dev/null +++ b/frontend/app/src/app/modules/mail/parts/mail-attachment-text.pipe.ts @@ -0,0 +1,23 @@ +/* eslint-disable unicorn/no-null */ +import {Pipe, PipeTransform} from '@angular/core'; +import {DomSanitizer} from '@angular/platform-browser'; + +@Pipe({ + name: 'mailAttachmentText', + standalone: true, + pure: true, +}) +export class MailAttachmentTextPipe implements PipeTransform { + constructor(readonly sanitizer: DomSanitizer) {} + + transform(attachment: null, encoding?: string): null; + transform(attachment: ArrayBuffer, encoding?: string): string; + transform(attachment: ArrayBuffer | null, encoding?: string): string | null; + transform(attachment: ArrayBuffer | null, encoding?: string): string | null { + if (attachment === null) { + return null; + } + const decoder = new TextDecoder(encoding ?? 'utf8'); + return decoder.decode(attachment); + } +} diff --git a/frontend/app/src/app/modules/mail/parts/mail-part-attachment.component.ts b/frontend/app/src/app/modules/mail/parts/mail-part-attachment.component.ts new file mode 100644 index 00000000..ae196561 --- /dev/null +++ b/frontend/app/src/app/modules/mail/parts/mail-part-attachment.component.ts @@ -0,0 +1,19 @@ +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; +import {IonicModule} from '@ionic/angular'; +import {DataSizePipe} from 'src/app/util/data-size.pipe'; +import {IonIconModule} from 'src/app/util/ion-icon/ion-icon.module'; +import {BodyStructure} from '../types'; + +@Component({ + selector: 'stapps-mail-part-attachment', + templateUrl: 'mail-part-attachment.html', + styleUrl: 'mail-part-attachment.scss', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [IonicModule, DataSizePipe, IonIconModule], +}) +export class MailPartAttachmentComponent { + @Input({required: true}) part: BodyStructure; + + @Input({required: true}) mail: string; +} diff --git a/frontend/app/src/app/modules/mail/parts/mail-part-attachment.html b/frontend/app/src/app/modules/mail/parts/mail-part-attachment.html new file mode 100644 index 00000000..7ed688ad --- /dev/null +++ b/frontend/app/src/app/modules/mail/parts/mail-part-attachment.html @@ -0,0 +1,9 @@ + + + @if (part.parameters?.name) { + {{ part.parameters?.name }} + } + {{ part.size | dataSize }} + + + diff --git a/frontend/app/src/app/modules/mail/parts/mail-part-attachment.scss b/frontend/app/src/app/modules/mail/parts/mail-part-attachment.scss new file mode 100644 index 00000000..28bbbd12 --- /dev/null +++ b/frontend/app/src/app/modules/mail/parts/mail-part-attachment.scss @@ -0,0 +1,21 @@ +ion-card { + display: flex; + flex-direction: row; + + width: fit-content; + margin: 0; + margin-block-start: var(--spacing-md); + + outline: 1px solid var(--ion-border-color); + box-shadow: none; +} + +ion-card-header { + padding: var(--spacing-sm) var(--spacing-md); +} + +ion-card-title { + font-size: 1rem; + text-wrap: wrap; + word-break: break-word; +} diff --git a/frontend/app/src/app/modules/mail/parts/mail-part.component.ts b/frontend/app/src/app/modules/mail/parts/mail-part.component.ts new file mode 100644 index 00000000..53032d80 --- /dev/null +++ b/frontend/app/src/app/modules/mail/parts/mail-part.component.ts @@ -0,0 +1,48 @@ +/* eslint-disable unicorn/no-useless-undefined */ +import {ChangeDetectionStrategy, Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; +import {BodyStructure} from '../types'; +import {MailService} from '../mail.service'; +import {AsyncPipe} from '@angular/common'; +import {IonicModule} from '@ionic/angular'; +import {ReplaySubject, mergeMap} from 'rxjs'; +import {MailAttachmentTextPipe} from './mail-attachment-text.pipe'; +import {MailPartAttachmentComponent} from './mail-part-attachment.component'; +import {MailPreferredAlternativePipe} from './mail-preferred-alternative.pipe'; +import {ShadowHtmlDirective} from './shadow-html.directive'; + +@Component({ + selector: 'stapps-mail-part', + templateUrl: 'mail-part.html', + styleUrl: 'mail-part.scss', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [ + AsyncPipe, + IonicModule, + ShadowHtmlDirective, + MailAttachmentTextPipe, + MailPartAttachmentComponent, + MailPreferredAlternativePipe, + ], +}) +export class MailPartComponent implements OnChanges, OnInit { + @Input({required: true}) part: BodyStructure; + + @Input({required: true}) mail: string; + + data = new ReplaySubject<[BodyStructure, string]>(1); + + content = this.data.pipe(mergeMap(([part, mail]) => this.mailService.getAttachment(mail, part.part))); + + constructor(readonly mailService: MailService) {} + + ngOnInit() { + this.data.next([this.part, this.mail]); + } + + ngOnChanges(changes: SimpleChanges) { + if ('mail' in changes || 'part' in changes) { + this.data.next([this.part, this.mail]); + } + } +} diff --git a/frontend/app/src/app/modules/mail/parts/mail-part.html b/frontend/app/src/app/modules/mail/parts/mail-part.html new file mode 100644 index 00000000..b9fb555f --- /dev/null +++ b/frontend/app/src/app/modules/mail/parts/mail-part.html @@ -0,0 +1,23 @@ +@if (part.type === 'text/html') { + @if (content | async | mailAttachmentText: part.parameters?.charset; as content) { +
+ } @else { + + } +} @else if (part.type === 'text/plain') { + @if (content | async | mailAttachmentText: part.parameters?.charset; as content) { +
{{ content }}
+ } @else { + + } +} @else if (part.type === 'multipart/alternative') { + @if (part.childNodes && part.childNodes.length > 0) { + + } +} @else if (part.type.startsWith('multipart')) { + @for (child of part.childNodes; track child) { + + } +} @else { + +} diff --git a/frontend/app/src/app/modules/mail/parts/mail-part.scss b/frontend/app/src/app/modules/mail/parts/mail-part.scss new file mode 100644 index 00000000..404da90e --- /dev/null +++ b/frontend/app/src/app/modules/mail/parts/mail-part.scss @@ -0,0 +1,9 @@ +.html { + overflow-x: auto; +} + +pre { + font-family: inherit; + word-wrap: break-word; + white-space: pre-wrap; +} diff --git a/frontend/app/src/app/modules/mail/parts/mail-preferred-alternative.pipe.ts b/frontend/app/src/app/modules/mail/parts/mail-preferred-alternative.pipe.ts new file mode 100644 index 00000000..49b21acd --- /dev/null +++ b/frontend/app/src/app/modules/mail/parts/mail-preferred-alternative.pipe.ts @@ -0,0 +1,13 @@ +import {Pipe, PipeTransform} from '@angular/core'; +import {BodyStructure} from '../types'; + +@Pipe({name: 'mailPreferredAlternative', standalone: true, pure: true}) +export class MailPreferredAlternativePipe implements PipeTransform { + transform(value: BodyStructure[]): BodyStructure { + return ( + value.find(part => part.type === 'text/html') ?? + value.find(part => part.type === 'text/plain') ?? + value[0] + ); + } +} diff --git a/frontend/app/src/app/modules/mail/parts/shadow-html.directive.ts b/frontend/app/src/app/modules/mail/parts/shadow-html.directive.ts new file mode 100644 index 00000000..78a8e708 --- /dev/null +++ b/frontend/app/src/app/modules/mail/parts/shadow-html.directive.ts @@ -0,0 +1,18 @@ +import {Directive, ElementRef, Host, Input} from '@angular/core'; +import {sanitize} from 'dompurify'; + +@Directive({ + selector: '[shadowHTML]', + standalone: true, +}) +export class ShadowHtmlDirective { + @Input({required: true}) + set shadowHTML(content: string) { + this.shadowRoot.innerHTML = ''; + this.shadowRoot.append(sanitize(content, {RETURN_DOM_FRAGMENT: true, USE_PROFILES: {html: true}})); + } + + shadowRoot = (this.elementRef.nativeElement as HTMLElement).attachShadow({mode: 'open'}); + + constructor(@Host() readonly elementRef: ElementRef) {} +} diff --git a/frontend/app/src/app/modules/mail/types.ts b/frontend/app/src/app/modules/mail/types.ts new file mode 100644 index 00000000..484cf83d --- /dev/null +++ b/frontend/app/src/app/modules/mail/types.ts @@ -0,0 +1,44 @@ +export interface BodyStructure { + type: string; + part?: string; + parameters?: { + name?: string; + encoding?: string; + charset?: string; + }; + disposition: string; + dispositionParameters?: unknown; + size: number; + childNodes?: BodyStructure[]; +} + +export interface BodyPartInfo { + type: string; + name?: string; + encoding?: string; + size: number; + part?: string; +} + +export interface EnvelopeAddress { + name: string; + address: string; +} + +export interface Envelope { + date: string; + from: EnvelopeAddress[]; + messageId: string; + replyTo: EnvelopeAddress[]; + sender: EnvelopeAddress[]; + subject: string; + to: EnvelopeAddress[]; +} + +export interface EmailData { + bodyStructure: BodyStructure; + labels: string[]; + flags: string[]; + envelope: Envelope; + seq: number; +} diff --git a/frontend/app/src/app/modules/profile/page/profile-page-section.html b/frontend/app/src/app/modules/profile/page/profile-page-section.html index 308b92ad..cff4822e 100644 --- a/frontend/app/src/app/modules/profile/page/profile-page-section.html +++ b/frontend/app/src/app/modules/profile/page/profile-page-section.html @@ -39,6 +39,11 @@ } {{ 'name' | translateSimple: link }} + @if (link.beta) { + + {{ 'beta' | translate }} + + } } diff --git a/frontend/app/src/app/modules/profile/page/profile-page-section.scss b/frontend/app/src/app/modules/profile/page/profile-page-section.scss index bde1c548..c8b85bc1 100644 --- a/frontend/app/src/app/modules/profile/page/profile-page-section.scss +++ b/frontend/app/src/app/modules/profile/page/profile-page-section.scss @@ -50,6 +50,13 @@ ion-item { } } +ion-note { + position: absolute; + top: 0; + right: 0; + padding: var(--spacing-xs); +} + simple-swiper { --swiper-slide-width: #{$width}; diff --git a/frontend/app/src/app/util/data-size.pipe.ts b/frontend/app/src/app/util/data-size.pipe.ts new file mode 100644 index 00000000..40e1df7b --- /dev/null +++ b/frontend/app/src/app/util/data-size.pipe.ts @@ -0,0 +1,25 @@ +import {Pipe, PipeTransform} from '@angular/core'; + +/** + * Format a data size in bytes to a human readable string + */ +export function formatDataSize(value: number, precision = 2): string { + const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; + let unit = 0; + while (value >= 1024 && unit < units.length - 1) { + value /= 1024; + unit++; + } + return `${value.toFixed(precision)} ${units[unit]}`; +} + +@Pipe({ + name: 'dataSize', + pure: true, + standalone: true, +}) +export class DataSizePipe implements PipeTransform { + transform(value: number, precision = 2): string { + return formatDataSize(value, precision); + } +} diff --git a/frontend/app/src/app/util/skeleton-data.directive.ts b/frontend/app/src/app/util/skeleton-data.directive.ts new file mode 100644 index 00000000..89c59148 --- /dev/null +++ b/frontend/app/src/app/util/skeleton-data.directive.ts @@ -0,0 +1,7 @@ +import {Directive} from '@angular/core'; + +@Directive({ + selector: 'ng-template[skeletonData]', + standalone: true, +}) +export class SkeletonDataDirective {} diff --git a/frontend/app/src/app/util/skeleton-placeholder.directive.ts b/frontend/app/src/app/util/skeleton-placeholder.directive.ts new file mode 100644 index 00000000..de5a4fff --- /dev/null +++ b/frontend/app/src/app/util/skeleton-placeholder.directive.ts @@ -0,0 +1,7 @@ +import {Directive} from '@angular/core'; + +@Directive({ + selector: 'ng-template[skeletonPlaceholder]', + standalone: true, +}) +export class SkeletonPlaceholderDirective {} diff --git a/frontend/app/src/app/util/skeleton.component.ts b/frontend/app/src/app/util/skeleton.component.ts new file mode 100644 index 00000000..1bc36d89 --- /dev/null +++ b/frontend/app/src/app/util/skeleton.component.ts @@ -0,0 +1,22 @@ +import {ChangeDetectionStrategy, Component, ContentChild, Input, TemplateRef} from '@angular/core'; +import {Observable} from 'rxjs'; +import {SkeletonDataDirective} from './skeleton-data.directive'; +import {SkeletonPlaceholderDirective} from './skeleton-placeholder.directive'; + +@Component({ + selector: 'stapps-skeleton', + templateUrl: 'skeleton.html', + styleUrl: 'skeleton.scss', + standalone: true, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class SkeletonComponent { + @ContentChild(SkeletonDataDirective) dataTemplate: TemplateRef; + + @ContentChild(SkeletonPlaceholderDirective) placeholderTemplate: TemplateRef; + + @Input() + set data(value: Observable | Promise) {} + + static ngTemplateContextGuard< +} diff --git a/frontend/app/src/app/util/skeleton.html b/frontend/app/src/app/util/skeleton.html new file mode 100644 index 00000000..e69de29b diff --git a/frontend/app/src/app/util/skeleton.scss b/frontend/app/src/app/util/skeleton.scss new file mode 100644 index 00000000..e69de29b diff --git a/frontend/app/src/assets/i18n/de.json b/frontend/app/src/assets/i18n/de.json index 48a1a1c1..7fe7a217 100644 --- a/frontend/app/src/assets/i18n/de.json +++ b/frontend/app/src/assets/i18n/de.json @@ -8,6 +8,7 @@ "export": "Exportieren", "share": "Teilen", "timeSuffix": "Uhr", + "beta": "Beta", "ratings": { "thank_you": "Vielen Dank für die Bewertung!" }, @@ -386,6 +387,12 @@ } } }, + "mail": { + "FROM": "von", + "SENDER": "Absender", + "TO": "an", + "DATE": "Datum" + }, "menu": { "context": { "title": "Kontext Menü", diff --git a/frontend/app/src/assets/i18n/en.json b/frontend/app/src/assets/i18n/en.json index 66af8a05..013aaac4 100644 --- a/frontend/app/src/assets/i18n/en.json +++ b/frontend/app/src/assets/i18n/en.json @@ -7,6 +7,7 @@ "back": "back", "export": "Export", "share": "Share", + "beta": "beta", "timeSuffix": "", "ratings": { "thank_you": "Thank you for your feedback!" @@ -386,6 +387,12 @@ } } }, + "mail": { + "FROM": "from", + "SENDER": "sender", + "TO": "to", + "DATE": "date" + }, "menu": { "context": { "title": "context menu", diff --git a/frontend/app/src/assets/icons.min.woff2 b/frontend/app/src/assets/icons.min.woff2 index 76cd6dc3..ad7ecc10 100644 Binary files a/frontend/app/src/assets/icons.min.woff2 and b/frontend/app/src/assets/icons.min.woff2 differ diff --git a/frontend/app/src/config/profile-page-sections.ts b/frontend/app/src/config/profile-page-sections.ts index 6b5f9845..efba4fa8 100644 --- a/frontend/app/src/config/profile-page-sections.ts +++ b/frontend/app/src/config/profile-page-sections.ts @@ -49,6 +49,7 @@ export interface SCSectionLink extends SCThing { link: string[]; needsAuth?: true; icon?: string; + beta?: true; } export interface SCSection extends SCThing { @@ -150,6 +151,18 @@ export const profilePageSections: SCSection[] = [ }, ...SCSectionLinkConstantValues, }, + { + name: 'Mail', + icon: SCIcon.mail, + link: ['/mail'], + beta: true, + translations: { + de: { + name: 'Email', + }, + }, + ...SCSectionLinkConstantValues, + }, ], translations: { de: { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e9d01d74..4317be2c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -246,6 +246,97 @@ importers: backend/database: {} + backend/mail-plugin: + dependencies: + '@openstapps/core': + specifier: workspace:* + version: link:../../packages/core + '@openstapps/core-tools': + specifier: workspace:* + version: link:../../packages/core-tools + '@openstapps/logger': + specifier: workspace:* + version: link:../../packages/logger + commander: + specifier: 10.0.0 + version: 10.0.0 + dotenv: + specifier: 16.4.5 + version: 16.4.5 + express: + specifier: 4.18.2 + version: 4.18.2 + imapflow: + specifier: 1.0.162 + version: 1.0.162 + mailparser: + specifier: 3.7.1 + version: 3.7.1 + node-forge: + specifier: 1.3.1 + version: 1.3.1 + nodemailer: + specifier: 6.9.14 + version: 6.9.14 + ts-node: + specifier: 10.9.2 + version: 10.9.2(@types/node@18.15.3)(typescript@5.4.2) + devDependencies: + '@openstapps/eslint-config': + specifier: workspace:* + version: link:../../configuration/eslint-config + '@openstapps/prettier-config': + specifier: workspace:* + version: link:../../configuration/prettier-config + '@openstapps/tsconfig': + specifier: workspace:* + version: link:../../configuration/tsconfig + '@types/express': + specifier: 4.17.17 + version: 4.17.17 + '@types/imapflow': + specifier: 1.0.18 + version: 1.0.18 + '@types/mailparser': + specifier: 3.4.4 + version: 3.4.4 + '@types/node': + specifier: 18.15.3 + version: 18.15.3 + '@types/node-forge': + specifier: 1.3.11 + version: 1.3.11 + '@types/nodemailer': + specifier: 6.4.15 + version: 6.4.15 + '@typescript-eslint/eslint-plugin': + specifier: 7.2.0 + version: 7.2.0(@typescript-eslint/parser@7.2.0)(eslint@8.57.0)(typescript@5.4.2) + '@typescript-eslint/parser': + specifier: 7.2.0 + version: 7.2.0(eslint@8.57.0)(typescript@5.4.2) + eslint: + specifier: 8.57.0 + version: 8.57.0 + eslint-config-prettier: + specifier: 9.1.0 + version: 9.1.0(eslint@8.57.0) + eslint-plugin-jsdoc: + specifier: 48.2.1 + version: 48.2.1(eslint@8.57.0) + eslint-plugin-unicorn: + specifier: 51.0.1 + version: 51.0.1(eslint@8.57.0) + prettier: + specifier: 3.1.1 + version: 3.1.1 + tsup: + specifier: 6.7.0 + version: 6.7.0(ts-node@10.9.2)(typescript@5.4.2) + typescript: + specifier: 5.4.2 + version: 5.4.2 + backend/proxy: dependencies: '@openstapps/logger': @@ -863,9 +954,15 @@ importers: opening_hours: specifier: 3.8.0 version: 3.8.0 + pkijs: + specifier: 3.1.0 + version: 3.1.0 pmtiles: specifier: 3.0.3 version: 3.0.3 + postal-mime: + specifier: 2.2.5 + version: 2.2.5 rxjs: specifier: 7.8.1 version: 7.8.1 @@ -957,6 +1054,9 @@ importers: '@openstapps/tsconfig': specifier: workspace:* version: link:../../configuration/tsconfig + '@types/dompurify': + specifier: ^3.0.5 + version: 3.0.5 '@types/fontkit': specifier: 2.0.7 version: 2.0.7 @@ -1002,6 +1102,9 @@ importers: cypress: specifier: 13.7.0 version: 13.7.0 + dompurify: + specifier: ^3.1.6 + version: 3.1.6 eslint: specifier: 8.57.0 version: 8.57.0 @@ -2144,7 +2247,7 @@ packages: css-loader: 6.10.0(webpack@5.90.3) esbuild-wasm: 0.20.1 fast-glob: 3.3.2 - http-proxy-middleware: 2.0.6(@types/express@4.17.21) + http-proxy-middleware: 2.0.6(@types/express@4.17.17) https-proxy-agent: 7.0.4 inquirer: 9.2.15 jsonc-parser: 3.2.1 @@ -5084,7 +5187,7 @@ packages: '@ionic/utils-subprocess': 2.1.14 '@ionic/utils-terminal': 2.3.5 commander: 9.5.0 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6(supports-color@8.1.1) env-paths: 2.2.1 kleur: 4.1.5 native-run: 2.0.1 @@ -5275,7 +5378,7 @@ packages: fs-extra: 7.0.1 lodash.startcase: 4.4.0 outdent: 0.5.0 - prettier: 2.8.6 + prettier: 2.8.8 resolve-from: 5.0.0 semver: 7.6.0 dev: true @@ -5443,7 +5546,7 @@ packages: '@changesets/types': 5.2.1 fs-extra: 7.0.1 human-id: 1.0.2 - prettier: 2.8.6 + prettier: 2.8.8 dev: true /@colors/colors@1.5.0: @@ -6619,7 +6722,7 @@ packages: resolution: {integrity: sha512-0JZ1Zkp3wURnv8oq6Qt7fMPo5MpjbLoUoa9Bu2Q4PJuSDWM8H8gwF3dQO7VTeUj3/0o1IB1wGkFWZZYgUXZMUg==} engines: {node: '>=16.0.0'} dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6(supports-color@8.1.1) tslib: 2.6.2 transitivePeerDependencies: - supports-color @@ -6642,7 +6745,7 @@ packages: engines: {node: '>=16.0.0'} dependencies: '@types/fs-extra': 8.1.5 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.3.6(supports-color@8.1.1) fs-extra: 9.1.0 tslib: 2.6.2 transitivePeerDependencies: @@ -6884,15 +6987,6 @@ packages: '@sinclair/typebox': 0.27.8 dev: true - /@jridgewell/gen-mapping@0.3.3: - resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 - '@jridgewell/trace-mapping': 0.3.20 - dev: true - /@jridgewell/gen-mapping@0.3.5: resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} engines: {node: '>=6.0.0'} @@ -6916,11 +7010,6 @@ packages: engines: {node: '>=6.0.0'} dev: true - /@jridgewell/set-array@1.1.2: - resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} - engines: {node: '>=6.0.0'} - dev: true - /@jridgewell/set-array@1.2.1: resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} engines: {node: '>=6.0.0'} @@ -6951,13 +7040,6 @@ packages: '@jridgewell/sourcemap-codec': 1.4.14 dev: true - /@jridgewell/trace-mapping@0.3.20: - resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==} - dependencies: - '@jridgewell/resolve-uri': 3.1.1 - '@jridgewell/sourcemap-codec': 1.4.15 - dev: true - /@jridgewell/trace-mapping@0.3.25: resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} dependencies: @@ -7570,6 +7652,13 @@ packages: - chokidar dev: true + /@selderee/plugin-htmlparser2@0.11.0: + resolution: {integrity: sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==} + dependencies: + domhandler: 5.0.3 + selderee: 0.11.0 + dev: false + /@sideway/address@4.1.4: resolution: {integrity: sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==} dependencies: @@ -7863,13 +7952,6 @@ packages: '@types/connect': 3.4.35 '@types/node': 18.15.3 - /@types/body-parser@1.19.5: - resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} - dependencies: - '@types/connect': 3.4.38 - '@types/node': 18.15.3 - dev: true - /@types/bonjour@3.5.13: resolution: {integrity: sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==} dependencies: @@ -7914,12 +7996,6 @@ packages: dependencies: '@types/node': 18.15.3 - /@types/connect@3.4.38: - resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} - dependencies: - '@types/node': 18.15.3 - dev: true - /@types/cookie@0.4.1: resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==} dev: true @@ -7990,6 +8066,12 @@ packages: resolution: {integrity: sha512-oDuagM6G+xPLrLU4KeCKlr1oalMF5mJqV5pDPMDVIEaa8AkUW00i6u+5P02XCjdEEUQJC9dpnxqSLsZeAciSLQ==} dev: false + /@types/dompurify@3.0.5: + resolution: {integrity: sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==} + dependencies: + '@types/trusted-types': 2.0.7 + dev: true + /@types/eslint-scope@3.7.7: resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} dependencies: @@ -8008,14 +8090,6 @@ packages: resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} dev: true - /@types/express-serve-static-core@4.17.35: - resolution: {integrity: sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==} - dependencies: - '@types/node': 18.15.3 - '@types/qs': 6.9.7 - '@types/range-parser': 1.2.4 - '@types/send': 0.17.1 - /@types/express-serve-static-core@4.19.5: resolution: {integrity: sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==} dependencies: @@ -8023,24 +8097,14 @@ packages: '@types/qs': 6.9.15 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 - dev: true /@types/express@4.17.17: resolution: {integrity: sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==} dependencies: '@types/body-parser': 1.19.2 - '@types/express-serve-static-core': 4.17.35 - '@types/qs': 6.9.7 - '@types/serve-static': 1.15.2 - - /@types/express@4.17.21: - resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} - dependencies: - '@types/body-parser': 1.19.5 '@types/express-serve-static-core': 4.19.5 '@types/qs': 6.9.15 '@types/serve-static': 1.15.7 - dev: true /@types/fontkit@2.0.7: resolution: {integrity: sha512-f5BjGam6y3FrfEY2JxXwba66SYzqP+FREZh4UuBN1WDePl8EhTKjba3ZZQ2iORUufkrFt/c/UIugj0Uv/HEdRg==} @@ -8083,12 +8147,8 @@ packages: resolution: {integrity: sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==} dev: false - /@types/http-errors@2.0.1: - resolution: {integrity: sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ==} - /@types/http-errors@2.0.4: resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} - dev: true /@types/http-proxy@1.17.14: resolution: {integrity: sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==} @@ -8096,6 +8156,12 @@ packages: '@types/node': 18.15.3 dev: true + /@types/imapflow@1.0.18: + resolution: {integrity: sha512-BoWZUoMktji2YJmkRY8z0KsjvyDNpBzeC/rLVMFKcHkPxaKp+SHBFfx/kj7ltKh3l010Lc9RZqnJs8KUMNhf6Q==} + dependencies: + '@types/node': 18.15.3 + dev: true + /@types/is-ci@3.0.0: resolution: {integrity: sha512-Q0Op0hdWbYd1iahB+IFNQcWXFq4O0Q5MwQP7uN0souuQ4rPg1vEYcnIOfr1gY+M+6rc8FGoRaBO1mOOvL29sEQ==} dependencies: @@ -8183,6 +8249,13 @@ packages: '@types/geojson': 1.0.6 dev: false + /@types/mailparser@3.4.4: + resolution: {integrity: sha512-C6Znp2QVS25JqtuPyxj38Qh+QoFcLycdxsvcc6IZCGekhaMBzbdTXzwGzhGoYb3TfKu8IRCNV0sV1o3Od97cEQ==} + dependencies: + '@types/node': 18.15.3 + iconv-lite: 0.6.3 + dev: true + /@types/mapbox__point-geometry@0.1.4: resolution: {integrity: sha512-mUWlSxAmYLfwnRBmgYV86tgYmMIICX4kza8YnE/eIlywGe2XoOxlpVnXWwir92xRLjwyarqwpu2EJKD2pk0IUA==} dev: false @@ -8203,15 +8276,8 @@ packages: dev: false optional: true - /@types/mime@1.3.2: - resolution: {integrity: sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==} - /@types/mime@1.3.5: resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} - dev: true - - /@types/mime@3.0.1: - resolution: {integrity: sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==} /@types/minimatch@5.1.2: resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} @@ -8260,6 +8326,12 @@ packages: /@types/node@18.15.3: resolution: {integrity: sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw==} + /@types/nodemailer@6.4.15: + resolution: {integrity: sha512-0EBJxawVNjPkng1zm2vopRctuWVCxk34JcIlRuXSf54habUWdz1FB7wHDqOqvDa8Mtpt0Q3LTXQkAs2LNyK5jQ==} + dependencies: + '@types/node': 18.15.3 + dev: true + /@types/nodemailer@6.4.7: resolution: {integrity: sha512-f5qCBGAn/f0qtRcd4SEn88c8Fp3Swct1731X4ryPKqS61/A3LmmzN8zaEz7hneJvpjFbUUgY7lru/B/7ODTazg==} dependencies: @@ -8283,17 +8355,9 @@ packages: /@types/qs@6.9.15: resolution: {integrity: sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==} - dev: true - - /@types/qs@6.9.7: - resolution: {integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==} - - /@types/range-parser@1.2.4: - resolution: {integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==} /@types/range-parser@1.2.7: resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} - dev: true /@types/retry@0.12.0: resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} @@ -8312,39 +8376,24 @@ packages: /@types/semver@7.5.8: resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} - /@types/send@0.17.1: - resolution: {integrity: sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==} - dependencies: - '@types/mime': 1.3.2 - '@types/node': 18.15.3 - /@types/send@0.17.4: resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} dependencies: '@types/mime': 1.3.5 '@types/node': 18.15.3 - dev: true /@types/serve-index@1.9.4: resolution: {integrity: sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==} dependencies: - '@types/express': 4.17.21 + '@types/express': 4.17.17 dev: true - /@types/serve-static@1.15.2: - resolution: {integrity: sha512-J2LqtvFYCzaj8pVYKw8klQXrLLk7TBZmQ4ShlcdkELFKGwGMfevMLneMMRkMgZxotOD9wg497LpC7O8PcvAmfw==} - dependencies: - '@types/http-errors': 2.0.1 - '@types/mime': 3.0.1 - '@types/node': 18.15.3 - /@types/serve-static@1.15.7: resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==} dependencies: '@types/http-errors': 2.0.4 '@types/node': 18.15.3 '@types/send': 0.17.4 - dev: true /@types/sha1@1.1.3: resolution: {integrity: sha512-bXfx/6xrPu1l6pLItGRMPX00lhnJavpj2qiQeLHflXvL2Ix97aC8FTF2/pQoqukRzcCwKyN3csZvOLzamIoaSA==} @@ -8426,6 +8475,10 @@ packages: resolution: {integrity: sha512-RBz2uRZVCXuMg93WD//aTS5B120QlT4lR/gL+935QtGsKHLS6sCtZBaKfWjIfk7ZXv/r8mtGbwjVIee6/3XTow==} dev: true + /@types/trusted-types@2.0.7: + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + dev: true + /@types/unist@2.0.10: resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==} requiresBuild: true @@ -8868,6 +8921,13 @@ packages: engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} dev: true + /abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + dependencies: + event-target-shim: 5.0.1 + dev: false + /accepts@1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} @@ -8981,17 +9041,6 @@ packages: ajv: 8.12.0 dev: true - /ajv-formats@2.1.1(ajv@8.17.1): - resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - dependencies: - ajv: 8.17.1 - dev: true - /ajv-keywords@3.5.2(ajv@6.12.6): resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==} peerDependencies: @@ -9000,12 +9049,12 @@ packages: ajv: 6.12.6 dev: true - /ajv-keywords@5.1.0(ajv@8.17.1): + /ajv-keywords@5.1.0(ajv@8.12.0): resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} peerDependencies: ajv: ^8.8.2 dependencies: - ajv: 8.17.1 + ajv: 8.12.0 fast-deep-equal: 3.1.3 dev: true @@ -9250,6 +9299,15 @@ packages: dependencies: safer-buffer: 2.1.2 + /asn1js@3.0.5: + resolution: {integrity: sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==} + engines: {node: '>=12.0.0'} + dependencies: + pvtsutils: 1.3.5 + pvutils: 1.1.3 + tslib: 2.6.2 + dev: false + /assert-plus@1.0.0: resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} engines: {node: '>=0.8'} @@ -9293,6 +9351,11 @@ packages: resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} engines: {node: '>= 4.0.0'} + /atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} + dev: false + /autoprefixer@10.4.18(postcss@8.4.35): resolution: {integrity: sha512-1DKbDfsr6KUElM6wg+0zRNkB/Q7WcKYAaK+pzXn+Xqmszm/5Xa9coeNdtP88Vi+dPzZnMjhge8GIV49ZQkDa+g==} engines: {node: ^10 || ^12 || >=14} @@ -9634,7 +9697,6 @@ packages: unpipe: 1.0.0 transitivePeerDependencies: - supports-color - dev: false /body-parser@1.20.2: resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==} @@ -9710,13 +9772,13 @@ packages: engines: {node: '>=8'} dependencies: fill-range: 7.0.1 + dev: true /braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} dependencies: fill-range: 7.1.1 - dev: true /breakword@1.0.6: resolution: {integrity: sha512-yjxDAYyK/pBvws9H4xKYpLDpYKEH6CzrBPAuXq3x18I+c/2MkVtT3qAr7Oloi6Dss9qNhPVueAAVU1CSeNDIXw==} @@ -9758,6 +9820,13 @@ packages: base64-js: 1.5.1 ieee754: 1.2.1 + /buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: false + /buildcheck@0.0.6: resolution: {integrity: sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A==} engines: {node: '>=10.0.0'} @@ -9795,6 +9864,11 @@ packages: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} + /bytestreamjs@2.0.1: + resolution: {integrity: sha512-U1Z/ob71V/bXfVABvNr/Kumf5VyeQRBEm6Txb0PQ6S7V5GpBM3w4Cbqz/xPDicR5tN0uvDifng8C+5qECeGwyQ==} + engines: {node: '>=6.0.0'} + dev: false + /bytewise-core@1.2.3: resolution: {integrity: sha512-nZD//kc78OOxeYtRlVk8/zXqTB4gf/nlguL1ggWA8FuchMyOxcyHR4QPQZMUmA7czC+YnaBrPUCubqAWe50DaA==} dependencies: @@ -10644,12 +10718,6 @@ packages: /cookie@0.5.0: resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} engines: {node: '>= 0.6'} - dev: false - - /cookie@0.6.0: - resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} - engines: {node: '>= 0.6'} - dev: true /cookiejar@2.1.4: resolution: {integrity: sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==} @@ -11802,7 +11870,6 @@ packages: domelementtype: 2.3.0 domhandler: 5.0.3 entities: 4.5.0 - dev: true /dom7@4.0.6: resolution: {integrity: sha512-emjdpPLhpNubapLFdjNL9tP06Sr+GZkrIHEXLWvOGsytACUrkbeIdjO5g77m00BrHTznnlcNqgmn7pCN192TBA==} @@ -11812,7 +11879,6 @@ packages: /domelementtype@2.3.0: resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} - dev: true /domhandler@4.3.1: resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} @@ -11826,13 +11892,10 @@ packages: engines: {node: '>= 4'} dependencies: domelementtype: 2.3.0 - dev: true /dompurify@3.1.6: resolution: {integrity: sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ==} requiresBuild: true - dev: false - optional: true /domutils@2.8.0: resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} @@ -11848,7 +11911,6 @@ packages: dom-serializer: 2.0.0 domelementtype: 2.3.0 domhandler: 5.0.3 - dev: true /dot-prop@5.3.0: resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} @@ -11866,7 +11928,7 @@ packages: hasBin: true dependencies: cross-spawn: 7.0.3 - dotenv: 16.3.1 + dotenv: 16.4.5 dotenv-expand: 10.0.0 minimist: 1.2.8 dev: true @@ -11876,16 +11938,15 @@ packages: engines: {node: '>=12'} dev: true - /dotenv@16.3.1: - resolution: {integrity: sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==} - engines: {node: '>=12'} - dev: true - /dotenv@16.3.2: resolution: {integrity: sha512-HTlk5nmhkm8F6JcdXvHIzaorzCoziNQT9mGxLPVXW8wJF1TiGSL60ZGB4gHWabHOaMmWmhvk2/lPHfnBiT78AQ==} engines: {node: '>=12'} dev: true + /dotenv@16.4.5: + resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} + engines: {node: '>=12'} + /duplexer2@0.1.4: resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} dependencies: @@ -11966,6 +12027,16 @@ packages: resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} engines: {node: '>= 0.8'} + /encoding-japanese@2.0.0: + resolution: {integrity: sha512-++P0RhebUC8MJAwJOsT93dT+5oc5oPImp1HubZpAuCZ5kTLnhuuBhKHj2jJeO/Gj93idPBWmIuQ9QWMe5rX3pQ==} + engines: {node: '>=8.10.0'} + dev: false + + /encoding-japanese@2.1.0: + resolution: {integrity: sha512-58XySVxUgVlBikBTbQ8WdDxBDHIdXucB16LO5PBHR8t75D54wQrNo4cg+58+R1CtJfKnsVsvt9XlteRaR8xw1w==} + engines: {node: '>=8.10.0'} + dev: false + /encoding@0.1.13: resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} requiresBuild: true @@ -12557,6 +12628,11 @@ packages: through: 2.3.8 dev: true + /event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + dev: false + /eventemitter2@6.4.7: resolution: {integrity: sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==} dev: true @@ -12571,7 +12647,6 @@ packages: /events@3.3.0: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} - dev: true /execa@4.1.0: resolution: {integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==} @@ -12683,46 +12758,6 @@ packages: vary: 1.1.2 transitivePeerDependencies: - supports-color - dev: false - - /express@4.19.2: - resolution: {integrity: sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==} - engines: {node: '>= 0.10.0'} - dependencies: - accepts: 1.3.8 - array-flatten: 1.1.1 - body-parser: 1.20.2 - content-disposition: 0.5.4 - content-type: 1.0.5 - cookie: 0.6.0 - cookie-signature: 1.0.6 - debug: 2.6.9 - depd: 2.0.0 - encodeurl: 1.0.2 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 1.2.0 - fresh: 0.5.2 - http-errors: 2.0.0 - merge-descriptors: 1.0.1 - methods: 1.1.2 - on-finished: 2.4.1 - parseurl: 1.3.3 - path-to-regexp: 0.1.7 - proxy-addr: 2.0.7 - qs: 6.11.0 - range-parser: 1.2.1 - safe-buffer: 5.2.1 - send: 0.18.0 - serve-static: 1.15.0 - setprototypeof: 1.2.0 - statuses: 2.0.1 - type-is: 1.6.18 - utils-merge: 1.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - dev: true /extend-shallow@2.0.1: resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} @@ -12800,16 +12835,6 @@ packages: resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} dev: true - /fast-glob@3.3.1: - resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} - engines: {node: '>=8.6.0'} - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.5 - /fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} @@ -12819,7 +12844,6 @@ packages: glob-parent: 5.1.2 merge2: 1.4.1 micromatch: 4.0.7 - dev: true /fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -12827,6 +12851,11 @@ packages: /fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + /fast-redact@3.5.0: + resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} + engines: {node: '>=6'} + dev: false + /fast-safe-stringify@2.1.1: resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} dev: true @@ -12904,13 +12933,13 @@ packages: engines: {node: '>=8'} dependencies: to-regex-range: 5.0.1 + dev: true /fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} dependencies: to-regex-range: 5.0.1 - dev: true /finalhandler@1.1.2: resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} @@ -13570,8 +13599,8 @@ packages: dependencies: array-union: 2.1.0 dir-glob: 3.0.1 - fast-glob: 3.3.1 - ignore: 5.2.4 + fast-glob: 3.3.2 + ignore: 5.3.1 merge2: 1.4.1 slash: 3.0.0 @@ -13777,7 +13806,6 @@ packages: /he@1.2.0: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true - dev: true /hexoid@1.0.0: resolution: {integrity: sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==} @@ -13856,6 +13884,17 @@ packages: engines: {node: '>=8'} dev: true + /html-to-text@9.0.5: + resolution: {integrity: sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==} + engines: {node: '>=14'} + dependencies: + '@selderee/plugin-htmlparser2': 0.11.0 + deepmerge: 4.3.1 + dom-serializer: 2.0.0 + htmlparser2: 8.0.2 + selderee: 0.11.0 + dev: false + /htmlparser2@8.0.2: resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} dependencies: @@ -13863,7 +13902,6 @@ packages: domhandler: 5.0.3 domutils: 3.1.0 entities: 4.5.0 - dev: true /http-auth-connect@1.0.6: resolution: {integrity: sha512-yaO0QSCPqGCjPrl3qEEHjJP+lwZ6gMpXLuCBE06eWwcXomkI5TARtu0kxf9teFuBj6iaV3Ybr15jaWUvbzNzHw==} @@ -13932,7 +13970,7 @@ packages: - supports-color dev: true - /http-proxy-middleware@2.0.6(@types/express@4.17.21): + /http-proxy-middleware@2.0.6(@types/express@4.17.17): resolution: {integrity: sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==} engines: {node: '>=12.0.0'} peerDependencies: @@ -13941,7 +13979,7 @@ packages: '@types/express': optional: true dependencies: - '@types/express': 4.17.21 + '@types/express': 4.17.17 '@types/http-proxy': 1.17.14 http-proxy: 1.18.1 is-glob: 4.0.3 @@ -14125,10 +14163,6 @@ packages: minimatch: 9.0.5 dev: true - /ignore@5.2.4: - resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} - engines: {node: '>= 4'} - /ignore@5.3.1: resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} engines: {node: '>= 4'} @@ -14141,6 +14175,20 @@ packages: dev: true optional: true + /imapflow@1.0.162: + resolution: {integrity: sha512-pfx45n2gEIC9MeXAadcfehu5MboUzXqgQiZviKbnIxI6a/QkonOSAMXvBBkWbXQ5FXc9M5IpziJs6TP7jikBrg==} + dependencies: + encoding-japanese: 2.1.0 + iconv-lite: 0.6.3 + libbase64: 1.3.0 + libmime: 5.3.5 + libqp: 2.1.0 + mailsplit: 5.4.0 + nodemailer: 6.9.13 + pino: 9.0.0 + socks: 2.8.3 + dev: false + /immediate@3.0.6: resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} requiresBuild: true @@ -14332,7 +14380,6 @@ packages: dependencies: jsbn: 1.1.0 sprintf-js: 1.1.3 - dev: true /ip-regex@4.3.0: resolution: {integrity: sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==} @@ -14914,7 +14961,6 @@ packages: /jsbn@1.1.0: resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} - dev: true /jsdoc-type-pratt-parser@4.0.0: resolution: {integrity: sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==} @@ -15237,6 +15283,10 @@ packages: engines: {node: '> 0.8'} dev: true + /leac@0.6.0: + resolution: {integrity: sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==} + dev: false + /leek@0.0.24: resolution: {integrity: sha512-6PVFIYXxlYF0o6hrAsHtGpTmi06otkwNrMcmQ0K96SeSRHPREPa9J3nJZ1frliVH7XT0XFswoJFQoXsDukzGNQ==} dependencies: @@ -15289,6 +15339,40 @@ packages: prelude-ls: 1.2.1 type-check: 0.4.0 + /libbase64@1.2.1: + resolution: {integrity: sha512-l+nePcPbIG1fNlqMzrh68MLkX/gTxk/+vdvAb388Ssi7UuUN31MI44w4Yf33mM3Cm4xDfw48mdf3rkdHszLNew==} + dev: false + + /libbase64@1.3.0: + resolution: {integrity: sha512-GgOXd0Eo6phYgh0DJtjQ2tO8dc0IVINtZJeARPeiIJqge+HdsWSuaDTe8ztQ7j/cONByDZ3zeB325AHiv5O0dg==} + dev: false + + /libmime@5.2.0: + resolution: {integrity: sha512-X2U5Wx0YmK0rXFbk67ASMeqYIkZ6E5vY7pNWRKtnNzqjvdYYG8xtPDpCnuUEnPU9vlgNev+JoSrcaKSUaNvfsw==} + dependencies: + encoding-japanese: 2.0.0 + iconv-lite: 0.6.3 + libbase64: 1.2.1 + libqp: 2.0.1 + dev: false + + /libmime@5.3.5: + resolution: {integrity: sha512-nSlR1yRZ43L3cZCiWEw7ali3jY29Hz9CQQ96Oy+sSspYnIP5N54ucOPHqooBsXzwrX1pwn13VUE05q4WmzfaLg==} + dependencies: + encoding-japanese: 2.1.0 + iconv-lite: 0.6.3 + libbase64: 1.3.0 + libqp: 2.1.0 + dev: false + + /libqp@2.0.1: + resolution: {integrity: sha512-Ka0eC5LkF3IPNQHJmYBWljJsw0UvM6j+QdKRbWyCdTmYwvIDE6a7bCm0UkTAL/K+3KXK5qXT/ClcInU01OpdLg==} + dev: false + + /libqp@2.1.0: + resolution: {integrity: sha512-O6O6/fsG5jiUVbvdgT7YX3xY3uIadR6wEZ7+vy9u7PKHAlSEB6blvC1o5pHBjgsi95Uo0aiBBdkyFecj6jtb7A==} + dev: false + /license-checker@25.0.1: resolution: {integrity: sha512-mET5AIwl7MR2IAKYYoVBBpV0OnkKQ1xGj2IMMeEFIs42QAkEVjRtFZGWmQ28WeU7MP779iAgOaOy93Mn44mn6g==} hasBin: true @@ -15339,6 +15423,12 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dev: true + /linkify-it@5.0.0: + resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + dependencies: + uc.micro: 2.1.0 + dev: false + /listr2@3.14.0(enquirer@2.4.1): resolution: {integrity: sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==} engines: {node: '>=10.0.0'} @@ -15650,6 +15740,29 @@ packages: '@jridgewell/sourcemap-codec': 1.5.0 dev: true + /mailparser@3.7.1: + resolution: {integrity: sha512-RCnBhy5q8XtB3mXzxcAfT1huNqN93HTYYyL6XawlIKycfxM/rXPg9tXoZ7D46+SgCS1zxKzw+BayDQSvncSTTw==} + dependencies: + encoding-japanese: 2.1.0 + he: 1.2.0 + html-to-text: 9.0.5 + iconv-lite: 0.6.3 + libmime: 5.3.5 + linkify-it: 5.0.0 + mailsplit: 5.4.0 + nodemailer: 6.9.13 + punycode.js: 2.3.1 + tlds: 1.252.0 + dev: false + + /mailsplit@5.4.0: + resolution: {integrity: sha512-wnYxX5D5qymGIPYLwnp6h8n1+6P6vz/MJn5AzGjZ8pwICWssL+CCQjWBIToOVHASmATot4ktvlLo6CyLfOXWYA==} + dependencies: + libbase64: 1.2.1 + libmime: 5.2.0 + libqp: 2.0.1 + dev: false + /make-dir@2.1.0: resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} engines: {node: '>=6'} @@ -16163,6 +16276,7 @@ packages: dependencies: braces: 3.0.2 picomatch: 2.3.1 + dev: true /micromatch@4.0.7: resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} @@ -16170,7 +16284,6 @@ packages: dependencies: braces: 3.0.3 picomatch: 2.3.1 - dev: true /mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} @@ -16782,7 +16895,6 @@ packages: /node-forge@1.3.1: resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} engines: {node: '>= 6.13.0'} - dev: true /node-gyp-build@4.8.1: resolution: {integrity: sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==} @@ -16849,6 +16961,16 @@ packages: engines: {node: '>=6.0.0'} dev: false + /nodemailer@6.9.13: + resolution: {integrity: sha512-7o38Yogx6krdoBf3jCAqnIN4oSQFx+fMa0I7dK1D+me9kBxx12D+/33wSb+fhOCtIxvYJ+4x4IMEhmhCKfAiOA==} + engines: {node: '>=6.0.0'} + dev: false + + /nodemailer@6.9.14: + resolution: {integrity: sha512-Dobp/ebDKBvz91sbtRKhcznLThrKxKt97GI2FAlAyy+fk19j73Uz3sBXolVtmcXjaorivqsbbbjDY+Jkt4/bQA==} + engines: {node: '>=6.0.0'} + dev: false + /nodemon@2.0.22: resolution: {integrity: sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==} engines: {node: '>=8.10.0'} @@ -17149,6 +17271,11 @@ packages: resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} dev: true + /on-exit-leak-free@2.1.2: + resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} + engines: {node: '>=14.0.0'} + dev: false + /on-finished@2.3.0: resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} engines: {node: '>= 0.8'} @@ -17527,6 +17654,13 @@ packages: dependencies: entities: 4.5.0 + /parseley@0.12.1: + resolution: {integrity: sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==} + dependencies: + leac: 0.6.0 + peberminta: 0.9.0 + dev: false + /parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -17632,6 +17766,10 @@ packages: xmldoc: 1.3.0 dev: true + /peberminta@0.9.0: + resolution: {integrity: sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==} + dev: false + /pend@1.2.0: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} dev: true @@ -17668,6 +17806,34 @@ packages: requiresBuild: true dev: true + /pino-abstract-transport@1.2.0: + resolution: {integrity: sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==} + dependencies: + readable-stream: 4.5.2 + split2: 4.2.0 + dev: false + + /pino-std-serializers@6.2.2: + resolution: {integrity: sha512-cHjPPsE+vhj/tnhCy/wiMh3M3z3h/j15zHQX+S9GkTBgqJuTuJzYJ4gUyACLhDaJ7kk9ba9iRDmbH2tJU03OiA==} + dev: false + + /pino@9.0.0: + resolution: {integrity: sha512-uI1ThkzTShNSwvsUM6b4ND8ANzWURk9zTELMztFkmnCQeR/4wkomJ+echHee5GMWGovoSfjwdeu80DsFIt7mbA==} + hasBin: true + dependencies: + atomic-sleep: 1.0.0 + fast-redact: 3.5.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 1.2.0 + pino-std-serializers: 6.2.2 + process-warning: 3.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.4.3 + sonic-boom: 3.8.1 + thread-stream: 2.7.0 + dev: false + /pirates@4.0.6: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} @@ -17693,6 +17859,17 @@ packages: find-up: 6.3.0 dev: true + /pkijs@3.1.0: + resolution: {integrity: sha512-N+OCWUp6xrg7OkG+4DIiZUOsp3qMztjq8RGCc1hSY92dsUG8cTlAo7pEkfRGjcdyBv2c1Y9bjAzqdTJAlctuNg==} + engines: {node: '>=12.0.0'} + dependencies: + asn1js: 3.0.5 + bytestreamjs: 2.0.1 + pvtsutils: 1.3.5 + pvutils: 1.1.3 + tslib: 2.6.2 + dev: false + /plantuml-encoder@1.4.0: resolution: {integrity: sha512-sxMwpDw/ySY1WB2CE3+IdMuEcWibJ72DDOsXLkSmEaSzwEUaYBT6DWgOfBiHGCux4q433X6+OEFWjlVqp7gL6g==} dev: false @@ -17737,6 +17914,10 @@ packages: engines: {node: '>= 0.4'} dev: true + /postal-mime@2.2.5: + resolution: {integrity: sha512-6eTJf+B47JMdDuLF/4MBiGpTinxl0W8bA9CzrSoiQrNVRqK8Vhe59VrS6sXh2lG/lgo0bxpZFcWOF4Dv1FaSfg==} + dev: false + /postcss-load-config@3.1.4(ts-node@10.9.2): resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} engines: {node: '>= 10'} @@ -17925,12 +18106,6 @@ packages: fast-diff: 1.3.0 dev: true - /prettier@2.8.6: - resolution: {integrity: sha512-mtuzdiBbHwPEgl7NxWlqOkithPyp4VN93V7VeHVWBF+ad3I5avc0RVDT4oImXQy9H/AqxA2NSQH8pSxHW6FYbQ==} - engines: {node: '>=10.13.0'} - hasBin: true - dev: true - /prettier@2.8.8: resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} engines: {node: '>=10.13.0'} @@ -17976,10 +18151,13 @@ packages: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} dev: true + /process-warning@3.0.0: + resolution: {integrity: sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==} + dev: false + /process@0.11.10: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} - dev: true /progress@1.1.8: resolution: {integrity: sha512-UdA8mJ4weIkUBO224tIarHzuHs4HuYiJvsuGT7j/SPQiUJVjYvNDBIPa0hAorduOfjGohB/qHWRa/lrrWX/mXw==} @@ -18101,6 +18279,11 @@ packages: end-of-stream: 1.4.4 once: 1.4.0 + /punycode.js@2.3.1: + resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} + engines: {node: '>=6'} + dev: false + /punycode@1.4.1: resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} dev: true @@ -18118,6 +18301,17 @@ packages: resolution: {integrity: sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==} dev: true + /pvtsutils@1.3.5: + resolution: {integrity: sha512-ARvb14YB9Nm2Xi6nBq1ZX6dAM0FsJnuk+31aUp4TrcZEdKUlSqOqsxJHUPJDNE3qiIp+iUPEIeR6Je/tgV7zsA==} + dependencies: + tslib: 2.6.2 + dev: false + + /pvutils@1.1.3: + resolution: {integrity: sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==} + engines: {node: '>=6.0.0'} + dev: false + /q@1.5.1: resolution: {integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==} engines: {node: '>=0.6.0', teleport: '>=0.2.0'} @@ -18171,6 +18365,10 @@ packages: resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==} dev: true + /quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + dev: false + /quick-lru@4.0.1: resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==} engines: {node: '>=8'} @@ -18207,7 +18405,6 @@ packages: http-errors: 2.0.0 iconv-lite: 0.4.24 unpipe: 1.0.0 - dev: false /raw-body@2.5.2: resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} @@ -18365,6 +18562,17 @@ packages: string_decoder: 1.3.0 util-deprecate: 1.0.2 + /readable-stream@4.5.2: + resolution: {integrity: sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + string_decoder: 1.3.0 + dev: false + /readdir-scoped-modules@1.1.0: resolution: {integrity: sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==} deprecated: This functionality has been moved to @npmcli/fs @@ -18382,6 +18590,11 @@ packages: picomatch: 2.3.1 dev: true + /real-require@0.2.0: + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} + engines: {node: '>= 12.13.0'} + dev: false + /rechoir@0.6.2: resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} engines: {node: '>= 0.10'} @@ -18849,9 +19062,9 @@ packages: engines: {node: '>= 12.13.0'} dependencies: '@types/json-schema': 7.0.15 - ajv: 8.17.1 - ajv-formats: 2.1.1(ajv@8.17.1) - ajv-keywords: 5.1.0(ajv@8.17.1) + ajv: 8.12.0 + ajv-formats: 2.1.1(ajv@8.12.0) + ajv-keywords: 5.1.0(ajv@8.12.0) dev: true /secure-compare@3.0.1: @@ -18862,6 +19075,12 @@ packages: resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} dev: false + /selderee@0.11.0: + resolution: {integrity: sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==} + dependencies: + parseley: 0.12.1 + dev: false + /select-hose@2.0.0: resolution: {integrity: sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==} dev: true @@ -19333,7 +19552,12 @@ packages: dependencies: ip-address: 9.0.5 smart-buffer: 4.2.0 - dev: true + + /sonic-boom@3.8.1: + resolution: {integrity: sha512-y4Z8LCDBuum+PBP3lSV7RHrXscqksve/bi0as7mhwVnBW+/wUqKT/2Kb7um8yqcFy0duYbbPxzt89Zy2nOCaxg==} + dependencies: + atomic-sleep: 1.0.0 + dev: false /sort-asc@0.2.0: resolution: {integrity: sha512-umMGhjPeHAI6YjABoSTrFp2zaBtXBej1a0yKkuMUyjjqu6FJsTF+JYwCswWDg+zJfk/5npWUUbd33HH/WLzpaA==} @@ -19498,7 +19722,6 @@ packages: /split2@4.2.0: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} - dev: true /split@0.3.1: resolution: {integrity: sha512-hCHXkQDs1HFKRsrT9EutGT1hmjS1FW1Aei8dk/CxrT7mslcMtAxbiv8LYA/AYDvjB6h9rSXgW8zAZwg20tKMTw==} @@ -19518,7 +19741,6 @@ packages: /sprintf-js@1.1.3: resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} - dev: true /ssh-config@1.1.6: resolution: {integrity: sha512-ZPO9rECxzs5JIQ6G/2EfL1I9ho/BVZkx9HRKn8+0af7QgwAmumQ7XBFP1ggMyPMo+/tUbmv0HFdv4qifdO/9JA==} @@ -19956,7 +20178,7 @@ packages: engines: {node: '>=8'} hasBin: true dependencies: - '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/gen-mapping': 0.3.5 commander: 4.1.1 glob: 7.1.6 lines-and-columns: 1.2.4 @@ -20345,6 +20567,12 @@ packages: any-promise: 1.3.0 dev: true + /thread-stream@2.7.0: + resolution: {integrity: sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw==} + dependencies: + real-require: 0.2.0 + dev: false + /throttleit@1.0.1: resolution: {integrity: sha512-vDZpf9Chs9mAdfY046mcPt8fg5QSZr37hEH4TXYBnDF+izxgrbRGUAAaBvIk/fJm9aOFCGFd1EsNg5AZCbnQCQ==} dev: true @@ -20389,6 +20617,11 @@ packages: resolution: {integrity: sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==} dev: false + /tlds@1.252.0: + resolution: {integrity: sha512-GA16+8HXvqtfEnw/DTcwB0UU354QE1n3+wh08oFjr6Znl7ZLAeUgYzCcK+/CCrOyE0vnHR8/pu3XXG3vDijXpQ==} + hasBin: true + dev: false + /tmp@0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} @@ -20645,8 +20878,8 @@ packages: dependencies: bundle-require: 4.0.1(esbuild@0.17.19) cac: 6.7.14 - chokidar: 3.5.3 - debug: 4.3.4(supports-color@8.1.1) + chokidar: 3.6.0 + debug: 4.3.6(supports-color@8.1.1) esbuild: 0.17.19 execa: 5.1.1 globby: 11.1.0 @@ -20968,6 +21201,10 @@ packages: resolution: {integrity: sha512-fYmIy7fKTSFAhG3fuPlubeGaMoAd6r0rSnfEsO5nEY55i26KSLt9EH7PLQiiqPUhNqYIJvSkTy1oArIcXAbPbA==} dev: true + /uc.micro@2.1.0: + resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + dev: false + /uglify-js@3.19.1: resolution: {integrity: sha512-y/2wiW+ceTYR2TSSptAhfnEtpLaQ4Ups5zrjB2d3kuVxHj16j/QJwPl5PvuGy9uARb39J0+iKxcRPvtpsx4A4A==} engines: {node: '>=0.8.0'} @@ -21473,7 +21710,7 @@ packages: dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 - '@types/express': 4.17.21 + '@types/express': 4.17.17 '@types/serve-index': 1.9.4 '@types/serve-static': 1.15.7 '@types/sockjs': 0.3.36 @@ -21485,10 +21722,10 @@ packages: compression: 1.7.4 connect-history-api-fallback: 2.0.0 default-gateway: 6.0.3 - express: 4.19.2 + express: 4.18.2 graceful-fs: 4.2.11 html-entities: 2.5.2 - http-proxy-middleware: 2.0.6(@types/express@4.17.21) + http-proxy-middleware: 2.0.6(@types/express@4.17.17) ipaddr.js: 2.2.0 launch-editor: 2.8.0 open: 8.4.2