From d229da6af70c2596de1eb72d543b4a58e8c8d06b Mon Sep 17 00:00:00 2001 From: Miguel Cabrerizo <30386061+doncicuto@users.noreply.github.com> Date: Thu, 11 Apr 2024 09:16:10 +0200 Subject: [PATCH] feat: SMTP Templates (#6932) * feat: smtp templates poc * feat: add isActive & ProviderType to SMTP backend * feat: change providertype to uint32 and fix tests * feat: minimal smtp provider component * feat: woking on diiferent providers * feat: keep working on providers * feat: initial stepper for new provider * fix: settings list and working on stepper * feat: step 1 and 2 form inputs * feat: starter for smtp test step * fix: misspelled SMPT * fix: remove tests for now * feat: add tls toggle remove old google provider * feat: working on add smtp and table * fix: duplicated identifiers * fix: settings list * fix: add missing smtp config properties * fix: add configID to smtp config table * fix: working on listproviders * feat: working in listSMTPConfigs * fix: add count to listsmtpconfigs * fix: getting empty results from listSMTPConfigs * feat: table now shows real data * fix: remaining styles for smtp-table * fix: remove old notification-smtp-provider-component * feat: delete smtp configuration * feat: deactivate smtp config * feat: replace isActive with state for smtp config * feat: activate smtp config * fix: remaining errors after main merge * fix: list smtp providers panic and material mdc * feat: refactor to only one provider component * feat: current provider details view * fix: refactor AddSMTPConfig and ChangeSMTPConfig * fix: smtp config reduce issue * fix: recover domain in NewIAMSMTPConfigWriteModel * fix: add code needed by SetUpInstance * fix: go tests and warn about passing context to InstanceAggregateFromWriteModel * fix: i18n and add missing trans for fr, it, zh * fix: add e2e tests * docs: add smtp templates * fix: remove provider_type, add description * fix: remaining error from merge main * fix: add @stebenz change for primary key * fix: inactive placed after removed to prevent deleted configs to show as inactive * fix: smtp provider id can be empty (migrated) * feat: add mailchimp transactional template * feat: add Brevo (Sendinblue) template * feat: change brevo logo, add color to tls icon * fix: queries use resourceowner, id must not be empty * fix: deal with old smtp settings and tests * fix: resourceOwner is the instanceID * fix: remove aggregate_id, rename SMTPConfigByAggregateID with SMTPConfigActive * fix: add tests for multiple configs with different IDs * fix: conflict * fix: remove notification-smtp-provider * fix: add @peintnermax suggestions, rename module and fix e2e tests * fix: remove material legacy modules * fix: remove ctx as parameter for InstanceAggregateFromWriteModel * fix: add Id to SMTPConfigToPb * fix: change InstanceAggregateFromWriteModel to avoid linter errors * fix import * rm unused package-lock * update yarn lock --------- Co-authored-by: Elio Bischof Co-authored-by: Max Peintner Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com> --- console/src/app/app.component.ts | 2 + .../dialog-add-sms-provider.component.spec.ts | 24 + .../dialog-add-sms-provider.component.ts | 4 +- .../notification-sms-provider.module.ts | 6 +- ...ssword-dialog-sms-provider.component.html} | 0 ...ssword-dialog-sms-provider.component.scss} | 0 ...ord-dialog-sms-provider.component.spec.ts} | 2 +- ...password-dialog-sms-provider.component.ts} | 10 +- .../notification-smtp-provider.component.html | 95 +- .../notification-smtp-provider.component.scss | 135 +- ...tification-smtp-provider.component.spec.ts | 2 +- .../notification-smtp-provider.component.ts | 171 +- .../notification-smtp-provider.module.ts | 39 +- .../settings-list/settings-list.module.ts | 5 +- .../known-smtp-providers-settings.ts | 174 + .../smtp-provider-routing.module.ts | 39 + .../smtp-provider.component.html | 144 + .../smtp-provider.component.spec.ts | 23 + .../smtp-provider/smtp-provider.component.ts | 278 + .../smtp-provider/smtp-provider.module.ts | 51 + .../modules/smtp-provider/smtp-provider.scss | 71 + .../smtp-table/smtp-table.component.html | 129 + .../smtp-table/smtp-table.component.scss | 81 + .../smtp-table/smtp-table.component.spec.ts | 24 + .../smtp-table/smtp-table.component.ts | 194 + .../modules/smtp-table/smtp-table.module.ts | 46 + .../pages/instance/instance-routing.module.ts | 9 + console/src/app/services/admin.service.ts | 39 + console/src/assets/i18n/bg.json | 45 + console/src/assets/i18n/cs.json | 45 + console/src/assets/i18n/de.json | 45 + console/src/assets/i18n/en.json | 45 + console/src/assets/i18n/es.json | 45 + console/src/assets/i18n/fr.json | 45 + console/src/assets/i18n/it.json | 45 + console/src/assets/i18n/ja.json | 45 + console/src/assets/i18n/mk.json | 45 + console/src/assets/i18n/nl.json | 45 + console/src/assets/i18n/pl.json | 45 + console/src/assets/i18n/pt.json | 45 + console/src/assets/i18n/ru.json | 44 + console/src/assets/i18n/zh.json | 45 + console/src/assets/images/smtp/aws-ses.svg | 10 + console/src/assets/images/smtp/brevo.svg | 3 + console/src/assets/images/smtp/google.png | Bin 0 -> 4571 bytes console/src/assets/images/smtp/mailchimp.svg | 1 + console/src/assets/images/smtp/mailgun.svg | 15 + console/src/assets/images/smtp/mailjet.svg | 7 + console/src/assets/images/smtp/postmark.png | Bin 0 -> 1039 bytes console/src/assets/images/smtp/sendgrid.png | Bin 0 -> 3528 bytes console/src/assets/mdi/mail.svg | 1 + console/src/component-themes.scss | 6 + .../manage/console/default-settings.mdx | 42 +- docs/static/img/guides/console/smtp.png | Bin 51616 -> 49076 bytes .../e2e/instance/settings/notifications.cy.ts | 119 +- e2e/package-lock.json | 5366 ----------------- e2e/yarn.lock | 1729 ++++++ internal/api/grpc/admin/iam_settings.go | 63 - .../api/grpc/admin/iam_settings_converter.go | 11 +- internal/api/grpc/admin/smtp.go | 130 + internal/api/grpc/admin/smtp_converters.go | 41 + internal/command/instance.go | 1 + internal/command/instance_model.go | 8 +- .../command/instance_smtp_config_model.go | 171 +- internal/command/smtp.go | 381 +- internal/command/smtp_test.go | 496 +- internal/domain/smtp.go | 5 + .../notification/channels/smtp/channel.go | 14 +- internal/notification/channels/smtp/config.go | 1 + internal/notification/handlers/config_smtp.go | 3 +- .../handlers/mock/queries.mock.go | 12 +- internal/notification/handlers/queries.go | 2 +- internal/query/projection/smtp.go | 130 +- internal/query/projection/smtp_test.go | 100 +- internal/query/smtp.go | 161 +- internal/query/smtp_test.go | 125 +- internal/repository/instance/eventstore.go | 2 + internal/repository/instance/smtp_config.go | 153 +- internal/static/i18n/bg.yaml | 6 + internal/static/i18n/cs.yaml | 6 + internal/static/i18n/de.yaml | 6 + internal/static/i18n/en.yaml | 8 +- internal/static/i18n/es.yaml | 6 + internal/static/i18n/fr.yaml | 171 + internal/static/i18n/it.yaml | 181 +- internal/static/i18n/ja.yaml | 6 + internal/static/i18n/mk.yaml | 6 + internal/static/i18n/pl.yaml | 6 + internal/static/i18n/pt.yaml | 6 + internal/static/i18n/ru.yaml | 8 +- internal/static/i18n/zh.yaml | 186 +- proto/zitadel/admin.proto | 141 +- proto/zitadel/settings.proto | 13 + 93 files changed, 6359 insertions(+), 6132 deletions(-) create mode 100644 console/src/app/modules/policies/notification-sms-provider/dialog-add-sms-provider/dialog-add-sms-provider.component.spec.ts rename console/src/app/modules/policies/notification-sms-provider/{password-dialog/password-dialog.component.html => password-dialog-sms-provider/password-dialog-sms-provider.component.html} (100%) rename console/src/app/modules/policies/notification-sms-provider/{password-dialog/password-dialog.component.scss => password-dialog-sms-provider/password-dialog-sms-provider.component.scss} (100%) rename console/src/app/modules/policies/notification-sms-provider/{password-dialog/password-dialog.component.spec.ts => password-dialog-sms-provider/password-dialog-sms-provider.component.spec.ts} (88%) rename console/src/app/modules/policies/notification-sms-provider/{password-dialog/password-dialog.component.ts => password-dialog-sms-provider/password-dialog-sms-provider.component.ts} (52%) create mode 100644 console/src/app/modules/smtp-provider/known-smtp-providers-settings.ts create mode 100644 console/src/app/modules/smtp-provider/smtp-provider-routing.module.ts create mode 100644 console/src/app/modules/smtp-provider/smtp-provider.component.html create mode 100644 console/src/app/modules/smtp-provider/smtp-provider.component.spec.ts create mode 100644 console/src/app/modules/smtp-provider/smtp-provider.component.ts create mode 100644 console/src/app/modules/smtp-provider/smtp-provider.module.ts create mode 100644 console/src/app/modules/smtp-provider/smtp-provider.scss create mode 100644 console/src/app/modules/smtp-table/smtp-table.component.html create mode 100644 console/src/app/modules/smtp-table/smtp-table.component.scss create mode 100644 console/src/app/modules/smtp-table/smtp-table.component.spec.ts create mode 100644 console/src/app/modules/smtp-table/smtp-table.component.ts create mode 100644 console/src/app/modules/smtp-table/smtp-table.module.ts create mode 100644 console/src/assets/images/smtp/aws-ses.svg create mode 100644 console/src/assets/images/smtp/brevo.svg create mode 100644 console/src/assets/images/smtp/google.png create mode 100644 console/src/assets/images/smtp/mailchimp.svg create mode 100644 console/src/assets/images/smtp/mailgun.svg create mode 100644 console/src/assets/images/smtp/mailjet.svg create mode 100644 console/src/assets/images/smtp/postmark.png create mode 100644 console/src/assets/images/smtp/sendgrid.png create mode 100644 console/src/assets/mdi/mail.svg delete mode 100644 e2e/package-lock.json create mode 100644 e2e/yarn.lock create mode 100644 internal/api/grpc/admin/smtp.go create mode 100644 internal/api/grpc/admin/smtp_converters.go diff --git a/console/src/app/app.component.ts b/console/src/app/app.component.ts index 6f15b30a58..46e0168231 100644 --- a/console/src/app/app.component.ts +++ b/console/src/app/app.component.ts @@ -159,6 +159,8 @@ export class AppComponent implements OnDestroy { this.matIconRegistry.addSvgIcon('mdi_jwt', this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/jwt.svg')); + this.matIconRegistry.addSvgIcon('mdi_smtp', this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/mail.svg')); + this.matIconRegistry.addSvgIcon('mdi_symbol', this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/symbol.svg')); this.matIconRegistry.addSvgIcon( diff --git a/console/src/app/modules/policies/notification-sms-provider/dialog-add-sms-provider/dialog-add-sms-provider.component.spec.ts b/console/src/app/modules/policies/notification-sms-provider/dialog-add-sms-provider/dialog-add-sms-provider.component.spec.ts new file mode 100644 index 0000000000..b2e99391d6 --- /dev/null +++ b/console/src/app/modules/policies/notification-sms-provider/dialog-add-sms-provider/dialog-add-sms-provider.component.spec.ts @@ -0,0 +1,24 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; + +import { DialogAddSMSProviderComponent } from './dialog-add-sms-provider.component'; + +describe('PasswordDialogComponent', () => { + let component: DialogAddSMSProviderComponent; + let fixture: ComponentFixture; + + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [DialogAddSMSProviderComponent], + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DialogAddSMSProviderComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/console/src/app/modules/policies/notification-sms-provider/dialog-add-sms-provider/dialog-add-sms-provider.component.ts b/console/src/app/modules/policies/notification-sms-provider/dialog-add-sms-provider/dialog-add-sms-provider.component.ts index 6d9aa749fb..e766f6c360 100644 --- a/console/src/app/modules/policies/notification-sms-provider/dialog-add-sms-provider/dialog-add-sms-provider.component.ts +++ b/console/src/app/modules/policies/notification-sms-provider/dialog-add-sms-provider/dialog-add-sms-provider.component.ts @@ -10,7 +10,7 @@ import { import { SMSProvider, TwilioConfig } from 'src/app/proto/generated/zitadel/settings_pb'; import { AdminService } from 'src/app/services/admin.service'; import { ToastService } from 'src/app/services/toast.service'; -import { PasswordDialogComponent } from '../password-dialog/password-dialog.component'; +import { PasswordDialogSMSProviderComponent } from '../password-dialog-sms-provider/password-dialog-sms-provider.component'; enum SMSProviderType { Twilio = 1, @@ -73,7 +73,7 @@ export class DialogAddSMSProviderComponent { } public changeToken(): void { - const dialogRef = this.dialog.open(PasswordDialogComponent, { + const dialogRef = this.dialog.open(PasswordDialogSMSProviderComponent, { width: '400px', data: { i18nTitle: 'SETTING.SMS.TWILIO.SETTOKEN', diff --git a/console/src/app/modules/policies/notification-sms-provider/notification-sms-provider.module.ts b/console/src/app/modules/policies/notification-sms-provider/notification-sms-provider.module.ts index 112fd3e6d1..f3bcf260ef 100644 --- a/console/src/app/modules/policies/notification-sms-provider/notification-sms-provider.module.ts +++ b/console/src/app/modules/policies/notification-sms-provider/notification-sms-provider.module.ts @@ -6,6 +6,7 @@ import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatIconModule } from '@angular/material/icon'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatSelectModule } from '@angular/material/select'; + import { TranslateModule } from '@ngx-translate/core'; import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module'; @@ -16,10 +17,11 @@ import { InputModule } from '../../input/input.module'; import { WarnDialogModule } from '../../warn-dialog/warn-dialog.module'; import { DialogAddSMSProviderComponent } from './dialog-add-sms-provider/dialog-add-sms-provider.component'; import { NotificationSMSProviderComponent } from './notification-sms-provider.component'; +import { PasswordDialogSMSProviderComponent } from './password-dialog-sms-provider/password-dialog-sms-provider.component'; import { MatDialogModule } from '@angular/material/dialog'; @NgModule({ - declarations: [NotificationSMSProviderComponent, DialogAddSMSProviderComponent], + declarations: [NotificationSMSProviderComponent, DialogAddSMSProviderComponent, PasswordDialogSMSProviderComponent], imports: [ CommonModule, CardModule, @@ -34,9 +36,9 @@ import { MatDialogModule } from '@angular/material/dialog'; FormFieldModule, WarnDialogModule, MatSelectModule, - MatDialogModule, MatProgressSpinnerModule, MatSelectModule, + MatDialogModule, TranslateModule, ], exports: [NotificationSMSProviderComponent], diff --git a/console/src/app/modules/policies/notification-sms-provider/password-dialog/password-dialog.component.html b/console/src/app/modules/policies/notification-sms-provider/password-dialog-sms-provider/password-dialog-sms-provider.component.html similarity index 100% rename from console/src/app/modules/policies/notification-sms-provider/password-dialog/password-dialog.component.html rename to console/src/app/modules/policies/notification-sms-provider/password-dialog-sms-provider/password-dialog-sms-provider.component.html diff --git a/console/src/app/modules/policies/notification-sms-provider/password-dialog/password-dialog.component.scss b/console/src/app/modules/policies/notification-sms-provider/password-dialog-sms-provider/password-dialog-sms-provider.component.scss similarity index 100% rename from console/src/app/modules/policies/notification-sms-provider/password-dialog/password-dialog.component.scss rename to console/src/app/modules/policies/notification-sms-provider/password-dialog-sms-provider/password-dialog-sms-provider.component.scss diff --git a/console/src/app/modules/policies/notification-sms-provider/password-dialog/password-dialog.component.spec.ts b/console/src/app/modules/policies/notification-sms-provider/password-dialog-sms-provider/password-dialog-sms-provider.component.spec.ts similarity index 88% rename from console/src/app/modules/policies/notification-sms-provider/password-dialog/password-dialog.component.spec.ts rename to console/src/app/modules/policies/notification-sms-provider/password-dialog-sms-provider/password-dialog-sms-provider.component.spec.ts index 45f7f38a66..034bbe8de0 100644 --- a/console/src/app/modules/policies/notification-sms-provider/password-dialog/password-dialog.component.spec.ts +++ b/console/src/app/modules/policies/notification-sms-provider/password-dialog-sms-provider/password-dialog-sms-provider.component.spec.ts @@ -1,6 +1,6 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { PasswordDialogComponent } from './password-dialog.component'; +import { PasswordDialogComponent } from './password-dialog-sms-provider.component'; describe('PasswordDialogComponent', () => { let component: PasswordDialogComponent; diff --git a/console/src/app/modules/policies/notification-sms-provider/password-dialog/password-dialog.component.ts b/console/src/app/modules/policies/notification-sms-provider/password-dialog-sms-provider/password-dialog-sms-provider.component.ts similarity index 52% rename from console/src/app/modules/policies/notification-sms-provider/password-dialog/password-dialog.component.ts rename to console/src/app/modules/policies/notification-sms-provider/password-dialog-sms-provider/password-dialog-sms-provider.component.ts index 1f8cbafe4c..cbd2d30b02 100644 --- a/console/src/app/modules/policies/notification-sms-provider/password-dialog/password-dialog.component.ts +++ b/console/src/app/modules/policies/notification-sms-provider/password-dialog-sms-provider/password-dialog-sms-provider.component.ts @@ -2,14 +2,14 @@ import { Component, Inject } from '@angular/core'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; @Component({ - selector: 'cnsl-password-dialog', - templateUrl: './password-dialog.component.html', - styleUrls: ['./password-dialog.component.scss'], + selector: 'cnsl-password-dialog-sms-provider', + templateUrl: './password-dialog-sms-provider.component.html', + styleUrls: ['./password-dialog-sms-provider.component.scss'], }) -export class PasswordDialogComponent { +export class PasswordDialogSMSProviderComponent { public password: string = ''; constructor( - public dialogRef: MatDialogRef, + public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: any, ) {} diff --git a/console/src/app/modules/policies/notification-smtp-provider/notification-smtp-provider.component.html b/console/src/app/modules/policies/notification-smtp-provider/notification-smtp-provider.component.html index 7fb2a83630..5f86d23009 100644 --- a/console/src/app/modules/policies/notification-smtp-provider/notification-smtp-provider.component.html +++ b/console/src/app/modules/policies/notification-smtp-provider/notification-smtp-provider.component.html @@ -1,70 +1,37 @@ -

{{ 'DESCRIPTIONS.SETTINGS.SMTP_PROVIDER.TITLE' | translate }}

-

{{ 'DESCRIPTIONS.SETTINGS.SMTP_PROVIDER.DESCRIPTION' | translate }}

+

{{ 'SMTP.LIST.TITLE' | translate }}

+

{{ 'SMTP.LIST.DESCRIPTION' | translate }}

-
- +
+
-{{ 'SETTING.SMTP.REQUIREDWARN' | translate }} +

{{ 'SMTP.CREATE.TITLE' | translate }}

+

{{ 'SMTP.CREATE.DESCRIPTION' | translate }}

-
- - {{ 'SETTING.SMTP.SENDERADDRESS' | translate }} - - - - - {{ 'SETTING.SMTP.SENDERNAME' | translate }} - - - - - {{ 'SETTING.SMTP.REPLYTOADDRESS' | translate }} - - - - - {{ 'SETTING.SMTP.TLS' | translate }} - - - - {{ 'SETTING.SMTP.HOSTANDPORT' | translate }} - - - - - {{ 'SETTING.SMTP.USER' | translate }} - - - - - - -
+
diff --git a/console/src/app/modules/policies/notification-smtp-provider/notification-smtp-provider.component.scss b/console/src/app/modules/policies/notification-smtp-provider/notification-smtp-provider.component.scss index aa056af7e5..0e97db7c0f 100644 --- a/console/src/app/modules/policies/notification-smtp-provider/notification-smtp-provider.component.scss +++ b/console/src/app/modules/policies/notification-smtp-provider/notification-smtp-provider.component.scss @@ -1,32 +1,113 @@ -.spinner-wr { - margin: 0.5rem 0; -} +@use '@angular/material' as mat; -.smtp-form-field, -.info-section-warn { - max-width: 400px; - display: block; -} +@mixin smtp-settings-theme($theme) { + $primary: map-get($theme, primary); + $primary-color: mat.get-color-from-palette($primary, 500); + $is-dark-theme: map-get($theme, is-dark); + $background: map-get($theme, background); + $foreground: map-get($theme, foreground); -.info-section-warn { - margin-bottom: 0.5rem; -} - -.smtp-checkbox { - max-width: 400px; - display: block; - margin: 1rem 0; -} - -.set-password-btn { - margin-bottom: 1rem; -} - -.general-btn-container { - display: flex; - justify-content: flex-start; - - .save-button { + .cnsl-smtp-table-wrapper { display: block; } + + .new-smtp-wrapper { + display: grid; + row-gap: 1.5rem; + column-gap: 1.5rem; + box-sizing: border-box; + width: 100%; + grid-template-columns: 1fr; + + @media only screen and (min-width: 700px) { + grid-template-columns: 1fr 1fr; + } + + @media only screen and (min-width: 1000px) { + grid-template-columns: 1fr 1fr 1fr; + } + + @media only screen and (min-width: 1300px) { + grid-template-columns: 1fr 1fr 1fr 1fr; + } + + .item { + position: relative; + z-index: 100; + display: flex; + text-decoration: none; + cursor: pointer; + padding-top: 1rem; + padding-right: 1rem; + padding-bottom: 1rem; + padding-left: 1rem; + border-radius: 0.5rem; + box-sizing: border-box; + transition: box-shadow 0.1s ease-in; + align-items: center; + color: map-get($foreground, text); + + .coming-soon-label { + position: absolute; + top: 0; + right: 1rem; + transform: translateY(-50%); + width: fit-content; + } + + &:hover { + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.12); + } + + .smtp-logo { + margin-right: 1rem; + height: 36px; + width: 36px; + + &.apple { + margin-bottom: 4px; + } + + &.dark { + display: if($is-dark-theme, block, none); + } + + &.light { + display: if($is-dark-theme, none, block); + } + } + + .smtp-icon { + margin-right: 1rem; + display: flex; + justify-content: center; + align-items: center; + height: 36px; + width: 36px; + + .icon { + font-size: 2.25rem; + height: 2.25rem; + width: 2.25rem; + } + } + + .text-container { + display: flex; + flex-direction: column; + + .title { + } + } + + &.coming-soon { + filter: grayscale(1); + cursor: not-allowed; + + &:hover { + box-shadow: none; + } + } + } + } } diff --git a/console/src/app/modules/policies/notification-smtp-provider/notification-smtp-provider.component.spec.ts b/console/src/app/modules/policies/notification-smtp-provider/notification-smtp-provider.component.spec.ts index 65d781de8b..5a773d4b1f 100644 --- a/console/src/app/modules/policies/notification-smtp-provider/notification-smtp-provider.component.spec.ts +++ b/console/src/app/modules/policies/notification-smtp-provider/notification-smtp-provider.component.spec.ts @@ -2,7 +2,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { NotificationSMTPProviderComponent } from './notification-smtp-provider.component'; -describe('NotificationSMTPProviderComponent', () => { +describe('IdpSettingsComponent', () => { let component: NotificationSMTPProviderComponent; let fixture: ComponentFixture; diff --git a/console/src/app/modules/policies/notification-smtp-provider/notification-smtp-provider.component.ts b/console/src/app/modules/policies/notification-smtp-provider/notification-smtp-provider.component.ts index 8d65bc634a..6af684f0f1 100644 --- a/console/src/app/modules/policies/notification-smtp-provider/notification-smtp-provider.component.ts +++ b/console/src/app/modules/policies/notification-smtp-provider/notification-smtp-provider.component.ts @@ -1,22 +1,9 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { AbstractControl, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; -import { MatDialog } from '@angular/material/dialog'; -import { take } from 'rxjs'; -import { - AddSMTPConfigRequest, - AddSMTPConfigResponse, - UpdateSMTPConfigPasswordRequest, - UpdateSMTPConfigRequest, - UpdateSMTPConfigResponse, -} from 'src/app/proto/generated/zitadel/admin_pb'; +import { Component, Injector, Input, OnInit, Type } from '@angular/core'; import { AdminService } from 'src/app/services/admin.service'; -import { GrpcAuthService } from 'src/app/services/grpc-auth.service'; -import { ToastService } from 'src/app/services/toast.service'; -import { requiredValidator } from '../../form-field/validators/validators'; +import { ManagementService } from 'src/app/services/mgmt.service'; -import { InfoSectionType } from '../../info-section/info-section.component'; -import { PasswordDialogComponent } from '../notification-sms-provider/password-dialog/password-dialog.component'; import { PolicyComponentServiceType } from '../policy-component-types.enum'; +import { SMTPKnownProviders } from '../../smtp-provider/known-smtp-providers-settings'; @Component({ selector: 'cnsl-notification-smtp-provider', @@ -25,151 +12,21 @@ import { PolicyComponentServiceType } from '../policy-component-types.enum'; }) export class NotificationSMTPProviderComponent implements OnInit { @Input() public serviceType!: PolicyComponentServiceType; + public service!: ManagementService | AdminService; - public smtpLoading: boolean = false; + public PolicyComponentServiceType: any = PolicyComponentServiceType; + public providers = SMTPKnownProviders; - public form!: UntypedFormGroup; - - public InfoSectionType: any = InfoSectionType; - - public hasSMTPConfig: boolean = false; - - // show available providers - - constructor( - private service: AdminService, - private dialog: MatDialog, - private toast: ToastService, - private fb: UntypedFormBuilder, - private authService: GrpcAuthService, - ) { - this.form = this.fb.group({ - senderAddress: [{ disabled: true, value: '' }, [requiredValidator]], - senderName: [{ disabled: true, value: '' }, [requiredValidator]], - replyToAddress: [{ disabled: true, value: '' }], - tls: [{ disabled: true, value: true }, [requiredValidator]], - hostAndPort: [{ disabled: true, value: '' }, [requiredValidator]], - user: [{ disabled: true, value: '' }, [requiredValidator]], - }); - } + constructor(private injector: Injector) {} ngOnInit(): void { - this.fetchData(); - this.authService - .isAllowed(['iam.write']) - .pipe(take(1)) - .subscribe((allowed) => { - if (allowed) { - this.form.enable(); - } - }); - } - - private fetchData(): void { - this.smtpLoading = true; - this.service - .getSMTPConfig() - .then((smtpConfig) => { - this.smtpLoading = false; - if (smtpConfig.smtpConfig) { - this.hasSMTPConfig = true; - this.form.patchValue(smtpConfig.smtpConfig); - this.form.patchValue({ ['hostAndPort']: smtpConfig.smtpConfig.host }); - } - }) - .catch((error) => { - this.smtpLoading = false; - if (error && error.code === 5) { - console.log(error); - this.hasSMTPConfig = false; - } - }); - } - - private updateData(): Promise { - if (this.hasSMTPConfig) { - const req = new UpdateSMTPConfigRequest(); - req.setHost(this.hostAndPort?.value ?? ''); - req.setSenderAddress(this.senderAddress?.value ?? ''); - req.setSenderName(this.senderName?.value ?? ''); - req.setReplyToAddress(this.replyToAddress?.value ?? ''); - req.setTls(this.tls?.value ?? false); - req.setUser(this.user?.value ?? ''); - - return this.service.updateSMTPConfig(req); - } else { - const req = new AddSMTPConfigRequest(); - req.setHost(this.hostAndPort?.value ?? ''); - req.setSenderAddress(this.senderAddress?.value ?? ''); - req.setSenderName(this.senderName?.value ?? ''); - req.setReplyToAddress(this.replyToAddress?.value ?? ''); - req.setTls(this.tls?.value ?? false); - req.setUser(this.user?.value ?? ''); - - return this.service.addSMTPConfig(req); + switch (this.serviceType) { + case PolicyComponentServiceType.MGMT: + this.service = this.injector.get(ManagementService as Type); + break; + case PolicyComponentServiceType.ADMIN: + this.service = this.injector.get(AdminService as Type); + break; } } - - public savePolicy(): void { - this.updateData() - .then(() => { - this.toast.showInfo('SETTING.SMTP.SAVED', true); - setTimeout(() => { - this.fetchData(); - }, 2000); - }) - .catch((error: unknown) => { - this.toast.showError(error); - }); - } - - public setSMTPPassword(): void { - const dialogRef = this.dialog.open(PasswordDialogComponent, { - width: '400px', - data: { - i18nTitle: 'SETTING.SMTP.SETPASSWORD', - i18nLabel: 'SETTING.SMTP.PASSWORD', - }, - }); - - dialogRef.afterClosed().subscribe((password: string) => { - if (password) { - const passwordReq = new UpdateSMTPConfigPasswordRequest(); - passwordReq.setPassword(password); - - this.service - .updateSMTPConfigPassword(passwordReq) - .then(() => { - this.toast.showInfo('SETTING.SMTP.PASSWORDSET', true); - }) - .catch((error) => { - this.toast.showError(error); - }); - } - }); - } - - public get senderAddress(): AbstractControl | null { - return this.form.get('senderAddress'); - } - - public get senderName(): AbstractControl | null { - return this.form.get('senderName'); - } - - public get replyToAddress(): AbstractControl | null { - return this.form.get('replyToAddress'); - } - - public get tls(): AbstractControl | null { - return this.form.get('tls'); - } - - public get user(): AbstractControl | null { - return this.form.get('user'); - } - - public get hostAndPort(): AbstractControl | null { - return this.form.get('hostAndPort'); - } } diff --git a/console/src/app/modules/policies/notification-smtp-provider/notification-smtp-provider.module.ts b/console/src/app/modules/policies/notification-smtp-provider/notification-smtp-provider.module.ts index 91e68a4e66..4dbf109639 100644 --- a/console/src/app/modules/policies/notification-smtp-provider/notification-smtp-provider.module.ts +++ b/console/src/app/modules/policies/notification-smtp-provider/notification-smtp-provider.module.ts @@ -1,43 +1,32 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatIconModule } from '@angular/material/icon'; -import { MatButtonModule } from '@angular/material/button'; -import { MatCheckboxModule } from '@angular/material/checkbox'; -import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; -import { MatSelectModule } from '@angular/material/select'; +import { RouterModule } from '@angular/router'; import { TranslateModule } from '@ngx-translate/core'; import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module'; import { CardModule } from '../../card/card.module'; -import { FormFieldModule } from '../../form-field/form-field.module'; -import { InfoSectionModule } from '../../info-section/info-section.module'; -import { InputModule } from '../../input/input.module'; -import { WarnDialogModule } from '../../warn-dialog/warn-dialog.module'; -import { PasswordDialogComponent } from '../notification-sms-provider/password-dialog/password-dialog.component'; import { NotificationSMTPProviderComponent } from './notification-smtp-provider.component'; -import { MatDialogModule } from '@angular/material/dialog'; +import { InputModule } from '../../input/input.module'; +import { FormFieldModule } from '../../form-field/form-field.module'; +import { SMTPTableModule } from '../../smtp-table/smtp-table.module'; +import { MatButtonModule } from '@angular/material/button'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; @NgModule({ - declarations: [NotificationSMTPProviderComponent, PasswordDialogComponent], + declarations: [NotificationSMTPProviderComponent], imports: [ - CommonModule, - CardModule, - InfoSectionModule, - FormsModule, - ReactiveFormsModule, - HasRolePipeModule, - MatButtonModule, - MatCheckboxModule, InputModule, - MatIconModule, FormFieldModule, - WarnDialogModule, - MatSelectModule, + CommonModule, + MatButtonModule, + CardModule, + MatIconModule, + SMTPTableModule, + RouterModule, + HasRolePipeModule, MatProgressSpinnerModule, - MatSelectModule, TranslateModule, - MatDialogModule, ], exports: [NotificationSMTPProviderComponent], }) diff --git a/console/src/app/modules/settings-list/settings-list.module.ts b/console/src/app/modules/settings-list/settings-list.module.ts index 0472476c51..5538c49bef 100644 --- a/console/src/app/modules/settings-list/settings-list.module.ts +++ b/console/src/app/modules/settings-list/settings-list.module.ts @@ -14,7 +14,6 @@ import { LoginTextsPolicyModule } from '../policies/login-texts/login-texts.modu import { MessageTextsPolicyModule } from '../policies/message-texts/message-texts.module'; import { NotificationPolicyModule } from '../policies/notification-policy/notification-policy.module'; import { NotificationSMSProviderModule } from '../policies/notification-sms-provider/notification-sms-provider.module'; -import { NotificationSMTPProviderModule } from '../policies/notification-smtp-provider/notification-smtp-provider.module'; import { OIDCConfigurationModule } from '../policies/oidc-configuration/oidc-configuration.module'; import { PasswordComplexityPolicyModule } from '../policies/password-complexity-policy/password-complexity-policy.module'; import { PasswordLockoutPolicyModule } from '../policies/password-lockout-policy/password-lockout-policy.module'; @@ -28,7 +27,9 @@ import FailedEventsModule from '../failed-events/failed-events.module'; import IamViewsModule from '../iam-views/iam-views.module'; import EventsModule from '../events/events.module'; import { OrgTableModule } from '../org-table/org-table.module'; +import { NotificationSMTPProviderModule } from '../policies/notification-smtp-provider/notification-smtp-provider.module'; import { FeaturesComponent } from 'src/app/components/features/features.component'; +import OrgListModule from 'src/app/pages/org-list/org-list.module'; @NgModule({ declarations: [SettingsListComponent], @@ -44,12 +45,14 @@ import { FeaturesComponent } from 'src/app/components/features/features.componen LanguageSettingsModule, NotificationPolicyModule, IdpSettingsModule, + NotificationSMTPProviderModule, PrivacyPolicyModule, MessageTextsPolicyModule, SecurityPolicyModule, DomainsModule, LoginTextsPolicyModule, OrgTableModule, + OrgListModule, DomainPolicyModule, TranslateModule, HasRolePipeModule, diff --git a/console/src/app/modules/smtp-provider/known-smtp-providers-settings.ts b/console/src/app/modules/smtp-provider/known-smtp-providers-settings.ts new file mode 100644 index 0000000000..ec6087ea43 --- /dev/null +++ b/console/src/app/modules/smtp-provider/known-smtp-providers-settings.ts @@ -0,0 +1,174 @@ +export interface AmazonRegionsEndpoints { + 'US East (Ohio)': string; + 'US East (N. Virginia)': string; + 'US West (N. California)': string; + 'US West (Oregon)': string; + 'Asia Pacific (Mumbai)': string; + 'Asia Pacific (Osaka)': string; + 'Asia Pacific (Seoul)': string; + 'Asia Pacific (Singapore)': string; + 'Asia Pacific (Sydney)': string; + 'Asia Pacific (Tokyo)': string; + 'Canada (Central)': string; + 'Europe (Frankfurt)': string; + 'Europe (London)': string; + 'Europe (Paris)': string; + 'Europe (Stockholm)': string; + 'South America (São Paulo)': string; +} + +const amazonEndpoints = { + 'US East (Ohio)': 'email-smtp.us-east-2.amazonaws.com', + 'US East (N. Virginia)': 'email-smtp.us-east-1.amazonaws.com', + 'US West (N. California)': 'email-smtp.us-west-1.amazonaws.com', + 'US West (Oregon)': 'email-smtp.us-west-2.amazonaws.com', + 'Asia Pacific (Mumbai)': 'email-smtp.ap-south-1.amazonaws.com', + 'Asia Pacific (Osaka)': 'email-smtp.ap-northeast-3.amazonaws.com', + 'Asia Pacific (Seoul)': 'email-smtp.ap-northeast-2.amazonaws.com', + 'Asia Pacific (Singapore)': 'email-smtp.ap-southeast-1.amazonaws.com', + 'Asia Pacific (Sydney)': 'email-smtp.ap-southeast-2.amazonaws.com', + 'Asia Pacific (Tokyo)': 'email-smtp.ap-northeast-1.amazonaws.com', + 'Canada (Central)': 'email-smtp.ca-central-1.amazonaws.com', + 'Europe (Frankfurt)': 'email-smtp.eu-central-1.amazonaws.com', + 'Europe (Ireland)': 'email-smtp.eu-west-1.amazonaws.com', + 'Europe (London)': 'email-smtp.eu-west-2.amazonaws.com', + 'Europe (Paris)': 'email-smtp.eu-west-3.amazonaws.com', + 'Europe (Stockholm)': 'email-smtp.eu-north-1.amazonaws.com', + 'South America (São Paulo)': 'email-smtp.sa-east-1.amazonaws.com', +}; + +export interface ProviderDefaultSettings { + name: string; + regions?: AmazonRegionsEndpoints; + multiHostsLabel?: string; + requiredTls: boolean; + host?: string; + unencryptedPort?: number; + encryptedPort?: number; + user: { + value: string; + placeholder: string; + }; + password: { + value: string; + placeholder: string; + }; + image?: string; + routerLinkElement: string; +} + +export const AmazonSESDefaultSettings: ProviderDefaultSettings = { + name: 'amazon SES', + regions: amazonEndpoints, + multiHostsLabel: 'Choose your region', + requiredTls: true, + encryptedPort: 587, + user: { value: '', placeholder: 'your Amazon SES credentials for this region' }, + password: { value: '', placeholder: 'your Amazon SES credentials for this region' }, + image: './assets/images/smtp/aws-ses.svg', + routerLinkElement: 'aws-ses', +}; + +export const GoogleDefaultSettings: ProviderDefaultSettings = { + name: 'google', + requiredTls: true, + host: 'smtp.gmail.com', + unencryptedPort: 587, + encryptedPort: 587, + user: { value: '', placeholder: 'your complete Google Workspace email address' }, + password: { value: '', placeholder: 'your complete Google Workspace password' }, + image: './assets/images/smtp/google.png', + routerLinkElement: 'google', +}; + +export const MailgunDefaultSettings: ProviderDefaultSettings = { + name: 'mailgun', + requiredTls: false, + host: 'smtp.mailgun.org', + unencryptedPort: 587, + encryptedPort: 465, + user: { value: '', placeholder: 'postmaster@YOURDOMAIN' }, + password: { value: '', placeholder: 'Your mailgun smtp password' }, + image: './assets/images/smtp/mailgun.svg', + routerLinkElement: 'mailgun', +}; + +export const MailjetDefaultSettings: ProviderDefaultSettings = { + name: 'mailjet', + requiredTls: false, + host: 'in-v3.mailjet.com', + unencryptedPort: 587, + encryptedPort: 465, + user: { value: '', placeholder: 'Your Mailjet API key' }, + password: { value: '', placeholder: 'Your Mailjet Secret key' }, + image: './assets/images/smtp/mailjet.svg', + routerLinkElement: 'mailjet', +}; + +export const PostmarkDefaultSettings: ProviderDefaultSettings = { + name: 'postmark', + requiredTls: false, + host: 'smtp.postmarkapp.com', + unencryptedPort: 587, + encryptedPort: 587, + user: { value: '', placeholder: 'Your Server API token' }, + password: { value: '', placeholder: 'Your Server API token' }, + image: './assets/images/smtp/postmark.png', + routerLinkElement: 'postmark', +}; + +export const SendgridDefaultSettings: ProviderDefaultSettings = { + name: 'sendgrid', + requiredTls: false, + host: 'smtp.sendgrid.net', + unencryptedPort: 587, + encryptedPort: 465, + user: { value: 'apikey', placeholder: '' }, + password: { value: '', placeholder: ' Your SendGrid API Key' }, + image: './assets/images/smtp/sendgrid.png', + routerLinkElement: 'sendgrid', +}; + +export const MailchimpDefaultSettings: ProviderDefaultSettings = { + name: 'mailchimp', + requiredTls: false, + host: 'smtp.mandrillapp.com', + unencryptedPort: 587, + encryptedPort: 465, + user: { value: '', placeholder: 'Your Mailchimp primary contact email' }, + password: { value: '', placeholder: 'Your Mailchimp Transactional API key' }, + image: './assets/images/smtp/mailchimp.svg', + routerLinkElement: 'mailchimp', +}; + +export const BrevoDefaultSettings: ProviderDefaultSettings = { + name: 'brevo', + requiredTls: false, + host: 'smtp-relay.sendinblue.com', + unencryptedPort: 587, + encryptedPort: 465, + user: { value: '', placeholder: 'Your SMTP login email address' }, + password: { value: '', placeholder: 'Your SMTP key' }, + image: './assets/images/smtp/brevo.svg', + routerLinkElement: 'brevo', +}; + +export const GenericDefaultSettings: ProviderDefaultSettings = { + name: 'generic', + requiredTls: false, + user: { value: '', placeholder: 'your SMTP user' }, + password: { value: '', placeholder: 'your SMTP password' }, + routerLinkElement: 'generic', +}; + +export const SMTPKnownProviders = [ + AmazonSESDefaultSettings, + BrevoDefaultSettings, + // GoogleDefaultSettings, + MailgunDefaultSettings, + MailchimpDefaultSettings, + MailjetDefaultSettings, + PostmarkDefaultSettings, + SendgridDefaultSettings, + GenericDefaultSettings, +]; diff --git a/console/src/app/modules/smtp-provider/smtp-provider-routing.module.ts b/console/src/app/modules/smtp-provider/smtp-provider-routing.module.ts new file mode 100644 index 0000000000..849be82a45 --- /dev/null +++ b/console/src/app/modules/smtp-provider/smtp-provider-routing.module.ts @@ -0,0 +1,39 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; + +import { SMTPProviderComponent } from './smtp-provider.component'; + +const types = [ + { path: 'aws-ses', component: SMTPProviderComponent }, + { path: 'generic', component: SMTPProviderComponent }, + { path: 'google', component: SMTPProviderComponent }, + { path: 'mailgun', component: SMTPProviderComponent }, + { path: 'postmark', component: SMTPProviderComponent }, + { path: 'sendgrid', component: SMTPProviderComponent }, + { path: 'mailjet', component: SMTPProviderComponent }, + { path: 'mailchimp', component: SMTPProviderComponent }, + { path: 'brevo', component: SMTPProviderComponent }, +]; + +const routes: Routes = types.map((value) => { + return { + path: value.path, + children: [ + { + path: 'create', + component: value.component, + }, + ], + }; +}); + +routes.push({ + path: ':id', + component: SMTPProviderComponent, +}); + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], +}) +export class SMTPProvidersRoutingModule {} diff --git a/console/src/app/modules/smtp-provider/smtp-provider.component.html b/console/src/app/modules/smtp-provider/smtp-provider.component.html new file mode 100644 index 0000000000..c23b19f66e --- /dev/null +++ b/console/src/app/modules/smtp-provider/smtp-provider.component.html @@ -0,0 +1,144 @@ + +
+ +
+ +
+

+ {{ + !id + ? ('SMTP.CREATE.STEPS.CREATE_DESC_TITLE' | translate: { value: providerDefaultSetting.name | titlecase }) + : ('SMTP.CREATE.STEPS.CURRENT_DESC_TITLE' | translate) + }} +

+
+ + + + + {{ 'SMTP.CREATE.STEPS.PROVIDER_SETTINGS' | translate }} +
+ + {{ 'SETTING.SMTP.TLS' | translate }} + + + + {{ providerDefaultSetting.multiHostsLabel }} + + + {{ region.key }} + + + + + + {{ 'SETTING.SMTP.DESCRIPTION' | translate }} + + + + + {{ 'SETTING.SMTP.HOSTANDPORT' | translate }} + + + + + {{ 'SETTING.SMTP.USER' | translate }} + + + + + {{ 'SETTING.SMTP.PASSWORD' | translate }} + + +
+ +
+ +
+
+ + +
+ {{ 'SMTP.CREATE.STEPS.SENDER_SETTINGS' | translate }} + + + {{ 'SETTING.SMTP.SENDERADDRESS' | translate }} + + + + + {{ 'SETTING.SMTP.SENDERNAME' | translate }} + + + + + {{ 'SETTING.SMTP.REPLYTOADDRESS' | translate }} + + +
+ +
+ + +
+
+ + + check + +
+
diff --git a/console/src/app/modules/smtp-provider/smtp-provider.component.spec.ts b/console/src/app/modules/smtp-provider/smtp-provider.component.spec.ts new file mode 100644 index 0000000000..6a82f69f6a --- /dev/null +++ b/console/src/app/modules/smtp-provider/smtp-provider.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; +import { SMTPProviderComponent } from './smtp-provider.component'; + +describe('SMTPProviderSendgridComponent', () => { + let component: SMTPProviderComponent; + let fixture: ComponentFixture; + + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [SMTPProviderComponent], + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SMTPProviderComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/console/src/app/modules/smtp-provider/smtp-provider.component.ts b/console/src/app/modules/smtp-provider/smtp-provider.component.ts new file mode 100644 index 0000000000..c3991a55c8 --- /dev/null +++ b/console/src/app/modules/smtp-provider/smtp-provider.component.ts @@ -0,0 +1,278 @@ +import { COMMA, ENTER, SPACE } from '@angular/cdk/keycodes'; +import { Location } from '@angular/common'; +import { Component } from '@angular/core'; +import { AbstractControl, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { Subject } from 'rxjs'; +import { StepperSelectionEvent } from '@angular/cdk/stepper'; +import { Options } from 'src/app/proto/generated/zitadel/idp_pb'; +import { requiredValidator } from '../form-field/validators/validators'; + +import { PolicyComponentServiceType } from '../policies/policy-component-types.enum'; +import { + AddSMTPConfigRequest, + AddSMTPConfigResponse, + UpdateSMTPConfigRequest, + UpdateSMTPConfigResponse, +} from 'src/app/proto/generated/zitadel/admin_pb'; +import { AdminService } from 'src/app/services/admin.service'; +import { ToastService } from 'src/app/services/toast.service'; +import { ActivatedRoute, Router } from '@angular/router'; +import { MatCheckboxChange } from '@angular/material/checkbox'; +import { + AmazonSESDefaultSettings, + BrevoDefaultSettings, + GenericDefaultSettings, + GoogleDefaultSettings, + MailchimpDefaultSettings, + MailgunDefaultSettings, + MailjetDefaultSettings, + PostmarkDefaultSettings, + ProviderDefaultSettings, + SendgridDefaultSettings, +} from './known-smtp-providers-settings'; + +@Component({ + selector: 'cnsl-smtp-provider', + templateUrl: './smtp-provider.component.html', + styleUrls: ['./smtp-provider.scss'], +}) +export class SMTPProviderComponent { + public showOptional: boolean = false; + public options: Options = new Options().setIsCreationAllowed(true).setIsLinkingAllowed(true); + public id: string = ''; + public providerDefaultSetting: ProviderDefaultSettings = GenericDefaultSettings; + public serviceType: PolicyComponentServiceType = PolicyComponentServiceType.MGMT; + + public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE]; + + public smtpLoading: boolean = false; + public hasSMTPConfig: boolean = false; + + public updateClientSecret: boolean = false; + + // stepper + public currentCreateStep: number = 1; + public requestRedirectValuesSubject$: Subject = new Subject(); + public firstFormGroup!: UntypedFormGroup; + public secondFormGroup!: UntypedFormGroup; + + constructor( + private service: AdminService, + private _location: Location, + private fb: UntypedFormBuilder, + private toast: ToastService, + private router: Router, + private route: ActivatedRoute, + ) { + this.route.parent?.url.subscribe((urlPath) => { + const providerName = urlPath[urlPath.length - 1].path; + switch (providerName) { + case 'aws-ses': + this.providerDefaultSetting = AmazonSESDefaultSettings; + break; + case 'google': + this.providerDefaultSetting = GoogleDefaultSettings; + break; + case 'mailgun': + this.providerDefaultSetting = MailgunDefaultSettings; + break; + case 'mailjet': + this.providerDefaultSetting = MailjetDefaultSettings; + break; + case 'postmark': + this.providerDefaultSetting = PostmarkDefaultSettings; + break; + case 'sendgrid': + this.providerDefaultSetting = SendgridDefaultSettings; + break; + case 'mailchimp': + this.providerDefaultSetting = MailchimpDefaultSettings; + break; + case 'brevo': + this.providerDefaultSetting = BrevoDefaultSettings; + break; + } + + this.firstFormGroup = this.fb.group({ + description: [this.providerDefaultSetting.name], + tls: [{ value: this.providerDefaultSetting.requiredTls, disabled: this.providerDefaultSetting.requiredTls }], + region: [''], + hostAndPort: [ + this.providerDefaultSetting?.host + ? `${this.providerDefaultSetting?.host}:${this.providerDefaultSetting?.unencryptedPort}` + : '', + ], + user: [this.providerDefaultSetting?.user.value || ''], + password: [this.providerDefaultSetting?.password.value || ''], + }); + + this.secondFormGroup = this.fb.group({ + senderAddress: ['', [requiredValidator]], + senderName: ['', [requiredValidator]], + replyToAddress: [''], + }); + + this.region?.valueChanges.subscribe((region: string) => { + this.hostAndPort?.setValue( + `${region}:${ + this.tls ? this.providerDefaultSetting?.encryptedPort : this.providerDefaultSetting?.unencryptedPort + }`, + ); + }); + + if (!this.router.url.endsWith('/create')) { + this.id = this.route.snapshot.paramMap.get('id') || ''; + if (this.id) { + this.fetchData(this.id); + } + } + }); + } + + public changeStep(event: StepperSelectionEvent): void { + this.currentCreateStep = event.selectedIndex + 1; + + if (event.selectedIndex >= 2) { + this.requestRedirectValuesSubject$.next(); + } + } + + public close(): void { + this._location.back(); + } + + public toggleTLS(event: MatCheckboxChange) { + if (this.providerDefaultSetting.host) { + this.hostAndPort?.setValue( + `${this.providerDefaultSetting?.host}:${ + event.checked ? this.providerDefaultSetting?.encryptedPort : this.providerDefaultSetting?.unencryptedPort + }`, + ); + } + } + + private fetchData(id: string): void { + this.smtpLoading = true; + this.service + .getSMTPConfigById(id) + .then((data) => { + this.smtpLoading = false; + if (data.smtpConfig) { + this.hasSMTPConfig = true; + this.firstFormGroup.patchValue({ + ['description']: data.smtpConfig.description, + ['tls']: data.smtpConfig.tls, + ['hostAndPort']: data.smtpConfig.host, + ['user']: data.smtpConfig.user, + }); + this.secondFormGroup.patchValue({ + ['senderAddress']: data.smtpConfig.senderAddress, + ['senderName']: data.smtpConfig.senderName, + ['replyToAddress']: data.smtpConfig.replyToAddress, + }); + } + }) + .catch((error) => { + this.smtpLoading = false; + if (error && error.code === 5) { + this.hasSMTPConfig = false; + } + }); + } + + private updateData(): Promise { + if (this.hasSMTPConfig) { + const req = new UpdateSMTPConfigRequest(); + req.setId(this.id); + req.setDescription(this.description?.value || ''); + req.setTls(this.tls?.value ?? false); + + if (this.hostAndPort && this.hostAndPort.value) { + req.setHost(this.hostAndPort.value); + } + if (this.user && this.user.value) { + req.setUser(this.user.value); + } + if (this.password && this.password.value) { + req.setPassword(this.password.value); + } + if (this.senderAddress && this.senderAddress.value) { + req.setSenderAddress(this.senderAddress.value); + } + if (this.senderName && this.senderName.value) { + req.setSenderName(this.senderName.value); + } + if (this.replyToAddress && this.replyToAddress.value) { + req.setReplyToAddress(this.replyToAddress.value); + } + return this.service.updateSMTPConfig(req); + } else { + const req = new AddSMTPConfigRequest(); + req.setDescription(this.description?.value ?? ''); + req.setHost(this.hostAndPort?.value ?? ''); + req.setSenderAddress(this.senderAddress?.value ?? ''); + req.setSenderName(this.senderName?.value ?? ''); + req.setReplyToAddress(this.replyToAddress?.value ?? ''); + req.setTls(this.tls?.value ?? false); + req.setUser(this.user?.value ?? ''); + req.setPassword(this.password?.value ?? ''); + return this.service.addSMTPConfig(req); + } + } + + public savePolicy(): void { + this.updateData() + .then(() => { + this.toast.showInfo('SETTING.SMTP.SAVED', true); + setTimeout(() => { + this.close(); + }, 2000); + }) + .catch((error: unknown) => { + if (`${error}`.includes('No changes')) { + this.toast.showInfo('SETTING.SMTP.NOCHANGES', true); + setTimeout(() => { + this.close(); + }, 2000); + } else { + this.toast.showError(error); + } + }); + } + + public get description(): AbstractControl | null { + return this.firstFormGroup.get('description'); + } + + public get tls(): AbstractControl | null { + return this.firstFormGroup.get('tls'); + } + + public get region(): AbstractControl | null { + return this.firstFormGroup.get('region'); + } + + public get hostAndPort(): AbstractControl | null { + return this.firstFormGroup.get('hostAndPort'); + } + + public get user(): AbstractControl | null { + return this.firstFormGroup.get('user'); + } + + public get password(): AbstractControl | null { + return this.firstFormGroup.get('password'); + } + + public get senderAddress(): AbstractControl | null { + return this.secondFormGroup.get('senderAddress'); + } + + public get senderName(): AbstractControl | null { + return this.secondFormGroup.get('senderName'); + } + + public get replyToAddress(): AbstractControl | null { + return this.secondFormGroup.get('replyToAddress'); + } +} diff --git a/console/src/app/modules/smtp-provider/smtp-provider.module.ts b/console/src/app/modules/smtp-provider/smtp-provider.module.ts new file mode 100644 index 0000000000..8d197a4f12 --- /dev/null +++ b/console/src/app/modules/smtp-provider/smtp-provider.module.ts @@ -0,0 +1,51 @@ +import { CommonModule, TitleCasePipe } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatIconModule } from '@angular/material/icon'; +import { TranslateModule } from '@ngx-translate/core'; +import { InputModule } from 'src/app/modules/input/input.module'; + +import { MatStepperModule } from '@angular/material/stepper'; +import { CardModule } from '../card/card.module'; +import { CreateLayoutModule } from '../create-layout/create-layout.module'; +import { InfoSectionModule } from '../info-section/info-section.module'; +import { ProviderOptionsModule } from '../provider-options/provider-options.module'; +import { StringListModule } from '../string-list/string-list.module'; +import { SMTPProvidersRoutingModule } from './smtp-provider-routing.module'; +import { SMTPProviderComponent } from './smtp-provider.component'; +import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module'; +import { MatButtonModule } from '@angular/material/button'; +import { MatProgressBarModule } from '@angular/material/progress-bar'; +import { MatSelectModule } from '@angular/material/select'; +import { MatChipsModule } from '@angular/material/chips'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; + +@NgModule({ + declarations: [SMTPProviderComponent], + imports: [ + SMTPProvidersRoutingModule, + CommonModule, + FormsModule, + ReactiveFormsModule, + CreateLayoutModule, + StringListModule, + InfoSectionModule, + InputModule, + MatButtonModule, + MatProgressBarModule, + MatSelectModule, + MatIconModule, + MatChipsModule, + CardModule, + MatCheckboxModule, + MatTooltipModule, + MatStepperModule, + TranslateModule, + ProviderOptionsModule, + HasRolePipeModule, + MatProgressSpinnerModule, + ], +}) +export default class SMTPProviderModule {} diff --git a/console/src/app/modules/smtp-provider/smtp-provider.scss b/console/src/app/modules/smtp-provider/smtp-provider.scss new file mode 100644 index 0000000000..06fdcefe6e --- /dev/null +++ b/console/src/app/modules/smtp-provider/smtp-provider.scss @@ -0,0 +1,71 @@ +@use '@angular/material' as mat; + +@mixin smtp-provider-theme($theme) { + $is-dark-theme: map-get($theme, is-dark); + $background: map-get($theme, background); + $foreground: map-get($theme, foreground); + + .stepper { + background: inherit !important; + margin: 0 -1.5rem; + } + + .smtp-create-actions { + margin-top: 2rem; + display: flex; + align-items: center; + justify-content: space-between; + + .bck-button { + margin-right: 1rem; + } + + .create-button { + padding: 0.5rem 4rem; + } + } + + .smtp-form-field, + .info-section-warn { + max-width: 400px; + display: block; + } + + .wizard-header { + display: flex; + align-items: center; + + .smtp-logo { + margin-right: 1rem; + height: 48px; + width: 48px; + flex-shrink: 0; + } + + .smtp-icon { + margin-right: 1rem; + display: flex; + justify-content: center; + align-items: center; + height: 36px; + width: 36px; + + .icon { + font-size: 2.25rem; + height: 2.25rem; + width: 2.25rem; + } + } + } + + .row { + display: flex; + justify-content: space-between; + + .left, + .right { + margin-bottom: 0.5rem; + font-size: 14px; + } + } +} diff --git a/console/src/app/modules/smtp-table/smtp-table.component.html b/console/src/app/modules/smtp-table/smtp-table.component.html new file mode 100644 index 0000000000..ba8ac58518 --- /dev/null +++ b/console/src/app/modules/smtp-table/smtp-table.component.html @@ -0,0 +1,129 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ {{ 'SMTP.LIST.ACTIVATED' | translate }} + + + {{ 'SETTING.SMTP.DESCRIPTION' | translate }} + {{ config?.description }} + + TLS + + + + {{ 'SETTING.SMTP.HOSTANDPORT' | translate }} + {{ config?.host }} + {{ 'SETTING.SMTP.SENDERADDRESS' | translate }} + {{ config?.senderAddress }} + + + + + + + + +
+
+ +
+ + {{ 'SMTP.LIST.EMPTY' | translate }} +
+ + +
diff --git a/console/src/app/modules/smtp-table/smtp-table.component.scss b/console/src/app/modules/smtp-table/smtp-table.component.scss new file mode 100644 index 0000000000..076614c03f --- /dev/null +++ b/console/src/app/modules/smtp-table/smtp-table.component.scss @@ -0,0 +1,81 @@ +@mixin smtp-table-theme($theme) { + $primary: map-get($theme, primary); + $warn: map-get($theme, warn); + $background: map-get($theme, background); + $accent: map-get($theme, accent); + $primary-color: map-get($primary, 500); + $warn-color: map-get($warn, 500); + $accent-color: map-get($accent, 500); + $foreground: map-get($theme, foreground); + $is-dark-theme: map-get($theme, is-dark); + $back: map-get($background, background); + + .smtp-table-provider-type { + display: flex; + align-items: center; + + .smtp-logo { + margin-right: 1rem; + height: 28px; + width: 28px; + flex-shrink: 0; + + &.dark { + display: if($is-dark-theme, block, none); + } + + &.light { + display: if($is-dark-theme, none, block); + } + } + + .smtp-icon { + font-size: 1.75rem; + height: 1.75rem; + width: 1.75rem; + margin-right: 1rem; + flex-shrink: 0; + } + } +} +.smtp-margin-right { + margin-right: 0.5rem; +} + +td { + outline: none; +} + +tr { + outline: none; + + &.disabled, + &.disabled * { + opacity: 0.8; + cursor: default; + } +} + +.availability { + width: 40px; +} + +.smtp-available { + color: var(--success); +} + +.smtp-not-available { + color: var(--warn); +} + +.smtp-table-actions { + width: 100px; +} + +.la-unlock { + color: orangered; +} + +.la-lock { + color: darkorange; +} diff --git a/console/src/app/modules/smtp-table/smtp-table.component.spec.ts b/console/src/app/modules/smtp-table/smtp-table.component.spec.ts new file mode 100644 index 0000000000..8095d73255 --- /dev/null +++ b/console/src/app/modules/smtp-table/smtp-table.component.spec.ts @@ -0,0 +1,24 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; + +import { IdpTableComponent } from './smtp-table.component'; + +describe('UserTableComponent', () => { + let component: IdpTableComponent; + let fixture: ComponentFixture; + + beforeEach(waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [IdpTableComponent], + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(IdpTableComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/console/src/app/modules/smtp-table/smtp-table.component.ts b/console/src/app/modules/smtp-table/smtp-table.component.ts new file mode 100644 index 0000000000..ee0da1a329 --- /dev/null +++ b/console/src/app/modules/smtp-table/smtp-table.component.ts @@ -0,0 +1,194 @@ +import { SelectionModel } from '@angular/cdk/collections'; +import { Component, EventEmitter, OnInit, Output, ViewChild } from '@angular/core'; +import { Router, RouterLink } from '@angular/router'; +import { TranslateService } from '@ngx-translate/core'; +import { BehaviorSubject, Observable } from 'rxjs'; +import { SMTPConfigState } from 'src/app/proto/generated/zitadel/settings_pb'; +import { ListQuery } from 'src/app/proto/generated/zitadel/object_pb'; +import { LoginPolicy } from 'src/app/proto/generated/zitadel/policy_pb'; +import { AdminService } from 'src/app/services/admin.service'; +import { ToastService } from 'src/app/services/toast.service'; + +import { PageEvent, PaginatorComponent } from '../paginator/paginator.component'; +import { PolicyComponentServiceType } from '../policies/policy-component-types.enum'; +import { ListSMTPConfigsRequest, ListSMTPConfigsResponse } from 'src/app/proto/generated/zitadel/admin_pb'; +import { SMTPConfig } from 'src/app/proto/generated/zitadel/settings_pb'; +import { WarnDialogComponent } from '../warn-dialog/warn-dialog.component'; +import { MatTableDataSource } from '@angular/material/table'; +import { MatDialog } from '@angular/material/dialog'; + +@Component({ + selector: 'cnsl-smtp-table', + templateUrl: './smtp-table.component.html', + styleUrls: ['./smtp-table.component.scss'], +}) +export class SMTPTableComponent implements OnInit { + @ViewChild(PaginatorComponent) public paginator!: PaginatorComponent; + public dataSource: MatTableDataSource = new MatTableDataSource(); + public selection: SelectionModel = new SelectionModel(true, []); + public configsResult?: ListSMTPConfigsResponse.AsObject; + private loadingSubject: BehaviorSubject = new BehaviorSubject(false); + public loading$: Observable = this.loadingSubject.asObservable(); + public PolicyComponentServiceType: any = PolicyComponentServiceType; + public displayedColumns: string[] = ['activated', 'description', 'tls', 'host', 'senderAddress', 'actions']; + @Output() public changedSelection: EventEmitter> = new EventEmitter(); + + public loginPolicy!: LoginPolicy.AsObject; + + constructor( + private adminService: AdminService, + public translate: TranslateService, + private toast: ToastService, + private dialog: MatDialog, + private router: Router, + ) { + this.selection.changed.subscribe(() => { + this.changedSelection.emit(this.selection.selected); + }); + } + + ngOnInit(): void { + this.getData(10, 0); + } + + public isActive(state: number) { + return state === SMTPConfigState.SMTP_CONFIG_ACTIVE; + } + + public isAllSelected(): boolean { + const numSelected = this.selection.selected.length; + const numRows = this.dataSource.data.length; + return numSelected === numRows; + } + + public masterToggle(): void { + this.isAllSelected() ? this.selection.clear() : this.dataSource.data.forEach((row) => this.selection.select(row)); + } + + public changePage(event: PageEvent): void { + this.getData(event.pageSize, event.pageIndex * event.pageSize); + } + + public activateSMTPConfig(id: string): void { + const dialogRef = this.dialog.open(WarnDialogComponent, { + data: { + confirmKey: 'ACTIONS.CONTINUE', + cancelKey: 'ACTIONS.CANCEL', + titleKey: 'SMTP.LIST.DIALOG.ACTIVATE_WARN_TITLE', + descriptionKey: 'SMTP.LIST.DIALOG.ACTIVATE_WARN_DESCRIPTION', + }, + width: '400px', + }); + + dialogRef.afterClosed().subscribe((resp) => { + if (resp) { + this.adminService + .activateSMTPConfig(id) + .then(() => { + this.toast.showInfo('SMTP.LIST.DIALOG.ACTIVATED', true); + this.refreshPage(); + }) + .catch((error) => { + this.toast.showError(error); + }); + } + }); + } + + public deactivateSMTPConfig(id: string): void { + const dialogRef = this.dialog.open(WarnDialogComponent, { + data: { + confirmKey: 'ACTIONS.CONTINUE', + cancelKey: 'ACTIONS.CANCEL', + titleKey: 'SMTP.LIST.DIALOG.DEACTIVATE_WARN_TITLE', + descriptionKey: 'SMTP.LIST.DIALOG.DEACTIVATE_WARN_DESCRIPTION', + }, + width: '400px', + }); + + dialogRef.afterClosed().subscribe((resp) => { + if (resp) { + this.adminService + .deactivateSMTPConfig(id) + .then(() => { + this.toast.showInfo('SMTP.LIST.DIALOG.DEACTIVATED', true); + this.refreshPage(); + }) + .catch((error) => { + this.toast.showError(error); + }); + } + }); + } + + public deleteSMTPConfig(id: string, senderName: string): void { + const dialogRef = this.dialog.open(WarnDialogComponent, { + data: { + confirmKey: 'ACTIONS.DELETE', + cancelKey: 'ACTIONS.CANCEL', + titleKey: 'SMTP.LIST.DIALOG.DELETE_TITLE', + descriptionKey: 'SMTP.LIST.DIALOG.DELETE_DESCRIPTION', + confirmationKey: 'SMTP.LIST.DIALOG.SENDER', + confirmation: senderName, + }, + width: '400px', + }); + + dialogRef.afterClosed().subscribe((resp) => { + if (resp) { + this.adminService + .removeSMTPConfig(id) + .then(() => { + this.toast.showInfo('SMTP.LIST.DIALOG.DELETED', true); + this.refreshPage(); + }) + .catch((error) => { + this.toast.showError(error); + }); + } + }); + } + + private async getData(limit: number, offset: number): Promise { + this.loadingSubject.next(true); + + const req = new ListSMTPConfigsRequest(); + const lq = new ListQuery(); + lq.setOffset(offset); + lq.setLimit(limit); + req.setQuery(lq); + this.adminService + .listSMTPConfigs() + .then((resp) => { + this.configsResult = resp; + if (resp.resultList) { + this.dataSource.data = resp.resultList; + } + this.loadingSubject.next(false); + }) + .catch((error) => { + this.toast.showError(error); + this.loadingSubject.next(false); + }); + } + + public refreshPage(): void { + this.getData(this.paginator.pageSize, this.paginator.pageIndex * this.paginator.pageSize); + } + + public get createRouterLink(): RouterLink | any { + return ['/instance', 'idp', 'create']; + } + + public routerLinkForRow(row: SMTPConfig.AsObject): any { + return ['/instance', 'smtpprovider', row.id]; + } + + public get displayedColumnsWithActions(): string[] { + return ['actions', ...this.displayedColumns]; + } + + public navigateToProvider(row: SMTPConfig.AsObject) { + this.router.navigate(this.routerLinkForRow(row)); + } +} diff --git a/console/src/app/modules/smtp-table/smtp-table.module.ts b/console/src/app/modules/smtp-table/smtp-table.module.ts new file mode 100644 index 0000000000..3ce1c3d05e --- /dev/null +++ b/console/src/app/modules/smtp-table/smtp-table.module.ts @@ -0,0 +1,46 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatIconModule } from '@angular/material/icon'; +import { RouterModule } from '@angular/router'; +import { TranslateModule } from '@ngx-translate/core'; +import { HasRoleModule } from 'src/app/directives/has-role/has-role.module'; +import { RefreshTableModule } from 'src/app/modules/refresh-table/refresh-table.module'; +import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module'; +import { LocalizedDatePipeModule } from 'src/app/pipes/localized-date-pipe/localized-date-pipe.module'; +import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe/timestamp-to-date-pipe.module'; +import { TruncatePipeModule } from 'src/app/pipes/truncate-pipe/truncate-pipe.module'; + +import { PaginatorModule } from '../paginator/paginator.module'; +import { TableActionsModule } from '../table-actions/table-actions.module'; +import { SMTPTableComponent } from './smtp-table.component'; +import { MatButtonModule } from '@angular/material/button'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { MatTableModule } from '@angular/material/table'; + +@NgModule({ + declarations: [SMTPTableComponent], + imports: [ + CommonModule, + FormsModule, + ReactiveFormsModule, + MatButtonModule, + TableActionsModule, + MatCheckboxModule, + MatIconModule, + MatTooltipModule, + TranslateModule, + LocalizedDatePipeModule, + TimestampToDatePipeModule, + MatTableModule, + PaginatorModule, + RouterModule, + RefreshTableModule, + HasRoleModule, + HasRolePipeModule, + TruncatePipeModule, + ], + exports: [SMTPTableComponent], +}) +export class SMTPTableModule {} diff --git a/console/src/app/pages/instance/instance-routing.module.ts b/console/src/app/pages/instance/instance-routing.module.ts index c88cbafaf7..ca03086e85 100644 --- a/console/src/app/pages/instance/instance-routing.module.ts +++ b/console/src/app/pages/instance/instance-routing.module.ts @@ -32,6 +32,15 @@ const routes: Routes = [ serviceType: PolicyComponentServiceType.ADMIN, }, }, + { + path: 'smtpprovider', + canActivate: [AuthGuard, RoleGuard], + loadChildren: () => import('src/app/modules/smtp-provider/smtp-provider.module'), + data: { + roles: ['iam.idp.read'], + serviceType: PolicyComponentServiceType.ADMIN, + }, + }, ]; @NgModule({ diff --git a/console/src/app/services/admin.service.ts b/console/src/app/services/admin.service.ts index 7149317ab4..d1460b06f2 100644 --- a/console/src/app/services/admin.service.ts +++ b/console/src/app/services/admin.service.ts @@ -6,6 +6,8 @@ import { ActivateLabelPolicyResponse, ActivateSMSProviderRequest, ActivateSMSProviderResponse, + ActivateSMTPConfigRequest, + ActivateSMTPConfigResponse, AddAppleProviderRequest, AddAppleProviderResponse, AddAzureADProviderRequest, @@ -52,6 +54,8 @@ import { DeactivateIDPResponse, DeactivateSMSProviderRequest, DeactivateSMSProviderResponse, + DeactivateSMTPConfigRequest, + DeactivateSMTPConfigResponse, DeleteProviderRequest, DeleteProviderResponse, GetAllowedLanguagesRequest, @@ -135,6 +139,8 @@ import { GetSecurityPolicyResponse, GetSMSProviderRequest, GetSMSProviderResponse, + GetSMTPConfigByIdRequest, + GetSMTPConfigByIdResponse, GetSMTPConfigRequest, GetSMTPConfigResponse, GetSupportedLanguagesRequest, @@ -167,6 +173,8 @@ import { ListSecretGeneratorsResponse, ListSMSProvidersRequest, ListSMSProvidersResponse, + ListSMTPConfigsRequest, + ListSMTPConfigsResponse, ListViewsRequest, ListViewsResponse, ReactivateIDPRequest, @@ -193,6 +201,8 @@ import { RemoveSecondFactorFromLoginPolicyResponse, RemoveSMSProviderRequest, RemoveSMSProviderResponse, + RemoveSMTPConfigRequest, + RemoveSMTPConfigResponse, ResetCustomDomainPolicyToDefaultRequest, ResetCustomDomainPolicyToDefaultResponse, ResetCustomLoginTextsToDefaultRequest, @@ -894,6 +904,17 @@ export class AdminService { return this.grpcService.admin.getSMTPConfig(req, null).then((resp) => resp.toObject()); } + public getSMTPConfigById(id: string): Promise { + const req = new GetSMTPConfigByIdRequest(); + req.setId(id); + return this.grpcService.admin.getSMTPConfigById(req, null).then((resp) => resp.toObject()); + } + + public listSMTPConfigs(): Promise { + const req = new ListSMTPConfigsRequest(); + return this.grpcService.admin.listSMTPConfigs(req, null).then((resp) => resp.toObject()); + } + public addSMTPConfig(req: AddSMTPConfigRequest): Promise { return this.grpcService.admin.addSMTPConfig(req, null).then((resp) => resp.toObject()); } @@ -906,6 +927,24 @@ export class AdminService { return this.grpcService.admin.updateSMTPConfigPassword(req, null).then((resp) => resp.toObject()); } + public activateSMTPConfig(id: string): Promise { + const req = new ActivateSMTPConfigRequest(); + req.setId(id); + return this.grpcService.admin.activateSMTPConfig(req, null).then((resp) => resp.toObject()); + } + + public deactivateSMTPConfig(id: string): Promise { + const req = new DeactivateSMTPConfigRequest(); + req.setId(id); + return this.grpcService.admin.deactivateSMTPConfig(req, null).then((resp) => resp.toObject()); + } + + public removeSMTPConfig(id: string): Promise { + const req = new RemoveSMTPConfigRequest(); + req.setId(id); + return this.grpcService.admin.removeSMTPConfig(req, null).then((resp) => resp.toObject()); + } + /* sms */ public listSMSProviders(): Promise { diff --git a/console/src/assets/i18n/bg.json b/console/src/assets/i18n/bg.json index 14aeaa99ac..d606ceb64a 100644 --- a/console/src/assets/i18n/bg.json +++ b/console/src/assets/i18n/bg.json @@ -1374,6 +1374,8 @@ } }, "SMTP": { + "TITLE": "SMTP настройки", + "DESCRIPTION": "Описание", "SENDERADDRESS": "Имейл адрес на изпращача", "SENDERNAME": "Име на изпращача", "REPLYTOADDRESS": "Reply-to адрес", @@ -1384,6 +1386,7 @@ "PASSWORDSET": "Паролата за SMTP бе зададена успешно.", "TLS": "Сигурност на транспортния слой (TLS)", "SAVED": "Запазено успешно!", + "NOCHANGES": "Без промени!", "REQUIREDWARN": "За да изпращате известия от вашия домейн, трябва да въведете своите SMTP данни." }, "SMS": { @@ -2208,6 +2211,48 @@ "1": "Позволен" } }, + "SMTP": { + "LIST": { + "TITLE": "SMTP доставчик", + "DESCRIPTION": "Това са SMTP доставчиците за вашето копие на Zitadel. Активирайте този, който искате да използвате, за да изпращате известия до вашите потребители.", + "EMPTY": "Няма наличен SMTP доставчик", + "ACTIVATED": "Активиран", + "ACTIVATE": "Активирайте доставчика", + "DEACTIVATE": "Деактивирайте доставчика", + "TYPE": "Тип", + "DIALOG": { + "ACTIVATED": "SMTP конфигурацията е активирана", + "ACTIVATE_WARN_TITLE": "Активирайте SMTP конфигурацията", + "ACTIVATE_WARN_DESCRIPTION": "На път сте да активирате SMTP конфигурация. Първо ще деактивираме текущия активен доставчик и след това ще активираме тази конфигурация. Сигурен ли си?", + "DEACTIVATE_WARN_TITLE": "Деактивирайте SMTP конфигурацията", + "DEACTIVATE_WARN_DESCRIPTION": "На път сте да деактивирате SMTP конфигурация. Сигурен ли си?", + "DEACTIVATED": "SMTP конфигурацията е деактивирана", + "DELETE_TITLE": "Изтриване на SMTP конфигурация", + "DELETE_DESCRIPTION": "На път сте да изтриете конфигурация. Потвърдете това действие, като въведете името на подателя", + "DELETED": "SMTP конфигурацията е изтрита", + "SENDER": "Въведете {{ value }}, за да изтриете тази SMTP конфигурация." + } + }, + "CREATE": { + "TITLE": "Добавете SMTP доставчик", + "DESCRIPTION": "Изберете един или повече от следните доставчици.", + "STEPS": { + "TITLE": "Добавете {{ value }} SMTP доставчик", + "CREATE_DESC_TITLE": "Въведете своите {{ value }} SMTP настройки стъпка по стъпка", + "CURRENT_DESC_TITLE": "Това са вашите SMTP настройки", + "PROVIDER_SETTINGS": "Настройки на SMTP доставчик", + "SENDER_SETTINGS": "Настройки на изпращача", + "TEST_SETTINGS": "Тествайте настройките на SMTP" + } + }, + "DETAIL": { + "TITLE": "Настройки на SMTP доставчик" + }, + "EMPTY": "Няма наличен SMTP доставчик", + "STEPS": { + "SENDGRID": {} + } + }, "APP": { "LIST": "Приложения", "COMPLIANCE": "Съответствие с OIDC", diff --git a/console/src/assets/i18n/cs.json b/console/src/assets/i18n/cs.json index 2caac0adbc..c9a01468ac 100644 --- a/console/src/assets/i18n/cs.json +++ b/console/src/assets/i18n/cs.json @@ -1381,6 +1381,8 @@ } }, "SMTP": { + "TITLE": "Nastavení SMTP", + "DESCRIPTION": "Popis", "SENDERADDRESS": "E-mailová adresa odesílatele", "SENDERNAME": "Jméno odesílatele", "REPLYTOADDRESS": "Adresa pro odpovědi", @@ -1391,6 +1393,7 @@ "PASSWORDSET": "SMTP heslo bylo úspěšně nastaveno.", "TLS": "Zabezpečení transportní vrstvy (TLS)", "SAVED": "Úspěšně uloženo!", + "NOCHANGES": "Žádné změny!", "REQUIREDWARN": "Pro odesílání oznámení z vaší domény musíte zadat vaše SMTP údaje." }, "SMS": { @@ -2227,6 +2230,48 @@ "1": "Povoleno" } }, + "SMTP": { + "LIST": { + "TITLE": "Poskytovatel SMTP", + "DESCRIPTION": "Toto jsou poskytovatelé SMTP pro vaši instanci Zitadel. Aktivujte ten, který chcete používat k odesílání upozornění svým uživatelům.", + "EMPTY": "Není k dispozici žádný poskytovatel SMTP", + "ACTIVATED": "Aktivováno", + "ACTIVATE": "Aktivujte poskytovatele", + "DEACTIVATE": "Deaktivovat poskytovatele", + "TYPE": "Typ", + "DIALOG": { + "ACTIVATED": "Konfigurace SMTP byla aktivována", + "ACTIVATE_WARN_TITLE": "Aktivujte konfiguraci SMTP", + "ACTIVATE_WARN_DESCRIPTION": "Chystáte se aktivovat konfiguraci SMTP. Nejprve deaktivujeme aktuálního aktivního poskytovatele a poté aktivujeme tuto konfiguraci. Jsi si jistá?", + "DEACTIVATE_WARN_TITLE": "Deaktivujte konfiguraci SMTP", + "DEACTIVATE_WARN_DESCRIPTION": "Chystáte se deaktivovat konfiguraci SMTP. Jsi si jistá?", + "DEACTIVATED": "Konfigurace SMTP byla deaktivována", + "DELETE_TITLE": "Smazat konfiguraci SMTP", + "DELETE_DESCRIPTION": "Chystáte se smazat konfiguraci. Potvrďte tuto akci zadáním jména odesílatele", + "DELETED": "Konfigurace SMTP byla smazána", + "SENDER": "Chcete-li smazat tuto konfiguraci SMTP, zadejte {{ value }}." + } + }, + "CREATE": { + "TITLE": "Přidat poskytovatele SMTP", + "DESCRIPTION": "Vyberte jednoho nebo více z následujících poskytovatelů.", + "STEPS": { + "TITLE": "Přidejte {{ value }} poskytovatele SMTP", + "CREATE_DESC_TITLE": "Krok za krokem zadejte nastavení SMTP {{ value }}", + "CURRENT_DESC_TITLE": "Toto jsou vaše nastavení SMTP", + "PROVIDER_SETTINGS": "Nastavení poskytovatele SMTP", + "SENDER_SETTINGS": "Nastavení odesílatele", + "TEST_SETTINGS": "Otestujte nastavení SMTP" + } + }, + "DETAIL": { + "TITLE": "Nastavení poskytovatele SMTP" + }, + "EMPTY": "Není k dispozici žádný poskytovatel SMTP", + "STEPS": { + "SENDGRID": {} + } + }, "APP": { "LIST": "Aplikace", "COMPLIANCE": "OIDC Kompatibilita", diff --git a/console/src/assets/i18n/de.json b/console/src/assets/i18n/de.json index 452d51925a..7ea9423b05 100644 --- a/console/src/assets/i18n/de.json +++ b/console/src/assets/i18n/de.json @@ -1380,6 +1380,8 @@ } }, "SMTP": { + "TITLE": "SMTP Einstellungen", + "DESCRIPTION": "Beschreibung", "SENDERADDRESS": "Sender Email-Adresse", "SENDERNAME": "Sender Name", "REPLYTOADDRESS": "Reply-to-Adresse", @@ -1390,6 +1392,7 @@ "PASSWORDSET": "SMTP Passwort erfolgreich gesetzt.", "TLS": "Transport Layer Security (TLS)", "SAVED": "Erfolgreich gespeichert.", + "NOCHANGES": "Keine Änderungen!", "REQUIREDWARN": "Damit Mails von Ihrer Domain verschickt werden können, müssen Sie Ihre SMTP Einstellungen konfigurieren." }, "SMS": { @@ -2217,6 +2220,48 @@ "1": "Erlaubt" } }, + "SMTP": { + "LIST": { + "TITLE": "SMTP-Anbieter", + "DESCRIPTION": "Dies sind die SMTP-Anbieter für Ihre Zitadel-Instanz. Aktivieren Sie diejenige, die Sie zum Senden von Benachrichtigungen an Ihre Benutzer verwenden möchten.", + "EMPTY": "Kein SMTP-Anbieter verfügbar", + "ACTIVATED": "Aktiviert", + "ACTIVATE": "Anbieter aktivieren", + "DEACTIVATE": "Anbieter deaktivieren", + "TYPE": "Typ", + "DIALOG": { + "ACTIVATED": "Die SMTP-Konfiguration wurde aktiviert", + "ACTIVATE_WARN_TITLE": "Aktivieren Sie die SMTP-Konfiguration", + "ACTIVATE_WARN_DESCRIPTION": "Sie sind dabei, eine SMTP-Konfiguration zu aktivieren. Zuerst deaktivieren wir den aktuell aktiven Anbieter und aktivieren dann diese Konfiguration. Bist du sicher?", + "DEACTIVATE_WARN_TITLE": "Deaktivieren Sie die SMTP-Konfiguration", + "DEACTIVATE_WARN_DESCRIPTION": "Sie sind dabei, eine SMTP-Konfiguration zu deaktivieren. Bist du sicher?", + "DEACTIVATED": "Die SMTP-Konfiguration wurde deaktiviert", + "DELETE_TITLE": "SMTP-Konfiguration löschen", + "DELETE_DESCRIPTION": "Sie sind dabei, eine Konfiguration zu löschen. Bestätigen Sie diese Aktion, indem Sie den Absendernamen eingeben", + "DELETED": "SMTP-Konfiguration wurde gelöscht", + "SENDER": "Geben Sie {{ value }} ein, um diese SMTP-Konfiguration zu löschen." + } + }, + "CREATE": { + "TITLE": "SMTP-Anbieter hinzufügen", + "DESCRIPTION": "Wählen Sie einen oder mehrere der folgenden Anbieter aus.", + "STEPS": { + "TITLE": "Fügen Sie {{ value }} SMTP-Anbieter hinzu", + "CREATE_DESC_TITLE": "Geben Sie Schritt für Schritt Ihre {{ value }} SMTP-Einstellungen ein", + "CURRENT_DESC_TITLE": "Dies sind Ihre SMTP-Einstellungen", + "PROVIDER_SETTINGS": "SMTP-Anbietereinstellungen", + "SENDER_SETTINGS": "Absendereinstellungen", + "TEST_SETTINGS": "Testen Sie die SMTP-Einstellungen" + } + }, + "DETAIL": { + "TITLE": "SMTP-Anbietereinstellungen" + }, + "EMPTY": "Kein SMTP-Anbieter verfügbar", + "STEPS": { + "SENDGRID": {} + } + }, "APP": { "LIST": "Apps", "COMPLIANCE": "OIDC Einhaltung", diff --git a/console/src/assets/i18n/en.json b/console/src/assets/i18n/en.json index ec2d50ddcf..658f59ba9e 100644 --- a/console/src/assets/i18n/en.json +++ b/console/src/assets/i18n/en.json @@ -1381,6 +1381,8 @@ } }, "SMTP": { + "TITLE": "SMTP Provider", + "DESCRIPTION": "Description", "SENDERADDRESS": "Sender Email Address", "SENDERNAME": "Sender Name", "REPLYTOADDRESS": "Reply-to Address", @@ -1391,6 +1393,7 @@ "PASSWORDSET": "SMTP Password was set successfully.", "TLS": "Transport Layer Security (TLS)", "SAVED": "Saved successfully!", + "NOCHANGES": "No changes!", "REQUIREDWARN": "To send notifications from your domain, you have to enter your SMTP data." }, "SMS": { @@ -2236,6 +2239,48 @@ "1": "Allowed" } }, + "SMTP": { + "LIST": { + "TITLE": "SMTP Provider", + "DESCRIPTION": "These are the SMTP providers for your Zitadel instance. Activate the one you want to use to send notifications to your users.", + "EMPTY": "No SMTP Provider available", + "ACTIVATED": "Activated", + "ACTIVATE": "Activate provider", + "DEACTIVATE": "Deactivate provider", + "TYPE": "Type", + "DIALOG": { + "ACTIVATED": "SMTP config has been activated", + "ACTIVATE_WARN_TITLE": "Activate SMTP config", + "ACTIVATE_WARN_DESCRIPTION": "You are about to activate an SMTP configuration. First we'll deactivate the current active provider and then activate this configuration. Are you sure?", + "DEACTIVATE_WARN_TITLE": "Deactivate SMTP config", + "DEACTIVATE_WARN_DESCRIPTION": "You are about to deactivate an SMTP configuration. Are you sure?", + "DEACTIVATED": "SMTP config has been deactivated", + "DELETE_TITLE": "Delete SMTP config", + "DELETE_DESCRIPTION": "You are about to delete a configuration. Confirm this action typing the sender name", + "DELETED": "SMTP config has been deleted", + "SENDER": "Type {{value}}, to delete this SMTP configuration." + } + }, + "CREATE": { + "TITLE": "Add SMTP provider", + "DESCRIPTION": "Select one ore more of the following providers.", + "STEPS": { + "TITLE": "Add {{ value }} SMTP Provider", + "CREATE_DESC_TITLE": "Enter your {{ value }} SMTP settings step by step", + "CURRENT_DESC_TITLE": "These are your SMTP settings", + "PROVIDER_SETTINGS": "SMTP Provider Settings", + "SENDER_SETTINGS": "Sender Settings", + "TEST_SETTINGS": "Test SMTP Settings" + } + }, + "DETAIL": { + "TITLE": "SMTP Provider Settings" + }, + "EMPTY": "No SMTP provider available", + "STEPS": { + "SENDGRID": {} + } + }, "APP": { "LIST": "Applications", "COMPLIANCE": "OIDC Compliance", diff --git a/console/src/assets/i18n/es.json b/console/src/assets/i18n/es.json index 0240083bd7..ce50afa77d 100644 --- a/console/src/assets/i18n/es.json +++ b/console/src/assets/i18n/es.json @@ -1382,6 +1382,8 @@ } }, "SMTP": { + "TITLE": "Ajustes SMTP", + "DESCRIPTION": "Descripción", "SENDERADDRESS": "Dirección email del emisor", "SENDERNAME": "Nombre del emisor", "REPLYTOADDRESS": "Dirección Reply-To", @@ -1392,6 +1394,7 @@ "PASSWORDSET": "La contraseña SMTP se estableció con éxito.", "TLS": "Transport Layer Security (TLS)", "SAVED": "¡Se guardó con éxito!", + "NOCHANGES": "¡Sin cambios!", "REQUIREDWARN": "Para enviar notificaciones para tu dominio, debes introducir tus datos SMTP." }, "SMS": { @@ -2215,6 +2218,48 @@ "1": "Permitido" } }, + "SMTP": { + "LIST": { + "TITLE": "Proveedor SMTP", + "DESCRIPTION": "Estos son los proveedores SMTP para tu instancia de Zitadel. Activa el que quieras utilizar para enviar notificaciones a tus usuarios.", + "EMPTY": "No hay ningún proveedor SMTP disponible", + "ACTIVATED": "Activado", + "ACTIVATE": "Activar proveedor", + "DEACTIVATE": "Desactivar proveedor", + "TYPE": "Tipo", + "DIALOG": { + "ACTIVATED": "Tu configuración SMTP ha sido activada", + "ACTIVATE_WARN_TITLE": "Activar configuración SMTP", + "ACTIVATE_WARN_DESCRIPTION": "Estás a punto de activar una configuración SMTP. Primero desactivaremos la configuración de tu proveedor actual y después activaremos esta configuración. ¿Estás seguro?", + "DEACTIVATE_WARN_TITLE": "Desactivar configuración SMTP", + "DEACTIVATE_WARN_DESCRIPTION": "Estás a punto de desactivar una configuración SMTP. ¿Está seguro?", + "DEACTIVATED": "La configuración SMTP ha sido desactivada", + "DELETE_TITLE": "Eliminar configuración SMTP", + "DELETE_DESCRIPTION": "Estás a punto de eliminar una configuración. Confirma esta acción escribiendo el nombre del remitente", + "DELETED": "La configuración SMTP ha sido eliminada", + "SENDER": "Escribe {{ value }} para eliminar esta configuración SMTP." + } + }, + "CREATE": { + "TITLE": "Agrega un proveedor SMTP", + "DESCRIPTION": "Selecciona uno o más de los siguientes proveedores.", + "STEPS": { + "TITLE": "Agrega un proveedor SMTP {{ value }} ", + "CREATE_DESC_TITLE": "Introduce tu configuración SMTP de {{ value }} paso a paso", + "CURRENT_DESC_TITLE": "Estas son tus configuraciones SMTP", + "PROVIDER_SETTINGS": "Configuración del proveedor SMTP", + "SENDER_SETTINGS": "Configuración del remitente", + "TEST_SETTINGS": "Probar la configuración SMTP" + } + }, + "DETAIL": { + "TITLE": "Configuración del proveedor SMTP" + }, + "EMPTY": "No hay ningún proveedor SMTP disponible", + "STEPS": { + "SENDGRID": {} + } + }, "APP": { "LIST": "Aplicaciones", "COMPLIANCE": "Cumplimiento OIDC", diff --git a/console/src/assets/i18n/fr.json b/console/src/assets/i18n/fr.json index fa6fc918d6..33a9bc11bb 100644 --- a/console/src/assets/i18n/fr.json +++ b/console/src/assets/i18n/fr.json @@ -1380,6 +1380,8 @@ } }, "SMTP": { + "TITLE": "Paramètres SMTP", + "DESCRIPTION": "Description", "SENDERADDRESS": "Adresse e-mail de l'expéditeur", "SENDERNAME": "Nom de l'expéditeur", "REPLYTOADDRESS": "Adresse Reply-to", @@ -1390,6 +1392,7 @@ "PASSWORDSET": "Le mot de passe SMTP a été défini avec succès.", "TLS": "Sécurité de la couche de transport (TLS)", "SAVED": "Enregistré avec succès!", + "NOCHANGES": "Aucun changement!", "REQUIREDWARN": "Pour envoyer des notifications depuis votre domaine, vous devez entrer vos données SMTP." }, "SMS": { @@ -2218,6 +2221,48 @@ "1": "Autorisée" } }, + "SMTP": { + "LIST": { + "TITLE": "Fournisseur SMTP", + "DESCRIPTION": "Ce sont les fournisseurs SMTP de votre instance Zitadel. Activez celui que vous souhaitez utiliser pour envoyer des notifications à vos utilisateurs.", + "EMPTY": "Aucun fournisseur SMTP disponible", + "ACTIVATED": "Activé", + "ACTIVATE": "Activer le fournisseur", + "DEACTIVATE": "Désactiver le fournisseur", + "TYPE": "Taper", + "DIALOG": { + "ACTIVATED": "La configuration SMTP a été activée", + "ACTIVATE_WARN_TITLE": "Activer la configuration SMTP", + "ACTIVATE_WARN_DESCRIPTION": "Vous êtes sur le point d'activer une configuration SMTP. Nous allons d’abord désactiver le fournisseur actif actuel, puis activer cette configuration. Es-tu sûr?", + "DEACTIVATE_WARN_TITLE": "Désactiver la configuration SMTP", + "DEACTIVATE_WARN_DESCRIPTION": "Vous êtes sur le point de désactiver une configuration SMTP. Es-tu sûr?", + "DEACTIVATED": "La configuration SMTP a été désactivée", + "DELETE_TITLE": "Supprimer la configuration SMTP", + "DELETE_DESCRIPTION": "Vous êtes sur le point de supprimer une configuration. Confirmez cette action en tapant le nom de l'expéditeur", + "DELETED": "La configuration SMTP a été supprimée", + "SENDER": "Tapez {{ value }} pour supprimer cette configuration SMTP." + } + }, + "CREATE": { + "TITLE": "Ajouter un fournisseur SMTP", + "DESCRIPTION": "Sélectionnez un ou plusieurs des fournisseurs suivants.", + "STEPS": { + "TITLE": "Ajouter {{ value }} fournisseur SMTP", + "CREATE_DESC_TITLE": "Entrez vos paramètres SMTP {{ value }} étape par étape", + "CURRENT_DESC_TITLE": "Ce sont vos paramètres SMTP", + "PROVIDER_SETTINGS": "Paramètres du fournisseur SMTP", + "SENDER_SETTINGS": "Paramètres de l'expéditeur", + "TEST_SETTINGS": "Tester les paramètres SMTP" + } + }, + "DETAIL": { + "TITLE": "Paramètres du fournisseur SMTP" + }, + "EMPTY": "Aucun fournisseur SMTP disponible", + "STEPS": { + "SENDGRID": {} + } + }, "APP": { "LIST": "Applications", "COMPLIANCE": "Conformité à l'OIDC", diff --git a/console/src/assets/i18n/it.json b/console/src/assets/i18n/it.json index da104c2ca8..3a1e32a0d0 100644 --- a/console/src/assets/i18n/it.json +++ b/console/src/assets/i18n/it.json @@ -1380,6 +1380,8 @@ } }, "SMTP": { + "TITLE": "Impostazioni SMTP", + "DESCRIPTION": "Descrizione", "SENDERADDRESS": "Indirizzo email del mittente", "SENDERNAME": "Nome del mittente", "REPLYTOADDRESS": "Indirizzo Reply-to", @@ -1390,6 +1392,7 @@ "PASSWORDSET": "SMTP Password impostata con successo.", "TLS": "Transport Layer Security (TLS)", "SAVED": "Salvato con successo!", + "NOCHANGES": "Nessun cambiamento!", "REQUIREDWARN": "Per inviare notifiche dal tuo dominio, devi inserire i tuoi dati SMTP." }, "SMS": { @@ -2218,6 +2221,48 @@ "1": "Consentito" } }, + "SMTP": { + "LIST": { + "TITLE": "Fornitore SMTP", + "DESCRIPTION": "Questi sono i provider SMTP per la tua istanza Zitadel. Attiva quello che desideri utilizzare per inviare notifiche ai tuoi utenti.", + "EMPTY": "Nessun provider SMTP disponibile", + "ACTIVATED": "Attivato", + "ACTIVATE": "Attiva fornitore", + "DEACTIVATE": "Disattiva fornitore", + "TYPE": "Tipo", + "DIALOG": { + "ACTIVATED": "La configurazione SMTP è stata attivata", + "ACTIVATE_WARN_TITLE": "Attiva la configurazione SMTP", + "ACTIVATE_WARN_DESCRIPTION": "Stai per attivare una configurazione SMTP. Per prima cosa disattiveremo il provider attualmente attivo e poi attiveremo questa configurazione. Sei sicuro?", + "DEACTIVATE_WARN_TITLE": "Disattiva la configurazione SMTP", + "DEACTIVATE_WARN_DESCRIPTION": "Stai per disattivare una configurazione SMTP. Sei sicuro?", + "DEACTIVATED": "La configurazione SMTP è stata disattivata", + "DELETE_TITLE": "Elimina configurazione SMTP", + "DELETE_DESCRIPTION": "Stai per eliminare una configurazione. Conferma questa azione digitando il nome del mittente", + "DELETED": "La configurazione SMTP è stata eliminata", + "SENDER": "Digita {{ value }} per eliminare questa configurazione SMTP." + } + }, + "CREATE": { + "TITLE": "Aggiungi provider SMTP", + "DESCRIPTION": "Seleziona uno o più dei seguenti fornitori.", + "STEPS": { + "TITLE": "Aggiungi {{ value }} provider SMTP", + "CREATE_DESC_TITLE": "Inserisci le tue impostazioni SMTP {{ value }} passo dopo passo", + "CURRENT_DESC_TITLE": "Queste sono le tue impostazioni SMTP", + "PROVIDER_SETTINGS": "Impostazioni del provider SMTP", + "SENDER_SETTINGS": "Impostazioni mittente", + "TEST_SETTINGS": "Testare le impostazioni SMTP" + } + }, + "DETAIL": { + "TITLE": "Impostazioni del provider SMTP" + }, + "EMPTY": "Nessun provider SMTP disponibile", + "STEPS": { + "SENDGRID": {} + } + }, "APP": { "LIST": "Applicazioni", "COMPLIANCE": "Conformità con OIDC", diff --git a/console/src/assets/i18n/ja.json b/console/src/assets/i18n/ja.json index 0f56cf7eb5..35b93bbb6b 100644 --- a/console/src/assets/i18n/ja.json +++ b/console/src/assets/i18n/ja.json @@ -1381,6 +1381,8 @@ } }, "SMTP": { + "TITLE": "SMTP設定", + "DESCRIPTION": "説明", "SENDERADDRESS": "送信者のメールアドレス", "SENDERNAME": "送信者名", "REPLYTOADDRESS": "返信先アドレス", @@ -1391,6 +1393,7 @@ "PASSWORDSET": "SMTPパスワードは正常に設定されました。", "TLS": "Transport Layer Security (TLS)", "SAVED": "正常に保存されました!", + "NOCHANGES": "変更はありません!", "REQUIREDWARN": "ドメインから通知を送信するには、SMTP情報を入力する必要があります。" }, "SMS": { @@ -2209,6 +2212,48 @@ "1": "有効" } }, + "SMTP": { + "LIST": { + "TITLE": "SMTPプロバイダー", + "DESCRIPTION": "これらは、Zitadel インスタンスの SMTP プロバイダーです。ユーザーに通知を送信するために使用するものをアクティブにします。", + "EMPTY": "使用可能な SMTP プロバイダーがありません", + "ACTIVATED": "アクティブ化された", + "ACTIVATE": "プロバイダーをアクティブ化する", + "DEACTIVATE": "プロバイダーを非アクティブ化する", + "TYPE": "タイプ", + "DIALOG": { + "ACTIVATED": "SMTP設定が有効化されました", + "ACTIVATE_WARN_TITLE": "SMTP設定を有効にする", + "ACTIVATE_WARN_DESCRIPTION": "SMTP 構成をアクティブにしようとしています。まず、現在アクティブなプロバイダーを非アクティブ化してから、この構成をアクティブ化します。本気ですか?", + "DEACTIVATE_WARN_TITLE": "SMTP設定を無効にする", + "DEACTIVATE_WARN_DESCRIPTION": "SMTP 構成を非アクティブ化しようとしています。本気ですか?", + "DEACTIVATED": "SMTP設定が無効化されました", + "DELETE_TITLE": "SMTP設定を削除する", + "DELETE_DESCRIPTION": "構成を削除しようとしています。送信者名を入力してこのアクションを確認します", + "DELETED": "SMTP設定が削除されました", + "SENDER": "この SMTP 構成を削除するには、「{{ value }}」と入力します。" + } + }, + "CREATE": { + "TITLE": "SMTPプロバイダーの追加", + "DESCRIPTION": "次のプロバイダーから 1 つ以上を選択します。", + "STEPS": { + "TITLE": "{{ value }} SMTP プロバイダーを追加", + "CREATE_DESC_TITLE": "{{ value }} SMTP 設定をステップごとに入力します", + "CURRENT_DESC_TITLE": "これらは SMTP 設定です", + "PROVIDER_SETTINGS": "SMTPプロバイダーの設定", + "SENDER_SETTINGS": "送信者の設定", + "TEST_SETTINGS": "SMTP設定をテストする" + } + }, + "DETAIL": { + "TITLE": "SMTPプロバイダーの設定" + }, + "EMPTY": "使用可能な SMTP プロバイダーがありません", + "STEPS": { + "SENDGRID": {} + } + }, "APP": { "LIST": "アプリケーション", "COMPLIANCE": "OIDCコンプライアンス", diff --git a/console/src/assets/i18n/mk.json b/console/src/assets/i18n/mk.json index 88237890ca..03447afd33 100644 --- a/console/src/assets/i18n/mk.json +++ b/console/src/assets/i18n/mk.json @@ -1382,6 +1382,8 @@ } }, "SMTP": { + "TITLE": "SMTP подесувања", + "DESCRIPTION": "Опис", "SENDERADDRESS": "Адреса на испраќачот", "SENDERNAME": "Име на испраќачот", "REPLYTOADDRESS": "Reply-to адреса", @@ -1392,6 +1394,7 @@ "PASSWORDSET": "SMTP лозинката е успешно поставена.", "TLS": "Transport Layer Security (TLS)", "SAVED": "Успешно зачувано!", + "NOCHANGES": "Нема промени!", "REQUIREDWARN": "За да испраќате известувања од вашиот домен, мора да ги внесете вашите SMTP податоци." }, "SMS": { @@ -2215,6 +2218,48 @@ "1": "Дозволено" } }, + "SMTP": { + "LIST": { + "TITLE": "SMTP провајдер", + "DESCRIPTION": "Ова се давателите на SMTP за вашиот пример Zitadel. Активирајте го оној што сакате да го користите за испраќање известувања до вашите корисници.", + "EMPTY": "Нема достапен SMTP провајдер", + "ACTIVATED": "Активиран", + "ACTIVATE": "Активирајте го провајдерот", + "DEACTIVATE": "Деактивирајте го провајдерот", + "TYPE": "Тип", + "DIALOG": { + "ACTIVATED": "SMTP конфигурацијата е активирана", + "ACTIVATE_WARN_TITLE": "Активирајте SMTP конфигурација", + "ACTIVATE_WARN_DESCRIPTION": "Ќе активирате SMTP конфигурација. Прво ќе го деактивираме тековниот активен провајдер, а потоа ќе ја активираме оваа конфигурација. Дали си сигурен?", + "DEACTIVATE_WARN_TITLE": "Деактивирајте ја конфигурацијата SMTP", + "DEACTIVATE_WARN_DESCRIPTION": "Ќе деактивирате SMTP конфигурација. Дали си сигурен?", + "DEACTIVATED": "SMTP конфигурацијата е деактивирана", + "DELETE_TITLE": "Избришете ја конфигурацијата SMTP", + "DELETE_DESCRIPTION": "Ќе избришете конфигурација. Потврдете го ова дејство со внесување на името на испраќачот", + "DELETED": "SMTP конфигурацијата е избришана", + "SENDER": "Внесете {{ value }}, за да ја избришете оваа SMTP конфигурација." + } + }, + "CREATE": { + "TITLE": "Додадете SMTP провајдер", + "DESCRIPTION": "Изберете еден или повеќе од следните провајдери.", + "STEPS": { + "TITLE": "Додадете {{ value }} SMTP провајдер", + "CREATE_DESC_TITLE": "Внесете ги вашите поставки за {{ value }} SMTP чекор по чекор", + "CURRENT_DESC_TITLE": "Ова се вашите поставки за SMTP", + "PROVIDER_SETTINGS": "Поставки на провајдерот SMTP", + "SENDER_SETTINGS": "Поставки на испраќачот", + "TEST_SETTINGS": "Тестирајте ги поставките за SMTP" + } + }, + "DETAIL": { + "TITLE": "Поставки на провајдерот SMTP" + }, + "EMPTY": "Нема достапен SMTP провајдер", + "STEPS": { + "SENDGRID": {} + } + }, "APP": { "LIST": "Апликации", "COMPLIANCE": "OIDC Соодветност", diff --git a/console/src/assets/i18n/nl.json b/console/src/assets/i18n/nl.json index 398156ddb2..767db991fd 100644 --- a/console/src/assets/i18n/nl.json +++ b/console/src/assets/i18n/nl.json @@ -1381,6 +1381,8 @@ } }, "SMTP": { + "TITLE": "SMTP Instellingen", + "DESCRIPTION": "Beschrijving", "SENDERADDRESS": "Afzender Email Adres", "SENDERNAME": "Afzender Naam", "REPLYTOADDRESS": "Antwoord-naar Adres", @@ -1391,6 +1393,7 @@ "PASSWORDSET": "SMTP Wachtwoord is succesvol ingesteld.", "TLS": "Transport Layer Security (TLS)", "SAVED": "Succesvol opgeslagen!", + "NOCHANGES": "Geen veranderingen!", "REQUIREDWARN": "Om notificaties te kunnen versturen vanaf uw domein, moet u uw SMTP-gegevens invoeren." }, "SMS": { @@ -2236,6 +2239,48 @@ "1": "Toegestaan" } }, + "SMTP": { + "LIST": { + "TITLE": "SMTP-provider", + "DESCRIPTION": "Dit zijn de SMTP-providers voor uw Zitadel-instantie. Activeer degene die u wilt gebruiken om meldingen naar uw gebruikers te sturen.", + "EMPTY": "Geen SMTP-provider beschikbaar", + "ACTIVATED": "Geactiveerd", + "ACTIVATE": "Aanbieder activeren", + "DEACTIVATE": "Aanbieder deactiveren", + "TYPE": "Type", + "DIALOG": { + "ACTIVATED": "SMTP-configuratie is geactiveerd", + "ACTIVATE_WARN_TITLE": "Activeer SMTP-configuratie", + "ACTIVATE_WARN_DESCRIPTION": "U staat op het punt een SMTP-configuratie te activeren. Eerst deactiveren we de huidige actieve provider en activeren vervolgens deze configuratie. Weet je het zeker?", + "DEACTIVATE_WARN_TITLE": "Deactiveer SMTP-configuratie", + "DEACTIVATE_WARN_DESCRIPTION": "U staat op het punt een SMTP-configuratie te deactiveren. Weet je het zeker?", + "DEACTIVATED": "SMTP-configuratie is gedeactiveerd", + "DELETE_TITLE": "SMTP-configuratie verwijderen", + "DELETE_DESCRIPTION": "U staat op het punt een configuratie te verwijderen. Bevestig deze actie door de naam van de afzender te typen", + "DELETED": "SMTP-configuratie is verwijderd", + "SENDER": "Typ {{ value }} om deze SMTP-configuratie te verwijderen." + } + }, + "CREATE": { + "TITLE": "SMTP-provider toevoegen", + "DESCRIPTION": "Selecteer één of meer van de volgende aanbieders.", + "STEPS": { + "TITLE": "Voeg {{ value }} SMTP-provider toe", + "CREATE_DESC_TITLE": "Voer stap voor stap uw {{ value }} SMTP-instellingen in", + "CURRENT_DESC_TITLE": "Dit zijn uw SMTP-instellingen", + "PROVIDER_SETTINGS": "SMTP-providerinstellingen", + "SENDER_SETTINGS": "Afzenderinstellingen", + "TEST_SETTINGS": "SMTP-instellingen testen" + } + }, + "DETAIL": { + "TITLE": "SMTP-providerinstellingen" + }, + "EMPTY": "Geen SMTP-provider beschikbaar", + "STEPS": { + "SENDGRID": {} + } + }, "APP": { "LIST": "Toepassingen", "COMPLIANCE": "OIDC Conformiteit", diff --git a/console/src/assets/i18n/pl.json b/console/src/assets/i18n/pl.json index 7f3cbc226b..c4f9591f3d 100644 --- a/console/src/assets/i18n/pl.json +++ b/console/src/assets/i18n/pl.json @@ -1380,6 +1380,8 @@ } }, "SMTP": { + "TITLE": "Ustawienia SMTP", + "DESCRIPTION": "Opis", "SENDERADDRESS": "Adres e-mail nadawcy", "SENDERNAME": "Nazwa nadawcy", "REPLYTOADDRESS": "Adres Reply-to", @@ -1390,6 +1392,7 @@ "PASSWORDSET": "Hasło SMTP zostało pomyślnie ustawione.", "TLS": "Bezpieczeństwo warstwy transportu (TLS)", "SAVED": "Pomyślnie zapisano!", + "NOCHANGES": "Bez zmian!", "REQUIREDWARN": "Aby wysyłać powiadomienia z twojej domeny, musisz podać dane SMTP." }, "SMS": { @@ -2218,6 +2221,48 @@ "1": "Dozwolone" } }, + "SMTP": { + "LIST": { + "TITLE": "Dostawca SMTP", + "DESCRIPTION": "To są dostawcy SMTP dla Twojej instancji Zitadel. Aktywuj ten, którego chcesz używać do wysyłania powiadomień do użytkowników.", + "EMPTY": "Brak dostępnego dostawcy SMTP", + "ACTIVATED": "Aktywowany", + "ACTIVATE": "Aktywuj dostawcę", + "DEACTIVATE": "Dezaktywuj dostawcę", + "TYPE": "Typ", + "DIALOG": { + "ACTIVATED": "Konfiguracja SMTP została aktywowana", + "ACTIVATE_WARN_TITLE": "Aktywuj konfigurację SMTP", + "ACTIVATE_WARN_DESCRIPTION": "Zamierzasz aktywować konfigurację SMTP. Najpierw dezaktywujemy bieżącego aktywnego dostawcę, a następnie aktywujemy tę konfigurację. Jesteś pewny?", + "DEACTIVATE_WARN_TITLE": "Dezaktywuj konfigurację SMTP", + "DEACTIVATE_WARN_DESCRIPTION": "Zamierzasz dezaktywować konfigurację SMTP. Jesteś pewny?", + "DEACTIVATED": "Konfiguracja SMTP została dezaktywowana", + "DELETE_TITLE": "Usuń konfigurację SMTP", + "DELETE_DESCRIPTION": "Zamierzasz usunąć konfigurację. Potwierdź tę czynność, wpisując nazwę nadawcy", + "DELETED": "Konfiguracja SMTP została usunięta", + "SENDER": "Wpisz {{ value }}, aby usunąć tę konfigurację SMTP." + } + }, + "CREATE": { + "TITLE": "Dodaj dostawcę SMTP", + "DESCRIPTION": "Wybierz jednego lub więcej z poniższych dostawców.", + "STEPS": { + "TITLE": "Dodaj {{ value }} dostawcę SMTP", + "CREATE_DESC_TITLE": "Wprowadź krok po kroku ustawienia SMTP {{ value }}", + "CURRENT_DESC_TITLE": "To są Twoje ustawienia SMTP", + "PROVIDER_SETTINGS": "Ustawienia dostawcy SMTP", + "SENDER_SETTINGS": "Ustawienia nadawcy", + "TEST_SETTINGS": "Przetestuj ustawienia SMTP" + } + }, + "DETAIL": { + "TITLE": "Ustawienia dostawcy SMTP" + }, + "EMPTY": "Brak dostępnego dostawcy SMTP", + "STEPS": { + "SENDGRID": {} + } + }, "APP": { "LIST": "Aplikacje", "COMPLIANCE": "Zgodność OIDC", diff --git a/console/src/assets/i18n/pt.json b/console/src/assets/i18n/pt.json index c19bb19e9d..930fa9795d 100644 --- a/console/src/assets/i18n/pt.json +++ b/console/src/assets/i18n/pt.json @@ -1382,6 +1382,8 @@ } }, "SMTP": { + "TITLE": "Configurações SMTP", + "DESCRIPTION": "Descrição", "SENDERADDRESS": "Endereço de e-mail do remetente", "SENDERNAME": "Nome do remetente", "REPLYTOADDRESS": "Endereço Reply-To", @@ -1392,6 +1394,7 @@ "PASSWORDSET": "Senha do SMTP definida com sucesso.", "TLS": "Transport Layer Security (TLS)", "SAVED": "Salvo com sucesso!", + "NOCHANGES": "Sem alterações!", "REQUIREDWARN": "Para enviar notificações do seu domínio, você precisa inserir seus dados SMTP." }, "SMS": { @@ -2213,6 +2216,48 @@ "1": "Permitido" } }, + "SMTP": { + "LIST": { + "TITLE": "Provedor SMTP", + "DESCRIPTION": "Estes são os provedores SMTP para sua instância Zitadel. Ative aquele que deseja usar para enviar notificações aos seus usuários.", + "EMPTY": "Nenhum provedor SMTP disponível", + "ACTIVATED": "Ativado", + "ACTIVATE": "Ativar provedor", + "DEACTIVATE": "Desativar provedor", + "TYPE": "Tipo", + "DIALOG": { + "ACTIVATED": "A configuração SMTP foi ativada", + "ACTIVATE_WARN_TITLE": "Ativar configuração SMTP", + "ACTIVATE_WARN_DESCRIPTION": "Você está prestes a ativar uma configuração SMTP. Primeiro, desativaremos o provedor ativo atual e depois ativaremos esta configuração. Tem certeza?", + "DEACTIVATE_WARN_TITLE": "Desativar configuração SMTP", + "DEACTIVATE_WARN_DESCRIPTION": "Você está prestes a desativar uma configuração SMTP. Tem certeza?", + "DEACTIVATED": "A configuração SMTP foi desativada", + "DELETE_TITLE": "Excluir configuração SMTP", + "DELETE_DESCRIPTION": "Você está prestes a excluir uma configuração. Confirme esta ação digitando o nome do remetente", + "DELETED": "A configuração SMTP foi excluída", + "SENDER": "Digite {{ value }} para excluir esta configuração SMTP." + } + }, + "CREATE": { + "TITLE": "Adicionar provedor SMTP", + "DESCRIPTION": "Selecione um ou mais dos seguintes fornecedores.", + "STEPS": { + "TITLE": "Adicionar {{ value }} provedor SMTP", + "CREATE_DESC_TITLE": "Insira suas configurações SMTP de {{ value }} passo a passo", + "CURRENT_DESC_TITLE": "Estas são suas configurações de SMTP", + "PROVIDER_SETTINGS": "Configurações do provedor SMTP", + "SENDER_SETTINGS": "Configurações do remetente", + "TEST_SETTINGS": "Testar configurações de SMTP" + } + }, + "DETAIL": { + "TITLE": "Configurações do provedor SMTP" + }, + "EMPTY": "Nenhum provedor SMTP disponível", + "STEPS": { + "SENDGRID": {} + } + }, "APP": { "LIST": "Aplicações", "COMPLIANCE": "Conformidade OIDC", diff --git a/console/src/assets/i18n/ru.json b/console/src/assets/i18n/ru.json index 1310a4645e..491cbf120c 100644 --- a/console/src/assets/i18n/ru.json +++ b/console/src/assets/i18n/ru.json @@ -1425,6 +1425,7 @@ }, "SMTP": { "TITLE": "Настройки SMTP", + "DESCRIPTION": "Описание", "SENDERADDRESS": "Адрес электронной почты отправителя", "SENDERNAME": "Имя отправителя", "HOSTANDPORT": "Хост и порт", @@ -1434,6 +1435,7 @@ "PASSWORDSET": "Пароль SMTP был успешно установлен.", "TLS": "Безопасность транспортного уровня (TLS)", "SAVED": "Успешно сохранено!", + "NOCHANGES": "Без изменений!", "REQUIREDWARN": "Для того, чтобы отправлять уведомления с вашего домена, вам необходимо ввести свои данные SMTP." }, "SMS": { @@ -2331,6 +2333,48 @@ "1": "Разрешён" } }, + "SMTP": { + "LIST": { + "TITLE": "SMTP-провайдер", + "DESCRIPTION": "Это поставщики SMTP для вашего экземпляра Zitadel. Активируйте тот, который вы хотите использовать для отправки уведомлений вашим пользователям.", + "EMPTY": "SMTP-провайдер не доступен", + "ACTIVATED": "Активировано", + "ACTIVATE": "Активировать провайдера", + "DEACTIVATE": "Деактивировать провайдера", + "TYPE": "Тип", + "DIALOG": { + "ACTIVATED": "Конфигурация SMTP активирована", + "ACTIVATE_WARN_TITLE": "Активируйте конфигурацию SMTP", + "ACTIVATE_WARN_DESCRIPTION": "Вы собираетесь активировать конфигурацию SMTP. Сначала мы деактивируем текущего активного провайдера, а затем активируем эту конфигурацию. Вы уверены?", + "DEACTIVATE_WARN_TITLE": "Деактивировать конфигурацию SMTP", + "DEACTIVATE_WARN_DESCRIPTION": "Вы собираетесь деактивировать конфигурацию SMTP. Вы уверены?", + "DEACTIVATED": "Конфигурация SMTP деактивирована", + "DELETE_TITLE": "Удалить конфигурацию SMTP", + "DELETE_DESCRIPTION": "Вы собираетесь удалить конфигурацию. Подтвердите это действие, введя имя отправителя.", + "DELETED": "Конфигурация SMTP удалена.", + "SENDER": "Введите {{ value }}, чтобы удалить эту конфигурацию SMTP." + } + }, + "CREATE": { + "TITLE": "Добавить SMTP-провайдера", + "DESCRIPTION": "Выберите одного или нескольких из следующих поставщиков.", + "STEPS": { + "TITLE": "Добавить {{ value }} SMTP-провайдера", + "CREATE_DESC_TITLE": "Введите {{ value }} настройки SMTP шаг за шагом.", + "CURRENT_DESC_TITLE": "Это ваши настройки SMTP", + "PROVIDER_SETTINGS": "Настройки SMTP-провайдера", + "SENDER_SETTINGS": "Настройки отправителя", + "TEST_SETTINGS": "Проверка настроек SMTP" + } + }, + "DETAIL": { + "TITLE": "Настройки SMTP-провайдера" + }, + "EMPTY": "Нет доступного поставщика SMTP", + "STEPS": { + "SENDGRID": {} + } + }, "APP": { "LIST": "Приложения", "COMPLIANCE": "Соответствие OIDC", diff --git a/console/src/assets/i18n/zh.json b/console/src/assets/i18n/zh.json index be584045ba..659a25907e 100644 --- a/console/src/assets/i18n/zh.json +++ b/console/src/assets/i18n/zh.json @@ -1380,6 +1380,8 @@ } }, "SMTP": { + "TITLE": "SMTP 设置", + "DESCRIPTION": "描述", "SENDERADDRESS": "发件人地址", "SENDERNAME": "发件人名称", "REPLYTOADDRESS": "Reply-to 地址", @@ -1390,6 +1392,7 @@ "PASSWORDSET": "SMTP 密码设置成功。", "TLS": "使用安全传输层 (TLS)", "SAVED": "保存成功!", + "NOCHANGES": "没有变化!", "REQUIREDWARN": "要从您的域发送通知,您必须输入您的 SMTP 数据。" }, "SMS": { @@ -2217,6 +2220,48 @@ "1": "允许" } }, + "SMTP": { + "LIST": { + "TITLE": "SMTP 提供商", + "DESCRIPTION": "这些是您的 Zitadel 实例的 SMTP 提供商。激活您想要用来向用户发送通知的通知。", + "EMPTY": "没有可用的 SMTP 提供商", + "ACTIVATED": "活性", + "ACTIVATE": "激活提供商", + "DEACTIVATE": "停用提供商", + "TYPE": "类型", + "DIALOG": { + "ACTIVATED": "SMTP 配置已激活", + "ACTIVATE_WARN_TITLE": "激活 SMTP 配置", + "ACTIVATE_WARN_DESCRIPTION": "您即将激活 SMTP 配置。首先,我们将停用当前活动的提供程序,然后激活此配置。你确定吗?", + "DEACTIVATE_WARN_TITLE": "停用 SMTP 配置", + "DEACTIVATE_WARN_DESCRIPTION": "您即将停用 SMTP 配置。你确定吗?", + "DEACTIVATED": "SMTP 配置已停用", + "DELETE_TITLE": "删除 SMTP 配置", + "DELETE_DESCRIPTION": "您将要删除一个配置。输入发件人姓名确认此操作", + "DELETED": "SMTP 配置已被删除", + "SENDER": "输入 {{ value }},删除此 SMTP 配置。" + } + }, + "CREATE": { + "TITLE": "添加 SMTP 提供商", + "DESCRIPTION": "选择以下一个或多个提供商。", + "STEPS": { + "TITLE": "添加 {{ value }} SMTP 提供商", + "CREATE_DESC_TITLE": "逐步输入您的 {{ value }} SMTP 设置", + "CURRENT_DESC_TITLE": "这些是您的 SMTP 设置", + "PROVIDER_SETTINGS": "SMTP 提供商设置", + "SENDER_SETTINGS": "发件人设置", + "TEST_SETTINGS": "测试 SMTP 设置" + } + }, + "DETAIL": { + "TITLE": "SMTP 提供商设置" + }, + "EMPTY": "没有可用的 SMTP 提供商", + "STEPS": { + "SENDGRID": {} + } + }, "APP": { "LIST": "应用", "COMPLIANCE": "OIDC 兼容性", diff --git a/console/src/assets/images/smtp/aws-ses.svg b/console/src/assets/images/smtp/aws-ses.svg new file mode 100644 index 0000000000..c3b9b61984 --- /dev/null +++ b/console/src/assets/images/smtp/aws-ses.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/console/src/assets/images/smtp/brevo.svg b/console/src/assets/images/smtp/brevo.svg new file mode 100644 index 0000000000..a86cb89a46 --- /dev/null +++ b/console/src/assets/images/smtp/brevo.svg @@ -0,0 +1,3 @@ + + + diff --git a/console/src/assets/images/smtp/google.png b/console/src/assets/images/smtp/google.png new file mode 100644 index 0000000000000000000000000000000000000000..94e00f90b3e6cf05a6d8af0833513cee8e6b7f47 GIT binary patch literal 4571 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 Z_H=T*!C3l%@zwtfP1XA \ No newline at end of file diff --git a/console/src/assets/images/smtp/mailgun.svg b/console/src/assets/images/smtp/mailgun.svg new file mode 100644 index 0000000000..8cfc319bad --- /dev/null +++ b/console/src/assets/images/smtp/mailgun.svg @@ -0,0 +1,15 @@ + + + + + + diff --git a/console/src/assets/images/smtp/mailjet.svg b/console/src/assets/images/smtp/mailjet.svg new file mode 100644 index 0000000000..44edfb093b --- /dev/null +++ b/console/src/assets/images/smtp/mailjet.svg @@ -0,0 +1,7 @@ + + + Mailjet + + + + diff --git a/console/src/assets/images/smtp/postmark.png b/console/src/assets/images/smtp/postmark.png new file mode 100644 index 0000000000000000000000000000000000000000..42e51675c072f85af5af340a997a1d7627808d2b GIT binary patch literal 1039 zcmeAS@N?(olHy`uVBq!ia0vp^A3&Ic8Ax(=OD+IXO9OmDT>sx=0HVZThJSY%_Ah5p zkYQkCWNZ1&Ivx`3(Q=F|41-P?*RN zAIvbJhG9Z2!@Khg3%VHA&tTZMjKSZPA<&JXzm_4umBCP(VO|%5055~1CBwv8hI3mO z_AO-)QcfBPlLPdr=1g$)p_p; zJUBeH{lv*72dkNCrug{h2wOBgeA^^a9hM-XuUT+b*r(g~xUkRpSEj)RF~Zj2M@4ze zuPmOSZE^PTgC_MEa*s@-3#8(Yez!UJ#Vz(T%jM!*EZZKuwz#p0<#P9plA42+A~7FW zzo+wtZDmLxs4vr7TtAUZ&)9Q)RL1(%4azgV?P^i|q5RTxn&OYwPFJS3Kajqatz%wbt}tC9 z!S2BZt1{o!n{*Bw>|6c!g7UPie{$yp=IlN3x7NSF@4@BOYjie9I42O|qkSz~;Daodzz2#ADj%kc0turAm4bZ6Ck?Y1cQPH&^-E)XkoJNhnRnjoUoR!M z@*LDKUAFK4Hyfs7Of`Zp%{>34*|Qz^(eUv9k_1-mh=W`pU#`Kz>~GXf{-DQp?-T2E zy|8m)bMEcTxL?_LIezL+l@hLdY-qq#ZIl--+tQANE+HUh#_Ed{9x?!6-~x z$dR4?hfTo?2{vlfdbpznTDA|q^4Uwp)N$+FSiW9|3w`{bGB(E=vmE>t<@GB}A!Msc z-L@tPh8eT-;`+DEPHHHaTNbXrhGELo(F{YNG{T;zMl%eFjZM1LW}rMvN=q1$VcwVn zb4beEttB_kO)~dpIPkx_d(j3aYPFsRK{-N?b|k5lJoaowMC8G8Uc=E3+6Nd8CY42L T^tWgOYfA=CS3j3^P6 \ No newline at end of file diff --git a/console/src/component-themes.scss b/console/src/component-themes.scss index f495704c81..d695affe9d 100644 --- a/console/src/component-themes.scss +++ b/console/src/component-themes.scss @@ -72,6 +72,9 @@ @import 'src/app/modules/info-overlay/info-overlay.component.scss'; @import 'src/app/modules/create-layout/create-layout.component.scss'; @import 'src/app/modules/domains/domain-verification/domain-verification.component.scss'; +@import 'src/app/modules/smtp-table/smtp-table.component.scss'; +@import 'src/app/modules/smtp-provider/smtp-provider.scss'; +@import 'src/app/modules/policies/notification-smtp-provider/notification-smtp-provider.component.scss'; @import './styles/codemirror.scss'; @import 'src/app/components/copy-row/copy-row.component.scss'; @import 'src/app/modules/providers/provider-next/provider-next.component.scss'; @@ -85,6 +88,8 @@ @include header-theme($theme); @include app-type-radio-theme($theme); @include idp-table-theme($theme); + @include smtp-table-theme($theme); + @include smtp-provider-theme($theme); @include events-theme($theme); @include projects-theme($theme); @include grants-theme($theme); @@ -153,4 +158,5 @@ @include domain-verification-theme($theme); @include copy-row-theme($theme); @include provider-next-theme($theme); + @include smtp-settings-theme($theme); } diff --git a/docs/docs/guides/manage/console/default-settings.mdx b/docs/docs/guides/manage/console/default-settings.mdx index a715f8a4db..c2b7773789 100644 --- a/docs/docs/guides/manage/console/default-settings.mdx +++ b/docs/docs/guides/manage/console/default-settings.mdx @@ -37,12 +37,12 @@ We recommend setting your Branding and SMTP settings initially as it will comfor In the Branding settings, you can upload you Logo for the login interface, set your own colors for buttons, background, links, and choose between multiple behavours. You don't need to be an expert as those settings can all be set without any knowledge of CSS. -| Setting | Description | -| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Logo | Upload your logo for the light and the dark design. This is used mainly in the login interface. | -| Icon | Upload your icon for the light and the dark design. Icons are used for smaller components. For example in console on the top left as the home button. | -| Colors | You can set four different colors to design your login page and email. (Background-, Primary-, Warn- and Font Color) | -| Font | Upload your custom font | +| Setting | Description | +| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Logo | Upload your logo for the light and the dark design. This is used mainly in the login interface. | +| Icon | Upload your icon for the light and the dark design. Icons are used for smaller components. For example in console on the top left as the home button. | +| Colors | You can set four different colors to design your login page and email. (Background-, Primary-, Warn- and Font Color) | +| Font | Upload your custom font | | Advanced Behavior | **Hide Loginname suffix**: If enabled, your loginname suffix (Domain) will not be shown in the login page. **Disable Watermark**: If you disable the watermark you will not see the "Powered by ZITADEL" in the login page | Make sure you click the "Apply configuration" button after you finish your configuration. This will ensure your design is visible for your customers. @@ -66,7 +66,14 @@ You can configure on which changes the users will be notified. The text of the m ### SMTP -On each instance we configure our default SMTP provider. To make sure, that you only send some E-Mails from domains you own. You need to add a custom domain on your instance. +On each instance we configure our default SMTP provider. To make sure, that you only send some E-Mails from domains you own, you need to add a custom domain on your instance. + +You can configure many SMTP providers using templates for popular providers. The templates will add known settings like host, port or default user and will suggest values for user and/or password. + +:::important +You have to activate your SMTP provider so Zitadel can use it to send your emails. Only one provider can be active. +::: + Go to the ZITADEL [customer portal](https://zitadel.cloud) to configure a custom domain. To configure your custom SMTP please fill the following fields: @@ -90,16 +97,16 @@ No default provider is configured to send some SMS to your users. If you like to The Login Policy defines how the login process should look like and which authentication options a user has to authenticate. -| Setting | Description | -| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Username Password allowed | Possibility to login with username and password. If this is disabled only login with external identity providers will be allowed | -| Register allowed | Enable self register possibility in the login ui, this enables username password registration as well as registration with configured external identity providers | -| External IDP allowed | Possibility to login with an external identity (e.g Google, Microsoft, Apple, etc), If you like to allow external Identity providers add them to the providers list | -| Hide password reset | Disable the self-service option for users to reset their password. | -| Domain discovery allowed | If this setting is enabled, the user does't not mandatory have to exist when entering the username. It is required to have verified domains on the organization. Example: ZITADEL is registered as organization with the domain zitadel.com and Entra ID as identity provider. A user enters john@zitadel.com in the login but the user doesn't exist. The domain can be mapped to the organization and therefore the user can be redirected to the Entra ID. -| Ignore unknown usernames | This setting can be enabled, if no error message should be shown if the user doesn't exist. Example: A user enters the login name john@zitadel.com, the user doesn't exist, but will be redirected to the password screen. After entering a password, the user will get an error that either username or password are wrong. | -| Disable login with email address | By default users can additionally [login with the email attribute](/docs/guides/solution-scenarios/configurations#use-an-email-address-as-username) of their user. Check this option to disable. | -| Disable login with phone number | By default users can additionally [login with the phonenumber attribute](/docs/guides/solution-scenarios/configurations#use-a-phone-number-as-username) of their user. Check this option to disable. | +| Setting | Description | +| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Username Password allowed | Possibility to login with username and password. If this is disabled only login with external identity providers will be allowed | +| Register allowed | Enable self register possibility in the login ui, this enables username password registration as well as registration with configured external identity providers | +| External IDP allowed | Possibility to login with an external identity (e.g Google, Microsoft, Apple, etc), If you like to allow external Identity providers add them to the providers list | +| Hide password reset | Disable the self-service option for users to reset their password. | +| Domain discovery allowed | If this setting is enabled, the user does't not mandatory have to exist when entering the username. It is required to have verified domains on the organization. Example: ZITADEL is registered as organization with the domain zitadel.com and Entra ID as identity provider. A user enters john@zitadel.com in the login but the user doesn't exist. The domain can be mapped to the organization and therefore the user can be redirected to the Entra ID. | +| Ignore unknown usernames | This setting can be enabled, if no error message should be shown if the user doesn't exist. Example: A user enters the login name john@zitadel.com, the user doesn't exist, but will be redirected to the password screen. After entering a password, the user will get an error that either username or password are wrong. | +| Disable login with email address | By default users can additionally [login with the email attribute](/docs/guides/solution-scenarios/configurations#use-an-email-address-as-username) of their user. Check this option to disable. | +| Disable login with phone number | By default users can additionally [login with the phonenumber attribute](/docs/guides/solution-scenarios/configurations#use-a-phone-number-as-username) of their user. Check this option to disable. | /ui/console/ Reasons why ZITADEL doesn't have a redirect URI: + - The login has not been called with an OIDC authorize request - The user landed on the login through an email link, e.g. Password Reset, Initialize User diff --git a/docs/static/img/guides/console/smtp.png b/docs/static/img/guides/console/smtp.png index 4334264eda575f17abc217890c37d3af5a635750..900235cf77392197d1946c8b37515f712ee44afa 100644 GIT binary patch literal 49076 zcmeFZWmuGL_&x|00s;ck-69~}rGSK#(%nNycQXblB_LfQCDPs9Eg>~@4c%R{_xS$) zd+f(Oj@=Ktd+dC8ofk*udG7nZuIs$c^SqvrcS`xOkW+gMUOtb_g2DfjxV+JFQMEUBaW{5?pjg=1+d|l!O`RYRJ7-IK zm;L+AV&FrJ$PY<6L5y9j?Cq%4tZX4DX7;w!oPyML_HNW%99-PgoLoYjyh2>uG0?Vd z6clO{IjPrb9w|F>u6hL1i0(ro>Z;%(Jhy^f9qU4hsnWW-qPe-bM)04axe)Mfj&_Rn z`PY_xoH&;FhR05~cRu1&I8-=^!p`dh1A^&^!>QcPYt!`pvRT`GXRr#(0OT`Qg2UxF@8t8 zjcu6mwNFu+cu#)rWNE3~tJWJ&kJFPnIRpk#AI__7LagwdW)G)WVa>>LyEUH|>JAvr zw^7<>x^KVt#Fclum)fn}IKXY+RWlZ+8RWY3{v3J7{ojrR@8fv2NuQ&H*xEH`Yhz`%2+6gKezkk}z|DDHzF}-_})FEoL0) zpenq0OG{g))a;Tpb5l9Jj^uW?0m4MYZb&EngheG=K`9#p^89_l)68x~)72?v;|V&h zem~4S6-Fk-t?%Gh;j(Bbi22<-+jV{V@2b!hD;Tq^RC2SxH|@+p6K1eE=s~loASBC57=clEmg>taCWa@Qx3$twc zx|SMD!J<*J`Pz1&GIEV&lI)K1YS`m!PfNafs8GAq>;5^F$Q2{FBBGZD8CLy6HFct@ zT>l;Xg;Yz5vSg-7b}en~Ql~*_NiK|oqc!WUuyi{fti_8E?gpRBq}R7~K|1E=FKvVI zh52A^JGYFkZr*1p+RlW=5XhUn=r=!Yr+<~TdJ1YK{@}Bouw9=yO@6O4*+MDmcdtb`1pkfKw6_(G{DJL@$uGadRc}h%7 zVovj;>fc-_iClM29zf?$tm749gczJHA~Id_ex``JN7)LWEnm)yYuis3poYSgJNx>+ z;$|{&8;>gN?8cNio;Ir$X+07b7mq8{8)ly_|HiMZl@`X+&S~}vM=3=}K31HR z^sGDOQeLpZ9^X_3+XTLM%c@@*L8(8Z0)jF{?0T&hro)?$2O=?!mD|rz)o53TmnJb& z)Rn9fa;=0g9_rU9TA4m3I@vl~D_U0;XD~5ZD6)Z-#$PEm(dT=gQLT?J?ecth7iz^# zM4W@Tlp*-QZ#g)B8$?$T`9F6~uq%G;bU3Q+$6^p7gas=xzcp9Maxm*y@SR?2_$=UP z5>zv=RXL>B=8D>@0%jZcqLC z^To;5Isb54b8s1?{*=__d)Pg-=bB%&N=>*d=J7IDXOC~a314al=#SDrdyx>?9jPzi zut5yHF^EdwEW|qgdzmj}F{Hmb6Rw*vQEImhd?<-_qXKq?g+Q0vw$j8M4cXe-Zd%HhE|9Yy_nkocun#;A#;l+2BH}Tko z#A045!TnDzEy(lZ2QyszrIC5+MQk6JW1r1znrP%`ojR*w($_Wl6*#;*U(+63-E&p* z0r=G6*!#MId|0{B*l4c&{g&PO^Dn+`*F&NxquKIwMT4LWy!rYDaAx=9TvJ zrhAhF>GZvxJgM|^T<%~5TPJ+(56$Iw-TICK0vT7_&@gj&xhuRq(U~YbM-SkS$$xu%a>zxXXtr7kt#Q~F74?%h zGR8JiX=4O3Xlu^Hn=HkTgD|(lt5dSAn^QEhlxo%UVsQ_|(*12d8}v#&7I}n)gQ$o| zdto~qk@nj5PZq_w#6>Ns`?>p49L+yCfEQ;;RYr!FPs~|TQnI)UD~U;IZSVRfP|Bv1 z{gumVMsL2!H8O`(I@0@`>fXUI)cx&!`Eqw+3DNey30&-F``CNilU$GBVbKL$O00zK~#utl}<^KC~Erz z>>H`#{@+1FwxF>4K92LHGn~EL>{7>WuBp4AHnd5dchDRb(dcuvs#xCTT3T`AWVzfG zBKgG&dbGU85(QHYUOt>0qG?O#6+m4oDdB}g*=+TIf+2q7TU=mavJ9p=lvBuq@)XqUgpQ_cRN zy3$%$=Z*NzTvOa%YyQKb_86b$_2tM91SA431Bib1hyM-_{gsrp#7zDI$Jvgs zLTJwE^BY|;aK!p=(IScYoM=^ZhTHjj`knox#w>38SD2Ko7IK(xz1+JdC*#5Dsy1ri zgY<}NbH~s>$;D^k7RPF6t#T<7nfg<%f9Pa)Is`p4=;&a?bbY|E57cgf26xqxvUE}J z*YJqKjgdl%rluy4EWQkhK9cS&FZ;K8N2cYntKXO}$XxzA-BL}Z`^(wV|E=uN%KQJ% z;L1=-d0EWW{`QDL7KvMat62^dz9Mbek+z3F^L0jwWHatf!5Dax2-RUW#>THfkx3Ny zrXAWQ z5d6uk_dCrf44;6Nl{JCelzcFG9Md%|!Zw-v7xdgRPkFBS&Zsk5yFg2XTW8|DkS#%! zbNp;1S4IX!sM@}D^$oXpFQc+ zi9S9N&t>Rl*QV1~a?)rCr)=4{f!24`%wup|emioMuLLh;0n#H8u?aK26L#Oj=QdYB$r(x*22ob3 zXeoJF#y|qDa#!el3DnN_O{uuX#>StDBiWn$n#>E)UQG;;V%3h2AHgPxG z25U<=i37r=Sn@-q4O7kyXZy4ux_EGSG$sgS+T*%yy6 zX59DYa~<1fo{;cOSZZ5aTW^j3?wYH|c`{}<+hBSDy{fP}I6OpmYq-}$;d?b64)XPV zhqD_7b7d;|%HISD9G)6#b|(IpS68FIeR0YsXkKlNGdnoCuAEF`t{1)iUh8_DHnM<@ zKeMRzo0yEx7T%|h$nriqsg*t!5b&uNdx{G#@?E`O{&VL3k=BT79LhIx+6$uqEE-wF z`=iHLjFsAQ<8?%K3*#uq#9?jLJQS^p!cCmIU|aburR34Q4$auV+1O>t+FhteaDbx4 zcatir%V^N-*Z)L(H4607ts*%ydVuSs$LBGB}#(g4pT>mvgXnO2#K-Z!u<$sOLfEd(~?~vkO7C zBD-Pj3NwPBh?K`wd*Clde_Hwa^`<3)Dqm(af^kMAf^mVP-J3uo3R;Z}$nhf&--Dly zp-P}3dRKf#rBgu^w+S^$yR-tw_>y(C zAO}FwcuY!WJZu{xESmON7S(PbV|=pawwO`frxT*B9L`Q6>{plZ68!wf!Vlc>eElye&1R6JirSr7=a0{r zqet@eoy*MnK3>Bye6M1P^J9MIrAoUH^0eHspT`^-^T-?r7!#(BU^P59W)#c7``R%yy=PJ*| zQP6OxEY?#3d@dFV*6$uqMI2@Z{mC(9&lH~ja^>Fr_mrf3{UwHLGwOFX{gfQVEz;B} z;VN6DpB+`;gvSA3&*}1x{R)fx^>EQHNEc}nyWU3~oxJ0w3mJ;4A`8tHtv}ZStw83a zhkRW;Y1w40>bq{rOu=W(!z%LY4b0bPF*Uy*#2#O2}PAq0SX&`2a^g!Pb@|LKS% zimYUTkJQ3Yisot{8w>G8dYMXvA3DNFVkqj*xGnDRKE7M&Pa#>6jpY)2gF*DeZ!XDZ zrr`?!^8O_9f!I5}wa4+YX|qwI457Ws?C z{a_OnBG711+caQ&%hHatNAR--e^IG zyEX{utRsSQE&OM~nQvXDg3-r+86@sZbNQ-2DON9k0bow1aXEJ2=ETGVs{u!Bh^o2s zO$Q0a`mkg<*mwo3X1YCdD>@u@bpVDdUUvaCq;6su07e%{I^KKXF`lO?J7d&U|9F z{W~+0v=(a40bO#cvRg1sFlhYnFy$>#rhcy2!i^q>AxA{Ua z_uWi=coUMruuE+gITvtwr|fgMdFJ?D+XxL;iROCwtZ#a4%B`4~RTV>c24l~!5> zZ&9YE=#APEGRQ?-!i2D9IIOnFXR58F1JlPI>ALUlQFt62aHiJdm~|K3o@|UxY>L zF2>{}W7$fv_o^+}KPy&OR3J$tR=u*XI;T2L>pKr0;cR@WtgKu*1}!qcp!mq+omWm& z0{X!YPRUw#1dXlGsrhV2qFTPnr#k5Er^rYgP$)7ARM9g}zq61XeS4=1^A95x`*=*m zK2~MQUS$JQoER`nbLY)29RH;eV%EEp$mvZ(mRcPnq>eFDZP(_{Ty8b`6JI7GwM{6e za>OgXP_G*-gQK&zQf*)5{3q}wg>Kn-i!q~OYP;&BMaGbBf$VEQ2o6u7kAe0{ zxWkiCF}Z)sbx5zyB^<2hSXnA!Zu`pBI+~|f`3bSe*AP_;Rd7t&kB8qo4k)N+z4P;X zn-ZK;SofzMA+DCE7Wnz0-$RK=cD5Opm8)-VT{v_^l-r|Z@Ego|%i z8BO=Ox@^yqf`vihDL7|RXNiZjWoh%+&xM!6Uq-Vg-Z%0RdHe!2L(kasK8jvruYk51 z0Dll4vzBRpCdg(SF>NN(zC2^s`3C3$vYc4g7p;I?@qjOpY;j_<@FkTM)}K?F96;&B z`qYaQ!Kyjp@aUBoq>?J6@ga{9BOnq%pL0K0tDZAEy~=Jn_!2W-wOq-0Z{C}DiMYx6 z92JkLi~%~Y7ijhH_*xw9eKaoU1n*Nq%9BTrF<93ZLx2VnMb+%eU83N)eG? zR}hck$iP}m_hEed{hP$YW0LjWbbfvih46N?VvcJ@|9OixVfgEfe;MNUTY{7eUS*}a zQ&Op1yZa8VzUBhmiB1XUKemt4 zZdqZ*WoNMQ8YfZU%zn8$l*kV8c@bU>R$O&=xJ&wYbtpC!wXwcr#8Y@s#~pH5#+#)W zgYj7OE_pQYULSU`y^o>|&QlFh1*?2OGwldF_=5`y%ZUf24@9HXb*&J6lvS>wvm!m- zxO?Kap|om$({APCjS+l}qUoOD%`s5!ZOR~nQXr7IKuiNzgFIHqT_4Ta%S1VR@YQQ2NcQG^TOPr8LD%ba+2`uEEBGo8@6DIOddW$@fwbxbuxTYGr;o%u zy~*Y{6~0l6fd;b8vtLOmz428TG3Q05&KvV#-L@}5kw_u}5E$>N4JkqQeLPq#Sb{YK zBjNPolJk2zaL{~R=CEhxH<(H{<97lC+(PN}Y#M!7WMxGRSlLE@HF% zZfzu!DMipd3QAP`Lu2r_mX1!D^)PCg#c&v4nLZ-=6{3ZOh?{P)3II3L;CCCC=uEhD zG#(DnwbRK|{4QU1VNLU~QBR4Z%|dNFSfrH=qo8y6@NAT8UQi@nk3ogw_Dk&OlFLwm;!9zCcou_NxRu)z&54S zJ0$7}mfwHxJfLtowZ@EiX%GUKMZ1OC?(F`_-n74npNth3cu5B)y`V7>1SDFzIMf`5 zji@I}%=N4&-pf(2zC?%pQ?*~95-=OOaPT{{6DUQM|Ymnw|=+Xpx5$L?p80t3?UT_7W@ zfC3XZLV_EP^*V8s|0h=!TCl9{9N^=`bCut!Or5rKXSH z8@XFgUPgAoKthQSU3dm){m~q`fb0Nl+^&Y8Wz2h-9sM}qwV$9Wc3oA?Q-9U3n0Bn{D5ELTPg~)bv^*&ZusW=@^ z%)Q%xkUXjZT14B5n*e!DM_1pjn`wOHQBAJi?2Cw8xF3FXfMd!1 zIlBRk7hcEtzB{rY5}HvM7#IZJQR(<_LXsuEGQ6(t?%$?6TrXzO9*EXZCS`pr z$vaxF*(Rp*J@G8ZV;m3E z`op=(b2Z-ksGu34bulTgmj7yt{F=vi+&rk@+XjX=!_&9>5@rqZsj4og?Dxtvhq7)gMJ;7=pF?k#>R3!d34U5fHzTos>Bi$u};Ia`9RAu*ZQ3RaNXsgiiRWfxTO6j#9i;LL-R$y>1GVDnf&V7Fq zw&581>qqxX+H2T%;`OD?kmI=2irsNCuy|z_gExO~pF2>r3o|_=Ox%wCCgOc|50F&R zf?QBpkCCYg518avz}2zAk(V-Uzq>CJ zLdL{bn8e=#FUJ8gAYUvrjekK z$6f{J0P1Z7_}UPXv7}kS^5dIJd7xuiY*&ePgc3zY>?Xx#07xUX9JzH%<)V~nD>VfBMA3px&GpgNU$UXp zW~tQX-{t!)OYfj$j-Z5?^`?AMVfgwK^aNiCU%twCC0=CvK^L9Xxhp*nFfr)M-R&S7 zsbs&!-GRT8K+3=1#7H8EE?^7*1^K5gd;*9#q7st!05J}P#utMY_JOb)wDu#Gee+y{ zD;gkKo~zaYK2qZuv)V_zPR!&6gO7j#Glf8UH_PF@alA1j;@$83<~!$ZDXd1b=;d>s zJR3+y1H7>cy}KDA!xXUeo%1i56S?nf5)iuN;Kb|rpdyS91fjjsaS9|oNrEeyozW;j zPO@>Ce?2Dc+LPLkhsAM)KAK#pS8N`$;6G6gXp;&=26K*B&Mvc(%+ zvj*fj>%ghR!3tp#phQ#v4VhL`L+Xd|qQR70#fFFX3>6@Lsx-r&S~OpYZrR4ASUFT- zie}eVQdRej0R3^3BE|;F6i1jFiWcyhKvKTGpU8WFeddNNYyjD7H4Y&ZQ#6a_sewcy z7thCAYSNiy+$iqoQi9`1u`lkkc=UH$4G77mOgHJ>erGoi*$ta=%tG1%ak-Z$st*#J zhA?N`Y0H}1LyaNwM7bU#3&8{|i~zVZDWwR^HX=AAy6LlQIo491QI}0J&>S9|tOD~4 zQW2yVXJE97PPhEq@F_2dVd|_9RuO9+z8%eC;TA18Gxpn4(#8g_WVadqxH$*vNY~-e7P%xJ^f8=b;D7fP8LEBdBxOd;wAjrZcvwmia|wC*3;V* zx1@KqM!eqN+dVwH8_1wzN+2_9YC)Qk))w57m)8sHUAD)Qo-vcxx?Bo@E*8W24&dp{ zSzi`}wYOmB)*pGcLgq@ez zbP74G_B=|M*SP0>dW8ilS=Q^hBo7adGVA@;cZM6!#y_^wS;6YiS7dNd7dH-72NEhd zQnEk8%J-jw#7%OmWaDwYyVgIckRp`Kh-E!irH+5LE8YeUY_IvUt}s4RRrUe2xQ;2EOaGh-d2F5_>e;W)sFp5z%YpYKWquBJydExGy+3cd|EWDoeg)e7zlV`l zxgWQ$my6LmgdM9^MKn16e(J2~C7@IT!I1b*E(<82DWcF2lJdKUZ4qc7AJDn&Oi4o^ z{YmKF^;sEBzf6xO^j-F610Ni&1k}!di_nz?YO+*JU}d;pTRCBDv>GRkiwl%imoR5Fsr9*JrvvO%e0{6lIz_TJfF& zXeFNj-HQlIGxOLS2V`t-8XLE%G=PcSkp+6?A;5YRsFRD&G#t&~{75PNvaAs>a9KKk zF+f_P;MlDRU}|tS_|xQkdZie1?(V@k(D^rQOZ35uUhd85N{V9(<;BC5+^}?!&=f%hDDFEW#7muCnPTOWy^&834sW1m z+47N}0@I7GlkNz{d&l4j91y~Avhf`Ke8$<@^N#?Y`>5M^9CcjecDHSlEuphip%JR+ zMp)WRHJ(2O`G~(x`eFk9;jy@w6hs(nH>qbv=n>FH!{$3);%~*`b@5`7 z2pfCVG~+Vka=REQBOCjl+4+O|1h^p&K&p&mOBpJO!mo8W{92n&NBjPl`Dx#?0R+q3 z^%G8ab*Uy6gsP<58+w8IEV-U!CMIFGU4HOm`e@**3kLEOLnbW(N4;Rt?8GuW_(E0U z#gTZC$>k{6`OV~pHEpS%nw>}4SmJZ^v1D=qV``X@uf-^9WAWnA5b&C@y#8l?NVOo$rO!*Q3Sc4tIj;{xWS|rafnO zx)zQyCsduGayd$`VEN@A9QGN|J$F|t{_EdwfwOot9y^@wi;~dnAZRgUu=r;_9Ei|Z zD43X_v3{#jG*6s&TjFsyZUl3?m|_Oz6p1g4yR`sfqhM`KWWBl*IoT2ptDjUxcF+Z^ zg&r3h=pcbE-v;5(On46p!DavMd*jX=Zp}D9#e^&6B&hOcUMBMtDBcS39-bbr9gM^P zxs9)H+vRcx^{e3R5U^XJ$gW!sU#TNhepo(4K}rp+xAmqm)Tkh76=*en>K$8OURn9l zsIQWvK&;f}kA85uBMCb5jWO;MH%cv8-&~N8k(!}bIE*ysbZb5hkQQZjD--Ot?bqCd zafIZeZeK@Mat{wznA&eZ^A9{04uGIg+?gt!F0cNm4rC6>GzGu`GYhu1f>x*evHyQo9 zFT25P&1|FJXTWFTwZC{&Y|xxxn>$}q-;BwbRtzf%aLjxZ!)DD0b|`_%_a)K~2FTjL zCp)Mup+v=&b4^T?X=#j9&`ZvMal79LgVtZ7(5sV>4^Tey_3tBkbxz?(2VtDML3OZs zVI3a$Hjd)R&t3jw7DL<)8 zuqlQ5dW>)L)QcYi!^&u>zH^^u;r*6ve*3&58A+5olF^_EHZo4X(SfJiw}>~E-7G)C zAH+S6Vq;6@{UMw8`{Lr_!1=0TL|-3}@EskTP*t$4dvnlW;Qa(;%?$W5pImuA0ZwhB z(>lchgKdTAbiCtU7%a<;QfC1b7)97Ylp4==kkCvpJHR$z<@lLFI9aOIchbk?B0ebq z!ys*-Rkk`^rQqluoIG*Xy~mD*G!lCruku)VuU%^6s#P;?t+wx{)$l_x6*$RM;XMZoy-p zc~zNEZiMcN_-*I%o&q-`w$yX`CDM`oE|(zG;(e~Mbvw~l}-;sao=i5|5$m z;g7eST*wTdSv+q9Tv&j*A>nm<0q9JcH%{HM_FsZ>neGRLAuD~%DRinWdjQnH+MR^K zk^#Rv0z_-1H3e3^kIe5O_%NhBadvJYQO!=)m#O7s8lh6DqWzYTo!m~4u3HHRmX0=f z9XN-_!|CGAK=|Y`mnGV(dO!#cE>Kv$z>bL+Z6kfCXlE$tMkfHJ-jP~=&a7YdOU^aK zl1#|`4iA70BqBfo4Gi^uvEVep#xf7s?TgDxPV-rp4{G^lDz&c@b-Iv>6*m+e81vB& zkN;ey0joJ+vBLH?9-N--3Okt%O8`OXXfuW%m^4vaKrctoFO18bgX~NrFS>ehn1Al( z?EhF&Aid_tM)>05B^B3-Ik}WzmhJ`-Shv+xaWlLOmOZ&H!W*rtv@S85CXJvJep6MD zDEm~Ll3A4=4m5z)rbe#6fMnIKG{<-SaEVj>0mSn9ZT*u2MBrUdX$&xMbhdS}SZNh& zXuUx#Ia$~gDAw%&Y>{Lt{A}(Tu+m5QTh?F2?%!n??hhfIHu7=BSZB4_*$mB^%=SDA z)8D-iQ26DYsG_c0j%#ROibz9v(q9&6x$9tpND>2PPN`Wd4`Vo)c|sbW>kFWY8SxYY zl|^qZEe6PD_&Ed1Ad+lgH7O6vnW6q7`C;=S1H)A2b?a=tS##E1cYYFB%8_PggUT^v^iw3BFH4HBf-wJc+Sy+zxk5%;0gc zfKg*X0jenz5VBGPD#Ahhzwv;rc0bdp&r{0?%P1zeVoNu^0`1O)cgKVE;WXJWVq=^J zOfTQ@dKomy#81s(B%(gl7Loh3nnOD$WCFBWg2tUm2SvMWp_o5Fn%_8^doq2?;7tgK z$5ww%NmS%;MdgRPApmJE1$~obV;dcMUudu=_k&JT*3z^+j~fn*1wZ%>mpdW7pRK^a zMl|!va2P2+0TosHyZ+ykHMTYF0;9Q#gP`=$s>4f=oY-i#H4veOExl-A{@_UXr>9c^ zbCnTr><11j!x0gDn1JDN8W+Y7U#bNWy#0S{CR|G z(j5`-#aBg7Pw(>L5I?g^2{JyFcd|d1h;5r3bZrB%^krHMB|2yp9<%==dzUJl_$4SJ zKqn5IFC>c%)DP*gPyo1(>)wDWz-4k`1}r@UdsSIVvC%6`!+(Iyz|CGCNeJcaid@?H zk5dw{X?Fs83o8=s0px@3eObUAKJ>Cr)4Q;&odI{xu}!We)h|obRZC;J;Jv-4wEL*=pAd~k z;`mfW#IV+j4rv23J8TOh<4xcqutrLsz(MmA%{ zQC$Y<@fw?wg|ie%CvrdwHEur|aiuu(9%$f5Zvn^}aBu`pHm=r|PJzWLid%*+rr+;o zl^LXIqniyH_I~2G2^dj!XH0N^`3?>+1q)cuW;TORn;K#rAAaFa8~kU5dbxU8IkAQ;z6oE89ZA@|pE~ zi)g%VSN=vj7APH-r~qIdF)*5rocxaMD;x1d17$G-+~?KMd#1F@OaS5=nK4G=&Oh z9j7WT{CryTXA)|Zvy(k2;x2H zU+agjfWT8`K4+fksZlsBwP29?glLvVyVOIYq(d&fTD=;|#!+yosfw-yHe1%FU{KzMfmdO>H~1(1@!j4=Qx)6&wANMN=d z(sk!DE<@;AtL7*S#bL=`-du7c*`KLw!-TbfN%zlJ7UNk)hU>uf96CIo-rDvV8GV_< zf1XdrwY=1C>grP`BNi%QLN?ENKAg?pW-?RtquDw4#eqEaxXMP>w$Of9slsmLF__BG z(*tg%>WArKm*=eqeNPIp0xI-gC887?G}5@E<{F(^Yc&(zJ|e++sMqXBcDg7NR#Q`c)$XUxU=RW z+TlfMXl?$}B1=Wtxdl%t_||{?#Hw%(P5pmk1pn8DSKn0JVS~w7A4A|}H99#5gxST# zW=!G-I`GTINs$Ax;w6gKM7VT;u}k}9vDVJpXZqX|vfwKG=t;|1Xpg>-iQ17C&YW_% z^MW6)qGf@R+f_99@>W+PTI7H}78q=~L}dn}v{8@A_fnCP5P30IhyBZI}5cDC!3=V`&YeB5$btbf%h(*$nKil z?w(r553hh3)6cQhK1)y9eY&x2a@^0cfn_+M0n6BGvJM^0#GxOSKXSF^@*VAYuB~kL zpvV-7nFZXPYWnpAYJn|uU^&U7i08h`8W@jIizs()f*Aq)e z1{lRGnT2M@-xo|^GKJpR1*K(Pj2T>e=jiAKPwWebQxf0rFF-Hd6Zeox`wZz(EqP+i zZ)4oKg%#KgWU!7^bX0_tQ)?3b!UABI0amf>|kL3OE@bJBq2sfw3WU1?1V4 zO33^oO2n?84P1kPR$$tvwB(~^@j`-{bnIJ*cH>YYm~TN2G~P){BaJ%%kq5bk5sN?% zqk%n)lx+-KCebFu9+A>~)CeZfG#0)ijC#y~=AAJ7&UhIHLjvQ@O(Pry%UfwE67=!G{)?Y=}# zzT>fV#yZ7AL^R31CNyx<_k>+6EO8>HP=965wY6= zyh?h4Wu@(&VDxm)c=lIo$5)aV!TSn3EiCRo0@FCWiGP@WsUv~f3>B2W`c8*s#J zyZl&(r_dq+Io@2LBSiKQP?4N9P7LC@VM}n3Kfb4k5u91Uvs~b_(n=PEX*h2k z@DUEASx$++EV2W3B`WW#!lfQD3(0#_9+z2iP?L%A5%OvHz?C|tY}x=SSmPi6tueS0 z{Nx9RwNAT_!0=$EY5jT&RBj0xqQ8cr1cpXFE+A|aDs>bs=YHZ&mzi_Du(<5QG8;^Z zx~-oWsq>U9D7=M+42-lwr*ey=@Eu8U5&h`e=TA9VU!GQf?ZRc0h) zJz<~mE~Kx))g5gS3}mbh#*A?o0>Lqn+a7&lf>W!`fz*D!PPNPj3mB9oQ>IF>u7!U@ z^paCN>2?5jhaBTXdP)D3l+p)NEkONbyiIg;k^WS_;^|;XnTWA6E8omDHa50P_cMBI zO2OB_2_WElZqQU2s6m$?K9VI5q-=}Ax2f-7AWF>C5gi5J`!`+co(*WNCmACUWxw^EXf*yET z5#96p(wdID#>CKNdYV?cnun7rU!Sr6nJ1iC-rIYbEt{bgT2J8a?#{foM@lX6@s-|w z(05e{JiHz9=lk}B1u*V%i(#nwklvB`*?^HPyHKu(0fjpZu`O6e`fE4yoTe&(qDvV2);jgIOfb2}D^_V?BrOx=+>a)P1Rk zt!Ox+0&dGZm&a?5s5OUdvfd`9?AD)+lo%*dik+D4_;30L21YSfh8hbThmsnS!-6Oc zR(n&w?7xW1l$;a;8Y_>^_4vyn0U>(xmc^)x%WKeoIO^%8WU?88;Rgu`N$t`P_rcEP z`qV}Pv*s3ClPxXnk)egv);%eyj*2_-(ReUkenED(vbI#JoPNax9l;Q)v~ErH-UA|< zvAw-a+yIH7%W91=iLkKn&HZ~OC#S1<>|knfZ82%m%`1TNnmfU1|8ny23U*ZRx1{80R$2=ZLuDdDUhn+`cmt|AkI z563413b?UCvFZZt!BY~FULf-Hq_gt}G_$rW(J|E^TJBr3utbC5?VuncLtpKWz^&$h zNT=yYGwn=d zHC9Rl)VAPb0kFhy`A-0Xa8E%0P>t*Z+aML)fM9XR}^iM8iU{~GmY zk;3}mn-SW8jd|}M8T)_!yaNuew|&o;e-`E{4W=KSoX~P{;aOX=c%4%Wl;V%1cU^B? zVU6jhqCdfC8(yILxTVf=e3Dm8Ba#NZPe*HSRZj9HZbsc7qgajQ@aa8d)5&^jH74cj zS1VmzkcfrD@;13E7W4opiyPk(z7q6teb{+My@jy}1mY)P8bCK1I7b(^uJ+p_Kx3WQ zZ22Yy#{~};*Yh>d)TG2rK}s|}ts4wXhY#N_>#ui~3=pM>dJm;M?0^1E90%~_9$ucu z2N_JUO~pX&=DV4x=LRE3aPYu~Ku8jQUiV2aU2in=eP9?yKA`})zrUgJ(ChQFv!&|R zOk&`UMmalk)6&&lIlky^KCS8S`5PAM{9<5ma0M%?XlRJDsDSj!!Le&4drdh_OlA$C z-ZDD+`M0>QGQdM%FGNwm<2`arF1ao)M3z8oASOu90LN3UW#9jG2F5u~HfG{vB7L6V1UtF9GKS}4 znwy)C7pe!iSgDrV-A-8cr-N^|XZhYbLc9dhaWO1Z2S;71TOJ>9%Eugg4joT7I!@5waR_4 z0jFx*cTziYZxdu1xi}tlOu}Lwg=7v-MgXMEwl2gII4;@K#Lri1)1eilhJH08ps{Aw z`-P%A$!@-VCh8%6#ObdH5F;Sa1IC(-Z6bJvK3rTQSttMXIYyrW%iY20%KE=(sFMA(JHrSgP?L>(Qn&KU4wRmY|zv zlJoL4$Qxp&$nNLgi!tNX|2%K#|MWZK@mHjjgmwde|LaD5;@TwI74#)O6Z3ux4D=-x z{_kNctEz-&A!h8Ek46_47nRMs!BrzK{A*i#J32Nxrz;7%iPa9l)iv6;=kIA*+1SA2 z3OLTT{`lSX4s59z zz?S-z4>6o^>v417R3Hw7D^GS_q(MfIyQ?#y$#zABQoJE-_=~)rKxO1+jP&C2&WXXq z=e_Kee=T@y?1FH=Z-a8kc=D>JLNI3*xfXzZ>yq@5kg1!>+Al#{4 z3JX=(O5ZZtGHYz10nN8H*!VWHl7z>MNAM_?TBZrF09FzkAg=))Ym>;wG}Lqq?;i|f z&YZ99y8CiR@0xR?Ry6aGUM`vg(nhsEYau~??H&4l0@>Nq(vAqyS9Oo|!^R;E{77&m zYh%B~h1c=xQ-xx`H1NVFs^$(mBR-+cd13#M{@a%&8#VB!3zQ=EeHjl=aasWZ|CSc& zcKFAZ7J+NG{%CY=?sE4cPFB{i#l@$L&yC7h6U7@`Pzj^M@P4|R+>XJ{h)vM z-!TLxLdF>y+|&E`NO-^by{Bfs#wO?UX+pGo5q6(rR^xzvj&pZ=+u0@<Ghym9`^;bDjM!mw1syJ6>&EUTH{ z92;sp_5HUHI{Nzt^(-L)SWt36HFrg(-fH>NGKvyVS5*jRv|vC}Q;$A>GA= zhfus@qgfo@(QA*I{5_RRPkU6*i~KVfLTMuc@dYp2AGC4Vm{Rvq1)`yf%sBpvP}UZE z7T2vji}(LM$kz0_3~cto;$n!nktsHwoaBGOlPd9h2l9Uwfjwt48;Az5x4?PCbYrrz zr=6V`rIvHrnM-k6&3)Ogd2MH|TPo)y2N-RG^{?gqKQErbRw?njqBl*ltL}m?s#1$E zBqRi_^Vo#M<&YG$QMZaJi zzqo;x{+@>LH<4JcPHkr|y87a{tK#D;5Bd&~ z(`b6#VIF5rHmo1UAE1FrpryelVXi0E?|1$?>-kQR3R`28O=e>Qdq%xy)l<|{7s`9z z8Om?TJntf#pGJLgak4YhgqK*2ndDc%fG*g_SJ$Tyn4}L1r}v48V;zTBjh3DjE}q8_b8c$so54nS4XwKy;E^v{^WUPg zHQ9sqvlc>lg<00tObI!3t~zW~>>h5|Wh?Xh^yhYO=Pug0x+eTCmN(=sHR+yb#n@xh z__s42OS61<#OHKE0+j{3t5oQy7v^%G^-O=XW2D>CwAk0VwjUE1F{1<54^Im;13JT5 ziERx1!6p6hY_p|;POaj3z1_+2X1~TdqIRn{utFI?Y~W5-Nm4$(@|G^`SOuiC`J81ldl9}-)!)3 z0`y(zKR#K$e2I2(abfYk7In$3E#Uw0xZ+k>WZA9P96%&7_`;n!FaY?d>Pm<2Q;h1E zeVv`1Mv%0%Yapf7946x`S32kOj7Mt0V8Nf9&p&WowK>XA+q}Cyb+gCPAs=u(-Vud2>vCI!42qp-Z6SdDbI3}ssKM7cLzx^-MaA(>0 zPcc8I`S=fw+0xFK$|#69qh2Cpu`ex!HH0tr?S)XRMva;nONz93(V+Tq>gGM7fjr+L zxt}kboh}V7*+W=T#d}Ky4+(akE1m>`_*5Ta<6ELWy0VckzCO%~bNun`dZGeXz9Zzl8%Od{NR-@q#C$i=MT<{xM2d zFy#~AtKxoyh6>aHT#?z3XX-UGQBpF4qKA?~;KKo#qHTxrqw6n<) zCR4;?i8QASy)Vdk_Z$(zwV&Z+URzt&kwBIdH7$yrVOx741eZG$-(F^EKd|-sFAYPmUZhJgE*r zY{oRH#Ezy8#Q^2k+2EG$u5;&G8eHYv7`MZy8y}BT=pufXvW4&I?Zs?S&vJ0-M$udd z@I&-R`oo zvI2A~4Tso$5}aS(^i773dsg+n;?W4961k8?^N{D^Pbd%%Rk>^>cVCIFi5eVaE2|xz zVyxw^`zOTfLEw4pOBED{s>E@tF7&=G)$H;-sad(Hc{F5G5dxGo3s9CnAt(Fj>Iduj zR*}P8v*q68TJ0}hsF&>w$#=MG2shQD#Po0yT^9h34IP6n_AXpKv+NwPuxBCD3BM@< zW%5#;4$in%2QAWEA`j@|c;b@~{>_t<2}!kwy7MdhYE`cD0Ym$mcYiPv*tMFEDM${N z9HOzWlxl$}%i>JqH}>@EjOL#tN!F`ZuO>@gZu@*49v$sX(KoC(Bzpt?gc;Y-aA>jB zc}kq~INuLtsbgVFGp?|kcYOI1y7Z@n{@$TWBtS!brTV(=>jM5ji|ZO1ih=^yBZIg} zF?-}?b+cJCs4(ecIltIcTdfBrsE-vmE`M0z_|O6R4WrQvsp8{>g@wJ9Ne^%@%RpA4 z`DB$OWM^RRuCK2xO_tDuc0q;!RpEz7E9|CWS=QPm*k$2ev7GLFJZ=%+LL>k7*RO_5 z+2ku4laqAnFZ^h5MGH(0Ym}yxpUc1j8A@T*IGfn942tOmFz```M})zfN-)Znp&Gv; z|NIJ*$%#@7TXt8lM=g`}5gN(m@v2~3o*$EL`?F?$0->6!a?B2Q)g-#mW-Q%qf2%NB zITVM$3~RgL3?3#S|Iv^UI~O-anqlHAaPIPs?x}GV+5FvnDkLH@vwG?eM@|T(oVOBk zby-dm;8p3a6@g~%+IRJ?5+pofG_#lARTnvihm~0M{xU+*+Vk6>wNA4&oHcfOH$<0O zx!Cq0K*AG^gM)ZBHa0am?;@Hy6mW@%+Mg!2pvV|FO9NJBg9=cU`;#Z1z_5UNozUD* z-6(v5;?RCfUf*8{@A6y=a=H^?bv8$c2EjBRmRw#=ZM;9J0Uy=Eua-q-(8!``9sk@9 zV^GEfs0s~LB&Bunlv!?fU9wQ1dWxNbC^kE)yEMHmM^4*3rRkBJfa^E03rew6%%`j7 zxnH|>qq%Q&u_MF7cDrx@6z3t`q$=NNMN1vWplYs%gYC$!jtOPzX|i}b3(yrx*Iv1) z1$ZL4SyXns*%Q=)%hSZ@D|A9<(5U$up861M2v`4B-ku*Wq(2#6?^1QxUMtu1x0|Y7 zl=_o*`%3V0{o6YWZQG-dkgoI2JBwWbp#1rh#>3718-Vp2XZ)W)6*IlKC=J`-NR18S zd@arOmpgM}R#sLsGpPt4#>867=A; zVf}acQ(AjNHGr}g>5nm>)FaEXO;bz!vasoP(s$m%zT;=-KK=SSYI|{WacG`o`0!=5 zTmAI7LP;B(uk|RTb5r1}w3gOAhyhD;+4KNnn3Xy3{-y?rU*4Zk`&{h{5cDGdS* zWeA_D0<_dja2GIJBqJHH0*D8JoKeOkX1;QXAZwo`zgGu%zR{mzGRT>6o{g!rGj15& zSH%+i4B&v|Xt5PWg&W3QU1NP=4rIn5wt9_oys5b|rsB1ZaGLsM(4q~O>S7Q4Jo{LS zK+~8E`mqnIRS4`w$GUSuyu6og{`;$wmHow5q)(nc1^HxVlADnc0r*2$#!XbAoHQRV z!+KeN)hWNQ@a=E+X8=owBQol~Cnf*zI$^v$M_H1^3fo8{Y{$^~UU^xPNL#R3r~Uf% zYj~HqHSuXNUw%+DM2Te90nPuX&S+h1feLQ>z#XK;fAv z0fj=}R!u?~q`4 z7qtN<49>hB2z8_Sj9B&ZD!W>1v`yb=`cgFo?& z%4!bYU8p-qKLQ8e3q{e&K(5HUcTCAGq6pIeI!D)p&Tr*H>dh_#HFm6NT`XOdDpQ_+HXpNd0QpwKpb+JD z$@@^@!fw0wp_k0RqK}y{`R)k27jPUg#cQT3Ec|a7YYjyHwf7gqbo6v6nDcxw?|)L( zs{#*`TcEvUu_N4+{P~_{duIoQYyS8jL^ZJlH1e|3u~65=-VooF=6s?IK;2_?mG(&b zrV&3y6jXM$=<`29o~rKfRb+l~;oNGT9~^M9a*?}Iu4Dr9{UhSzWlk*sgSHxO|1a=) zeB@d&l>9$HYiQd4HH7eVZ&)XMJB9eWCCcQDr;qc^^y_xc>%0bEe;$n$+ zq~v~ZyjbsS*(=b;KeQO*$u`b5qQ`yVKj0~z^DnT!k2Pi{u824JGe96Bhbw+9!V$SW${)x_F!nu z3#3Q{{E;;BaS$U`0C7SI{QK+@0!}NY#q-?>m8~a|W6Z4R_=eQ&5f?F27<)fl%Vpo^ z^~G&%Z8=O_7eQ@Hpndo8E5e0S#{C9Jnq?h^ni1HSNg*U-#(`8 z>hc$D^sOCtq2(Rmg2^S(99Gw$lG5ocGX~6@zPpA&tpbPsfvT!%f!2XudnBzGD5sPQO}mKA@-pMN zTs$Dxb9Q<;mFYj?BaOIFb$@XadLG@biZ0X9!q6GvJE6>i+{r`JVb3X{UDH18cJoF7 z-FVGm%QodULwqWyb>AP^Z=T0;1VqsK&`3yptZwWa!lY&7eKg}Ddx*13>tlk`HHlqukKZzr*o_klxhyw*Uk z@&iVNVJ5_ir$D*O`L$dIDdrVudhWuDLZvyWCSy1CqHRZ*^+$21@Ae9u!( zX`9{N`)QIS9z}A`8_rOu8N3?v?O}h%ZtG)BdEp<<|9614G*Ec3nM6pq?(4rAG#h>k zM}f~>^2Lqn)Bap#%F%m@KoO9PRN3F3lBa8d({=fL^Ir8FCj*L8`|FgA{B9K{!cA>}*7efpE|MO(B-=*@pq zR#LqruEC`&oIad#?gM8lw0jK~wLzBiD_CeM942*V%D4sj`C7w?vxKbX&jI6As&u^z zbTnGsSraWFDbhJB%nb-=O<#Z`#IQ%*zoZ%7cN8x<*?G&+<@9%^s^$$W(k?}>JB8Z& zt~g_3#G}#C(K0#h*qyOlWQa>NfCZw!ic6`L_n%0VIeLz)_rxyiO1^DV?V&$|YC#}C zwC{2yZlNIYsL5P;Txjy;kTR-}tarT*ysW5qG0*%`WB={9#*o~2RU2rmp357*R8o3R zpjKtdZWy%gY{nN~aoE({>8) z3{49rGk{eR1=!Lmn0<%N!=k`pW)a|0cefvd<@OB`FUCejMte(!(C(7*->rjthLU)E zteMC>a}$QZG$SKb_{v|yPRI@sxm8y|1oO$`+}Uz&SPX?l52v#l(9hLv*!h$2e}usW zTZi?@Ahd}bWzS-=pQ%+8KoyaY!mu>5c=*CZVrg3vQj>uS&u8mOaw^WQO`W3O^I{O?Y-5uD%71h}B&=cVWAxzCx~R)+S8pQTEkREg30 z>R@hr&X@z1_PiGcHt!F&3jiBXiks%_>)wB_ZLN*ioSmU-sP;ilSEh2__4%5tZpb7A zdOqDPHjQKi38|ZfjTN2ol^dPWwVu!~iK5_kFj(NBHleNj0%*9Ki>PrJEH>ictVo!g z;9+v#yLWeUN&>nGB}lQ4Mb_|})}Ay@%CB;u%jAtajcnb={oy6^@zPE8E-|r*L8pI> z^f~%f6gLB?wrrJA|L=+Gev01!*F@#17iTF}J_mpkEcN`|CpgZov)Zl?+$eQMZLsv!C%gorIxOo9D=>U^-=4 zG!Sovj1ELYl5NwNMFbt;m9m77rB+;S3%qV8*pyR|^920XSK(jkcP4(GF%{71)Pp-k zuw}vt2>dc6YP3kj1>Vn{lusDvS{lgVdvFI!xdJk#>?~i-yJckl*8)T!!vH zX)cb=O-8Z6f}!P3RgvmW`klvd+1x0l6M$ z%ApxhAwcuq0u-nK0wG&#&CbY?pfUNfKfKmtXzJqmatHKf+xu>AzoXgoIbf$r5-Dk4 z8?|{f$}|@gq8cHA2J8v-WGTc?U4H~-2G}TRMyu$ef8_d4R@ey)8PoVzN%OmlkQS;|F7&{u#q2Vv135_#W(^^_ z!*smxGn79B8o1U=Teof_lpl>|y+v!N_G5(DQ_PP)1upNIIR~05i(T~G`#TKu2u17= z{S!lbq){L3<+~6-r3%bi5{Aq}5ie05tY1Tigm4}nkCvtdQ`zmE59Zq8Le->HXlhs0 z0W_~4fXEPC=vRJRtND;eRh6hes~#{X@NIT7xpkCIfRZB#wtz5t`8Y4}nHuhs*RO*% zOG#a}cMsFWeH8vA+#@LoV4!%bhr3zv@51J0b^2*j>`W9XA29{9ug-hvuM%v(2VQ3yIc%}=MieG?r_6X$0XwZT3@?w(6DkHTCazom;3PkG6cHx z-fTO?PoD)b*BgHQLTx5ys_Zx3{N@*1+J<28Nd9wg7T9c{Ds2Nm$8lp(8upxwlikBT za<)&#h%T3+`2WaxD*a;G6xd9jik4>6X;csiT$XJTj#nRA0A}-Q|9NL^3&Hx& zlGtbJHMg?{O`pI)41%TWAQ_A1v$!>Xso22u;7D$uW|t9Cp`xchpMGO?=|7bLCur2) zd1~oc!CAa`sHOi7O~x+|reg8)OJ~Ry-7*&t+2x0*gxvYgc?a z4YBo;9LIz4AhL-$~&53Dt!n5S!E?LCsK1f%=^#mvC3O@+-}M zm3aZviHYXFWg#T=5;T4P{*w?wiPTX4HB$U9nIRe zW{ZVuD}z73mOGv4gIv;Z)thpzbK{_!9dM;-P9D*{qh7rOG z&U%ZU^4M=Azv?@HM*Q@1_M(}Wmk%!CeeD&NNo8P!?xR#V{|bA4oQP&M<&j>>G7x6< zUBqD2p#bg@d))gX7s6vrBW)S0p`LBQkLj^_dAZzoB(ir=T1~gbNepFVk=$E2B@3L! z7(lLg@oI3pbbNvwg7azRBDXbQFa8K+NK^$T>cWoSfWij4qQ6T^s3B9+mui$wT>ddo z0_NGvKRqJCMnf5@?Dk@Rn zklgVdQb8WJ_Q3LTE>%vt`YC~rKTBeWBI23#A3#}^)Ho!Zp^4;%0XzD={Uc};Vl%Bk zxjj>Qgnc+p4xRFQI4MH^ZoUVagn%Oh`=fS-C5)~CucuVpK9!K#)Ke&{Pz%!Ivnb&& z2f+UO(&TkN3|NSv_+#`F`^61)hlo72p7vDME)<~&X$Ax<5XFmw3Wssc)kwuLS7x=D=~pJ|&yo5@ao2RB#wU|? z;XWCe6l|%j3lUzRZTJn$!l$dBjmCfUnFP&RoLB6gl?wp5#GFkHd$B*kWMT!@STMD; zlsn9Wc`Hwh7R+Xh<7{gzUQ@*d*&zJTYkb{~_gy{Gx9R8v4DhJrlF8ZLOmwBcyV!gx z6k1-8H;aL{6wV|Xl+a+pJLeX+0cyX~QG+wR(r{`jMRL9U=+9>w&0M`=&4?>RoEgFe zKQw!@dN!f#3IG26QH8xZsR^t|(&1VR=zW$(4DW#p{wXMT7Tw+Zvxjg#lGS3)jJ++< zy+#d{XLBGyBh=K!eVLqaCG(5zm&xWiKfO8HzEP&CgugxOMcjk~;}__&p`T`@6EJ9e z1i4H?@i)v+j~`Z51HDNa!5C9M0vojDs88c_ClmtlwfpMW1k)5Sst`(UeK_gXEPdjq zd+8bZ3f&p!KH)2nY%Wipa@Nqj|A-|)cY)E-o2ray+vN zD@b|7qf@CzhJPUb_3Y(@iu`b)8z)RGsRz(^LgR#tVvfh|U|d+mZi!G{x9_g2Y9Ob0BJjWgih&03CZuC_Ku)mkdhM%fB2;5bWT%>M zwEVon&RnuLMGOtN2U3vEWy&DA!2kC5*hV0NPPG9RvF@H+)o^5r*!t^T4)tYVp5KN) z!&|Qmqc!CCDSzzY<);Yqwz3_AX2F>KOug_~X{j%!8weu2q2b&HAgTETLH-+;*u;d} ze!T;7Jz5j!#fy)(No!NYNS1pGC@T-hP}D5%-qsIEKM^pG{wWit_QoU^2gs?aMI3cD zN;G76>;dp^yYVMTG>8mEKI8SozTN*B?vdeg^z-734@~lZyVV^)1k1di=k$Q)>^f*e z{+#&cnL&exdVdgsF|9BL2DPf8^KXTYYc{7~=kVdS+d&*8(O7Oyy1^{Bj<{p-4CV6{ zBWz6~9&Nz(1m=OlwBJ09kPo~cC0swi?>)PTu*gl2qB)-d`a zcMX%A%L85ntMg`h6wL$eTJpIp%4(c;&K_jOa|pbV9FX{durvC{zW7WnodAHp9|Rn4 zNtQ32*XCc=X@e@pJF!*(BEo(_nH&)70K%zuun+)=_XN~S7V6TkkwY+d4^;Hq0L+mH zINfkK#E^*Q$A?D$;!wTZF{ooz0)ia{eS&P@vLbSo#6c04Un03DGL@-VZBo7M78FRr zBbLOtLp&G`IzkSM3E^qRJ7~ew4)##*mD$d#WS?)s2?Oq%`+#wQ$Oo-;Bcf@m7HEXW z6ck~Qj$t)D^AKfhJRjK2SgqF{z(BALcudLaZ4#~907&Xy{CY^I zUK0UC7ViD~uU7gQ#%&NE^EO#w6K+7kc6=KDb{ittZSH^&OA<)Xt3Hhf{TUZe0WX{d zZ3$FxsPvZjG32AO)TH#DgyRsl%%?pG=RA$Q0|Un;W~>Hp3~!oPJlFLuR;#pU9W91l zR?8&zW@IFp=L14QQQ?opGSp>w&SwRO|-kdxV3_O zx5hLS@u{KZDtBHNDF#W-6opM1=JwzP_cS9PMayPlmgRxH{qX2W&4CLD&j<_?H&rZL zr;;I2pci_WxOmwRfG2^j>gt|2UG6Kw4ULk7=70-YisH?Y4vl!S2M;7>8fB*H!6+wF zYI`deC>HS3a1~Y-*dC7#pE~JBApyN`RZYsCE=o_wmrgi4^@%$=fOn7p&Y=|3WgJva z_%BVoN4&hBl3S!(3WIvL`wt1p5(*O2x8oNXtB6L2a>rgT-lcDYr-{nFg+uWcx4^&B z_Q;>?jV5#mJ=t7-G*JTB$2)T~gRrRfHh8W{Gj0;BYm!kBp7ik9Tb0m*Cj(Sd7V?q6 zT7@){UB!9wg2EG=XROwpVMoNZUeKcf3z7tqQ}UEc&hX#sZdSZAx0T3WyH14;ISo0_ zo{~8^JJ|rn=~dGzijq0G?p;G=*HMLFE%&BQcQEc0IgYF#RSrGdSP9P;U$%!m_fABh zu`bfh%*s$P~B|LS6Cd*gAEoHyIJPiYm?S_c5;oPe3yzLVWPS+&nP(Gdgg0 z+kmElMi8_J{>a3m(a9Q{pcJvtzhTekiH98Ft1A}?)m}2ksv3Oy^l5v`U!Z@yd{t^A zZe-RCxdN>og=9?FTw5qn8dvIDF*y9kow`ExHpi<)fpeNX4gEA#li+E#`PnDI)7x_< zg5CK`YYe5_r^L9^wCOF$8o4~@A!pnjK5pwhit9V`Nv(>SmP@TxXsAdR!23~HJq%tr zZMH*4jhsZqfv0N|s}wIcL#vBZWg56<4&R1s@yv5AGHb{j`pqkVwTg%Q(#+Q#s!=-K z+1jCUDopva!C3-Yp|itEl3FmIfeg-H!_A!w>eZ8zG^g>LMB{$aur1{ggr+IpmaRrk481BY{TIT^g`+Y zptI5^w#KORLID1su(5@~EBp1~@wZ=Iw}tL#p@GfpDUA0iHd09hZ7eF88)SF|*8ASq zsuK(#F%rC8eUKFe;~xdVwzdpNF<9S%1~=Bq{XkdH@J=_)e;EZkEi$SF?$*5eLUiB+ zX+Efc%mY*9Hz1(}<4KBBsI!G7n~w9CGfqV{pgt%YAEbH8K0=V86jPAqNkR&f0qR`N z;Ft;#urRkaaCoX1Xu4gB2;J<@nkZtcF7|hbSVEcDAW7`QnT<48)%mu``&z1UYrO_g0-$1W*VjM8CX3SE z0Ou=or|#d=QV}68Bqk&j+pPI)41m6w3P&^ix?f~&Z_bbfq^;kn1KAj~6W@U%ctIi6 z33D}-%Jk&3Uoq8`o@1PgMc$<+6mVv`xZ<%kxr>~>-3>;WOenQA@!ES@nM0HL)>;9f zf#MJ4y@s8*hkf(AN!}IP4?}S@v);J(2pW@~w&;$_-TJ+WoGvz- z@ce_gdktbwbtR%XI4AAS_-!$BR5^5x{?{ILM44 zOpE8W!xI<3bC=xje7R!V%Jz*!c`xPC{;C!k?^fMta||4CX{fQum!~%YPyA7W09`dq z)-&qO=YVwqiJ^WCR=gvJUhoFN)%F3E1GN^ep#X{{B4POk0|1L0-MOR^xLd*qZI%zk z@daa%T<()Wu1gci=uqfR!yp*=MI1DqF(H|}coyUr8)ej9!^}{m$1oD$AeZ>X^&QH* z={)eZcyqjksjIm;ri69@H5V6j(gbOWup(eCYG0u`wp`dh)=OvH<&E%MLj}~Qs3r&+ z@cg2ZCXhCuGOi0|)1f{^eL_f(M_U3|g*K;P8v>n%2Ur$*tHo7eMO(ohk|q^|cvkig zAT2O%&HeYomnhHw&8GMw_UwO{^8dGgQi`#j4-^a44Q<6USrt-JQH?Ep5Q5D>N8uS9 z{OHr?t4;@d1!5n5b5SP}%OyH+FV5NMuGrkQooriN)P1oz>7~pPxfar_k!kltRhGLP z=f1JXJ1r({?IcehQG!a$`^km*Oc0*?Rj8CBDpq)>b@lP%R~{nD$ZoD~&8gOmwOoQ^KzPmj{snKSI|M_)%yKXN;aE&m({0UO3@rZxV>G0pDsHox+8t?g>e042;^7M(o z($i)7oNTx&RWpJK@SucrdQo@hFsY~Vur0%*e|$V63-_49wRQJ3T*n%Je|Zvo5BvZA zX1L94UxqBIBoPw2uzB#mnWz;1_dn4|s(&m<5yN}!vG;1O!>FMk)_2&B|J%)KK>&dG zZ8#Ks+hSAcy76M?-~F!^fTpl;dy_ehL9{Vr!-7w%&`wn3_2}l?DAV&Nn39d_0R3AGVCae8X38R0HJ0;-}cxYBiU{9to-5BHhr8Rja3G)rTcf7UJ z6B?oiV&5%HdyJOP_|J+KiO?{lyk#Gy<16@isa?6T$ywN25#yDawca_EUH6`X2Cpxr zoG*;qfFPIVMIIW*B!|WCI=p6VJk3C5S?kg-<9G10h?{ohf0%}-%-wnZIi$7gyIac; z4k77^=P2rfH{gRO)V}Nd$#>kmu5U&CyC>Xl2ts%`xSXjV(nDhJL&Lb7p$MZK!w*n?WjF1r$wow=kg|+eHzxcoyA?*i)>7Dof90tLqp=$DYM<;eCVyh)m-iG57Jc1@2eflD_QYd8 zw6!W#Tv}F@tK}PM@f8LH`)1RQL{u9$_KGof(W$cN6O7gELPS5MSCZ@BR!mn5iGkP* z#y@QJNs+gLFsWQ#dJGRe#^-XjH*r>w1LS%->E@gBY8^*9(QCrijxrP&Z0@647XsUT zQB+6HmBEaa)Ga-t6rVEkC-7Hm6#*$T7=ZY!X+JPay?A{oO zqq!mT2K=O^oMm6atHrJrKl%2eA^+VohwJTlKgB|LFB?8c9`%u#`OVaABZjSvXhgeB z)7(DG1nR0{(@FHK02bf4`|etbyr0j^g0suMR72HnVL9dQspX2!H4Yw!HA?k@zUGlE zdlr{ywL5)3zdu3C8y2K_>p#0MBu<5=YR;%1)>gb7Mkws$a?Q!N9>RHbl}1d;3hFHv zKThBFuBUA93d+9ND^jP#uvf!$?6HqO^hYx{dZ-biw|m$oR{o=eMm>X@U*n2z8kfyB z8qZyN?V%8PArT+6dts?xk{$ZlBuhzE!p!aP+P;`_EDc_Ex2UT>QnYtGv2sk~Riby0 zqJ45p|L9|}P~c5#j7GG!%HVxlq$~xJ^Hj>SIk(J(A?_2GMNf`z!N{$0tLVG(Yu7}N znT_p;_#FE`EetOH!W^Yn&cW@A=i>#bB9VDnWrC!9%8oOcQUL`*)J* zYt{5MdM(yp^@a zUG-@l1K(!(#P?cD2VU;7qx)Vb-s@kvDavlbWH-`oJ*B2*T-O!W?p%bRx6whdIqh#r zo70YEqnSz+^I2E%x@H3^P1d}2llruWyT%0X1;yQZO4S^wZI$|FqnPmZ(FrXUmzx%r zZY_B*)v-XUhOtV}fM2?`?cwdx+}Mu%S8lC|oRLLYlwwBacbeu6vdgjYTbR@p`{s1V z5o%Y?YRV4I0C6?~yMi*ApTBnlhcc_9{w$-LC?QRWHq0F^ z&pUB~qt%HQi?rwcAIuAsAs9Jwq9wb(o1z_^=*_^VR}B=*llFZX=R|+|z?;PCLfolB z5btu>$09D8wi5egYFfUj*~xn|ty%}TKLN8=dPCLO&T+{=ax9kYeBrO1^8 zXK%2FO3`5#V@?RF6ufzsaCnckLW!O?V#C$0p3j zv{ZNv-?PrS`2y(F*t1QG%8D8`-V**OAh;zmZp zq9>ZA7olc-kZ_>35#%Nibwbd(Go#r{>a?RGxJ%wR&%M@}T-v*$e3iv! zr+?)1ZDFW{$R2OJlh5!KZ{zFlCFp9vv`P zy(tSgr+&?4%Y7hamNZ`Dz_VY&X0h`G7T(!j2i?U;S-^s%hD1>z8O8P8#pZzlFCgI> zT`pHjv<^0;N3Msba5U{>n!(6x)L&HV-6~^tp=FIF*yZRk=wY zYl2iNgmC)NaN7Oc)*iGfcW*ndUK}5) zPc_o1A9G$ryEzp#WciY9g2e!@;n#}YW!j6){QNBn^sc!SF$qwn$hii#A_j7tPme=9 zlNb8BI;V7fW(AIgmfv@AYLb=Uin$T8Jc2Eg1hIL#8PXck^!a7&@MJ=Di(ozKp_9!{e12djcY&srIsUI=(}>R);%r-wh*C0_oBP6I@$T zm_Lsc8DFWqRImH}s=5s)_;>^1T5cFUJARv=*znZj zl64lYuHkSeMgj#6!UDdKjT>QAPVOn%(`Q}6ZE9B#tozQyISdLnFv*0eEEp%3$Dh}4 zlc|sC6pbA(oRZ^`*f`iEpT=6`J8!?gyQ$XQem&Iq9a5!=P2By`mj<_{#)MSET*lTJw47R?W&}VV?+IoPm`Kl1!mb7a*ktm6$7bW zXjJ^ZQ=BF6t=CJV?#=Yietp031Vg)n-g=?Ms5EZ`n9SRDN^FfL{7pTSXGm!QrUl*4 zLZopmNd2O(EplWl#tRtwPs7bLRbvkY2d-|(aTz0g$T?L9?^q1ud!57DJ180_eyqf@7?&|`*y(4>VfGL0 z>Xp6A4C2#LI-QQu@~ZcF-0n5}u7?AnYZFz$k|qYb(=Md5CClH}lnGhB`Y+!1gp}XB=21fTZ?@jh3LV{8}8%rZmM_%CbMUbPL1Kz4tF{7q8q+goTQFU$@Xe^ z-+9AYK9ce7(X<*<*8HTi{9C*&bn`^jM?({zQ%|>F4;bF;B&xG0!b96y{2>ov4Sh57 zp4BM~3<~Zf``1I$&!yHy)=}!VDYt!QToJeWu&D)^N-Gx*^T~Sn5Sc2YS7?RT4Ya%S zp5D5Hm8>}R*!5xn`+csGhXuyI)!bOpswkW5ykyI4x~73{(MS|KLLCL zH|}s7!=krP7~MVkfJeOo@e5`n60onyffXuYty2&<`Nly_7&&3CyEv`ypE%@|>33>5x3}QfQgpnSUT;(FxH|94D__W* z%h0A;mSQ?R)?kNB-O&-bWZ%jnx3sgHpFpa%xYQaV?conHo6a>}TSSE+S=1Z_*K(Ss zc2p+rtojQq56;_h7n?h4+Bre_h1U~Z2cgKu7a|U$wF8k`Uv3&m5_%vEGy%PRU7bb> zOx*&ahjSkOr@uZGyOE{lwCCwr|MdmBIhnNU<275EEN4nIFs75MM(U|e@hSXZ z5(qr`2C?^jd;8|DJ53Itt^NXsaJE`?f(jPw8zWIWW4xj~kd1?(9Uv%acy0754SULjj32lSPH%udI5Ac2A3EGF40fXQqx}B+jm{w=vGv z+Fz@|*q)n6vprKPc9DN}+X;JfJNE8_!Xcz@*dLU2SI zu}7@6n&&O8wLN|dbhbWR2)gTkXFVEFC27e|MI9J~1~cHI(|=a2 zMG2z)O&kfTspg&yZHpy-oD|4N^$|i;`?6(7y)U;|i8iD(9%OXb6e2dHbpmurH zv4CYXQgubObaOgB0sV#Z*#oc`17I9|@mYjr9_bXgi=vBHgyo*8f?4~|pE=BSktu1P z!s)4XwCq2^f-zsmG>yv}PQ8tFh;AGRrD-WP~CQrA-AKB|q{3T9u6*$2kpTM1LCS$XuL$5ulzt09rxdi;5{DKY61K{h_ENss? zl5j$OfsAdrD`2~N5sHWx4{{hS)Y{ghxgeo2v-!47%2(-?Y={gVU}U_c9q{bEp2g#Q zmR@X%_l_zO6e7`wqp zInAYFbL9!!!zF4@^bU3@n+={8|t+bsZHAQ4N*!zRErH{95-pPGuS2;jL# z818(BOKh~mk}riv%JJUA&>dln4G#JoM}G2byl26z>kEMfw^}7ip7$`V9#SghD75Gf zjyJ(&B-sZn;>6*Sr611yYU+U5*Y+z1+gmqtF?@nqpH_Z;KB)Eyml{JffjNPo)jfwqo3L>w&uCJ3M-MH@r=djGeX0Jl_tFnnmC;Fo;br_J*>u~`5eM`7Skm%b^0@v zqah3c*Y)Z4@zUcY?QLhKpd5PTF&ztG=UNpZQ_{;+z2r{Z#0$!jlRlT zx7~>#5XEm_R2F0nx^J0_LST6N5;-n5!@9l8C$13~K>S$o_UJgmsjO0FJDNH}@$}fS zme$9C;i(B8;*2$YBIB7;ndC8Pg2@eem6xCIZnYsTSNX+#Uo&lV3~My(6@Hl3vo|{m zEfGh|cl0>JOwLy^r7P|Ge~H^_YQ`W#G|hNtcla^bB1z0?)SkTHJv*>SGmcTKa1GFH zk!}*V0r8IYLYbSS^Km=7DAR4rv&OE~LAC9%bLiqG*$LJU7FPQmFO)}ZH`dDxBK)5= z><4=bDJvs}L))8VOW&VO)I4zIr4M6Rldk`M$yW7VO>KVOyTr=QE@><_4_ewGToMb| zICt@~%Vv*}L|MmE+|g7DtLq;hgTAin;)7s<(~1@NRi}qPKQ|}($j`?U%4i|=bI4*{ z=`kDJeLO$PSMTmvPRp9kc7JOUXw%=@WXl!Eg*gX*PD3rqU|zR65Aug)ebv##cx%>0 zM?AzUbkmlx8;^wZS66H~)gBTYZC7@x=Ev0}Vu{C#3H ztldA;3osLy&8|7qKdig{!c3{$oz=2SC&(A+CSm-8(7e(UpURwbs?xvd{!&`$CL*en zmT@S#g~x1rZwnPEcy_d#&69>yq60JCXP}^D3mvtuo}Gi1>hDrPXd8pgK@}zMX>H5# zetHrthv}7-_Mhy;NBL6|i}7jitw-Z{NnStA-5DAb%N}D6_~DeOy;;B>CAK!Ty1XD* zP=#C+H0R5ImXmd>@n9*4h|?=!Vzj_{qV_%FLixm%yPvs{kr_51QNKvdxosB8)&xFU zjRZ2!NlG`_s_N=|CAvNGJ-%5gsoF(Xp>H!QSFi893?2QwNm}O9G`1<8?r>tocXR`` zLJ|QhDvfs$yL^6S4F!>yvpe$1e#^&p$dY|CD!%xtkOFXFEQKl#dP#lqz-R$WV4a#HT9sqHAcD z$L#|yxtcnl@Vxpl5;C~V-DU7-;x2QqEPDvH7)>mrySlOb$+jZpcfOPasnL;99Wqme z)3>Cv;s5FFETgL2zP1k-sDOxcs~{+il(Y&+gMf60q=2x2O=E(9bVze( zknS#N5Rj5iNr_E|)H}E5oHxdJ-tl~S#(#g3fowMGzVEf>yykCSv*V?a7t0R{nn7;k zC4_ppPvOuj7I~)0)96HU5i=54{ z=BVMI_RhBR#9SEy$mLer{I*+$Q&x^gIeHT6+qXp-(=xw7HUL#;ilNnVI8kKZzi&m& zz8~SQxO1P_*x#hLPjzbwQCQVCQLh zC%0B@fAHhPy?Gc83G@{z&|-S+d+0%Rx!GZ+^e3`o9I*9V44cxm*zT{jb@hTP9-^c~ z#2R;=uyaFNuG(}{uX+S5#0ncTxsZ5c1r~0}n2f1wzim4F99c9A11BoqI%go5r%+RG z;MtoV;0{YQx!V5it>#bga%Gx!Kc~|!M>TS=tW9i6`fZc%c9Wf)xG$eAQs!tChlrA< zt%qNPjNPW4?X_>?wy?;^I{D8hc`sMyh}gA)$%{#gjEB!I1|>4|el;rmUSb!2%#<<2 z%x?F4m%nPCssYCNfDxwRcdixH)h8(o7dUi63dPeScdy;lhm<^3@qt2SP zutvh2lV3_t{TjL1<+b5F1c7q!caHrv;pVb+w@O#msC`>*`2td%*Ir*$9p2f#=kV;u z<+YxSFfjK?P4Mu}Hs(w@8EN-I^nQOw!q>K`<8Qe6=2U>%x^cd2nkI7f#aNaR{u1T* z3z-QWYrbY~4Rhz#YAXukuO@Vau`CvDvM&9D{BaK*y@ijja~Xs4pf7q5cqxhMi|o2b3C^9lg(#Opm57@E8*dBohNEl>KFd!cLKk_D)_UV!O8fLRFQ>sprJi!h2)VlQF8`)%x*Ayr@Zw{wl2BVZwHu`vQeNequvD*O|#- zaGlojgA1L(nD-mfZjd^~$xL;=?fFq7t!rfT@}$yPHMuQ_MzjS;FbJSGJR%UkcKNX` zTxfSg1ZB$fhG&?S?{D?H^Uc$-kl@t!>i0m9AV5>@nJId_?N(&g+c`*EpQO;;i9Uop zf6vPLk+L?lUGSbpOfre6B*1Y|Y;;DCzAM?*^$kI2snN)0()SQdXwSTNCnXuZG-$t= z#J1~6i#QRPnz?sUygk3Rs&Z}a>?J`k@GYL#Pk@J6CDTAJrslanV`qfPRzJ_dnNL`C z5#{CVPvh3P0jJ(SkLYC?uD6k!Z`F`Ds_$o?P$1su8?$jVI{EhOQ<_wc5>gm`9aa-m(or8TxC)VnEWxB;(0Riu^fUzxQf3~YW^=)>uUtc6Ar`-2K+%*Sr z`?uF1Ys)baj0$`QjPwInXRp9DtsYS8M?gp#@T7R!c;W(c6wQh2M533+vvGh{n;$(F z?peD}w{a@gNtdP5H#Xm+hV?o_hS#ZvHazW$=7S}>nkmnF9v75fuYlQ;bBnk1egU{D z1%|fZ{9IXiQyoj0&zr3X;XA7OguR|TpvA~=e~wQ6 z-H)iJw+qjz5AuTb@_YCZ^E%VDTb6XK9-_e+%;71JE`#)oZS;~?Ek_U4z64VvYo6_C zLchh6>4WO#aW#fCg()4ftS3h!waPfe?M+C1kNGH>NM%~jZ9Ga|>!l3Z%LL)VtHQ&w z{rcW`QkZA_Yb^mEu@57O3dh5_LFoA)tInvAb2~3<;G7=91|i*~36RKNG)L)cz?_t> z^QiV8jtGkrWqEOCB>=$vkN?7-wCmE7*^y4UxWcu$k= zx!&d3M9!1!AQ&h(8&QTrAD!6OX%-Ukv{%lR_#%6beai)FTg~)88I0wWjLzs9br(AG zyGr}tZ0af-`S3a!7w1Aww5Bb6?dX^V%dXv3gY)j$8c9~0ZzZn9jdPEqLOk^)K&yQ3 z!#E+plm|Jb!}$!3W$iQH3)-JKtminuD4!5@ZfWn}wSxzF*wek=xmkUG@vzrTgoq?w zhaLqi_a6t;7(dR6qtRc(qm!e-5q$s_e#4Sthe*V4yzKB#wrxqyli7Jr%BCD4#! z3`DvzlM-))3kSEdPCF^D)8~%qYMu1lRnN_sp6i&~!+dCG!&uL@(p8;*;vH+XcEv}N zS=4NL%g2kmqrnr^4+?{yh$jl6cy~`Yv)(a-G++LK{3li?iOC((+2w8tvnJ@jeX!d#$gq16c>h& zN>%jFk^OhFh2yjv1fn1~{2Zu56_`!m7CE7JELRJaj5U1JRP9i4ZdS`eAf4oM=T^YS zvdvyYMIGU_wTCul2UjV(6RQqRj9xOxmW@W2bb1>Ph!foIFW3wjO61+Ad|o@Mq7`R; zc_iPi$HtJ)CXQ35!iem>(QSVVMrNnZSc3U_^5!W^<=g3vq-vsp35Dbo$J zyOho-oVUKI&EAs;DohI z^_rZH#ZoHbNAiu1S7jO#qm~s)eV_hH77o2>O01p`Nq>^{WnGREn00kBv?OibOQugzcwD`}=KG5^L?q((5v*Mtn;`jKl_ zR<=!C)vwk#Rwwu#wC+uwRI6+M^^yKAa$Tk;?`=CBDv9b}XLNj#OMl!*@7$Rqy7n(S zcAw~9qEY4E-=^FI1R2l%_1{rQdi_tMXWSD^v~@4M9!gYQPE`sC(O~g=BVkjh#Ud{8 zG+pz|5^?8h+KXzHSVCzjAlg>gb79kvnSRa9ghfjFd6z|b{>|dtFPZ1h#bXxoc^N~W zX_ZxHW?s?J9a$i=U`YpTa^f{)V=T<=Ar-rUBI$?hzm%m(GTy9WDJL!}B^Y;Gm zJr!#OdK$&kAHJ#8C3UTG@+%a<-WT=TjCfulk&3-W5;Rg98#ZK-BTgY|gYe$)wxl=R zsr@Ca73N8hNIsU|xrEZ{D|P|V=wDVkZmlDLyo{35tEj9_GwZv9PlUurJ~(nltW1!v zIcdj4r0_D@YrB>Rmhy*;?`kuKp7m!>rZF^$W=2I%eW-GA4&~9lzLx%2+?k$}vv1_( z{%)SPR8^5yZbe1a%cKDY!@*mzzQ9))6ml09j!_r zjo?&L5|@y;K~A8sS<0-C^$wQPlIFb=+Cv*@dWcQTHBkMG4_~p!wCl|z_s1(i^b8CX zvE2z%LpP+=)v_w`OflzdOFT>0kvCd70hv)gwfQt$8o%dUGtnVnW2BHrZW5t%^bVM9Lo64O(4}ipb$(hBC5Yr_z{9+lkan{Z?)i2{RcoupDpa z`cgE*h%v_}?k`b)|85L?i$|6*42=QWgi8BfzBI^s%(FH^(cuCKL$+V|w@Ld8ywPYs zeBNi5QwB|ic%cfKe%R}j2M!4mRWeK$xLH$B$GYYtbMnw?7M;F;{y6RL#QZ6I+jS#Y zb%na$DZOUFjJ7y5~?30F>>hU(XC;*jdjNS=nR6Bq^VK7z7}%>T`(y4?fO@8eT9 z<T!%_&v-p)1m9n!6J?a#cf+T_Yx+xU)%2v) z+>ee-o;mu|eR)eko8CsMDT&omtfOd)9a z5hljpkf)>7F1LM{6nzc*BcyQVRBpZfvy&E{dZ9R&zZl=F$3k_^M|I*--IFIxFbWo?PDQwEj9$Z~ z;Ee>i$8VDDezc6J+Nb>b!`EOJ(cDESr6kgUt^prz`LJKzJTUH_j@2mqMZ1}7Hi3HIC)7Dn;vil%FJioT5 zeDp!RPpVE>U0Hby8Myh5ma*ik;#VD(zxQc7BTEq~wRv#QaN2z{FfuaA94;Y*?#BS6 z5Qi0pwVu^i=mk@$T|3_EZOwiDW$T(*&(wH80w`TA!;FNzYPK8g#)B32(fk*5SH|D+ zNKA;g=o8pd!iBgNF(Fj(0=(6sXS;1nph1)i4XV^!>Ovi!-{R)}bmXtjuXoPvLLz#) zc{jh*yrDvRfZyTpx|<#7Z|!1Gl1dfPEdE}iuP?-Px309ymXu|!f+}IT@Lu)@|GN_$ zH%AX!K0dgj5mRLxjkDMrke!VK{dgY_&W5ZSb!tiC{O+dZ7Zkku`t{~HWmi*&4IjCv z#pNB+T>EdQEUL*@aLj_1+B%A1xGfc6Pgi@gRZsb0F8l`B6g86Vi{XTgk6q$)K62V7 z0BYMYwNtE*p^5>HiQevlY(t&0){;SqRZ9rK)Ot%-8?R!GHM_q3oOcpS(JR`8AWk&t zu9Dvh)MO!Xts4kL+wT{qPSu0i&=OlZ=ta&&I`{vaxIvk?f-4)covqQzm_6{J%ht$k~}EQqGL*GLR1)zljI6Je4E3pO}>L9FOpw$2nj{?y3IDkY0H}oEV-p|L_)SN~>EV6Q`5lVF1mtO3p>I%{Q zLlXu38m`E%kAJ8?vG{8Bd~S4y)FovAyTk+ikm@!7DV5~NrN*A{6{r`x)Lz)+V9(n5 znaSQx9*!5=-8z!!nPQ(CnN`N2Yy?^zJD5p9i?v3%r)*KLY&Y-nYM5{S<+|P;Jg)+; zRini-0YA`^RvzjlxmyIT>q!T$y+K1zXf_4_Dkw*S^ltaNfdX{e{*WoaYG_a;FHZed zsK#qU>p!1A9Us#g7;?C-N-I(H>rD^sw@btrmZD}A< z$&!r2#DIMpthlnT*P4&kVWXcpo93lJe^Yo^O%t^b!tE`G}T$1+xcif@lFpEA#&1sAmisR8%^-ZC?sn z=Ijp53Y73KLrq9dwo)IibrEd2D*f!Cl+Wc)b+NxRyR_Pro?ET#pl4b77#K{F9&*KJ z`;V#|&coAlrwm8G)JF^LGc$#=ueW!>vZLzGqRv(CwZV8sa{hhNm%Q4^j>mALRXJI< ze5&*}A4(#f4oZ-NZL>X=(d=zWN~`>=>n2{^(Y6>#H+e4ziC>2qRg#aqKYZ93+T05F z%prq4#a|s7GHkjd*WEM<4)cjlsl&3>_GB>N=|H!4;g{nIn((C@!AD;k_j<3eu7$RS z(BidifFE$qSc2Y9Q3+VJfdV~8reW6zcrdXFtWb}IgoT!mJxQMi#QwT+8S45?KBsj~ z^QV)`iR2>lbm+SQL?ep>SCzL#X6UmB)C98E&@uX~!a$_xMHg1{{!}=VW;oIn&!nk- z9232#0De2WT&MyQ6sAJF03tF6UIw(YqrAkeci;sFLU(?NOAx5ZV9=%A^(NO}WhMV! z&y8{)?v1a!<$zZGBkN;%U;ibRbyFf!H|0U8Rr7`}1#kethCdItuKUxbwFK+xPmd&> z4ChZvl?Va6(zY74Oa>ybN-3Vx%K<8NQqnPpqu{8h5ex(vO~GZ4%8S?9a&0@HUW!SV z23l)_?BkQQ?ga0>FI)zjQco457M;(B$-Nk2&S0Y0p!s)iy~#0^`ko#4trfT3<4xAO zqccWWr_fucfPsC7C)?H0w)dpP%dmLVd{0Kqe(75B_;KQNq27JNLM|56F0M-(@g`&kmFC{EPs=?B?#5jwXwPDX~GDkwB;X z`ZbMR^S=He_rY`Ro>om49$_8)Ks<2|55oOxk#Kz_5UqlG=K?36DQ*<|pBn%$s z_nN&~>>1=0)^1bI^{V|I8WmNK{b9U_@`sKxW(Wv<_Rei&ouZK{xAbkCtShJ=wKb0% zTJK|tkRR%PnP*4G24Psrj1Qd;$!bN9yjO>9zn3DIuaSQ9&$nd&Kt%b(ckF%-N-ZO7 z=%ye(v*a^_qB28^fiylG(?H|idK_P0-&xmJS7>*S{Q!#m^qDQo|Ha2i)31}=tW%Nr z+pj*3XG9MMYYlwT-CgdLUhZ-fgpvaepE&ctd4YjC_< zW|j)Ys8AWEl)F3K%|#Jj1L?9T`d)d3<7=A-O*Z9-*|`P!firbTUl8XytuPZ#qkK)> zQZ+yP)~!n#Tf?qsZ5eh;hFc9m5N{npjpaTYN}(sNw!y8ozL{J8Nz+&USIhU3lC+5A zVeXJp#_K`f|6PJ**K1@9*BZCl>b}}bEph0q%X@Z;N&;3?gjQ0t>nX?g);U7OGUb1Mh#gJX!2 zy5p$??Bk3it~F~nH*???nQjGr-pJa1(GJ0E4(8bb@uw$i5@!HAff^p|j5;>kZ)s6I z5T-xH1BjkkJ)hHlnUUyQBIB009oEd?%XisowtqdUn+QxQD|dEvotfQ;Os>ID%MHlY zen+Y=^{l)ZSTWz^^Q#|aN!Z09BLTPgW9qKa(j^S8MV31Z4Bq+PLG{Ma5kL?!7-~rO zfpXS~fxY(4Y{=o3fTG(#iSwLx4%I}3Z}dBnHaQ2&6kh`Bh>dXv_4JHc|7QzbQ2(S>e{5N(aYePF9z&{$>4XzBg;c)u(^{fymM)J;*8j|TlX6T z7%ID(yf$NvU+-ogEuZpjZSNZF{FsF8FbFy29$)UZi)4|zJcB|>f+yit@8`zm{wyU$8hmaHhR449)Pajk&%4te12B5!?gI zz>B(iaK8snmzj-4KQB{J3ZBfzkQr!}d*Z-S$tR~Cw#vr^!gcFe*GoF3ls`gtDNLPi z;?$kwK#`w7niXpPNiy-n%l#X~mUYiUz{1s#?A1!YDwqb#pFgJ4EM?dmH_*^{7@+6j zKP4=%<&-fDh1c2nm11D=gHe)-bs4>AKUJ_U5cm1fy*%3O112IcQ8nBdAhe7QC#t$Yv%(8wf z)K?s_4V(`dTx$&P+IEuIEAEb*?NLVUZ)KFL-*LIPxAr3tj-Z93s@%C+{me%+5c$d! z4_BknP{yH+zED;-wLn@K&CNuetiDA{p>r09@h;Dt2GtvN+U_W)SYG!wd}VoVi2=o{ z*qjfq#W&Qo%KnyeAXRw2(c3C7cu$9e-NV&s(YNUCeXWP0XppQuDRFanEa0S=)3MC; z&xito%CJv@Ch8kqP%rD>$gP8ZmN@m8x{nz?*pRv`9vpR%iP}}|UnlmN34YeLqhPK5 zJ<~IQn|alB^OQ9Yrf|XmjTbz9xzhYf*-yU)xtm4bh;7_|oT+!rL znq{!H&0`Vyw>;v^ZK5u|!F1<=Uzx6JF;JowKMpN+{Dq~=_4k`jSMWIf1vPyR0n?!VBp zNn8Ku*^bp<3KTLgJN%lP{!oA<`%QJVn=1+P_9J^FvZBuA-ngo;X$P3jLHwb8? z<>a_|V})z8Z-?dqSjm>h=ImTy%qhpF`%w0|xN}u_E-zycliA<5W{e6}zqUIU_RPkt zZ)_|!o6WD<5Fc&1=S1*_ia&i%=)Uf!^6M}7ff($hNpyA}&(HHu6(L0OGw(e(4biXv jrl9bjR+s;)lEe|%}t6-1dQ4a?S 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∾Q0`i1BangHeF!#GtV8dsX@L-K) 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 D!Cop) diff --git a/e2e/cypress/e2e/instance/settings/notifications.cy.ts b/e2e/cypress/e2e/instance/settings/notifications.cy.ts index 4e6856dcac..24ac3488c6 100644 --- a/e2e/cypress/e2e/instance/settings/notifications.cy.ts +++ b/e2e/cypress/e2e/instance/settings/notifications.cy.ts @@ -17,27 +17,118 @@ describe('instance notifications', () => { describe('smtp settings', () => { it(`should show SMTP provider settings`, () => { cy.visit(smtpPath); - cy.contains('SMTP Settings'); + cy.contains('SMTP Provider'); }); - it(`should add SMTP provider settings`, () => { + it(`should add Mailgun SMTP provider settings`, () => { + let rowSelector = `a:contains('Mailgun')`; cy.visit(smtpPath); - cy.get('[formcontrolname="senderAddress"]').clear().type('sender@example.com'); - cy.get('[formcontrolname="senderName"]').clear().type('Zitadel'); - cy.get('[formcontrolname="hostAndPort"]').clear().type('smtp.mailtrap.io:2525'); + cy.get(rowSelector).click(); + cy.get('[formcontrolname="hostAndPort"]').should('have.value', 'smtp.mailgun.org:587'); cy.get('[formcontrolname="user"]').clear().type('user@example.com'); - cy.get('[data-e2e="save-smtp-settings-button"]').click(); + cy.get('[formcontrolname="password"]').clear().type('password'); + cy.get('[data-e2e="continue-button"]').click(); + cy.get('[formcontrolname="senderAddress"]').clear().type('sender1@example.com'); + cy.get('[formcontrolname="senderName"]').clear().type('Test1'); + cy.get('[formcontrolname="replyToAddress"]').clear().type('replyto1@example.com'); + cy.get('[data-e2e="create-button"]').click(); cy.shouldConfirmSuccess(); - cy.get('[formcontrolname="senderAddress"]').should('have.value', 'sender@example.com'); - cy.get('[formcontrolname="senderName"]').should('have.value', 'Zitadel'); - cy.get('[formcontrolname="hostAndPort"]').should('have.value', 'smtp.mailtrap.io:2525'); - cy.get('[formcontrolname="user"]').should('have.value', 'user@example.com'); + cy.get('tr').contains('mailgun'); + cy.get('tr').contains('smtp.mailgun.org:587'); + cy.get('tr').contains('sender1@example.com'); }); - it(`should add SMTP provider password`, () => { + it(`should change Mailgun SMTP provider settings`, () => { + let rowSelector = `tr:contains('mailgun')`; cy.visit(smtpPath); - cy.get('[data-e2e="add-smtp-password-button"]').click(); - cy.get('[data-e2e="notification-setting-password"]').clear().type('dummy@example.com'); - cy.get('[data-e2e="save-notification-setting-password-button"]').click(); + cy.get(rowSelector).click(); + cy.get('[formcontrolname="hostAndPort"]').should('have.value', 'smtp.mailgun.org:587'); + cy.get('[formcontrolname="user"]').should('have.value', 'user@example.com'); + cy.get('[formcontrolname="user"]').clear().type('change@example.com'); + cy.get('[data-e2e="continue-button"]').click(); + cy.get('[formcontrolname="senderAddress"]').should('have.value', 'sender1@example.com'); + cy.get('[formcontrolname="senderName"]').should('have.value', 'Test1'); + cy.get('[formcontrolname="replyToAddress"]').should('have.value', 'replyto1@example.com'); + cy.get('[formcontrolname="senderAddress"]').clear().type('senderchange1@example.com'); + cy.get('[formcontrolname="senderName"]').clear().type('Change1'); + cy.get('[data-e2e="create-button"]').click(); cy.shouldConfirmSuccess(); + rowSelector = `tr:contains('mailgun')`; + cy.get(rowSelector).contains('mailgun'); + cy.get(rowSelector).contains('smtp.mailgun.org:587'); + cy.get(rowSelector).contains('senderchange1@example.com'); + }); + it(`should activate Mailgun SMTP provider settings`, () => { + let rowSelector = `tr:contains('smtp.mailgun.org:587')`; + cy.visit(smtpPath); + cy.get(rowSelector).find('[data-e2e="activate-provider-button"]').click({ force: true }); + cy.get('[data-e2e="confirm-dialog-button"]').click(); + cy.shouldConfirmSuccess(); + rowSelector = `tr:contains('smtp.mailgun.org:587')`; + cy.get(rowSelector).find('[data-e2e="active-provider"]'); + cy.get(rowSelector).contains('mailgun'); + cy.get(rowSelector).contains('smtp.mailgun.org:587'); + cy.get(rowSelector).contains('senderchange1@example.com'); + }); + it(`should add Mailjet SMTP provider settings`, () => { + let rowSelector = `a:contains('Mailjet')`; + cy.visit(smtpPath); + cy.get(rowSelector).click(); + cy.get('[formcontrolname="hostAndPort"]').should('have.value', 'in-v3.mailjet.com:587'); + cy.get('[formcontrolname="user"]').clear().type('user@example.com'); + cy.get('[formcontrolname="password"]').clear().type('password'); + cy.get('[data-e2e="continue-button"]').click(); + cy.get('[formcontrolname="senderAddress"]').clear().type('sender2@example.com'); + cy.get('[formcontrolname="senderName"]').clear().type('Test2'); + cy.get('[formcontrolname="replyToAddress"]').clear().type('replyto2@example.com'); + cy.get('[data-e2e="create-button"]').click(); + cy.shouldConfirmSuccess(); + rowSelector = `tr:contains('mailjet')`; + cy.get(rowSelector).contains('mailjet'); + cy.get(rowSelector).contains('in-v3.mailjet.com:587'); + cy.get(rowSelector).contains('sender2@example.com'); + }); + it(`should activate Mailjet SMTP provider settings an disable Mailgun`, () => { + let rowSelector = `tr:contains('in-v3.mailjet.com:587')`; + cy.visit(smtpPath); + cy.get(rowSelector).find('[data-e2e="activate-provider-button"]').click({ force: true }); + cy.get('[data-e2e="confirm-dialog-button"]').click(); + cy.shouldConfirmSuccess(); + cy.get(rowSelector).find('[data-e2e="active-provider"]'); + cy.get(rowSelector).contains('mailjet'); + cy.get(rowSelector).contains('in-v3.mailjet.com:587'); + cy.get(rowSelector).contains('sender2@example.com'); + rowSelector = `tr:contains('mailgun')`; + cy.get(rowSelector).find('[data-e2e="active-provider"]').should('not.exist'); + }); + it(`should deactivate Mailjet SMTP provider`, () => { + let rowSelector = `tr:contains('mailjet')`; + cy.visit(smtpPath); + cy.get(rowSelector).find('[data-e2e="deactivate-provider-button"]').click({ force: true }); + cy.get('[data-e2e="confirm-dialog-button"]').click(); + cy.shouldConfirmSuccess(); + rowSelector = `tr:contains('mailjet')`; + cy.get(rowSelector).find('[data-e2e="active-provider"]').should('not.exist'); + rowSelector = `tr:contains('mailgun')`; + cy.get(rowSelector).find('[data-e2e="active-provider"]').should('not.exist'); + }); + it(`should delete Mailjet SMTP provider`, () => { + let rowSelector = `tr:contains('mailjet')`; + cy.visit(smtpPath); + cy.get(rowSelector).find('[data-e2e="delete-provider-button"]').click({ force: true }); + cy.get('[data-e2e="confirm-dialog-input"]').focus().type('Test2'); + cy.get('[data-e2e="confirm-dialog-button"]').click(); + cy.shouldConfirmSuccess(); + rowSelector = `tr:contains('mailjet')`; + cy.get(rowSelector).should('not.exist'); + }); + it(`should delete Mailgun SMTP provider`, () => { + let rowSelector = `tr:contains('mailgun')`; + cy.visit(smtpPath); + cy.get(rowSelector).find('[data-e2e="delete-provider-button"]').click({ force: true }); + cy.get('[data-e2e="confirm-dialog-input"]').focus().type('Change1'); + cy.get('[data-e2e="confirm-dialog-button"]').click(); + cy.shouldConfirmSuccess(); + rowSelector = `tr:contains('mailgun')`; + cy.get(rowSelector).should('not.exist'); }); }); diff --git a/e2e/package-lock.json b/e2e/package-lock.json deleted file mode 100644 index 886191596a..0000000000 --- a/e2e/package-lock.json +++ /dev/null @@ -1,5366 +0,0 @@ -{ - "name": "zitadel-e2e", - "version": "0.0.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "zitadel-e2e", - "version": "0.0.0", - "dependencies": { - "@types/pg": "^8.6.6", - "cypress-wait-until": "^1.7.2", - "jsonwebtoken": "^8.5.1", - "mochawesome": "^7.1.3", - "pg": "^8.8.0", - "prettier": "^2.7.1", - "typescript": "^4.8.4", - "uuid": "^9.0.0", - "wait-on": "^7.2.0" - }, - "devDependencies": { - "@types/node": "^18.8.3", - "cypress": "^13.3.1" - } - }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/@cypress/request": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.1.tgz", - "integrity": "sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==", - "dev": true, - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "http-signature": "~1.3.6", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "performance-now": "^2.1.0", - "qs": "6.10.4", - "safe-buffer": "^5.1.2", - "tough-cookie": "^4.1.3", - "tunnel-agent": "^0.6.0", - "uuid": "^8.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@cypress/request/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/@cypress/xvfb": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz", - "integrity": "sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==", - "dev": true, - "dependencies": { - "debug": "^3.1.0", - "lodash.once": "^4.1.1" - } - }, - "node_modules/@cypress/xvfb/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/@hapi/hoek": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", - "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==" - }, - "node_modules/@hapi/topo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", - "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", - "dependencies": { - "@hapi/hoek": "^9.0.0" - } - }, - "node_modules/@sideway/address": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", - "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", - "dependencies": { - "@hapi/hoek": "^9.0.0" - } - }, - "node_modules/@sideway/formula": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", - "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==" - }, - "node_modules/@sideway/pinpoint": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", - "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" - }, - "node_modules/@types/node": { - "version": "18.18.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.4.tgz", - "integrity": "sha512-t3rNFBgJRugIhackit2mVcLfF6IRc0JE4oeizPQL8Zrm8n2WY/0wOdpOPhdtG0V9Q2TlW/axbF1MJ6z+Yj/kKQ==" - }, - "node_modules/@types/pg": { - "version": "8.6.6", - "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.6.tgz", - "integrity": "sha512-O2xNmXebtwVekJDD+02udOncjVcMZQuTEQEMpKJ0ZRf5E7/9JJX3izhKUcUifBkyKpljyUM6BTgy2trmviKlpw==", - "dependencies": { - "@types/node": "*", - "pg-protocol": "*", - "pg-types": "^2.2.0" - } - }, - "node_modules/@types/sinonjs__fake-timers": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz", - "integrity": "sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==", - "dev": true - }, - "node_modules/@types/sizzle": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", - "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==", - "dev": true - }, - "node_modules/@types/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", - "dev": true, - "optional": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", - "peer": true - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "peer": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arch": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", - "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "peer": true - }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/async": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", - "dev": true - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", - "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", - "dev": true - }, - "node_modules/axios": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", - "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", - "dependencies": { - "follow-redirects": "^1.15.0", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "node_modules/axios/node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/axios/node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dev": true, - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/blob-util": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", - "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==", - "dev": true - }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "peer": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "peer": true - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" - }, - "node_modules/buffer-writer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", - "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/cachedir": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", - "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/check-more-types": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", - "integrity": "sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "peer": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/ci-info": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.2.tgz", - "integrity": "sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg==", - "dev": true - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-table3": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.2.tgz", - "integrity": "sha512-QyavHCaIC80cMivimWu4aWHilIpiDpfm3hGmqAmXVL1UsnbLuBSMd21hTX6VY4ZSDSM73ESLeF8TOYId3rBTbw==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0" - }, - "engines": { - "node": "10.* || >= 12.*" - }, - "optionalDependencies": { - "@colors/colors": "1.5.0" - } - }, - "node_modules/cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", - "dev": true, - "dependencies": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/colorette": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", - "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", - "dev": true - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/common-tags": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", - "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/cypress": { - "version": "13.3.1", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.3.1.tgz", - "integrity": "sha512-g4mJLZxYN+UAF2LMy3Znd4LBnUmS59Vynd81VES59RdW48Yt+QtR2cush3melOoVNz0PPbADpWr8DcUx6mif8Q==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "@cypress/request": "^3.0.0", - "@cypress/xvfb": "^1.2.4", - "@types/node": "^18.17.5", - "@types/sinonjs__fake-timers": "8.1.1", - "@types/sizzle": "^2.3.2", - "arch": "^2.2.0", - "blob-util": "^2.0.2", - "bluebird": "^3.7.2", - "buffer": "^5.6.0", - "cachedir": "^2.3.0", - "chalk": "^4.1.0", - "check-more-types": "^2.24.0", - "cli-cursor": "^3.1.0", - "cli-table3": "~0.6.1", - "commander": "^6.2.1", - "common-tags": "^1.8.0", - "dayjs": "^1.10.4", - "debug": "^4.3.4", - "enquirer": "^2.3.6", - "eventemitter2": "6.4.7", - "execa": "4.1.0", - "executable": "^4.1.1", - "extract-zip": "2.0.1", - "figures": "^3.2.0", - "fs-extra": "^9.1.0", - "getos": "^3.2.1", - "is-ci": "^3.0.0", - "is-installed-globally": "~0.4.0", - "lazy-ass": "^1.6.0", - "listr2": "^3.8.3", - "lodash": "^4.17.21", - "log-symbols": "^4.0.0", - "minimist": "^1.2.8", - "ospath": "^1.2.2", - "pretty-bytes": "^5.6.0", - "process": "^0.11.10", - "proxy-from-env": "1.0.0", - "request-progress": "^3.0.0", - "semver": "^7.5.3", - "supports-color": "^8.1.1", - "tmp": "~0.2.1", - "untildify": "^4.0.0", - "yauzl": "^2.10.0" - }, - "bin": { - "cypress": "bin/cypress" - }, - "engines": { - "node": "^16.0.0 || ^18.0.0 || >=20.0.0" - } - }, - "node_modules/cypress-wait-until": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/cypress-wait-until/-/cypress-wait-until-1.7.2.tgz", - "integrity": "sha512-uZ+M8/MqRcpf+FII/UZrU7g1qYZ4aVlHcgyVopnladyoBrpoaMJ4PKZDrdOJ05H5RHbr7s9Tid635X3E+ZLU/Q==" - }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/dateformat": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", - "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", - "engines": { - "node": "*" - } - }, - "node_modules/dayjs": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.5.tgz", - "integrity": "sha512-CAdX5Q3YW3Gclyo5Vpqkgpj8fSdLQcRuzfX6mC6Phy0nfJ0eGYOeS7m4mt2plDWLAtA4TqTakvbboHvUxfe4iA==", - "dev": true - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "dev": true, - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/eventemitter2": { - "version": "6.4.7", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz", - "integrity": "sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==", - "dev": true - }, - "node_modules/execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/executable": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", - "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", - "dev": true, - "dependencies": { - "pify": "^2.2.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "node_modules/extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - }, - "engines": { - "node": ">= 10.17.0" - }, - "optionalDependencies": { - "@types/yauzl": "^2.9.1" - } - }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "dev": true, - "engines": [ - "node >=0.6.0" - ] - }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dev": true, - "dependencies": { - "pend": "~1.2.0" - } - }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "peer": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "peer": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "peer": true, - "bin": { - "flat": "cli.js" - } - }, - "node_modules/follow-redirects": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", - "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "peer": true, - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/fsu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/fsu/-/fsu-1.1.1.tgz", - "integrity": "sha512-xQVsnjJ/5pQtcKh+KjUoZGzVWn4uNkchxTF6Lwjr4Gf7nQr8fmUfhKJ62zE77+xQg9xnxi5KUps7XGs+VC986A==" - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/getos": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz", - "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==", - "dev": true, - "dependencies": { - "async": "^3.2.0" - } - }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - } - }, - "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "peer": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/global-dirs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", - "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", - "dev": true, - "dependencies": { - "ini": "2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" - }, - "node_modules/has": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "peer": true, - "bin": { - "he": "bin/he" - } - }, - "node_modules/http-signature": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", - "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^2.0.2", - "sshpk": "^1.14.1" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "dev": true, - "engines": { - "node": ">=8.12.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "peer": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-ci": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", - "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", - "dev": true, - "dependencies": { - "ci-info": "^3.2.0" - }, - "bin": { - "is-ci": "bin.js" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "peer": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", - "dev": true, - "dependencies": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "peer": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true - }, - "node_modules/joi": { - "version": "17.11.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.11.0.tgz", - "integrity": "sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ==", - "dependencies": { - "@hapi/hoek": "^9.0.0", - "@hapi/topo": "^5.0.0", - "@sideway/address": "^4.1.3", - "@sideway/formula": "^3.0.1", - "@sideway/pinpoint": "^2.0.0" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "peer": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true - }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", - "dependencies": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=4", - "npm": ">=1.4.28" - } - }, - "node_modules/jsonwebtoken/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/jsprim": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", - "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - } - }, - "node_modules/jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "dependencies": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "dependencies": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/lazy-ass": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", - "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==", - "dev": true, - "engines": { - "node": "> 0.8" - } - }, - "node_modules/listr2": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", - "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==", - "dev": true, - "dependencies": { - "cli-truncate": "^2.1.0", - "colorette": "^2.0.16", - "log-update": "^4.0.0", - "p-map": "^4.0.0", - "rfdc": "^1.3.0", - "rxjs": "^7.5.1", - "through": "^2.3.8", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "enquirer": ">= 2.3.0 < 3" - }, - "peerDependenciesMeta": { - "enquirer": { - "optional": true - } - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "peer": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" - }, - "node_modules/lodash.isempty": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz", - "integrity": "sha512-oKMuF3xEeqDltrGMfDxAPGIVMSSRv8tbRSODbrs4KGsRRLEhrW8N8Rd4DRgB2+621hY8A8XwwrTVhXWpxFvMzg==" - }, - "node_modules/lodash.isfunction": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", - "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==" - }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" - }, - "node_modules/lodash.isobject": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz", - "integrity": "sha512-3/Qptq2vr7WeJbB4KHUSKlq8Pl7ASXi3UG6CMbBm8WRtXi8+GHm7mKaU3urfpSEzWe2wCIChs6/sdocUsTKJiA==" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" - }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", - "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.3.0", - "cli-cursor": "^3.1.0", - "slice-ansi": "^4.0.0", - "wrap-ansi": "^6.2.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/log-update/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "peer": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mocha": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz", - "integrity": "sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==", - "peer": true, - "dependencies": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" - }, - "engines": { - "node": ">= 14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" - } - }, - "node_modules/mocha/node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "peer": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/mocha/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "peer": true - }, - "node_modules/mochawesome": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/mochawesome/-/mochawesome-7.1.3.tgz", - "integrity": "sha512-Vkb3jR5GZ1cXohMQQ73H3cZz7RoxGjjUo0G5hu0jLaW+0FdUxUwg3Cj29bqQdh0rFcnyV06pWmqmi5eBPnEuNQ==", - "dependencies": { - "chalk": "^4.1.2", - "diff": "^5.0.0", - "json-stringify-safe": "^5.0.1", - "lodash.isempty": "^4.4.0", - "lodash.isfunction": "^3.0.9", - "lodash.isobject": "^3.0.2", - "lodash.isstring": "^4.0.1", - "mochawesome-report-generator": "^6.2.0", - "strip-ansi": "^6.0.1", - "uuid": "^8.3.2" - }, - "peerDependencies": { - "mocha": ">=7" - } - }, - "node_modules/mochawesome-report-generator": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/mochawesome-report-generator/-/mochawesome-report-generator-6.2.0.tgz", - "integrity": "sha512-Ghw8JhQFizF0Vjbtp9B0i//+BOkV5OWcQCPpbO0NGOoxV33o+gKDYU0Pr2pGxkIHnqZ+g5mYiXF7GMNgAcDpSg==", - "dependencies": { - "chalk": "^4.1.2", - "dateformat": "^4.5.1", - "escape-html": "^1.0.3", - "fs-extra": "^10.0.0", - "fsu": "^1.1.1", - "lodash.isfunction": "^3.0.9", - "opener": "^1.5.2", - "prop-types": "^15.7.2", - "tcomb": "^3.2.17", - "tcomb-validation": "^3.3.0", - "validator": "^13.6.0", - "yargs": "^17.2.1" - }, - "bin": { - "marge": "bin/cli.js" - } - }, - "node_modules/mochawesome-report-generator/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/mochawesome-report-generator/node_modules/yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/mochawesome-report-generator/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "engines": { - "node": ">=12" - } - }, - "node_modules/mochawesome/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "peer": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/opener": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", - "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", - "bin": { - "opener": "bin/opener-bin.js" - } - }, - "node_modules/ospath": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", - "integrity": "sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==", - "dev": true - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "peer": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "peer": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/packet-reader": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", - "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true - }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true - }, - "node_modules/pg": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.8.0.tgz", - "integrity": "sha512-UXYN0ziKj+AeNNP7VDMwrehpACThH7LUl/p8TDFpEUuSejCUIwGSfxpHsPvtM6/WXFy6SU4E5RG4IJV/TZAGjw==", - "dependencies": { - "buffer-writer": "2.0.0", - "packet-reader": "1.0.0", - "pg-connection-string": "^2.5.0", - "pg-pool": "^3.5.2", - "pg-protocol": "^1.5.0", - "pg-types": "^2.1.0", - "pgpass": "1.x" - }, - "engines": { - "node": ">= 8.0.0" - }, - "peerDependencies": { - "pg-native": ">=3.0.1" - }, - "peerDependenciesMeta": { - "pg-native": { - "optional": true - } - } - }, - "node_modules/pg-connection-string": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", - "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" - }, - "node_modules/pg-int8": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", - "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/pg-pool": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.5.2.tgz", - "integrity": "sha512-His3Fh17Z4eg7oANLob6ZvH8xIVen3phEZh2QuyrIl4dQSDVEabNducv6ysROKpDNPSD+12tONZVWfSgMvDD9w==", - "peerDependencies": { - "pg": ">=8.0" - } - }, - "node_modules/pg-protocol": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz", - "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==" - }, - "node_modules/pg-types": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", - "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", - "dependencies": { - "pg-int8": "1.0.1", - "postgres-array": "~2.0.0", - "postgres-bytea": "~1.0.0", - "postgres-date": "~1.0.4", - "postgres-interval": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pgpass": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", - "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", - "dependencies": { - "split2": "^4.1.0" - } - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "peer": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-array": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", - "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/postgres-bytea": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", - "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-date": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", - "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postgres-interval": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", - "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", - "dependencies": { - "xtend": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/pretty-bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "dev": true, - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/proxy-from-env": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", - "integrity": "sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==", - "dev": true - }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.10.4", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.4.tgz", - "integrity": "sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "peer": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "peer": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/request-progress": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", - "integrity": "sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==", - "dev": true, - "dependencies": { - "throttleit": "^1.0.0" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true - }, - "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/rfdc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", - "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", - "dev": true - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "peer": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/split2": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", - "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==", - "engines": { - "node": ">= 10.x" - } - }, - "node_modules/sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", - "dev": true, - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "peer": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/tcomb": { - "version": "3.2.29", - "resolved": "https://registry.npmjs.org/tcomb/-/tcomb-3.2.29.tgz", - "integrity": "sha512-di2Hd1DB2Zfw6StGv861JoAF5h/uQVu/QJp2g8KVbtfKnoHdBQl5M32YWq6mnSYBQ1vFFrns5B1haWJL7rKaOQ==" - }, - "node_modules/tcomb-validation": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/tcomb-validation/-/tcomb-validation-3.4.1.tgz", - "integrity": "sha512-urVVMQOma4RXwiVCa2nM2eqrAomHROHvWPuj6UkDGz/eb5kcy0x6P0dVt6kzpUZtYMNoAqJLWmz1BPtxrtjtrA==", - "dependencies": { - "tcomb": "^3.0.0" - } - }, - "node_modules/throttleit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", - "integrity": "sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g==", - "dev": true - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, - "node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dev": true, - "dependencies": { - "rimraf": "^3.0.0" - }, - "engines": { - "node": ">=8.17.0" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "peer": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tough-cookie": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", - "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", - "dev": true, - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tough-cookie/node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true - }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", - "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "node_modules/uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/validator": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz", - "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "node_modules/wait-on": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.2.0.tgz", - "integrity": "sha512-wCQcHkRazgjG5XoAq9jbTMLpNIjoSlZslrJ2+N9MxDsGEv1HnFoVjOCexL0ESva7Y9cu350j+DWADdk54s4AFQ==", - "dependencies": { - "axios": "^1.6.1", - "joi": "^17.11.0", - "lodash": "^4.17.21", - "minimist": "^1.2.8", - "rxjs": "^7.8.1" - }, - "bin": { - "wait-on": "bin/wait-on" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "peer": true - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "peer": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "peer": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "peer": true, - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dev": true, - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, - "dependencies": { - "@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "dev": true, - "optional": true - }, - "@cypress/request": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.1.tgz", - "integrity": "sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "http-signature": "~1.3.6", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "performance-now": "^2.1.0", - "qs": "6.10.4", - "safe-buffer": "^5.1.2", - "tough-cookie": "^4.1.3", - "tunnel-agent": "^0.6.0", - "uuid": "^8.3.2" - }, - "dependencies": { - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true - } - } - }, - "@cypress/xvfb": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz", - "integrity": "sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==", - "dev": true, - "requires": { - "debug": "^3.1.0", - "lodash.once": "^4.1.1" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "@hapi/hoek": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", - "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==" - }, - "@hapi/topo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", - "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", - "requires": { - "@hapi/hoek": "^9.0.0" - } - }, - "@sideway/address": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", - "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", - "requires": { - "@hapi/hoek": "^9.0.0" - } - }, - "@sideway/formula": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", - "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==" - }, - "@sideway/pinpoint": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", - "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" - }, - "@types/node": { - "version": "18.18.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.4.tgz", - "integrity": "sha512-t3rNFBgJRugIhackit2mVcLfF6IRc0JE4oeizPQL8Zrm8n2WY/0wOdpOPhdtG0V9Q2TlW/axbF1MJ6z+Yj/kKQ==" - }, - "@types/pg": { - "version": "8.6.6", - "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.6.tgz", - "integrity": "sha512-O2xNmXebtwVekJDD+02udOncjVcMZQuTEQEMpKJ0ZRf5E7/9JJX3izhKUcUifBkyKpljyUM6BTgy2trmviKlpw==", - "requires": { - "@types/node": "*", - "pg-protocol": "*", - "pg-types": "^2.2.0" - } - }, - "@types/sinonjs__fake-timers": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz", - "integrity": "sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==", - "dev": true - }, - "@types/sizzle": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", - "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==", - "dev": true - }, - "@types/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", - "dev": true, - "optional": true, - "requires": { - "@types/node": "*" - } - }, - "@ungap/promise-all-settled": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", - "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", - "peer": true - }, - "aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, - "ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true - }, - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "requires": { - "type-fest": "^0.21.3" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "peer": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "arch": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", - "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", - "dev": true - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "peer": true - }, - "asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "dev": true - }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true - }, - "async": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", - "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", - "dev": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "dev": true - }, - "aws4": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", - "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", - "dev": true - }, - "axios": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", - "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", - "requires": { - "follow-redirects": "^1.15.0", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - }, - "dependencies": { - "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - } - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dev": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "peer": true - }, - "blob-util": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", - "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==", - "dev": true - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "peer": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "peer": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "peer": true - }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true - }, - "buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" - }, - "buffer-writer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", - "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" - }, - "cachedir": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", - "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", - "dev": true - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "peer": true - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "check-more-types": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", - "integrity": "sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==", - "dev": true - }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "peer": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - } - }, - "ci-info": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.2.tgz", - "integrity": "sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg==", - "dev": true - }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true - }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "requires": { - "restore-cursor": "^3.1.0" - } - }, - "cli-table3": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.2.tgz", - "integrity": "sha512-QyavHCaIC80cMivimWu4aWHilIpiDpfm3hGmqAmXVL1UsnbLuBSMd21hTX6VY4ZSDSM73ESLeF8TOYId3rBTbw==", - "dev": true, - "requires": { - "@colors/colors": "1.5.0", - "string-width": "^4.2.0" - } - }, - "cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", - "dev": true, - "requires": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" - } - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "colorette": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", - "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", - "dev": true - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "dev": true - }, - "common-tags": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", - "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "cypress": { - "version": "13.3.1", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.3.1.tgz", - "integrity": "sha512-g4mJLZxYN+UAF2LMy3Znd4LBnUmS59Vynd81VES59RdW48Yt+QtR2cush3melOoVNz0PPbADpWr8DcUx6mif8Q==", - "dev": true, - "requires": { - "@cypress/request": "^3.0.0", - "@cypress/xvfb": "^1.2.4", - "@types/node": "^18.17.5", - "@types/sinonjs__fake-timers": "8.1.1", - "@types/sizzle": "^2.3.2", - "arch": "^2.2.0", - "blob-util": "^2.0.2", - "bluebird": "^3.7.2", - "buffer": "^5.6.0", - "cachedir": "^2.3.0", - "chalk": "^4.1.0", - "check-more-types": "^2.24.0", - "cli-cursor": "^3.1.0", - "cli-table3": "~0.6.1", - "commander": "^6.2.1", - "common-tags": "^1.8.0", - "dayjs": "^1.10.4", - "debug": "^4.3.4", - "enquirer": "^2.3.6", - "eventemitter2": "6.4.7", - "execa": "4.1.0", - "executable": "^4.1.1", - "extract-zip": "2.0.1", - "figures": "^3.2.0", - "fs-extra": "^9.1.0", - "getos": "^3.2.1", - "is-ci": "^3.0.0", - "is-installed-globally": "~0.4.0", - "lazy-ass": "^1.6.0", - "listr2": "^3.8.3", - "lodash": "^4.17.21", - "log-symbols": "^4.0.0", - "minimist": "^1.2.8", - "ospath": "^1.2.2", - "pretty-bytes": "^5.6.0", - "process": "^0.11.10", - "proxy-from-env": "1.0.0", - "request-progress": "^3.0.0", - "semver": "^7.5.3", - "supports-color": "^8.1.1", - "tmp": "~0.2.1", - "untildify": "^4.0.0", - "yauzl": "^2.10.0" - } - }, - "cypress-wait-until": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/cypress-wait-until/-/cypress-wait-until-1.7.2.tgz", - "integrity": "sha512-uZ+M8/MqRcpf+FII/UZrU7g1qYZ4aVlHcgyVopnladyoBrpoaMJ4PKZDrdOJ05H5RHbr7s9Tid635X3E+ZLU/Q==" - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "dateformat": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", - "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==" - }, - "dayjs": { - "version": "1.11.5", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.5.tgz", - "integrity": "sha512-CAdX5Q3YW3Gclyo5Vpqkgpj8fSdLQcRuzfX6mC6Phy0nfJ0eGYOeS7m4mt2plDWLAtA4TqTakvbboHvUxfe4iA==", - "dev": true - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "requires": { - "ms": "2.1.2" - } - }, - "decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "peer": true - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" - }, - "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==" - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "dev": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "requires": { - "ansi-colors": "^4.1.1" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "eventemitter2": { - "version": "6.4.7", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz", - "integrity": "sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==", - "dev": true - }, - "execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - } - }, - "executable": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", - "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", - "dev": true, - "requires": { - "pify": "^2.2.0" - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "dev": true, - "requires": { - "@types/yauzl": "^2.9.1", - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "dev": true - }, - "fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dev": true, - "requires": { - "pend": "~1.2.0" - } - }, - "figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "peer": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "peer": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "peer": true - }, - "follow-redirects": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", - "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==" - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "dev": true - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "optional": true, - "peer": true - }, - "fsu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/fsu/-/fsu-1.1.1.tgz", - "integrity": "sha512-xQVsnjJ/5pQtcKh+KjUoZGzVWn4uNkchxTF6Lwjr4Gf7nQr8fmUfhKJ62zE77+xQg9xnxi5KUps7XGs+VC986A==" - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" - }, - "get-intrinsic": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", - "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3" - } - }, - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "getos": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz", - "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==", - "dev": true, - "requires": { - "async": "^3.2.0" - } - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "dependencies": { - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - } - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "peer": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "global-dirs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", - "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", - "dev": true, - "requires": { - "ini": "2.0.0" - } - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" - }, - "has": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "peer": true - }, - "http-signature": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", - "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^2.0.2", - "sshpk": "^1.14.1" - } - }, - "human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "dev": true - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true - }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "peer": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-ci": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", - "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", - "dev": true, - "requires": { - "ci-info": "^3.2.0" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "peer": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "peer": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", - "dev": true, - "requires": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "peer": true - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true - }, - "is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "peer": true - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, - "is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true - }, - "joi": { - "version": "17.11.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.11.0.tgz", - "integrity": "sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ==", - "requires": { - "@hapi/hoek": "^9.0.0", - "@hapi/topo": "^5.0.0", - "@sideway/address": "^4.1.3", - "@sideway/formula": "^3.0.1", - "@sideway/pinpoint": "^2.0.0" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "peer": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true - }, - "json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", - "requires": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^5.6.0" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - } - } - }, - "jsprim": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", - "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - } - }, - "jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "requires": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, - "lazy-ass": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", - "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==", - "dev": true - }, - "listr2": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", - "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==", - "dev": true, - "requires": { - "cli-truncate": "^2.1.0", - "colorette": "^2.0.16", - "log-update": "^4.0.0", - "p-map": "^4.0.0", - "rfdc": "^1.3.0", - "rxjs": "^7.5.1", - "through": "^2.3.8", - "wrap-ansi": "^7.0.0" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "peer": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" - }, - "lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" - }, - "lodash.isempty": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz", - "integrity": "sha512-oKMuF3xEeqDltrGMfDxAPGIVMSSRv8tbRSODbrs4KGsRRLEhrW8N8Rd4DRgB2+621hY8A8XwwrTVhXWpxFvMzg==" - }, - "lodash.isfunction": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz", - "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==" - }, - "lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" - }, - "lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" - }, - "lodash.isobject": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-3.0.2.tgz", - "integrity": "sha512-3/Qptq2vr7WeJbB4KHUSKlq8Pl7ASXi3UG6CMbBm8WRtXi8+GHm7mKaU3urfpSEzWe2wCIChs6/sdocUsTKJiA==" - }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" - }, - "lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" - }, - "lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" - }, - "log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - } - }, - "log-update": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", - "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", - "dev": true, - "requires": { - "ansi-escapes": "^4.3.0", - "cli-cursor": "^3.1.0", - "slice-ansi": "^4.0.0", - "wrap-ansi": "^6.2.0" - }, - "dependencies": { - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - } - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - } - } - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "requires": { - "mime-db": "1.52.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "peer": true, - "requires": { - "brace-expansion": "^2.0.1" - } - }, - "minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" - }, - "mocha": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.0.0.tgz", - "integrity": "sha512-0Wl+elVUD43Y0BqPZBzZt8Tnkw9CMUdNYnUsTfOM1vuhJVZL+kiesFYsqwBkEEuEixaiPe5ZQdqDgX2jddhmoA==", - "peer": true, - "requires": { - "@ungap/promise-all-settled": "1.1.2", - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "dependencies": { - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "peer": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "peer": true - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "peer": true - } - } - }, - "mochawesome": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/mochawesome/-/mochawesome-7.1.3.tgz", - "integrity": "sha512-Vkb3jR5GZ1cXohMQQ73H3cZz7RoxGjjUo0G5hu0jLaW+0FdUxUwg3Cj29bqQdh0rFcnyV06pWmqmi5eBPnEuNQ==", - "requires": { - "chalk": "^4.1.2", - "diff": "^5.0.0", - "json-stringify-safe": "^5.0.1", - "lodash.isempty": "^4.4.0", - "lodash.isfunction": "^3.0.9", - "lodash.isobject": "^3.0.2", - "lodash.isstring": "^4.0.1", - "mochawesome-report-generator": "^6.2.0", - "strip-ansi": "^6.0.1", - "uuid": "^8.3.2" - }, - "dependencies": { - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" - } - } - }, - "mochawesome-report-generator": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/mochawesome-report-generator/-/mochawesome-report-generator-6.2.0.tgz", - "integrity": "sha512-Ghw8JhQFizF0Vjbtp9B0i//+BOkV5OWcQCPpbO0NGOoxV33o+gKDYU0Pr2pGxkIHnqZ+g5mYiXF7GMNgAcDpSg==", - "requires": { - "chalk": "^4.1.2", - "dateformat": "^4.5.1", - "escape-html": "^1.0.3", - "fs-extra": "^10.0.0", - "fsu": "^1.1.1", - "lodash.isfunction": "^3.0.9", - "opener": "^1.5.2", - "prop-types": "^15.7.2", - "tcomb": "^3.2.17", - "tcomb-validation": "^3.3.0", - "validator": "^13.6.0", - "yargs": "^17.2.1" - }, - "dependencies": { - "fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "yargs": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", - "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.0.0" - } - }, - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" - } - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "peer": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "peer": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" - }, - "object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "opener": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", - "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==" - }, - "ospath": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", - "integrity": "sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==", - "dev": true - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "peer": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "peer": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "requires": { - "aggregate-error": "^3.0.0" - } - }, - "packet-reader": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", - "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "peer": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true - }, - "pg": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.8.0.tgz", - "integrity": "sha512-UXYN0ziKj+AeNNP7VDMwrehpACThH7LUl/p8TDFpEUuSejCUIwGSfxpHsPvtM6/WXFy6SU4E5RG4IJV/TZAGjw==", - "requires": { - "buffer-writer": "2.0.0", - "packet-reader": "1.0.0", - "pg-connection-string": "^2.5.0", - "pg-pool": "^3.5.2", - "pg-protocol": "^1.5.0", - "pg-types": "^2.1.0", - "pgpass": "1.x" - } - }, - "pg-connection-string": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", - "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" - }, - "pg-int8": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", - "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" - }, - "pg-pool": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.5.2.tgz", - "integrity": "sha512-His3Fh17Z4eg7oANLob6ZvH8xIVen3phEZh2QuyrIl4dQSDVEabNducv6ysROKpDNPSD+12tONZVWfSgMvDD9w==", - "requires": {} - }, - "pg-protocol": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz", - "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==" - }, - "pg-types": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", - "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", - "requires": { - "pg-int8": "1.0.1", - "postgres-array": "~2.0.0", - "postgres-bytea": "~1.0.0", - "postgres-date": "~1.0.4", - "postgres-interval": "^1.1.0" - } - }, - "pgpass": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", - "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", - "requires": { - "split2": "^4.1.0" - } - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "peer": true - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true - }, - "postgres-array": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", - "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" - }, - "postgres-bytea": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", - "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==" - }, - "postgres-date": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", - "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" - }, - "postgres-interval": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", - "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", - "requires": { - "xtend": "^4.0.0" - } - }, - "prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==" - }, - "pretty-bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", - "dev": true - }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "dev": true - }, - "prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "proxy-from-env": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", - "integrity": "sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==", - "dev": true - }, - "psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true - }, - "qs": { - "version": "6.10.4", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.4.tgz", - "integrity": "sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==", - "dev": true, - "requires": { - "side-channel": "^1.0.4" - } - }, - "querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "peer": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "peer": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "request-progress": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", - "integrity": "sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==", - "dev": true, - "requires": { - "throttleit": "^1.0.0" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" - }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true - }, - "restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - } - }, - "rfdc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", - "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "requires": { - "tslib": "^2.1.0" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "peer": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - } - }, - "split2": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", - "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==" - }, - "sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", - "dev": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "peer": true - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "requires": { - "has-flag": "^4.0.0" - } - }, - "tcomb": { - "version": "3.2.29", - "resolved": "https://registry.npmjs.org/tcomb/-/tcomb-3.2.29.tgz", - "integrity": "sha512-di2Hd1DB2Zfw6StGv861JoAF5h/uQVu/QJp2g8KVbtfKnoHdBQl5M32YWq6mnSYBQ1vFFrns5B1haWJL7rKaOQ==" - }, - "tcomb-validation": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/tcomb-validation/-/tcomb-validation-3.4.1.tgz", - "integrity": "sha512-urVVMQOma4RXwiVCa2nM2eqrAomHROHvWPuj6UkDGz/eb5kcy0x6P0dVt6kzpUZtYMNoAqJLWmz1BPtxrtjtrA==", - "requires": { - "tcomb": "^3.0.0" - } - }, - "throttleit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", - "integrity": "sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g==", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, - "tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dev": true, - "requires": { - "rimraf": "^3.0.0" - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "peer": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "tough-cookie": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", - "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", - "dev": true, - "requires": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "dependencies": { - "universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true - } - } - }, - "tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true - }, - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true - }, - "typescript": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", - "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==" - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" - }, - "untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "dev": true - }, - "url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, - "requires": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" - }, - "validator": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz", - "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==" - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "wait-on": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.2.0.tgz", - "integrity": "sha512-wCQcHkRazgjG5XoAq9jbTMLpNIjoSlZslrJ2+N9MxDsGEv1HnFoVjOCexL0ESva7Y9cu350j+DWADdk54s4AFQ==", - "requires": { - "axios": "^1.6.1", - "joi": "^17.11.0", - "lodash": "^4.17.21", - "minimist": "^1.2.8", - "rxjs": "^7.8.1" - } - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "peer": true - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "peer": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - }, - "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "peer": true - }, - "yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "peer": true, - "requires": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - } - }, - "yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dev": true, - "requires": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "peer": true - } - } -} diff --git a/e2e/yarn.lock b/e2e/yarn.lock new file mode 100644 index 0000000000..84669a7fe1 --- /dev/null +++ b/e2e/yarn.lock @@ -0,0 +1,1729 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@colors/colors@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" + integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== + +"@cypress/request@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@cypress/request/-/request-3.0.1.tgz#72d7d5425236a2413bd3d8bb66d02d9dc3168960" + integrity sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + http-signature "~1.3.6" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + performance-now "^2.1.0" + qs "6.10.4" + safe-buffer "^5.1.2" + tough-cookie "^4.1.3" + tunnel-agent "^0.6.0" + uuid "^8.3.2" + +"@cypress/xvfb@^1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@cypress/xvfb/-/xvfb-1.2.4.tgz#2daf42e8275b39f4aa53c14214e557bd14e7748a" + integrity sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q== + dependencies: + debug "^3.1.0" + lodash.once "^4.1.1" + +"@hapi/hoek@^9.0.0", "@hapi/hoek@^9.3.0": + version "9.3.0" + resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb" + integrity sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ== + +"@hapi/topo@^5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.1.0.tgz#dc448e332c6c6e37a4dc02fd84ba8d44b9afb012" + integrity sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@sideway/address@^4.1.5": + version "4.1.5" + resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.5.tgz#4bc149a0076623ced99ca8208ba780d65a99b9d5" + integrity sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@sideway/formula@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.1.tgz#80fcbcbaf7ce031e0ef2dd29b1bfc7c3f583611f" + integrity sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg== + +"@sideway/pinpoint@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" + integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== + +"@types/node@*": + version "20.7.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.7.0.tgz#c03de4572f114a940bc2ca909a33ddb2b925e470" + integrity sha512-zI22/pJW2wUZOVyguFaUL1HABdmSVxpXrzIqkjsHmyUjNhPoWM1CKfvVuXfetHhIok4RY573cqS0mZ1SJEnoTg== + +"@types/node@^18.8.3": + version "18.18.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.18.0.tgz#bd19d5133a6e5e2d0152ec079ac27c120e7f1763" + integrity sha512-3xA4X31gHT1F1l38ATDIL9GpRLdwVhnEFC8Uikv5ZLlXATwrCYyPq7ZWHxzxc3J/30SUiwiYT+bQe0/XvKlWbw== + +"@types/pg@^8.6.6": + version "8.10.3" + resolved "https://registry.yarnpkg.com/@types/pg/-/pg-8.10.3.tgz#39b3acba4f313a65c8fbb4b241fcb21cc1ba4126" + integrity sha512-BACzsw64lCZesclRpZGu55tnqgFAYcrCBP92xLh1KLypZLCOsvJTSTgaoFVTy3lCys/aZTQzfeDxtjwrvdzL2g== + dependencies: + "@types/node" "*" + pg-protocol "*" + pg-types "^4.0.1" + +"@types/sinonjs__fake-timers@8.1.1": + version "8.1.1" + resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz#b49c2c70150141a15e0fa7e79cf1f92a72934ce3" + integrity sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g== + +"@types/sizzle@^2.3.2": + version "2.3.4" + resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.4.tgz#cd6531924f60834fa4a1b8081f9eecf9bb1117f0" + integrity sha512-jA2llq2zNkg8HrALI7DtWzhALcVH0l7i89yhY3iBdOz6cBPeACoFq+fkQrjHA39t1hnSFOboZ7A/AY5MMZSlag== + +"@types/yauzl@^2.9.1": + version "2.10.1" + resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.10.1.tgz#4e8f299f0934d60f36c74f59cb5a8483fd786691" + integrity sha512-CHzgNU3qYBnp/O4S3yv2tXPlvMTq0YWSTVg2/JYLqWZGHwwgJGAwd00poay/11asPq8wLFwHzubyInqHIFmmiw== + dependencies: + "@types/node" "*" + +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + +ansi-colors@^4.1.1: + version "4.1.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== + +ansi-escapes@^4.3.0: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +arch@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11" + integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ== + +asn1@~0.2.3: + version "0.2.6" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" + integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== + +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + +async@^3.2.0: + version "3.2.4" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" + integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +at-least-node@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA== + +aws4@^1.8.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.12.0.tgz#ce1c9d143389679e253b314241ea9aa5cec980d3" + integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg== + +axios@^1.6.1: + version "1.6.8" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.8.tgz#66d294951f5d988a00e87a0ffb955316a619ea66" + integrity sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w== + dependencies: + tweetnacl "^0.14.3" + +blob-util@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/blob-util/-/blob-util-2.0.2.tgz#3b4e3c281111bb7f11128518006cdc60b403a1eb" + integrity sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ== + +bluebird@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== + +buffer-equal-constant-time@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== + +buffer-writer@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-2.0.0.tgz#ce7eb81a38f7829db09c873f2fbb792c0c98ec04" + integrity sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw== + +buffer@^5.7.1: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +cachedir@^2.3.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-2.4.0.tgz#7fef9cf7367233d7c88068fe6e34ed0d355a610d" + integrity sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ== + +call-bind@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== + +chalk@^4.1.0, chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +check-more-types@^2.24.0: + version "2.24.0" + resolved "https://registry.yarnpkg.com/check-more-types/-/check-more-types-2.24.0.tgz#1420ffb10fd444dcfc79b43891bbfffd32a84600" + integrity sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA== + +ci-info@^3.2.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" + integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-table3@~0.6.1: + version "0.6.3" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.3.tgz#61ab765aac156b52f222954ffc607a6f01dbeeb2" + integrity sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg== + dependencies: + string-width "^4.2.0" + optionalDependencies: + "@colors/colors" "1.5.0" + +cli-truncate@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" + integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg== + dependencies: + slice-ansi "^3.0.0" + string-width "^4.2.0" + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colorette@^2.0.16: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + +combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@^6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" + integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== + +common-tags@^1.8.0: + version "1.8.2" + resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.2.tgz#94ebb3c076d26032745fd54face7f688ef5ac9c6" + integrity sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +core-util-is@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ== + +cross-spawn@^7.0.0: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +cypress-wait-until@^1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/cypress-wait-until/-/cypress-wait-until-1.7.2.tgz#7f534dd5a11c89b65359e7a0210f20d3dfc22107" + integrity sha512-uZ+M8/MqRcpf+FII/UZrU7g1qYZ4aVlHcgyVopnladyoBrpoaMJ4PKZDrdOJ05H5RHbr7s9Tid635X3E+ZLU/Q== + +cypress@^13.3.1: + version "13.7.2" + resolved "https://registry.yarnpkg.com/cypress/-/cypress-13.7.2.tgz#61e841382abb20e0a9a063086ee0d850af3ef6bc" + integrity sha512-FF5hFI5wlRIHY8urLZjJjj/YvfCBrRpglbZCLr/cYcL9MdDe0+5usa8kTIrDHthlEc9lwihbkb5dmwqBDNS2yw== + dependencies: + "@cypress/request" "^3.0.0" + "@cypress/xvfb" "^1.2.4" + "@types/sinonjs__fake-timers" "8.1.1" + "@types/sizzle" "^2.3.2" + arch "^2.2.0" + blob-util "^2.0.2" + bluebird "^3.7.2" + buffer "^5.7.1" + cachedir "^2.3.0" + chalk "^4.1.0" + check-more-types "^2.24.0" + cli-cursor "^3.1.0" + cli-table3 "~0.6.1" + commander "^6.2.1" + common-tags "^1.8.0" + dayjs "^1.10.4" + debug "^4.3.4" + enquirer "^2.3.6" + eventemitter2 "6.4.7" + execa "4.1.0" + executable "^4.1.1" + extract-zip "2.0.1" + figures "^3.2.0" + fs-extra "^9.1.0" + getos "^3.2.1" + is-ci "^3.0.1" + is-installed-globally "~0.4.0" + lazy-ass "^1.6.0" + listr2 "^3.8.3" + lodash "^4.17.21" + log-symbols "^4.0.0" + minimist "^1.2.8" + ospath "^1.2.2" + pretty-bytes "^5.6.0" + process "^0.11.10" + proxy-from-env "1.0.0" + request-progress "^3.0.0" + semver "^7.5.3" + supports-color "^8.1.1" + tmp "~0.2.1" + untildify "^4.0.0" + yauzl "^2.10.0" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g== + dependencies: + assert-plus "^1.0.0" + +dateformat@^4.5.1: + version "4.6.3" + resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-4.6.3.tgz#556fa6497e5217fedb78821424f8a1c22fa3f4b5" + integrity sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA== + +dayjs@^1.10.4: + version "1.11.10" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.10.tgz#68acea85317a6e164457d6d6947564029a6a16a0" + integrity sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ== + +debug@^3.1.0: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +debug@^4.1.1, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +diff@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.1.0.tgz#bc52d298c5ea8df9194800224445ed43ffc87e40" + integrity sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw== + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw== + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +ecdsa-sig-formatter@1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" + integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== + dependencies: + safe-buffer "^5.0.1" + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +enquirer@^2.3.6: + version "2.4.1" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.4.1.tgz#93334b3fbd74fc7097b224ab4a8fb7e40bf4ae56" + integrity sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ== + dependencies: + ansi-colors "^4.1.1" + strip-ansi "^6.0.1" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-html@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +eventemitter2@6.4.7: + version "6.4.7" + resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.7.tgz#a7f6c4d7abf28a14c1ef3442f21cb306a054271d" + integrity sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg== + +execa@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" + integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== + dependencies: + cross-spawn "^7.0.0" + get-stream "^5.0.0" + human-signals "^1.1.1" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.0" + onetime "^5.1.0" + signal-exit "^3.0.2" + strip-final-newline "^2.0.0" + +executable@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/executable/-/executable-4.1.1.tgz#41532bff361d3e57af4d763b70582db18f5d133c" + integrity sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg== + dependencies: + pify "^2.2.0" + +extend@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +extract-zip@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" + integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg== + dependencies: + debug "^4.1.1" + get-stream "^5.1.0" + yauzl "^2.10.0" + optionalDependencies: + "@types/yauzl" "^2.9.1" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g== + +extsprintf@^1.2.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" + integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== + +fd-slicer@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" + integrity sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g== + dependencies: + pend "~1.2.0" + +figures@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== + dependencies: + escape-string-regexp "^1.0.5" + +follow-redirects@^1.15.6: + version "1.15.6" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" + integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +fs-extra@^10.0.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" + integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-extra@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== + dependencies: + at-least-node "^1.0.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsu@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/fsu/-/fsu-1.1.1.tgz#bd36d3579907c59d85b257a75b836aa9e0c31834" + integrity sha512-xQVsnjJ/5pQtcKh+KjUoZGzVWn4uNkchxTF6Lwjr4Gf7nQr8fmUfhKJ62zE77+xQg9xnxi5KUps7XGs+VC986A== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" + integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-proto "^1.0.1" + has-symbols "^1.0.3" + +get-stream@^5.0.0, get-stream@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + +getos@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/getos/-/getos-3.2.1.tgz#0134d1f4e00eb46144c5a9c0ac4dc087cbb27dc5" + integrity sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q== + dependencies: + async "^3.2.0" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng== + dependencies: + assert-plus "^1.0.0" + +glob@^7.1.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-dirs@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-3.0.1.tgz#0c488971f066baceda21447aecb1a8b911d22485" + integrity sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA== + dependencies: + ini "2.0.0" + +graceful-fs@^4.1.6, graceful-fs@^4.2.0: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +http-signature@~1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.3.6.tgz#cb6fbfdf86d1c974f343be94e87f7fc128662cf9" + integrity sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw== + dependencies: + assert-plus "^1.0.0" + jsprim "^2.0.2" + sshpk "^1.14.1" + +human-signals@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" + integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== + +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ini@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" + integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== + +is-ci@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-3.0.1.tgz#db6ecbed1bd659c43dac0f45661e7674103d1867" + integrity sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ== + dependencies: + ci-info "^3.2.0" + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-installed-globally@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.4.0.tgz#9a0fd407949c30f86eb6959ef1b7994ed0b7b520" + integrity sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ== + dependencies: + global-dirs "^3.0.0" + is-path-inside "^3.0.2" + +is-path-inside@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== + +joi@^17.11.0: + version "17.12.3" + resolved "https://registry.yarnpkg.com/joi/-/joi-17.12.3.tgz#944646979cd3b460178547b12ba37aca8482f63d" + integrity sha512-2RRziagf555owrm9IRVtdKynOBeITiDpuZqIpgwqXShPncPKNiRQoiGsl/T8SQdq+8ugRzH2LqY67irr2y/d+g== + dependencies: + "@hapi/hoek" "^9.3.0" + "@hapi/topo" "^5.1.0" + "@sideway/address" "^4.1.5" + "@sideway/formula" "^3.0.1" + "@sideway/pinpoint" "^2.0.0" + +"js-tokens@^3.0.0 || ^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== + +json-schema@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" + integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== + +json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonwebtoken@^8.5.1: + version "8.5.1" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" + integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== + dependencies: + jws "^3.2.2" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.1.1" + semver "^5.6.0" + +jsprim@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-2.0.2.tgz#77ca23dbcd4135cd364800d22ff82c2185803d4d" + integrity sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ== + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.4.0" + verror "1.10.0" + +jwa@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" + integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== + dependencies: + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" + +jws@^3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" + integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== + dependencies: + jwa "^1.4.1" + safe-buffer "^5.0.1" + +lazy-ass@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/lazy-ass/-/lazy-ass-1.6.0.tgz#7999655e8646c17f089fdd187d150d3324d54513" + integrity sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw== + +listr2@^3.8.3: + version "3.14.0" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-3.14.0.tgz#23101cc62e1375fd5836b248276d1d2b51fdbe9e" + integrity sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g== + dependencies: + cli-truncate "^2.1.0" + colorette "^2.0.16" + log-update "^4.0.0" + p-map "^4.0.0" + rfdc "^1.3.0" + rxjs "^7.5.1" + through "^2.3.8" + wrap-ansi "^7.0.0" + +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w== + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== + +lodash.isempty@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e" + integrity sha512-oKMuF3xEeqDltrGMfDxAPGIVMSSRv8tbRSODbrs4KGsRRLEhrW8N8Rd4DRgB2+621hY8A8XwwrTVhXWpxFvMzg== + +lodash.isfunction@^3.0.9: + version "3.0.9" + resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz#06de25df4db327ac931981d1bdb067e5af68d051" + integrity sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw== + +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA== + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw== + +lodash.isobject@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/lodash.isobject/-/lodash.isobject-3.0.2.tgz#3c8fb8d5b5bf4bf90ae06e14f2a530a4ed935e1d" + integrity sha512-3/Qptq2vr7WeJbB4KHUSKlq8Pl7ASXi3UG6CMbBm8WRtXi8+GHm7mKaU3urfpSEzWe2wCIChs6/sdocUsTKJiA== + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== + +lodash.once@^4.0.0, lodash.once@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== + +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +log-symbols@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +log-update@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" + integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg== + dependencies: + ansi-escapes "^4.3.0" + cli-cursor "^3.1.0" + slice-ansi "^4.0.0" + wrap-ansi "^6.2.0" + +loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12, mime-types@~2.1.19: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +mochawesome-report-generator@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/mochawesome-report-generator/-/mochawesome-report-generator-6.2.0.tgz#65a30a11235ba7a68e1cf0ca1df80d764b93ae78" + integrity sha512-Ghw8JhQFizF0Vjbtp9B0i//+BOkV5OWcQCPpbO0NGOoxV33o+gKDYU0Pr2pGxkIHnqZ+g5mYiXF7GMNgAcDpSg== + dependencies: + chalk "^4.1.2" + dateformat "^4.5.1" + escape-html "^1.0.3" + fs-extra "^10.0.0" + fsu "^1.1.1" + lodash.isfunction "^3.0.9" + opener "^1.5.2" + prop-types "^15.7.2" + tcomb "^3.2.17" + tcomb-validation "^3.3.0" + validator "^13.6.0" + yargs "^17.2.1" + +mochawesome@^7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/mochawesome/-/mochawesome-7.1.3.tgz#07b358138f37f5b07b51a1b255d84babfa36fa83" + integrity sha512-Vkb3jR5GZ1cXohMQQ73H3cZz7RoxGjjUo0G5hu0jLaW+0FdUxUwg3Cj29bqQdh0rFcnyV06pWmqmi5eBPnEuNQ== + dependencies: + chalk "^4.1.2" + diff "^5.0.0" + json-stringify-safe "^5.0.1" + lodash.isempty "^4.4.0" + lodash.isfunction "^3.0.9" + lodash.isobject "^3.0.2" + lodash.isstring "^4.0.1" + mochawesome-report-generator "^6.2.0" + strip-ansi "^6.0.1" + uuid "^8.3.2" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +npm-run-path@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-inspect@^1.9.0: + version "1.12.3" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" + integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== + +obuf@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +opener@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" + integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A== + +ospath@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/ospath/-/ospath-1.2.2.tgz#1276639774a3f8ef2572f7fe4280e0ea4550c07b" + integrity sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA== + +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + +packet-reader@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74" + integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== + +pg-cloudflare@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz#e6d5833015b170e23ae819e8c5d7eaedb472ca98" + integrity sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q== + +pg-connection-string@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.6.2.tgz#713d82053de4e2bd166fab70cd4f26ad36aab475" + integrity sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA== + +pg-int8@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" + integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== + +pg-numeric@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pg-numeric/-/pg-numeric-1.0.2.tgz#816d9a44026086ae8ae74839acd6a09b0636aa3a" + integrity sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw== + +pg-pool@^3.6.1: + version "3.6.1" + resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.6.1.tgz#5a902eda79a8d7e3c928b77abf776b3cb7d351f7" + integrity sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og== + +pg-protocol@*, pg-protocol@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.6.0.tgz#4c91613c0315349363af2084608db843502f8833" + integrity sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q== + +pg-types@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" + integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== + dependencies: + pg-int8 "1.0.1" + postgres-array "~2.0.0" + postgres-bytea "~1.0.0" + postgres-date "~1.0.4" + postgres-interval "^1.1.0" + +pg-types@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-4.0.1.tgz#31857e89d00a6c66b06a14e907c3deec03889542" + integrity sha512-hRCSDuLII9/LE3smys1hRHcu5QGcLs9ggT7I/TCs0IE+2Eesxi9+9RWAAwZ0yaGjxoWICF/YHLOEjydGujoJ+g== + dependencies: + pg-int8 "1.0.1" + pg-numeric "1.0.2" + postgres-array "~3.0.1" + postgres-bytea "~3.0.0" + postgres-date "~2.0.1" + postgres-interval "^3.0.0" + postgres-range "^1.1.1" + +pg@^8.8.0: + version "8.11.3" + resolved "https://registry.yarnpkg.com/pg/-/pg-8.11.3.tgz#d7db6e3fe268fcedd65b8e4599cda0b8b4bf76cb" + integrity sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g== + dependencies: + buffer-writer "2.0.0" + packet-reader "1.0.0" + pg-connection-string "^2.6.2" + pg-pool "^3.6.1" + pg-protocol "^1.6.0" + pg-types "^2.1.0" + pgpass "1.x" + optionalDependencies: + pg-cloudflare "^1.1.1" + +pgpass@1.x: + version "1.0.5" + resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.5.tgz#9b873e4a564bb10fa7a7dbd55312728d422a223d" + integrity sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug== + dependencies: + split2 "^4.1.0" + +pify@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== + +postgres-array@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" + integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== + +postgres-array@~3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-3.0.2.tgz#68d6182cb0f7f152a7e60dc6a6889ed74b0a5f98" + integrity sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog== + +postgres-bytea@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" + integrity sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w== + +postgres-bytea@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-3.0.0.tgz#9048dc461ac7ba70a6a42d109221619ecd1cb089" + integrity sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw== + dependencies: + obuf "~1.1.2" + +postgres-date@~1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8" + integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== + +postgres-date@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-2.0.1.tgz#638b62e5c33764c292d37b08f5257ecb09231457" + integrity sha512-YtMKdsDt5Ojv1wQRvUhnyDJNSr2dGIC96mQVKz7xufp07nfuFONzdaowrMHjlAzY6GDLd4f+LUHHAAM1h4MdUw== + +postgres-interval@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695" + integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ== + dependencies: + xtend "^4.0.0" + +postgres-interval@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-3.0.0.tgz#baf7a8b3ebab19b7f38f07566c7aab0962f0c86a" + integrity sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw== + +postgres-range@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/postgres-range/-/postgres-range-1.1.3.tgz#9ccd7b01ca2789eb3c2e0888b3184225fa859f76" + integrity sha512-VdlZoocy5lCP0c/t66xAfclglEapXPCIVhqqJRncYpvbCgImF0w67aPKfbqUMr72tO2k5q0TdTZwCLjPTI6C9g== + +prettier@^2.7.1: + version "2.8.8" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" + integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== + +pretty-bytes@^5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" + integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg== + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== + +prop-types@^15.7.2: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + +proxy-from-env@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee" + integrity sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A== + +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + +psl@^1.1.33: + version "1.9.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" + integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +punycode@^2.1.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + +qs@6.10.4: + version "6.10.4" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.4.tgz#6a3003755add91c0ec9eacdc5f878b034e73f9e7" + integrity sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g== + dependencies: + side-channel "^1.0.4" + +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + +react-is@^16.13.1: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +request-progress@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/request-progress/-/request-progress-3.0.0.tgz#4ca754081c7fec63f505e4faa825aa06cd669dbe" + integrity sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg== + dependencies: + throttleit "^1.0.0" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +rfdc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" + integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== + +rimraf@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +rxjs@^7.5.1, rxjs@^7.8.1: + version "7.8.1" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" + integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== + dependencies: + tslib "^2.1.0" + +safe-buffer@^5.0.1, safe-buffer@^5.1.2: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +semver@^5.6.0: + version "5.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== + +semver@^7.5.3: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.2: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +slice-ansi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787" + integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +split2@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" + integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== + +sshpk@^1.14.1: + version "1.17.0" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.17.0.tgz#578082d92d4fe612b13007496e543fa0fbcbe4c5" + integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +tcomb-validation@^3.3.0: + version "3.4.1" + resolved "https://registry.yarnpkg.com/tcomb-validation/-/tcomb-validation-3.4.1.tgz#a7696ec176ce56a081d9e019f8b732a5a8894b65" + integrity sha512-urVVMQOma4RXwiVCa2nM2eqrAomHROHvWPuj6UkDGz/eb5kcy0x6P0dVt6kzpUZtYMNoAqJLWmz1BPtxrtjtrA== + dependencies: + tcomb "^3.0.0" + +tcomb@^3.0.0, tcomb@^3.2.17: + version "3.2.29" + resolved "https://registry.yarnpkg.com/tcomb/-/tcomb-3.2.29.tgz#32404fe9456d90c2cf4798682d37439f1ccc386c" + integrity sha512-di2Hd1DB2Zfw6StGv861JoAF5h/uQVu/QJp2g8KVbtfKnoHdBQl5M32YWq6mnSYBQ1vFFrns5B1haWJL7rKaOQ== + +throttleit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" + integrity sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g== + +through@^2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + +tmp@~0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" + integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== + dependencies: + rimraf "^3.0.0" + +tough-cookie@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" + integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.2.0" + url-parse "^1.5.3" + +tslib@^2.1.0: + version "2.6.2" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" + integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +typescript@^4.8.4: + version "4.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" + integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== + +universalify@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" + integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== + +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + +untildify@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" + integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== + +url-parse@^1.5.3: + version "1.5.10" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" + integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +uuid@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + +validator@^13.6.0: + version "13.11.0" + resolved "https://registry.yarnpkg.com/validator/-/validator-13.11.0.tgz#23ab3fd59290c61248364eabf4067f04955fbb1b" + integrity sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ== + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw== + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +wait-on@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/wait-on/-/wait-on-7.2.0.tgz#d76b20ed3fc1e2bebc051fae5c1ff93be7892928" + integrity sha512-wCQcHkRazgjG5XoAq9jbTMLpNIjoSlZslrJ2+N9MxDsGEv1HnFoVjOCexL0ESva7Y9cu350j+DWADdk54s4AFQ== + dependencies: + axios "^1.6.1" + joi "^17.11.0" + lodash "^4.17.21" + minimist "^1.2.8" + rxjs "^7.8.1" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +xtend@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.2.1: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + +yauzl@^2.10.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + integrity sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g== + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.1.0" diff --git a/internal/api/grpc/admin/iam_settings.go b/internal/api/grpc/admin/iam_settings.go index dde4100c32..04ca77305d 100644 --- a/internal/api/grpc/admin/iam_settings.go +++ b/internal/api/grpc/admin/iam_settings.go @@ -3,7 +3,6 @@ package admin import ( "context" - "github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/grpc/object" admin_pb "github.com/zitadel/zitadel/pkg/grpc/admin" ) @@ -46,68 +45,6 @@ func (s *Server) UpdateSecretGenerator(ctx context.Context, req *admin_pb.Update }, nil } -func (s *Server) GetSMTPConfig(ctx context.Context, req *admin_pb.GetSMTPConfigRequest) (*admin_pb.GetSMTPConfigResponse, error) { - smtp, err := s.query.SMTPConfigByAggregateID(ctx, authz.GetInstance(ctx).InstanceID()) - if err != nil { - return nil, err - } - return &admin_pb.GetSMTPConfigResponse{ - SmtpConfig: SMTPConfigToPb(smtp), - }, nil -} - -func (s *Server) AddSMTPConfig(ctx context.Context, req *admin_pb.AddSMTPConfigRequest) (*admin_pb.AddSMTPConfigResponse, error) { - details, err := s.command.AddSMTPConfig(ctx, AddSMTPToConfig(req)) - if err != nil { - return nil, err - } - return &admin_pb.AddSMTPConfigResponse{ - Details: object.ChangeToDetailsPb( - details.Sequence, - details.EventDate, - details.ResourceOwner), - }, nil -} - -func (s *Server) UpdateSMTPConfig(ctx context.Context, req *admin_pb.UpdateSMTPConfigRequest) (*admin_pb.UpdateSMTPConfigResponse, error) { - details, err := s.command.ChangeSMTPConfig(ctx, UpdateSMTPToConfig(req)) - if err != nil { - return nil, err - } - return &admin_pb.UpdateSMTPConfigResponse{ - Details: object.ChangeToDetailsPb( - details.Sequence, - details.EventDate, - details.ResourceOwner), - }, nil -} - -func (s *Server) RemoveSMTPConfig(ctx context.Context, _ *admin_pb.RemoveSMTPConfigRequest) (*admin_pb.RemoveSMTPConfigResponse, error) { - details, err := s.command.RemoveSMTPConfig(ctx) - if err != nil { - return nil, err - } - return &admin_pb.RemoveSMTPConfigResponse{ - Details: object.ChangeToDetailsPb( - details.Sequence, - details.EventDate, - details.ResourceOwner), - }, nil -} - -func (s *Server) UpdateSMTPConfigPassword(ctx context.Context, req *admin_pb.UpdateSMTPConfigPasswordRequest) (*admin_pb.UpdateSMTPConfigPasswordResponse, error) { - details, err := s.command.ChangeSMTPConfigPassword(ctx, req.Password) - if err != nil { - return nil, err - } - return &admin_pb.UpdateSMTPConfigPasswordResponse{ - Details: object.ChangeToDetailsPb( - details.Sequence, - details.EventDate, - details.ResourceOwner), - }, nil -} - func (s *Server) GetSecurityPolicy(ctx context.Context, req *admin_pb.GetSecurityPolicyRequest) (*admin_pb.GetSecurityPolicyResponse, error) { policy, err := s.query.SecurityPolicy(ctx) if err != nil { diff --git a/internal/api/grpc/admin/iam_settings_converter.go b/internal/api/grpc/admin/iam_settings_converter.go index 8fd1a26f06..66e0dd3653 100644 --- a/internal/api/grpc/admin/iam_settings_converter.go +++ b/internal/api/grpc/admin/iam_settings_converter.go @@ -133,6 +133,7 @@ func SecretGeneratorTypeToDomain(generatorType settings_pb.SecretGeneratorType) func AddSMTPToConfig(req *admin_pb.AddSMTPConfigRequest) *smtp.Config { return &smtp.Config{ + Description: req.Description, Tls: req.Tls, From: req.SenderAddress, FromName: req.SenderName, @@ -147,26 +148,30 @@ func AddSMTPToConfig(req *admin_pb.AddSMTPConfigRequest) *smtp.Config { func UpdateSMTPToConfig(req *admin_pb.UpdateSMTPConfigRequest) *smtp.Config { return &smtp.Config{ + Description: req.Description, Tls: req.Tls, From: req.SenderAddress, FromName: req.SenderName, ReplyToAddress: req.ReplyToAddress, SMTP: smtp.SMTP{ - Host: req.Host, - User: req.User, + Host: req.Host, + User: req.User, + Password: req.Password, }, } } func SMTPConfigToPb(smtp *query.SMTPConfig) *settings_pb.SMTPConfig { mapped := &settings_pb.SMTPConfig{ + Description: smtp.Description, Tls: smtp.TLS, SenderAddress: smtp.SenderAddress, SenderName: smtp.SenderName, ReplyToAddress: smtp.ReplyToAddress, Host: smtp.Host, User: smtp.User, - Details: obj_grpc.ToViewDetailsPb(smtp.Sequence, smtp.CreationDate, smtp.ChangeDate, smtp.AggregateID), + Details: obj_grpc.ToViewDetailsPb(smtp.Sequence, smtp.CreationDate, smtp.ChangeDate, smtp.ResourceOwner), + Id: smtp.ID, } return mapped } diff --git a/internal/api/grpc/admin/smtp.go b/internal/api/grpc/admin/smtp.go new file mode 100644 index 0000000000..c06e3654da --- /dev/null +++ b/internal/api/grpc/admin/smtp.go @@ -0,0 +1,130 @@ +package admin + +import ( + "context" + + "github.com/zitadel/zitadel/internal/api/authz" + "github.com/zitadel/zitadel/internal/api/grpc/object" + admin_pb "github.com/zitadel/zitadel/pkg/grpc/admin" +) + +func (s *Server) GetSMTPConfig(ctx context.Context, req *admin_pb.GetSMTPConfigRequest) (*admin_pb.GetSMTPConfigResponse, error) { + smtp, err := s.query.SMTPConfigActive(ctx, authz.GetInstance(ctx).InstanceID()) + if err != nil { + return nil, err + } + return &admin_pb.GetSMTPConfigResponse{ + SmtpConfig: SMTPConfigToPb(smtp), + }, nil +} + +func (s *Server) GetSMTPConfigById(ctx context.Context, req *admin_pb.GetSMTPConfigByIdRequest) (*admin_pb.GetSMTPConfigByIdResponse, error) { + instanceID := authz.GetInstance(ctx).InstanceID() + resourceOwner := instanceID // Will be replaced when orgs have smtp configs + + smtp, err := s.query.SMTPConfigByID(ctx, instanceID, resourceOwner, req.Id) + if err != nil { + return nil, err + } + return &admin_pb.GetSMTPConfigByIdResponse{ + SmtpConfig: SMTPConfigToPb(smtp), + }, nil +} + +func (s *Server) AddSMTPConfig(ctx context.Context, req *admin_pb.AddSMTPConfigRequest) (*admin_pb.AddSMTPConfigResponse, error) { + id, details, err := s.command.AddSMTPConfig(ctx, authz.GetInstance(ctx).InstanceID(), AddSMTPToConfig(req)) + if err != nil { + return nil, err + } + return &admin_pb.AddSMTPConfigResponse{ + Details: object.ChangeToDetailsPb( + details.Sequence, + details.EventDate, + details.ResourceOwner), + Id: id, + }, nil +} + +func (s *Server) UpdateSMTPConfig(ctx context.Context, req *admin_pb.UpdateSMTPConfigRequest) (*admin_pb.UpdateSMTPConfigResponse, error) { + details, err := s.command.ChangeSMTPConfig(ctx, authz.GetInstance(ctx).InstanceID(), req.Id, UpdateSMTPToConfig(req)) + if err != nil { + return nil, err + } + return &admin_pb.UpdateSMTPConfigResponse{ + Details: object.ChangeToDetailsPb( + details.Sequence, + details.EventDate, + details.ResourceOwner), + }, nil +} + +func (s *Server) RemoveSMTPConfig(ctx context.Context, req *admin_pb.RemoveSMTPConfigRequest) (*admin_pb.RemoveSMTPConfigResponse, error) { + details, err := s.command.RemoveSMTPConfig(ctx, authz.GetInstance(ctx).InstanceID(), req.Id) + if err != nil { + return nil, err + } + return &admin_pb.RemoveSMTPConfigResponse{ + Details: object.ChangeToDetailsPb( + details.Sequence, + details.EventDate, + details.ResourceOwner), + }, nil +} + +func (s *Server) UpdateSMTPConfigPassword(ctx context.Context, req *admin_pb.UpdateSMTPConfigPasswordRequest) (*admin_pb.UpdateSMTPConfigPasswordResponse, error) { + details, err := s.command.ChangeSMTPConfigPassword(ctx, authz.GetInstance(ctx).InstanceID(), req.Id, req.Password) + if err != nil { + return nil, err + } + return &admin_pb.UpdateSMTPConfigPasswordResponse{ + Details: object.ChangeToDetailsPb( + details.Sequence, + details.EventDate, + details.ResourceOwner), + }, nil +} + +func (s *Server) ListSMTPConfigs(ctx context.Context, req *admin_pb.ListSMTPConfigsRequest) (*admin_pb.ListSMTPConfigsResponse, error) { + queries, err := listSMTPConfigsToModel(req) + if err != nil { + return nil, err + } + result, err := s.query.SearchSMTPConfigs(ctx, queries) + if err != nil { + return nil, err + } + return &admin_pb.ListSMTPConfigsResponse{ + Details: object.ToListDetails(result.Count, result.Sequence, result.LastRun), + Result: SMTPConfigsToPb(result.Configs), + }, nil +} + +func (s *Server) ActivateSMTPConfig(ctx context.Context, req *admin_pb.ActivateSMTPConfigRequest) (*admin_pb.ActivateSMTPConfigResponse, error) { + // Get the ID of current SMTP active provider if any + currentActiveProviderID := "" + smtp, err := s.query.SMTPConfigActive(ctx, authz.GetInstance(ctx).InstanceID()) + if err == nil { + currentActiveProviderID = smtp.ID + } + + result, err := s.command.ActivateSMTPConfig(ctx, authz.GetInstance(ctx).InstanceID(), req.Id, currentActiveProviderID) + if err != nil { + return nil, err + + } + + return &admin_pb.ActivateSMTPConfigResponse{ + Details: object.DomainToAddDetailsPb(result), + }, nil +} + +func (s *Server) DeactivateSMTPConfig(ctx context.Context, req *admin_pb.DeactivateSMTPConfigRequest) (*admin_pb.DeactivateSMTPConfigResponse, error) { + result, err := s.command.DeactivateSMTPConfig(ctx, authz.GetInstance(ctx).InstanceID(), req.Id) + if err != nil { + return nil, err + + } + return &admin_pb.DeactivateSMTPConfigResponse{ + Details: object.DomainToAddDetailsPb(result), + }, nil +} diff --git a/internal/api/grpc/admin/smtp_converters.go b/internal/api/grpc/admin/smtp_converters.go new file mode 100644 index 0000000000..2ebeed58ef --- /dev/null +++ b/internal/api/grpc/admin/smtp_converters.go @@ -0,0 +1,41 @@ +package admin + +import ( + "github.com/zitadel/zitadel/internal/api/grpc/object" + "github.com/zitadel/zitadel/internal/query" + admin_pb "github.com/zitadel/zitadel/pkg/grpc/admin" + settings_pb "github.com/zitadel/zitadel/pkg/grpc/settings" +) + +func listSMTPConfigsToModel(req *admin_pb.ListSMTPConfigsRequest) (*query.SMTPConfigsSearchQueries, error) { + offset, limit, asc := object.ListQueryToModel(req.Query) + return &query.SMTPConfigsSearchQueries{ + SearchRequest: query.SearchRequest{ + Offset: offset, + Limit: limit, + Asc: asc, + }, + }, nil +} + +func SMTPConfigToProviderPb(config *query.SMTPConfig) *settings_pb.SMTPConfig { + return &settings_pb.SMTPConfig{ + Details: object.ToViewDetailsPb(config.Sequence, config.CreationDate, config.ChangeDate, config.ResourceOwner), + Id: config.ID, + Description: config.Description, + Tls: config.TLS, + Host: config.Host, + User: config.User, + State: settings_pb.SMTPConfigState(config.State), + SenderAddress: config.SenderAddress, + SenderName: config.SenderName, + } +} + +func SMTPConfigsToPb(configs []*query.SMTPConfig) []*settings_pb.SMTPConfig { + c := make([]*settings_pb.SMTPConfig, len(configs)) + for i, config := range configs { + c[i] = SMTPConfigToProviderPb(config) + } + return c +} diff --git a/internal/command/instance.go b/internal/command/instance.go index f9f9121889..4bd3194706 100644 --- a/internal/command/instance.go +++ b/internal/command/instance.go @@ -391,6 +391,7 @@ func setupSMTPSettings(commands *Commands, validations *[]preparation.Validation *validations = append(*validations, commands.prepareAddSMTPConfig( instanceAgg, + smtpConfig.Description, smtpConfig.From, smtpConfig.FromName, smtpConfig.ReplyToAddress, diff --git a/internal/command/instance_model.go b/internal/command/instance_model.go index 98d49926bf..59223936b5 100644 --- a/internal/command/instance_model.go +++ b/internal/command/instance_model.go @@ -82,5 +82,11 @@ func (wm *InstanceWriteModel) Query() *eventstore.SearchQueryBuilder { } func InstanceAggregateFromWriteModel(wm *eventstore.WriteModel) *eventstore.Aggregate { - return eventstore.AggregateFromWriteModel(wm, instance.AggregateType, instance.AggregateVersion) + return &eventstore.Aggregate{ + ID: wm.AggregateID, + Type: instance.AggregateType, + ResourceOwner: wm.ResourceOwner, + InstanceID: wm.InstanceID, + Version: instance.AggregateVersion, + } } diff --git a/internal/command/instance_smtp_config_model.go b/internal/command/instance_smtp_config_model.go index ee2c20700a..e165419093 100644 --- a/internal/command/instance_smtp_config_model.go +++ b/internal/command/instance_smtp_config_model.go @@ -9,16 +9,18 @@ import ( "github.com/zitadel/zitadel/internal/repository/instance" ) -type InstanceSMTPConfigWriteModel struct { +type IAMSMTPConfigWriteModel struct { eventstore.WriteModel - SenderAddress string - SenderName string - ReplyToAddress string + ID string + Description string TLS bool Host string User string Password *crypto.CryptoValue + SenderAddress string + SenderName string + ReplyToAddress string State domain.SMTPConfigState domain string @@ -26,17 +28,19 @@ type InstanceSMTPConfigWriteModel struct { smtpSenderAddressMatchesInstanceDomain bool } -func NewInstanceSMTPConfigWriteModel(instanceID, domain string) *InstanceSMTPConfigWriteModel { - return &InstanceSMTPConfigWriteModel{ +func NewIAMSMTPConfigWriteModel(instanceID, id, domain string) *IAMSMTPConfigWriteModel { + return &IAMSMTPConfigWriteModel{ WriteModel: eventstore.WriteModel{ AggregateID: instanceID, ResourceOwner: instanceID, + InstanceID: instanceID, }, + ID: id, domain: domain, } } -func (wm *InstanceSMTPConfigWriteModel) AppendEvents(events ...eventstore.Event) { +func (wm *IAMSMTPConfigWriteModel) AppendEvents(events ...eventstore.Event) { for _, event := range events { switch e := event.(type) { case *instance.DomainAddedEvent: @@ -56,46 +60,34 @@ func (wm *InstanceSMTPConfigWriteModel) AppendEvents(events ...eventstore.Event) } } -func (wm *InstanceSMTPConfigWriteModel) Reduce() error { +func (wm *IAMSMTPConfigWriteModel) Reduce() error { for _, event := range wm.Events { switch e := event.(type) { case *instance.SMTPConfigAddedEvent: - wm.TLS = e.TLS - wm.SenderAddress = e.SenderAddress - wm.SenderName = e.SenderName - wm.ReplyToAddress = e.ReplyToAddress - wm.Host = e.Host - wm.User = e.User - wm.Password = e.Password - wm.State = domain.SMTPConfigStateActive + if wm.ID != e.ID { + continue + } + wm.reduceSMTPConfigAddedEvent(e) case *instance.SMTPConfigChangedEvent: - if e.TLS != nil { - wm.TLS = *e.TLS - } - if e.FromAddress != nil { - wm.SenderAddress = *e.FromAddress - } - if e.FromName != nil { - wm.SenderName = *e.FromName - } - if e.ReplyToAddress != nil { - wm.ReplyToAddress = *e.ReplyToAddress - } - if e.Host != nil { - wm.Host = *e.Host - } - if e.User != nil { - wm.User = *e.User + if wm.ID != e.ID { + continue } + wm.reduceSMTPConfigChangedEvent(e) case *instance.SMTPConfigRemovedEvent: - wm.State = domain.SMTPConfigStateRemoved - wm.TLS = false - wm.SenderName = "" - wm.SenderAddress = "" - wm.ReplyToAddress = "" - wm.Host = "" - wm.User = "" - wm.Password = nil + if wm.ID != e.ID { + continue + } + wm.reduceSMTPConfigRemovedEvent(e) + case *instance.SMTPConfigActivatedEvent: + if wm.ID != e.ID { + continue + } + wm.State = domain.SMTPConfigStateActive + case *instance.SMTPConfigDeactivatedEvent: + if wm.ID != e.ID { + continue + } + wm.State = domain.SMTPConfigStateInactive case *instance.DomainAddedEvent: wm.domainState = domain.InstanceDomainStateActive case *instance.DomainRemovedEvent: @@ -111,7 +103,13 @@ func (wm *InstanceSMTPConfigWriteModel) Reduce() error { return wm.WriteModel.Reduce() } -func (wm *InstanceSMTPConfigWriteModel) Query() *eventstore.SearchQueryBuilder { +func (wm *IAMSMTPConfigWriteModel) Query() *eventstore.SearchQueryBuilder { + // If ID equals ResourceOwner we're dealing with the old and unique smtp settings + // Let's set the empty ID for the query + if wm.ID == wm.ResourceOwner { + wm.ID = "" + } + return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent). ResourceOwner(wm.ResourceOwner). AddQuery(). @@ -122,6 +120,9 @@ func (wm *InstanceSMTPConfigWriteModel) Query() *eventstore.SearchQueryBuilder { instance.SMTPConfigRemovedEventType, instance.SMTPConfigChangedEventType, instance.SMTPConfigPasswordChangedEventType, + instance.SMTPConfigActivatedEventType, + instance.SMTPConfigDeactivatedEventType, + instance.SMTPConfigRemovedEventType, instance.InstanceDomainAddedEventType, instance.InstanceDomainRemovedEventType, instance.DomainPolicyAddedEventType, @@ -129,10 +130,16 @@ func (wm *InstanceSMTPConfigWriteModel) Query() *eventstore.SearchQueryBuilder { Builder() } -func (wm *InstanceSMTPConfigWriteModel) NewChangedEvent(ctx context.Context, aggregate *eventstore.Aggregate, tls bool, fromAddress, fromName, replyToAddress, smtpHost, smtpUser string) (*instance.SMTPConfigChangedEvent, bool, error) { +func (wm *IAMSMTPConfigWriteModel) NewChangedEvent(ctx context.Context, aggregate *eventstore.Aggregate, id, description string, tls bool, fromAddress, fromName, replyToAddress, smtpHost, smtpUser string, smtpPassword *crypto.CryptoValue) (*instance.SMTPConfigChangedEvent, bool, error) { changes := make([]instance.SMTPConfigChanges, 0) var err error + if wm.ID != id { + changes = append(changes, instance.ChangeSMTPConfigID(id)) + } + if wm.Description != description { + changes = append(changes, instance.ChangeSMTPConfigDescription(description)) + } if wm.TLS != tls { changes = append(changes, instance.ChangeSMTPConfigTLS(tls)) } @@ -151,13 +158,87 @@ func (wm *InstanceSMTPConfigWriteModel) NewChangedEvent(ctx context.Context, agg if wm.User != smtpUser { changes = append(changes, instance.ChangeSMTPConfigSMTPUser(smtpUser)) } - + if smtpPassword != nil { + changes = append(changes, instance.ChangeSMTPConfigSMTPPassword(smtpPassword)) + } if len(changes) == 0 { return nil, false, nil } - changeEvent, err := instance.NewSMTPConfigChangeEvent(ctx, aggregate, changes) + changeEvent, err := instance.NewSMTPConfigChangeEvent(ctx, aggregate, id, changes) if err != nil { return nil, false, err } return changeEvent, true, nil } + +func (wm *IAMSMTPConfigWriteModel) reduceSMTPConfigAddedEvent(e *instance.SMTPConfigAddedEvent) { + wm.Description = e.Description + wm.TLS = e.TLS + wm.Host = e.Host + wm.User = e.User + wm.Password = e.Password + wm.SenderAddress = e.SenderAddress + wm.SenderName = e.SenderName + wm.ReplyToAddress = e.ReplyToAddress + wm.State = domain.SMTPConfigStateInactive + // If ID has empty value we're dealing with the old and unique smtp settings + // These would be the default values for ID and State + if e.ID == "" { + wm.Description = "generic" + wm.ID = e.Aggregate().ResourceOwner + wm.State = domain.SMTPConfigStateActive + } +} + +func (wm *IAMSMTPConfigWriteModel) reduceSMTPConfigChangedEvent(e *instance.SMTPConfigChangedEvent) { + if e.Description != nil { + wm.Description = *e.Description + } + if e.TLS != nil { + wm.TLS = *e.TLS + } + if e.Host != nil { + wm.Host = *e.Host + } + if e.User != nil { + wm.User = *e.User + } + if e.Password != nil { + wm.Password = e.Password + } + if e.FromAddress != nil { + wm.SenderAddress = *e.FromAddress + } + if e.FromName != nil { + wm.SenderName = *e.FromName + } + if e.ReplyToAddress != nil { + wm.ReplyToAddress = *e.ReplyToAddress + } + + // If ID has empty value we're dealing with the old and unique smtp settings + // These would be the default values for ID and State + if e.ID == "" { + wm.Description = "generic" + wm.ID = e.Aggregate().ResourceOwner + wm.State = domain.SMTPConfigStateActive + } +} + +func (wm *IAMSMTPConfigWriteModel) reduceSMTPConfigRemovedEvent(e *instance.SMTPConfigRemovedEvent) { + wm.Description = "" + wm.TLS = false + wm.SenderName = "" + wm.SenderAddress = "" + wm.ReplyToAddress = "" + wm.Host = "" + wm.User = "" + wm.Password = nil + wm.State = domain.SMTPConfigStateRemoved + + // If ID has empty value we're dealing with the old and unique smtp settings + // These would be the default values for ID and State + if e.ID == "" { + wm.ID = e.Aggregate().ResourceOwner + } +} diff --git a/internal/command/smtp.go b/internal/command/smtp.go index c52dd98f0c..fc51cabd59 100644 --- a/internal/command/smtp.go +++ b/internal/command/smtp.go @@ -15,51 +15,153 @@ import ( "github.com/zitadel/zitadel/internal/zerrors" ) -func (c *Commands) AddSMTPConfig(ctx context.Context, config *smtp.Config) (*domain.ObjectDetails, error) { - instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID()) - validation := c.prepareAddSMTPConfig(instanceAgg, config.From, config.FromName, config.ReplyToAddress, config.SMTP.Host, config.SMTP.User, []byte(config.SMTP.Password), config.Tls) - cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, validation) +func (c *Commands) AddSMTPConfig(ctx context.Context, instanceID string, config *smtp.Config) (string, *domain.ObjectDetails, error) { + id, err := c.idGenerator.Next() if err != nil { - return nil, err + return "", nil, err } - events, err := c.eventstore.Push(ctx, cmds...) + + from := strings.TrimSpace(config.From) + if from == "" { + return "", nil, zerrors.ThrowInvalidArgument(nil, "INST-ASv2d", "Errors.Invalid.Argument") + } + fromSplitted := strings.Split(from, "@") + senderDomain := fromSplitted[len(fromSplitted)-1] + description := strings.TrimSpace(config.Description) + replyTo := strings.TrimSpace(config.ReplyToAddress) + hostAndPort := strings.TrimSpace(config.SMTP.Host) + + if _, _, err := net.SplitHostPort(hostAndPort); err != nil { + return "", nil, zerrors.ThrowInvalidArgument(nil, "INST-9JdRe", "Errors.Invalid.Argument") + } + + var smtpPassword *crypto.CryptoValue + if config.SMTP.Password != "" { + smtpPassword, err = crypto.Encrypt([]byte(config.SMTP.Password), c.smtpEncryption) + if err != nil { + return "", nil, err + } + } + + smtpConfigWriteModel, err := c.getSMTPConfig(ctx, instanceID, id, senderDomain) if err != nil { - return nil, err + return "", nil, err } - return &domain.ObjectDetails{ - Sequence: events[len(events)-1].Sequence(), - EventDate: events[len(events)-1].CreatedAt(), - ResourceOwner: events[len(events)-1].Aggregate().InstanceID, - }, nil + + err = checkSenderAddress(smtpConfigWriteModel) + if err != nil { + return "", nil, err + } + + iamAgg := InstanceAggregateFromWriteModel(&smtpConfigWriteModel.WriteModel) + pushedEvents, err := c.eventstore.Push(ctx, instance.NewSMTPConfigAddedEvent( + ctx, + iamAgg, + id, + description, + config.Tls, + config.From, + config.FromName, + replyTo, + hostAndPort, + config.SMTP.User, + smtpPassword, + )) + if err != nil { + return "", nil, err + } + + err = AppendAndReduce(smtpConfigWriteModel, pushedEvents...) + if err != nil { + return "", nil, err + } + return id, writeModelToObjectDetails(&smtpConfigWriteModel.WriteModel), nil } -func (c *Commands) ChangeSMTPConfig(ctx context.Context, config *smtp.Config) (*domain.ObjectDetails, error) { - instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID()) - validation := c.prepareChangeSMTPConfig(instanceAgg, config.From, config.FromName, config.ReplyToAddress, config.SMTP.Host, config.SMTP.User, config.Tls) - cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, validation) +func (c *Commands) ChangeSMTPConfig(ctx context.Context, instanceID string, id string, config *smtp.Config) (*domain.ObjectDetails, error) { + if id == "" { + return nil, zerrors.ThrowInvalidArgument(nil, "SMTP-x8vo9", "Errors.IDMissing") + } + + from := strings.TrimSpace(config.From) + if from == "" { + return nil, zerrors.ThrowInvalidArgument(nil, "INST-HSv2d", "Errors.Invalid.Argument") + } + fromSplitted := strings.Split(from, "@") + senderDomain := fromSplitted[len(fromSplitted)-1] + description := strings.TrimSpace(config.Description) + replyTo := strings.TrimSpace(config.ReplyToAddress) + hostAndPort := strings.TrimSpace(config.SMTP.Host) + if _, _, err := net.SplitHostPort(hostAndPort); err != nil { + return nil, zerrors.ThrowInvalidArgument(nil, "INST-Kv875", "Errors.Invalid.Argument") + } + + var smtpPassword *crypto.CryptoValue + var err error + if config.SMTP.Password != "" { + smtpPassword, err = crypto.Encrypt([]byte(config.SMTP.Password), c.smtpEncryption) + if err != nil { + return nil, err + } + } + + smtpConfigWriteModel, err := c.getSMTPConfig(ctx, instanceID, id, senderDomain) if err != nil { return nil, err } - events, err := c.eventstore.Push(ctx, cmds...) + + if !smtpConfigWriteModel.State.Exists() { + return nil, zerrors.ThrowNotFound(nil, "COMMAND-7j8gv", "Errors.SMTPConfig.NotFound") + } + + err = checkSenderAddress(smtpConfigWriteModel) if err != nil { return nil, err } - return &domain.ObjectDetails{ - Sequence: events[len(events)-1].Sequence(), - EventDate: events[len(events)-1].CreatedAt(), - ResourceOwner: events[len(events)-1].Aggregate().InstanceID, - }, nil + + iamAgg := InstanceAggregateFromWriteModel(&smtpConfigWriteModel.WriteModel) + + changedEvent, hasChanged, err := smtpConfigWriteModel.NewChangedEvent( + ctx, + iamAgg, + id, + description, + config.Tls, + from, + config.FromName, + replyTo, + hostAndPort, + config.SMTP.User, + smtpPassword, + ) + if err != nil { + return nil, err + } + if !hasChanged { + return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-lh3op", "Errors.NoChangesFound") + } + + pushedEvents, err := c.eventstore.Push(ctx, changedEvent) + if err != nil { + return nil, err + } + err = AppendAndReduce(smtpConfigWriteModel, pushedEvents...) + if err != nil { + return nil, err + } + return writeModelToObjectDetails(&smtpConfigWriteModel.WriteModel), nil } -func (c *Commands) ChangeSMTPConfigPassword(ctx context.Context, password string) (*domain.ObjectDetails, error) { +func (c *Commands) ChangeSMTPConfigPassword(ctx context.Context, instanceID, id string, password string) (*domain.ObjectDetails, error) { instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID()) - smtpConfigWriteModel, err := getSMTPConfigWriteModel(ctx, c.eventstore.Filter, "") + smtpConfigWriteModel, err := c.getSMTPConfig(ctx, instanceID, id, "") if err != nil { return nil, err } if smtpConfigWriteModel.State != domain.SMTPConfigStateActive { return nil, zerrors.ThrowNotFound(nil, "COMMAND-3n9ls", "Errors.SMTPConfig.NotFound") } + var smtpPassword *crypto.CryptoValue if password != "" { smtpPassword, err = crypto.Encrypt([]byte(password), c.smtpEncryption) @@ -67,39 +169,144 @@ func (c *Commands) ChangeSMTPConfigPassword(ctx context.Context, password string return nil, err } } - events, err := c.eventstore.Push(ctx, instance.NewSMTPConfigPasswordChangedEvent( + + pushedEvents, err := c.eventstore.Push(ctx, instance.NewSMTPConfigPasswordChangedEvent( ctx, &instanceAgg.Aggregate, + id, smtpPassword)) if err != nil { return nil, err } - return &domain.ObjectDetails{ - Sequence: events[len(events)-1].Sequence(), - EventDate: events[len(events)-1].CreatedAt(), - ResourceOwner: events[len(events)-1].Aggregate().InstanceID, - }, nil -} - -func (c *Commands) RemoveSMTPConfig(ctx context.Context) (*domain.ObjectDetails, error) { - instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID()) - validation := c.prepareRemoveSMTPConfig(instanceAgg) - cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, validation) + err = AppendAndReduce(smtpConfigWriteModel, pushedEvents...) if err != nil { return nil, err } - events, err := c.eventstore.Push(ctx, cmds...) + + return writeModelToObjectDetails(&smtpConfigWriteModel.WriteModel), nil +} + +func (c *Commands) ActivateSMTPConfig(ctx context.Context, instanceID, id, activatedId string) (*domain.ObjectDetails, error) { + if id == "" { + return nil, zerrors.ThrowInvalidArgument(nil, "SMTP-nm56k", "Errors.IDMissing") + } + + if len(activatedId) > 0 { + _, err := c.DeactivateSMTPConfig(ctx, instanceID, activatedId) + if err != nil { + return nil, err + } + } + + smtpConfigWriteModel, err := c.getSMTPConfig(ctx, instanceID, id, "") if err != nil { return nil, err } - return &domain.ObjectDetails{ - Sequence: events[len(events)-1].Sequence(), - EventDate: events[len(events)-1].CreatedAt(), - ResourceOwner: events[len(events)-1].Aggregate().InstanceID, - }, nil + + if !smtpConfigWriteModel.State.Exists() { + return nil, zerrors.ThrowNotFound(nil, "COMMAND-kg8yr", "Errors.SMTPConfig.NotFound") + } + + if smtpConfigWriteModel.State == domain.SMTPConfigStateActive { + return nil, zerrors.ThrowNotFound(nil, "COMMAND-ed3lr", "Errors.SMTPConfig.AlreadyActive") + } + + iamAgg := InstanceAggregateFromWriteModel(&smtpConfigWriteModel.WriteModel) + pushedEvents, err := c.eventstore.Push(ctx, instance.NewSMTPConfigActivatedEvent( + ctx, + iamAgg, + id)) + if err != nil { + return nil, err + } + err = AppendAndReduce(smtpConfigWriteModel, pushedEvents...) + if err != nil { + return nil, err + } + return writeModelToObjectDetails(&smtpConfigWriteModel.WriteModel), nil } -func (c *Commands) prepareAddSMTPConfig(a *instance.Aggregate, from, name, replyTo, hostAndPort, user string, password []byte, tls bool) preparation.Validation { +func (c *Commands) DeactivateSMTPConfig(ctx context.Context, instanceID, id string) (*domain.ObjectDetails, error) { + if id == "" { + return nil, zerrors.ThrowInvalidArgument(nil, "SMTP-98ikl", "Errors.IDMissing") + } + + smtpConfigWriteModel, err := c.getSMTPConfig(ctx, instanceID, id, "") + if err != nil { + return nil, err + } + if !smtpConfigWriteModel.State.Exists() { + return nil, zerrors.ThrowNotFound(nil, "COMMAND-k39PJ", "Errors.SMTPConfig.NotFound") + } + if smtpConfigWriteModel.State == domain.SMTPConfigStateInactive { + return nil, zerrors.ThrowNotFound(nil, "COMMAND-km8g3", "Errors.SMTPConfig.AlreadyDeactivated") + } + + iamAgg := InstanceAggregateFromWriteModel(&smtpConfigWriteModel.WriteModel) + pushedEvents, err := c.eventstore.Push(ctx, instance.NewSMTPConfigDeactivatedEvent( + ctx, + iamAgg, + id)) + if err != nil { + return nil, err + } + err = AppendAndReduce(smtpConfigWriteModel, pushedEvents...) + if err != nil { + return nil, err + } + return writeModelToObjectDetails(&smtpConfigWriteModel.WriteModel), nil +} + +func (c *Commands) RemoveSMTPConfig(ctx context.Context, instanceID, id string) (*domain.ObjectDetails, error) { + if id == "" { + return nil, zerrors.ThrowInvalidArgument(nil, "SMTP-7f5cv", "Errors.IDMissing") + } + + smtpConfigWriteModel, err := c.getSMTPConfig(ctx, instanceID, id, "") + if err != nil { + return nil, err + } + if !smtpConfigWriteModel.State.Exists() { + return nil, zerrors.ThrowNotFound(nil, "COMMAND-kg8rt", "Errors.SMTPConfig.NotFound") + } + + iamAgg := InstanceAggregateFromWriteModel(&smtpConfigWriteModel.WriteModel) + pushedEvents, err := c.eventstore.Push(ctx, instance.NewSMTPConfigRemovedEvent( + ctx, + iamAgg, + id)) + if err != nil { + return nil, err + } + err = AppendAndReduce(smtpConfigWriteModel, pushedEvents...) + if err != nil { + return nil, err + } + return writeModelToObjectDetails(&smtpConfigWriteModel.WriteModel), nil +} + +func checkSenderAddress(writeModel *IAMSMTPConfigWriteModel) error { + if !writeModel.smtpSenderAddressMatchesInstanceDomain { + return nil + } + if !writeModel.domainState.Exists() { + return zerrors.ThrowInvalidArgument(nil, "INST-83nl8", "Errors.SMTPConfig.SenderAdressNotCustomDomain") + } + return nil +} + +func (c *Commands) getSMTPConfig(ctx context.Context, instanceID, id, domain string) (writeModel *IAMSMTPConfigWriteModel, err error) { + writeModel = NewIAMSMTPConfigWriteModel(instanceID, id, domain) + err = c.eventstore.FilterToQueryReducer(ctx, writeModel) + if err != nil { + return nil, err + } + + return writeModel, nil +} + +// TODO: SetUpInstance still uses this and would be removed as soon as deprecated PrepareCommands is removed +func (c *Commands) prepareAddSMTPConfig(a *instance.Aggregate, description, from, name, replyTo, hostAndPort, user string, password []byte, tls bool) preparation.Validation { return func() (preparation.CreateCommands, error) { if from = strings.TrimSpace(from); from == "" { return nil, zerrors.ThrowInvalidArgument(nil, "INST-mruNY", "Errors.Invalid.Argument") @@ -112,9 +319,14 @@ func (c *Commands) prepareAddSMTPConfig(a *instance.Aggregate, from, name, reply return nil, zerrors.ThrowInvalidArgument(nil, "INST-9JdRe", "Errors.Invalid.Argument") } return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) { + id, err := c.idGenerator.Next() + if err != nil { + return nil, zerrors.ThrowInternal(nil, "INST-9JdRe", "Errors.Invalid.Argument") + } + fromSplitted := strings.Split(from, "@") senderDomain := fromSplitted[len(fromSplitted)-1] - writeModel, err := getSMTPConfigWriteModel(ctx, filter, senderDomain) + writeModel, err := getSMTPConfigWriteModel(ctx, filter, id, senderDomain) if err != nil { return nil, err } @@ -136,6 +348,8 @@ func (c *Commands) prepareAddSMTPConfig(a *instance.Aggregate, from, name, reply instance.NewSMTPConfigAddedEvent( ctx, &a.Aggregate, + id, + description, tls, from, name, @@ -149,83 +363,8 @@ func (c *Commands) prepareAddSMTPConfig(a *instance.Aggregate, from, name, reply } } -func (c *Commands) prepareChangeSMTPConfig(a *instance.Aggregate, from, name, replyTo, hostAndPort, user string, tls bool) preparation.Validation { - return func() (preparation.CreateCommands, error) { - if from = strings.TrimSpace(from); from == "" { - return nil, zerrors.ThrowInvalidArgument(nil, "INST-ASv2d", "Errors.Invalid.Argument") - } - - replyTo = strings.TrimSpace(replyTo) - hostAndPort = strings.TrimSpace(hostAndPort) - if _, _, err := net.SplitHostPort(hostAndPort); err != nil { - return nil, zerrors.ThrowInvalidArgument(nil, "INST-Kv875", "Errors.Invalid.Argument") - } - return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) { - fromSplitted := strings.Split(from, "@") - senderDomain := fromSplitted[len(fromSplitted)-1] - writeModel, err := getSMTPConfigWriteModel(ctx, filter, senderDomain) - if err != nil { - return nil, err - } - if writeModel.State != domain.SMTPConfigStateActive { - return nil, zerrors.ThrowNotFound(nil, "INST-Svq1a", "Errors.SMTPConfig.NotFound") - } - err = checkSenderAddress(writeModel) - if err != nil { - return nil, err - } - changedEvent, hasChanged, err := writeModel.NewChangedEvent( - ctx, - &a.Aggregate, - tls, - from, - name, - replyTo, - hostAndPort, - user, - ) - if err != nil { - return nil, err - } - if !hasChanged { - return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-m0o3f", "Errors.NoChangesFound") - } - return []eventstore.Command{ - changedEvent, - }, nil - }, nil - } -} - -func (c *Commands) prepareRemoveSMTPConfig(a *instance.Aggregate) preparation.Validation { - return func() (preparation.CreateCommands, error) { - return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) { - writeModel, err := getSMTPConfigWriteModel(ctx, filter, "") - if err != nil { - return nil, err - } - if writeModel.State != domain.SMTPConfigStateActive { - return nil, zerrors.ThrowNotFound(nil, "INST-Sfefg", "Errors.SMTPConfig.NotFound") - } - return []eventstore.Command{ - instance.NewSMTPConfigRemovedEvent(ctx, &a.Aggregate), - }, nil - }, nil - } -} - -func checkSenderAddress(writeModel *InstanceSMTPConfigWriteModel) error { - if !writeModel.smtpSenderAddressMatchesInstanceDomain { - return nil - } - if !writeModel.domainState.Exists() { - return zerrors.ThrowInvalidArgument(nil, "INST-83nl8", "Errors.SMTPConfig.SenderAdressNotCustomDomain") - } - return nil -} - -func getSMTPConfigWriteModel(ctx context.Context, filter preparation.FilterToQueryReducer, domain string) (_ *InstanceSMTPConfigWriteModel, err error) { - writeModel := NewInstanceSMTPConfigWriteModel(authz.GetInstance(ctx).InstanceID(), domain) +func getSMTPConfigWriteModel(ctx context.Context, filter preparation.FilterToQueryReducer, id, domain string) (_ *IAMSMTPConfigWriteModel, err error) { + writeModel := NewIAMSMTPConfigWriteModel(authz.GetInstance(ctx).InstanceID(), id, domain) events, err := filter(ctx, writeModel.Query()) if err != nil { return nil, err diff --git a/internal/command/smtp_test.go b/internal/command/smtp_test.go index bb46968da6..204614632f 100644 --- a/internal/command/smtp_test.go +++ b/internal/command/smtp_test.go @@ -11,6 +11,8 @@ import ( "github.com/zitadel/zitadel/internal/crypto" "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/eventstore" + "github.com/zitadel/zitadel/internal/id" + id_mock "github.com/zitadel/zitadel/internal/id/mock" "github.com/zitadel/zitadel/internal/notification/channels/smtp" "github.com/zitadel/zitadel/internal/repository/instance" "github.com/zitadel/zitadel/internal/zerrors" @@ -18,12 +20,14 @@ import ( func TestCommandSide_AddSMTPConfig(t *testing.T) { type fields struct { - eventstore *eventstore.Eventstore - alg crypto.EncryptionAlgorithm + eventstore *eventstore.Eventstore + idGenerator id.Generator + alg crypto.EncryptionAlgorithm } type args struct { - ctx context.Context - smtp *smtp.Config + ctx context.Context + instanceID string + smtp *smtp.Config } type res struct { want *domain.ObjectDetails @@ -51,13 +55,13 @@ func TestCommandSide_AddSMTPConfig(t *testing.T) { ), ), ), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "configid"), + alg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), }, args: args{ ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), smtp: &smtp.Config{ - Tls: true, - From: "from@domain.ch", - FromName: "name", + From: "from@domain.ch", SMTP: smtp.SMTP{ Host: "host:587", User: "user", @@ -69,58 +73,6 @@ func TestCommandSide_AddSMTPConfig(t *testing.T) { err: zerrors.IsErrorInvalidArgument, }, }, - { - name: "smtp config, error already exists", - fields: fields{ - eventstore: eventstoreExpect( - t, - expectFilter( - eventFromEventPusher( - instance.NewDomainAddedEvent(context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - "domain.ch", - false, - ), - ), - eventFromEventPusher( - instance.NewDomainPolicyAddedEvent(context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - true, true, false, - ), - ), - eventFromEventPusher( - instance.NewSMTPConfigAddedEvent(context.Background(), - &instance.NewAggregate("INSTANCE").Aggregate, - true, - "from@domain.ch", - "name", - "", - "host:587", - "user", - &crypto.CryptoValue{}, - ), - ), - ), - ), - }, - args: args{ - ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), - smtp: &smtp.Config{ - Tls: true, - From: "from@domain.ch", - FromName: "name", - ReplyToAddress: "", - SMTP: smtp.SMTP{ - Host: "host:587", - User: "user", - Password: "password", - }, - }, - }, - res: res{ - err: zerrors.IsErrorAlreadyExists, - }, - }, { name: "add smtp config, ok", fields: fields{ @@ -145,6 +97,8 @@ func TestCommandSide_AddSMTPConfig(t *testing.T) { instance.NewSMTPConfigAddedEvent( context.Background(), &instance.NewAggregate("INSTANCE").Aggregate, + "configid", + "test", true, "from@domain.ch", "name", @@ -160,14 +114,16 @@ func TestCommandSide_AddSMTPConfig(t *testing.T) { ), ), ), - alg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "configid"), + alg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), }, args: args{ ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), smtp: &smtp.Config{ - Tls: true, - From: "from@domain.ch", - FromName: "name", + Description: "test", + Tls: true, + From: "from@domain.ch", + FromName: "name", SMTP: smtp.SMTP{ Host: "host:587", User: "user", @@ -205,6 +161,8 @@ func TestCommandSide_AddSMTPConfig(t *testing.T) { instance.NewSMTPConfigAddedEvent( context.Background(), &instance.NewAggregate("INSTANCE").Aggregate, + "configid", + "test", true, "from@domain.ch", "name", @@ -220,11 +178,13 @@ func TestCommandSide_AddSMTPConfig(t *testing.T) { ), ), ), - alg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "configid"), + alg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), }, args: args{ ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), smtp: &smtp.Config{ + Description: "test", Tls: true, From: "from@domain.ch", FromName: "name", @@ -245,14 +205,17 @@ func TestCommandSide_AddSMTPConfig(t *testing.T) { { name: "smtp config, port is missing", fields: fields{ - eventstore: eventstoreExpect(t), + eventstore: eventstoreExpect(t), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "configid"), + alg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), }, args: args{ ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), smtp: &smtp.Config{ - Tls: true, - From: "from@domain.ch", - FromName: "name", + Description: "test", + Tls: true, + From: "from@domain.ch", + FromName: "name", SMTP: smtp.SMTP{ Host: "host", User: "user", @@ -267,14 +230,17 @@ func TestCommandSide_AddSMTPConfig(t *testing.T) { { name: "smtp config, host is empty", fields: fields{ - eventstore: eventstoreExpect(t), + eventstore: eventstoreExpect(t), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "configid"), + alg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), }, args: args{ ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), smtp: &smtp.Config{ - Tls: true, - From: "from@domain.ch", - FromName: "name", + Description: "test", + Tls: true, + From: "from@domain.ch", + FromName: "name", SMTP: smtp.SMTP{ Host: " ", User: "user", @@ -310,6 +276,8 @@ func TestCommandSide_AddSMTPConfig(t *testing.T) { instance.NewSMTPConfigAddedEvent( context.Background(), &instance.NewAggregate("INSTANCE").Aggregate, + "configid", + "test", true, "from@domain.ch", "name", @@ -325,14 +293,16 @@ func TestCommandSide_AddSMTPConfig(t *testing.T) { ), ), ), - alg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + alg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), + idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "configid"), }, args: args{ ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), smtp: &smtp.Config{ - Tls: true, - From: "from@domain.ch", - FromName: "name", + Description: "test", + Tls: true, + From: "from@domain.ch", + FromName: "name", SMTP: smtp.SMTP{ Host: "[2001:db8::1]:2525", User: "user", @@ -351,9 +321,10 @@ func TestCommandSide_AddSMTPConfig(t *testing.T) { t.Run(tt.name, func(t *testing.T) { r := &Commands{ eventstore: tt.fields.eventstore, + idGenerator: tt.fields.idGenerator, smtpEncryption: tt.fields.alg, } - got, err := r.AddSMTPConfig(tt.args.ctx, tt.args.smtp) + _, got, err := r.AddSMTPConfig(tt.args.ctx, tt.args.instanceID, tt.args.smtp) if tt.res.err == nil { assert.NoError(t, err) } @@ -372,8 +343,10 @@ func TestCommandSide_ChangeSMTPConfig(t *testing.T) { eventstore *eventstore.Eventstore } type args struct { - ctx context.Context - smtp *smtp.Config + ctx context.Context + instanceID string + id string + smtp *smtp.Config } type res struct { want *domain.ObjectDetails @@ -385,6 +358,21 @@ func TestCommandSide_ChangeSMTPConfig(t *testing.T) { args args res res }{ + { + name: "id empty, precondition error", + fields: fields{ + eventstore: eventstoreExpect( + t, + ), + }, + args: args{ + ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), + smtp: &smtp.Config{}, + }, + res: res{ + err: zerrors.IsErrorInvalidArgument, + }, + }, { name: "empty config, invalid argument error", fields: fields{ @@ -395,6 +383,7 @@ func TestCommandSide_ChangeSMTPConfig(t *testing.T) { args: args{ ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), smtp: &smtp.Config{}, + id: "configID", }, res: res{ err: zerrors.IsErrorInvalidArgument, @@ -411,14 +400,17 @@ func TestCommandSide_ChangeSMTPConfig(t *testing.T) { args: args{ ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), smtp: &smtp.Config{ - Tls: true, - From: "from@domain.ch", - FromName: "name", + Description: "test", + Tls: true, + From: "from@domain.ch", + FromName: "name", SMTP: smtp.SMTP{ Host: "host:587", User: "user", }, }, + instanceID: "INSTANCE", + id: "ID", }, res: res{ err: zerrors.IsNotFound, @@ -447,6 +439,8 @@ func TestCommandSide_ChangeSMTPConfig(t *testing.T) { instance.NewSMTPConfigAddedEvent( context.Background(), &instance.NewAggregate("INSTANCE").Aggregate, + "ID", + "test", true, "from@domain.ch", "name", @@ -460,11 +454,14 @@ func TestCommandSide_ChangeSMTPConfig(t *testing.T) { ), }, args: args{ - ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), + ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), + instanceID: "INSTANCE", + id: "ID", smtp: &smtp.Config{ - Tls: true, - From: "from@wrongdomain.ch", - FromName: "name", + Description: "test", + Tls: true, + From: "from@wrongdomain.ch", + FromName: "name", SMTP: smtp.SMTP{ Host: "host:587", User: "user", @@ -498,6 +495,8 @@ func TestCommandSide_ChangeSMTPConfig(t *testing.T) { instance.NewSMTPConfigAddedEvent( context.Background(), &instance.NewAggregate("INSTANCE").Aggregate, + "ID", + "test", true, "from@domain.ch", "name", @@ -513,14 +512,17 @@ func TestCommandSide_ChangeSMTPConfig(t *testing.T) { args: args{ ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), smtp: &smtp.Config{ - Tls: true, - From: "from@domain.ch", - FromName: "name", + Description: "test", + Tls: true, + From: "from@domain.ch", + FromName: "name", SMTP: smtp.SMTP{ Host: "host:587", User: "user", }, }, + instanceID: "INSTANCE", + id: "ID", }, res: res{ err: zerrors.IsPreconditionFailed, @@ -549,6 +551,8 @@ func TestCommandSide_ChangeSMTPConfig(t *testing.T) { instance.NewSMTPConfigAddedEvent( context.Background(), &instance.NewAggregate("INSTANCE").Aggregate, + "ID", + "", true, "from@domain.ch", "name", @@ -562,6 +566,8 @@ func TestCommandSide_ChangeSMTPConfig(t *testing.T) { expectPush( newSMTPConfigChangedEvent( context.Background(), + "ID", + "test", false, "from2@domain.ch", "name2", @@ -575,6 +581,7 @@ func TestCommandSide_ChangeSMTPConfig(t *testing.T) { args: args{ ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), smtp: &smtp.Config{ + Description: "test", Tls: false, From: "from2@domain.ch", FromName: "name2", @@ -584,6 +591,8 @@ func TestCommandSide_ChangeSMTPConfig(t *testing.T) { User: "user2", }, }, + id: "ID", + instanceID: "INSTANCE", }, res: res{ want: &domain.ObjectDetails{ @@ -599,15 +608,18 @@ func TestCommandSide_ChangeSMTPConfig(t *testing.T) { args: args{ ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), smtp: &smtp.Config{ - Tls: true, - From: "from@domain.ch", - FromName: "name", + Description: "test", + Tls: true, + From: "from@domain.ch", + FromName: "name", SMTP: smtp.SMTP{ Host: "host", User: "user", Password: "password", }, }, + instanceID: "INSTANCE", + id: "ID", }, res: res{ err: zerrors.IsErrorInvalidArgument, @@ -621,15 +633,18 @@ func TestCommandSide_ChangeSMTPConfig(t *testing.T) { args: args{ ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), smtp: &smtp.Config{ - Tls: true, - From: "from@domain.ch", - FromName: "name", + Description: "test", + Tls: true, + From: "from@domain.ch", + FromName: "name", SMTP: smtp.SMTP{ Host: " ", User: "user", Password: "password", }, }, + instanceID: "INSTANCE", + id: "ID", }, res: res{ err: zerrors.IsErrorInvalidArgument, @@ -658,6 +673,8 @@ func TestCommandSide_ChangeSMTPConfig(t *testing.T) { instance.NewSMTPConfigAddedEvent( context.Background(), &instance.NewAggregate("INSTANCE").Aggregate, + "ID", + "", true, "from@domain.ch", "name", @@ -671,6 +688,8 @@ func TestCommandSide_ChangeSMTPConfig(t *testing.T) { expectPush( newSMTPConfigChangedEvent( context.Background(), + "ID", + "test", false, "from2@domain.ch", "name2", @@ -684,6 +703,7 @@ func TestCommandSide_ChangeSMTPConfig(t *testing.T) { args: args{ ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), smtp: &smtp.Config{ + Description: "test", Tls: false, From: "from2@domain.ch", FromName: "name2", @@ -693,6 +713,8 @@ func TestCommandSide_ChangeSMTPConfig(t *testing.T) { User: "user2", }, }, + instanceID: "INSTANCE", + id: "ID", }, res: res{ want: &domain.ObjectDetails{ @@ -706,7 +728,7 @@ func TestCommandSide_ChangeSMTPConfig(t *testing.T) { r := &Commands{ eventstore: tt.fields.eventstore, } - got, err := r.ChangeSMTPConfig(tt.args.ctx, tt.args.smtp) + got, err := r.ChangeSMTPConfig(tt.args.ctx, tt.args.instanceID, tt.args.id, tt.args.smtp) if tt.res.err == nil { assert.NoError(t, err) } @@ -726,8 +748,10 @@ func TestCommandSide_ChangeSMTPConfigPassword(t *testing.T) { alg crypto.EncryptionAlgorithm } type args struct { - ctx context.Context - password string + ctx context.Context + instanceID string + id string + password string } type res struct { want *domain.ObjectDetails @@ -750,6 +774,7 @@ func TestCommandSide_ChangeSMTPConfigPassword(t *testing.T) { args: args{ ctx: context.Background(), password: "", + id: "ID", }, res: res{ err: zerrors.IsNotFound, @@ -765,6 +790,8 @@ func TestCommandSide_ChangeSMTPConfigPassword(t *testing.T) { instance.NewSMTPConfigAddedEvent( context.Background(), &instance.NewAggregate("INSTANCE").Aggregate, + "ID", + "test", true, "from", "name", @@ -774,11 +801,19 @@ func TestCommandSide_ChangeSMTPConfigPassword(t *testing.T) { &crypto.CryptoValue{}, ), ), + eventFromEventPusher( + instance.NewSMTPConfigActivatedEvent( + context.Background(), + &instance.NewAggregate("INSTANCE").Aggregate, + "ID", + ), + ), ), expectPush( instance.NewSMTPConfigPasswordChangedEvent( context.Background(), &instance.NewAggregate("INSTANCE").Aggregate, + "ID", &crypto.CryptoValue{ CryptoType: crypto.TypeEncryption, Algorithm: "enc", @@ -791,8 +826,10 @@ func TestCommandSide_ChangeSMTPConfigPassword(t *testing.T) { alg: crypto.CreateMockEncryptionAlg(gomock.NewController(t)), }, args: args{ - ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), - password: "password", + ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), + password: "password", + id: "ID", + instanceID: "INSTANCE", }, res: res{ want: &domain.ObjectDetails{ @@ -807,7 +844,246 @@ func TestCommandSide_ChangeSMTPConfigPassword(t *testing.T) { eventstore: tt.fields.eventstore, smtpEncryption: tt.fields.alg, } - got, err := r.ChangeSMTPConfigPassword(tt.args.ctx, tt.args.password) + got, err := r.ChangeSMTPConfigPassword(tt.args.ctx, tt.args.instanceID, tt.args.id, tt.args.password) + if tt.res.err == nil { + assert.NoError(t, err) + } + if tt.res.err != nil && !tt.res.err(err) { + t.Errorf("got wrong err: %v ", err) + } + if tt.res.err == nil { + assert.Equal(t, tt.res.want, got) + } + }) + } +} + +func TestCommandSide_ActivateSMTPConfig(t *testing.T) { + type fields struct { + eventstore *eventstore.Eventstore + alg crypto.EncryptionAlgorithm + } + type args struct { + ctx context.Context + instanceID string + id string + activatedId string + } + type res struct { + want *domain.ObjectDetails + err func(error) bool + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + name: "id empty, precondition error", + fields: fields{ + eventstore: eventstoreExpect( + t, + ), + }, + args: args{ + ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), + }, + res: res{ + err: zerrors.IsErrorInvalidArgument, + }, + }, + { + name: "smtp not existing, not found error", + fields: fields{ + eventstore: eventstoreExpect( + t, + expectFilter(), + ), + }, + args: args{ + ctx: context.Background(), + instanceID: "INSTANCE", + id: "id", + }, + res: res{ + err: zerrors.IsNotFound, + }, + }, + { + name: "activate smtp config, ok", + fields: fields{ + eventstore: eventstoreExpect( + t, + expectFilter( + eventFromEventPusher( + instance.NewSMTPConfigAddedEvent( + context.Background(), + &instance.NewAggregate("INSTANCE").Aggregate, + "ID", + "test", + true, + "from", + "name", + "", + "host:587", + "user", + &crypto.CryptoValue{}, + ), + ), + ), + expectPush( + instance.NewSMTPConfigActivatedEvent( + context.Background(), + &instance.NewAggregate("INSTANCE").Aggregate, + "ID", + ), + ), + ), + }, + args: args{ + ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), + id: "ID", + instanceID: "INSTANCE", + activatedId: "", + }, + res: res{ + want: &domain.ObjectDetails{ + ResourceOwner: "INSTANCE", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := &Commands{ + eventstore: tt.fields.eventstore, + smtpEncryption: tt.fields.alg, + } + got, err := r.ActivateSMTPConfig(tt.args.ctx, tt.args.instanceID, tt.args.id, tt.args.activatedId) + if tt.res.err == nil { + assert.NoError(t, err) + } + if tt.res.err != nil && !tt.res.err(err) { + t.Errorf("got wrong err: %v ", err) + } + if tt.res.err == nil { + assert.Equal(t, tt.res.want, got) + } + }) + } +} + +func TestCommandSide_DeactivateSMTPConfig(t *testing.T) { + type fields struct { + eventstore *eventstore.Eventstore + alg crypto.EncryptionAlgorithm + } + type args struct { + ctx context.Context + instanceID string + id string + activatedId string + } + type res struct { + want *domain.ObjectDetails + err func(error) bool + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + name: "id empty, precondition error", + fields: fields{ + eventstore: eventstoreExpect( + t, + ), + }, + args: args{ + ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), + }, + res: res{ + err: zerrors.IsErrorInvalidArgument, + }, + }, + { + name: "smtp not existing, not found error", + fields: fields{ + eventstore: eventstoreExpect( + t, + expectFilter(), + ), + }, + args: args{ + ctx: context.Background(), + instanceID: "INSTANCE", + id: "id", + }, + res: res{ + err: zerrors.IsNotFound, + }, + }, + { + name: "deactivate smtp config, ok", + fields: fields{ + eventstore: eventstoreExpect( + t, + expectFilter( + eventFromEventPusher( + instance.NewSMTPConfigAddedEvent( + context.Background(), + &instance.NewAggregate("INSTANCE").Aggregate, + "ID", + "test", + true, + "from", + "name", + "", + "host:587", + "user", + &crypto.CryptoValue{}, + ), + ), + eventFromEventPusher( + instance.NewSMTPConfigActivatedEvent( + context.Background(), + &instance.NewAggregate("INSTANCE").Aggregate, + "ID", + ), + ), + ), + expectPush( + instance.NewSMTPConfigDeactivatedEvent( + context.Background(), + &instance.NewAggregate("INSTANCE").Aggregate, + "ID", + ), + ), + ), + }, + args: args{ + ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), + id: "ID", + instanceID: "INSTANCE", + activatedId: "", + }, + res: res{ + want: &domain.ObjectDetails{ + ResourceOwner: "INSTANCE", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := &Commands{ + eventstore: tt.fields.eventstore, + smtpEncryption: tt.fields.alg, + } + got, err := r.DeactivateSMTPConfig(tt.args.ctx, tt.args.instanceID, tt.args.id) if tt.res.err == nil { assert.NoError(t, err) } @@ -827,7 +1103,9 @@ func TestCommandSide_RemoveSMTPConfig(t *testing.T) { alg crypto.EncryptionAlgorithm } type args struct { - ctx context.Context + ctx context.Context + instanceID string + id string } type res struct { want *domain.ObjectDetails @@ -849,6 +1127,7 @@ func TestCommandSide_RemoveSMTPConfig(t *testing.T) { }, args: args{ ctx: context.Background(), + id: "ID", }, res: res{ err: zerrors.IsNotFound, @@ -864,6 +1143,8 @@ func TestCommandSide_RemoveSMTPConfig(t *testing.T) { instance.NewSMTPConfigAddedEvent( context.Background(), &instance.NewAggregate("INSTANCE").Aggregate, + "ID", + "test", true, "from", "name", @@ -878,12 +1159,15 @@ func TestCommandSide_RemoveSMTPConfig(t *testing.T) { instance.NewSMTPConfigRemovedEvent( context.Background(), &instance.NewAggregate("INSTANCE").Aggregate, + "ID", ), ), ), }, args: args{ - ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), + ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), + id: "ID", + instanceID: "INSTANCE", }, res: res{ want: &domain.ObjectDetails{ @@ -898,7 +1182,7 @@ func TestCommandSide_RemoveSMTPConfig(t *testing.T) { eventstore: tt.fields.eventstore, smtpEncryption: tt.fields.alg, } - got, err := r.RemoveSMTPConfig(tt.args.ctx) + got, err := r.RemoveSMTPConfig(tt.args.ctx, tt.args.instanceID, tt.args.id) if tt.res.err == nil { assert.NoError(t, err) } @@ -912,8 +1196,9 @@ func TestCommandSide_RemoveSMTPConfig(t *testing.T) { } } -func newSMTPConfigChangedEvent(ctx context.Context, tls bool, fromAddress, fromName, replyTo, host, user string) *instance.SMTPConfigChangedEvent { +func newSMTPConfigChangedEvent(ctx context.Context, id, description string, tls bool, fromAddress, fromName, replyTo, host, user string) *instance.SMTPConfigChangedEvent { changes := []instance.SMTPConfigChanges{ + instance.ChangeSMTPConfigDescription(description), instance.ChangeSMTPConfigTLS(tls), instance.ChangeSMTPConfigFromAddress(fromAddress), instance.ChangeSMTPConfigFromName(fromName), @@ -923,6 +1208,7 @@ func newSMTPConfigChangedEvent(ctx context.Context, tls bool, fromAddress, fromN } event, _ := instance.NewSMTPConfigChangeEvent(ctx, &instance.NewAggregate("INSTANCE").Aggregate, + id, changes, ) return event diff --git a/internal/domain/smtp.go b/internal/domain/smtp.go index 02460ca8b2..e941616901 100644 --- a/internal/domain/smtp.go +++ b/internal/domain/smtp.go @@ -6,4 +6,9 @@ const ( SMTPConfigStateUnspecified SMTPConfigState = iota SMTPConfigStateActive SMTPConfigStateRemoved + SMTPConfigStateInactive ) + +func (s SMTPConfigState) Exists() bool { + return s != SMTPConfigStateUnspecified && s != SMTPConfigStateRemoved +} diff --git a/internal/notification/channels/smtp/channel.go b/internal/notification/channels/smtp/channel.go index 2d6dc9dadd..3524634765 100644 --- a/internal/notification/channels/smtp/channel.go +++ b/internal/notification/channels/smtp/channel.go @@ -91,9 +91,9 @@ func (smtpConfig SMTP) connectToSMTP(tlsRequired bool) (client *smtp.Client, err } if !tlsRequired { - client, err = smtpConfig.getSMPTClient() + client, err = smtpConfig.getSMTPClient() } else { - client, err = smtpConfig.getSMPTClientWithTls(host) + client, err = smtpConfig.getSMTPClientWithTls(host) } if err != nil { return nil, err @@ -106,7 +106,7 @@ func (smtpConfig SMTP) connectToSMTP(tlsRequired bool) (client *smtp.Client, err return client, nil } -func (smtpConfig SMTP) getSMPTClient() (*smtp.Client, error) { +func (smtpConfig SMTP) getSMTPClient() (*smtp.Client, error) { client, err := smtp.Dial(smtpConfig.Host) if err != nil { return nil, zerrors.ThrowInternal(err, "EMAIL-skwos", "could not make smtp dial") @@ -114,12 +114,12 @@ func (smtpConfig SMTP) getSMPTClient() (*smtp.Client, error) { return client, nil } -func (smtpConfig SMTP) getSMPTClientWithTls(host string) (*smtp.Client, error) { +func (smtpConfig SMTP) getSMTPClientWithTls(host string) (*smtp.Client, error) { conn, err := tls.Dial("tcp", smtpConfig.Host, &tls.Config{}) if errors.As(err, &tls.RecordHeaderError{}) { logging.Log("MAIN-xKIzT").OnError(err).Warn("could not connect using normal tls. trying starttls instead...") - return smtpConfig.getSMPTClientWithStartTls(host) + return smtpConfig.getSMTPClientWithStartTls(host) } if err != nil { @@ -133,8 +133,8 @@ func (smtpConfig SMTP) getSMPTClientWithTls(host string) (*smtp.Client, error) { return client, err } -func (smtpConfig SMTP) getSMPTClientWithStartTls(host string) (*smtp.Client, error) { - client, err := smtpConfig.getSMPTClient() +func (smtpConfig SMTP) getSMTPClientWithStartTls(host string) (*smtp.Client, error) { + client, err := smtpConfig.getSMTPClient() if err != nil { return nil, err } diff --git a/internal/notification/channels/smtp/config.go b/internal/notification/channels/smtp/config.go index 8646c9d58f..865a2f4cd1 100644 --- a/internal/notification/channels/smtp/config.go +++ b/internal/notification/channels/smtp/config.go @@ -1,6 +1,7 @@ package smtp type Config struct { + Description string SMTP SMTP Tls bool From string diff --git a/internal/notification/handlers/config_smtp.go b/internal/notification/handlers/config_smtp.go index aa245157c5..8cce47dec6 100644 --- a/internal/notification/handlers/config_smtp.go +++ b/internal/notification/handlers/config_smtp.go @@ -10,7 +10,7 @@ import ( // GetSMTPConfig reads the iam SMTP provider config func (n *NotificationQueries) GetSMTPConfig(ctx context.Context) (*smtp.Config, error) { - config, err := n.SMTPConfigByAggregateID(ctx, authz.GetInstance(ctx).InstanceID()) + config, err := n.SMTPConfigActive(ctx, authz.GetInstance(ctx).InstanceID()) if err != nil { return nil, err } @@ -19,6 +19,7 @@ func (n *NotificationQueries) GetSMTPConfig(ctx context.Context) (*smtp.Config, return nil, err } return &smtp.Config{ + Description: config.Description, From: config.SenderAddress, FromName: config.SenderName, ReplyToAddress: config.ReplyToAddress, diff --git a/internal/notification/handlers/mock/queries.mock.go b/internal/notification/handlers/mock/queries.mock.go index 18a1dd4164..210493d875 100644 --- a/internal/notification/handlers/mock/queries.mock.go +++ b/internal/notification/handlers/mock/queries.mock.go @@ -181,19 +181,19 @@ func (mr *MockQueriesMockRecorder) SMSProviderConfig(arg0 any, arg1 ...any) *gom return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SMSProviderConfig", reflect.TypeOf((*MockQueries)(nil).SMSProviderConfig), varargs...) } -// SMTPConfigByAggregateID mocks base method. -func (m *MockQueries) SMTPConfigByAggregateID(arg0 context.Context, arg1 string) (*query.SMTPConfig, error) { +// SMTPConfigActive mocks base method. +func (m *MockQueries) SMTPConfigActive(arg0 context.Context, arg1 string) (*query.SMTPConfig, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SMTPConfigByAggregateID", arg0, arg1) + ret := m.ctrl.Call(m, "SMTPConfigActive", arg0, arg1) ret0, _ := ret[0].(*query.SMTPConfig) ret1, _ := ret[1].(error) return ret0, ret1 } -// SMTPConfigByAggregateID indicates an expected call of SMTPConfigByAggregateID. -func (mr *MockQueriesMockRecorder) SMTPConfigByAggregateID(arg0, arg1 any) *gomock.Call { +// SMTPConfigActive indicates an expected call of SMTPConfigActive. +func (mr *MockQueriesMockRecorder) SMTPConfigActive(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SMTPConfigByAggregateID", reflect.TypeOf((*MockQueries)(nil).SMTPConfigByAggregateID), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SMTPConfigActive", reflect.TypeOf((*MockQueries)(nil).SMTPConfigActive), arg0, arg1) } // SearchInstanceDomains mocks base method. diff --git a/internal/notification/handlers/queries.go b/internal/notification/handlers/queries.go index 15cbf246f4..ce7597ead8 100644 --- a/internal/notification/handlers/queries.go +++ b/internal/notification/handlers/queries.go @@ -22,7 +22,7 @@ type Queries interface { SearchMilestones(ctx context.Context, instanceIDs []string, queries *query.MilestonesSearchQueries) (*query.Milestones, error) NotificationProviderByIDAndType(ctx context.Context, aggID string, providerType domain.NotificationProviderType) (*query.DebugNotificationProvider, error) SMSProviderConfig(ctx context.Context, queries ...query.SearchQuery) (*query.SMSConfig, error) - SMTPConfigByAggregateID(ctx context.Context, aggregateID string) (*query.SMTPConfig, error) + SMTPConfigActive(ctx context.Context, resourceOwner string) (*query.SMTPConfig, error) GetDefaultLanguage(ctx context.Context) language.Tag GetInstanceRestrictions(ctx context.Context) (restrictions query.Restrictions, err error) } diff --git a/internal/query/projection/smtp.go b/internal/query/projection/smtp.go index b753df7f57..9b53da4150 100644 --- a/internal/query/projection/smtp.go +++ b/internal/query/projection/smtp.go @@ -3,6 +3,7 @@ package projection import ( "context" + "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/eventstore" old_handler "github.com/zitadel/zitadel/internal/eventstore/handler" "github.com/zitadel/zitadel/internal/eventstore/handler/v2" @@ -11,14 +12,13 @@ import ( ) const ( - SMTPConfigProjectionTable = "projections.smtp_configs1" - - SMTPConfigColumnAggregateID = "aggregate_id" + SMTPConfigProjectionTable = "projections.smtp_configs2" + SMTPConfigColumnInstanceID = "instance_id" + SMTPConfigColumnResourceOwner = "resource_owner" + SMTPConfigColumnID = "id" SMTPConfigColumnCreationDate = "creation_date" SMTPConfigColumnChangeDate = "change_date" SMTPConfigColumnSequence = "sequence" - SMTPConfigColumnResourceOwner = "resource_owner" - SMTPConfigColumnInstanceID = "instance_id" SMTPConfigColumnTLS = "tls" SMTPConfigColumnSenderAddress = "sender_address" SMTPConfigColumnSenderName = "sender_name" @@ -26,6 +26,8 @@ const ( SMTPConfigColumnSMTPHost = "host" SMTPConfigColumnSMTPUser = "username" SMTPConfigColumnSMTPPassword = "password" + SMTPConfigColumnState = "state" + SMTPConfigColumnDescription = "description" ) type smtpConfigProjection struct{} @@ -41,7 +43,7 @@ func (*smtpConfigProjection) Name() string { func (*smtpConfigProjection) Init() *old_handler.Check { return handler.NewTableCheck( handler.NewTable([]*handler.InitColumn{ - handler.NewColumn(SMTPConfigColumnAggregateID, handler.ColumnTypeText), + handler.NewColumn(SMTPConfigColumnID, handler.ColumnTypeText), handler.NewColumn(SMTPConfigColumnCreationDate, handler.ColumnTypeTimestamp), handler.NewColumn(SMTPConfigColumnChangeDate, handler.ColumnTypeTimestamp), handler.NewColumn(SMTPConfigColumnSequence, handler.ColumnTypeInt64), @@ -54,8 +56,10 @@ func (*smtpConfigProjection) Init() *old_handler.Check { handler.NewColumn(SMTPConfigColumnSMTPHost, handler.ColumnTypeText), handler.NewColumn(SMTPConfigColumnSMTPUser, handler.ColumnTypeText), handler.NewColumn(SMTPConfigColumnSMTPPassword, handler.ColumnTypeJSONB, handler.Nullable()), + handler.NewColumn(SMTPConfigColumnState, handler.ColumnTypeEnum), + handler.NewColumn(SMTPConfigColumnDescription, handler.ColumnTypeText), }, - handler.NewPrimaryKey(SMTPConfigColumnInstanceID, SMTPConfigColumnAggregateID), + handler.NewPrimaryKey(SMTPConfigColumnInstanceID, SMTPConfigColumnResourceOwner, SMTPConfigColumnID), ), ) } @@ -77,6 +81,14 @@ func (p *smtpConfigProjection) Reducers() []handler.AggregateReducer { Event: instance.SMTPConfigPasswordChangedEventType, Reduce: p.reduceSMTPConfigPasswordChanged, }, + { + Event: instance.SMTPConfigActivatedEventType, + Reduce: p.reduceSMTPConfigActivated, + }, + { + Event: instance.SMTPConfigDeactivatedEventType, + Reduce: p.reduceSMTPConfigDeactivated, + }, { Event: instance.SMTPConfigRemovedEventType, Reduce: p.reduceSMTPConfigRemoved, @@ -95,15 +107,26 @@ func (p *smtpConfigProjection) reduceSMTPConfigAdded(event eventstore.Event) (*h if !ok { return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-sk99F", "reduce.wrong.event.type %s", instance.SMTPConfigAddedEventType) } + + // Deal with old and unique SMTP settings (empty ID) + id := e.ID + description := e.Description + state := domain.SMTPConfigStateInactive + if e.ID == "" { + id = e.Aggregate().ResourceOwner + description = "generic" + state = domain.SMTPConfigStateActive + } + return handler.NewCreateStatement( e, []handler.Column{ - handler.NewCol(SMTPConfigColumnAggregateID, e.Aggregate().ID), handler.NewCol(SMTPConfigColumnCreationDate, e.CreationDate()), handler.NewCol(SMTPConfigColumnChangeDate, e.CreationDate()), handler.NewCol(SMTPConfigColumnResourceOwner, e.Aggregate().ResourceOwner), handler.NewCol(SMTPConfigColumnInstanceID, e.Aggregate().InstanceID), handler.NewCol(SMTPConfigColumnSequence, e.Sequence()), + handler.NewCol(SMTPConfigColumnID, id), handler.NewCol(SMTPConfigColumnTLS, e.TLS), handler.NewCol(SMTPConfigColumnSenderAddress, e.SenderAddress), handler.NewCol(SMTPConfigColumnSenderName, e.SenderName), @@ -111,6 +134,8 @@ func (p *smtpConfigProjection) reduceSMTPConfigAdded(event eventstore.Event) (*h handler.NewCol(SMTPConfigColumnSMTPHost, e.Host), handler.NewCol(SMTPConfigColumnSMTPUser, e.User), handler.NewCol(SMTPConfigColumnSMTPPassword, e.Password), + handler.NewCol(SMTPConfigColumnState, state), + handler.NewCol(SMTPConfigColumnDescription, description), }, ), nil } @@ -124,6 +149,13 @@ func (p *smtpConfigProjection) reduceSMTPConfigChanged(event eventstore.Event) ( columns := make([]handler.Column, 0, 8) columns = append(columns, handler.NewCol(SMTPConfigColumnChangeDate, e.CreationDate()), handler.NewCol(SMTPConfigColumnSequence, e.Sequence())) + + // Deal with old and unique SMTP settings (empty ID) + id := e.ID + if e.ID == "" { + id = e.Aggregate().ResourceOwner + } + if e.TLS != nil { columns = append(columns, handler.NewCol(SMTPConfigColumnTLS, *e.TLS)) } @@ -142,11 +174,18 @@ func (p *smtpConfigProjection) reduceSMTPConfigChanged(event eventstore.Event) ( if e.User != nil { columns = append(columns, handler.NewCol(SMTPConfigColumnSMTPUser, *e.User)) } + if e.Password != nil { + columns = append(columns, handler.NewCol(SMTPConfigColumnSMTPPassword, *e.Password)) + } + if e.Description != nil { + columns = append(columns, handler.NewCol(SMTPConfigColumnDescription, *e.Description)) + } return handler.NewUpdateStatement( e, columns, []handler.Condition{ - handler.NewCond(SMTPConfigColumnAggregateID, e.Aggregate().ID), + handler.NewCond(SMTPConfigColumnID, id), + handler.NewCond(SMTPConfigColumnResourceOwner, e.Aggregate().ResourceOwner), handler.NewCond(SMTPConfigColumnInstanceID, e.Aggregate().InstanceID), }, ), nil @@ -158,6 +197,12 @@ func (p *smtpConfigProjection) reduceSMTPConfigPasswordChanged(event eventstore. return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-fk02f", "reduce.wrong.event.type %s", instance.SMTPConfigChangedEventType) } + // Deal with old and unique SMTP settings (empty ID) + id := e.ID + if e.ID == "" { + id = e.Aggregate().ResourceOwner + } + return handler.NewUpdateStatement( e, []handler.Column{ @@ -166,7 +211,62 @@ func (p *smtpConfigProjection) reduceSMTPConfigPasswordChanged(event eventstore. handler.NewCol(SMTPConfigColumnSMTPPassword, e.Password), }, []handler.Condition{ - handler.NewCond(SMTPConfigColumnAggregateID, e.Aggregate().ID), + handler.NewCond(SMTPConfigColumnID, id), + handler.NewCond(SMTPConfigColumnResourceOwner, e.Aggregate().ResourceOwner), + handler.NewCond(SMTPConfigColumnInstanceID, e.Aggregate().InstanceID), + }, + ), nil +} + +func (p *smtpConfigProjection) reduceSMTPConfigActivated(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*instance.SMTPConfigActivatedEvent) + if !ok { + return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-fq92r", "reduce.wrong.event.type %s", instance.SMTPConfigActivatedEventType) + } + + // Deal with old and unique SMTP settings (empty ID) + id := e.ID + if e.ID == "" { + id = e.Aggregate().ResourceOwner + } + + return handler.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(SMTPConfigColumnChangeDate, e.CreationDate()), + handler.NewCol(SMTPConfigColumnSequence, e.Sequence()), + handler.NewCol(SMTPConfigColumnState, domain.SMTPConfigStateActive), + }, + []handler.Condition{ + handler.NewCond(SMTPConfigColumnID, id), + handler.NewCond(SMTPConfigColumnResourceOwner, e.Aggregate().ResourceOwner), + handler.NewCond(SMTPConfigColumnInstanceID, e.Aggregate().InstanceID), + }, + ), nil +} + +func (p *smtpConfigProjection) reduceSMTPConfigDeactivated(event eventstore.Event) (*handler.Statement, error) { + e, ok := event.(*instance.SMTPConfigDeactivatedEvent) + if !ok { + return nil, zerrors.ThrowInvalidArgumentf(nil, "HANDL-hv89j", "reduce.wrong.event.type %s", instance.SMTPConfigDeactivatedEventType) + } + + // Deal with old and unique SMTP settings (empty ID) + id := e.ID + if e.ID == "" { + id = e.Aggregate().ResourceOwner + } + + return handler.NewUpdateStatement( + e, + []handler.Column{ + handler.NewCol(SMTPConfigColumnChangeDate, e.CreationDate()), + handler.NewCol(SMTPConfigColumnSequence, e.Sequence()), + handler.NewCol(SMTPConfigColumnState, domain.SMTPConfigStateInactive), + }, + []handler.Condition{ + handler.NewCond(SMTPConfigColumnID, id), + handler.NewCond(SMTPConfigColumnResourceOwner, e.Aggregate().ResourceOwner), handler.NewCond(SMTPConfigColumnInstanceID, e.Aggregate().InstanceID), }, ), nil @@ -177,10 +277,18 @@ func (p *smtpConfigProjection) reduceSMTPConfigRemoved(event eventstore.Event) ( if err != nil { return nil, err } + + // Deal with old and unique SMTP settings (empty ID) + id := e.ID + if e.ID == "" { + id = e.Aggregate().ResourceOwner + } + return handler.NewDeleteStatement( e, []handler.Condition{ - handler.NewCond(SMTPConfigColumnAggregateID, e.Aggregate().ID), + handler.NewCond(SMTPConfigColumnID, id), + handler.NewCond(SMTPConfigColumnResourceOwner, e.Aggregate().ResourceOwner), handler.NewCond(SMTPConfigColumnInstanceID, e.Aggregate().InstanceID), }, ), nil diff --git a/internal/query/projection/smtp_test.go b/internal/query/projection/smtp_test.go index 3fd78c7bc8..4d7b5e4a99 100644 --- a/internal/query/projection/smtp_test.go +++ b/internal/query/projection/smtp_test.go @@ -3,6 +3,7 @@ package projection import ( "testing" + "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/eventstore/handler/v2" "github.com/zitadel/zitadel/internal/repository/instance" @@ -27,12 +28,16 @@ func TestSMTPConfigProjection_reduces(t *testing.T) { instance.SMTPConfigChangedEventType, instance.AggregateType, []byte(`{ + "description": "test", "tls": true, "senderAddress": "sender", "senderName": "name", "replyToAddress": "reply-to", "host": "host", - "user": "user" + "user": "user", + "id": "44444", + "resource_owner": "ro-id", + "instance_id": "instance-id" }`, ), ), instance.SMTPConfigChangedEventMapper), @@ -44,7 +49,7 @@ func TestSMTPConfigProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.smtp_configs1 SET (change_date, sequence, tls, sender_address, sender_name, reply_to_address, host, username) = ($1, $2, $3, $4, $5, $6, $7, $8) WHERE (aggregate_id = $9) AND (instance_id = $10)", + expectedStmt: "UPDATE projections.smtp_configs2 SET (change_date, sequence, tls, sender_address, sender_name, reply_to_address, host, username, description) = ($1, $2, $3, $4, $5, $6, $7, $8, $9) WHERE (id = $10) AND (resource_owner = $11) AND (instance_id = $12)", expectedArgs: []interface{}{ anyArg{}, uint64(15), @@ -54,7 +59,9 @@ func TestSMTPConfigProjection_reduces(t *testing.T) { "reply-to", "host", "user", - "agg-id", + "test", + "44444", + "ro-id", "instance-id", }, }, @@ -71,6 +78,8 @@ func TestSMTPConfigProjection_reduces(t *testing.T) { instance.AggregateType, []byte(`{ "tls": true, + "id": "id", + "description": "test", "senderAddress": "sender", "senderName": "name", "replyToAddress": "reply-to", @@ -91,14 +100,14 @@ func TestSMTPConfigProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "INSERT INTO projections.smtp_configs1 (aggregate_id, creation_date, change_date, resource_owner, instance_id, sequence, tls, sender_address, sender_name, reply_to_address, host, username, password) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)", + expectedStmt: "INSERT INTO projections.smtp_configs2 (creation_date, change_date, resource_owner, instance_id, sequence, id, tls, sender_address, sender_name, reply_to_address, host, username, password, state, description) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)", expectedArgs: []interface{}{ - "agg-id", anyArg{}, anyArg{}, "ro-id", "instance-id", uint64(15), + "id", true, "sender", "name", @@ -106,6 +115,72 @@ func TestSMTPConfigProjection_reduces(t *testing.T) { "host", "user", anyArg{}, + domain.SMTPConfigState(3), + "test", + }, + }, + }, + }, + }, + }, + { + name: "reduceSMTPConfigActivated", + args: args{ + event: getEvent(testEvent( + instance.SMTPConfigActivatedEventType, + instance.AggregateType, + []byte(`{ + "id": "config-id" + }`), + ), instance.SMTPConfigActivatedEventMapper), + }, + reduce: (&smtpConfigProjection{}).reduceSMTPConfigActivated, + want: wantReduce{ + aggregateType: eventstore.AggregateType("instance"), + sequence: 15, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.smtp_configs2 SET (change_date, sequence, state) = ($1, $2, $3) WHERE (id = $4) AND (resource_owner = $5) AND (instance_id = $6)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + domain.SMTPConfigStateActive, + "config-id", + "ro-id", + "instance-id", + }, + }, + }, + }, + }, + }, + { + name: "reduceSMTPConfigDeactivated", + args: args{ + event: getEvent(testEvent( + instance.SMTPConfigDeactivatedEventType, + instance.AggregateType, + []byte(`{ + "id": "config-id" + }`), + ), instance.SMTPConfigDeactivatedEventMapper), + }, + reduce: (&smtpConfigProjection{}).reduceSMTPConfigDeactivated, + want: wantReduce{ + aggregateType: eventstore.AggregateType("instance"), + sequence: 15, + executer: &testExecuter{ + executions: []execution{ + { + expectedStmt: "UPDATE projections.smtp_configs2 SET (change_date, sequence, state) = ($1, $2, $3) WHERE (id = $4) AND (resource_owner = $5) AND (instance_id = $6)", + expectedArgs: []interface{}{ + anyArg{}, + uint64(15), + domain.SMTPConfigStateInactive, + "config-id", + "ro-id", + "instance-id", }, }, }, @@ -120,6 +195,7 @@ func TestSMTPConfigProjection_reduces(t *testing.T) { instance.SMTPConfigPasswordChangedEventType, instance.AggregateType, []byte(`{ + "id": "config-id", "password": { "cryptoType": 0, "algorithm": "RSA-265", @@ -135,12 +211,13 @@ func TestSMTPConfigProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "UPDATE projections.smtp_configs1 SET (change_date, sequence, password) = ($1, $2, $3) WHERE (aggregate_id = $4) AND (instance_id = $5)", + expectedStmt: "UPDATE projections.smtp_configs2 SET (change_date, sequence, password) = ($1, $2, $3) WHERE (id = $4) AND (resource_owner = $5) AND (instance_id = $6)", expectedArgs: []interface{}{ anyArg{}, uint64(15), anyArg{}, - "agg-id", + "config-id", + "ro-id", "instance-id", }, }, @@ -154,7 +231,7 @@ func TestSMTPConfigProjection_reduces(t *testing.T) { event: getEvent(testEvent( instance.SMTPConfigRemovedEventType, instance.AggregateType, - []byte(`{}`), + []byte(`{ "id": "config-id"}`), ), instance.SMTPConfigRemovedEventMapper), }, reduce: (&smtpConfigProjection{}).reduceSMTPConfigRemoved, @@ -164,9 +241,10 @@ func TestSMTPConfigProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.smtp_configs1 WHERE (aggregate_id = $1) AND (instance_id = $2)", + expectedStmt: "DELETE FROM projections.smtp_configs2 WHERE (id = $1) AND (resource_owner = $2) AND (instance_id = $3)", expectedArgs: []interface{}{ - "agg-id", + "config-id", + "ro-id", "instance-id", }, }, @@ -191,7 +269,7 @@ func TestSMTPConfigProjection_reduces(t *testing.T) { executer: &testExecuter{ executions: []execution{ { - expectedStmt: "DELETE FROM projections.smtp_configs1 WHERE (instance_id = $1)", + expectedStmt: "DELETE FROM projections.smtp_configs2 WHERE (instance_id = $1)", expectedArgs: []interface{}{ "agg-id", }, diff --git a/internal/query/smtp.go b/internal/query/smtp.go index 81202f2e51..b9dd3e0bff 100644 --- a/internal/query/smtp.go +++ b/internal/query/smtp.go @@ -11,20 +11,27 @@ import ( "github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/api/call" "github.com/zitadel/zitadel/internal/crypto" + "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/query/projection" "github.com/zitadel/zitadel/internal/telemetry/tracing" "github.com/zitadel/zitadel/internal/zerrors" ) +type SMTPConfigsSearchQueries struct { + SearchRequest + Queries []SearchQuery +} + +type SMTPConfigs struct { + SearchResponse + Configs []*SMTPConfig +} + var ( smtpConfigsTable = table{ name: projection.SMTPConfigProjectionTable, instanceIDCol: projection.SMTPConfigColumnInstanceID, } - SMTPConfigColumnAggregateID = Column{ - name: projection.SMTPConfigColumnAggregateID, - table: smtpConfigsTable, - } SMTPConfigColumnCreationDate = Column{ name: projection.SMTPConfigColumnCreationDate, table: smtpConfigsTable, @@ -73,20 +80,25 @@ var ( name: projection.SMTPConfigColumnSMTPPassword, table: smtpConfigsTable, } + SMTPConfigColumnID = Column{ + name: projection.SMTPConfigColumnID, + table: smtpConfigsTable, + } + SMTPConfigColumnState = Column{ + name: projection.SMTPConfigColumnState, + table: smtpConfigsTable, + } + SMTPConfigColumnDescription = Column{ + name: projection.SMTPConfigColumnDescription, + table: smtpConfigsTable, + } ) -type SMTPConfigs struct { - SearchResponse - SMTPConfigs []*SMTPConfig -} - type SMTPConfig struct { - AggregateID string - CreationDate time.Time - ChangeDate time.Time - ResourceOwner string - Sequence uint64 - + CreationDate time.Time + ChangeDate time.Time + ResourceOwner string + Sequence uint64 TLS bool SenderAddress string SenderName string @@ -94,19 +106,44 @@ type SMTPConfig struct { Host string User string Password *crypto.CryptoValue + ID string + State domain.SMTPConfigState + Description string } -func (q *Queries) SMTPConfigByAggregateID(ctx context.Context, aggregateID string) (config *SMTPConfig, err error) { +func (q *Queries) SMTPConfigActive(ctx context.Context, resourceOwner string) (config *SMTPConfig, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() stmt, scan := prepareSMTPConfigQuery(ctx, q.client) query, args, err := stmt.Where(sq.Eq{ - SMTPConfigColumnAggregateID.identifier(): aggregateID, - SMTPConfigColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), + SMTPConfigColumnResourceOwner.identifier(): resourceOwner, + SMTPConfigColumnInstanceID.identifier(): resourceOwner, + SMTPConfigColumnState.identifier(): domain.SMTPConfigStateActive, }).ToSql() if err != nil { - return nil, zerrors.ThrowInternal(err, "QUERY-3m9sl", "Errors.Query.SQLStatment") + return nil, zerrors.ThrowInternal(err, "QUERY-3m9sl", "Errors.Query.SQLStatement") + } + + err = q.client.QueryRowContext(ctx, func(row *sql.Row) error { + config, err = scan(row) + return err + }, query, args...) + return config, err +} + +func (q *Queries) SMTPConfigByID(ctx context.Context, instanceID, resourceOwner, id string) (config *SMTPConfig, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + + stmt, scan := prepareSMTPConfigQuery(ctx, q.client) + query, args, err := stmt.Where(sq.Eq{ + SMTPConfigColumnResourceOwner.identifier(): resourceOwner, + SMTPConfigColumnInstanceID.identifier(): instanceID, + SMTPConfigColumnID.identifier(): id, + }).ToSql() + if err != nil { + return nil, zerrors.ThrowInternal(err, "QUERY-8f8gw", "Errors.Query.SQLStatement") } err = q.client.QueryRowContext(ctx, func(row *sql.Row) error { @@ -120,7 +157,6 @@ func prepareSMTPConfigQuery(ctx context.Context, db prepareDatabase) (sq.SelectB password := new(crypto.CryptoValue) return sq.Select( - SMTPConfigColumnAggregateID.identifier(), SMTPConfigColumnCreationDate.identifier(), SMTPConfigColumnChangeDate.identifier(), SMTPConfigColumnResourceOwner.identifier(), @@ -131,13 +167,15 @@ func prepareSMTPConfigQuery(ctx context.Context, db prepareDatabase) (sq.SelectB SMTPConfigColumnReplyToAddress.identifier(), SMTPConfigColumnSMTPHost.identifier(), SMTPConfigColumnSMTPUser.identifier(), - SMTPConfigColumnSMTPPassword.identifier()). + SMTPConfigColumnSMTPPassword.identifier(), + SMTPConfigColumnID.identifier(), + SMTPConfigColumnState.identifier(), + SMTPConfigColumnDescription.identifier()). From(smtpConfigsTable.identifier() + db.Timetravel(call.Took(ctx))). PlaceholderFormat(sq.Dollar), func(row *sql.Row) (*SMTPConfig, error) { config := new(SMTPConfig) err := row.Scan( - &config.AggregateID, &config.CreationDate, &config.ChangeDate, &config.ResourceOwner, @@ -149,6 +187,9 @@ func prepareSMTPConfigQuery(ctx context.Context, db prepareDatabase) (sq.SelectB &config.Host, &config.User, &password, + &config.ID, + &config.State, + &config.Description, ) if err != nil { if errors.Is(err, sql.ErrNoRows) { @@ -160,3 +201,79 @@ func prepareSMTPConfigQuery(ctx context.Context, db prepareDatabase) (sq.SelectB return config, nil } } + +func prepareSMTPConfigsQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(*sql.Rows) (*SMTPConfigs, error)) { + return sq.Select( + SMTPConfigColumnCreationDate.identifier(), + SMTPConfigColumnChangeDate.identifier(), + SMTPConfigColumnResourceOwner.identifier(), + SMTPConfigColumnSequence.identifier(), + SMTPConfigColumnTLS.identifier(), + SMTPConfigColumnSenderAddress.identifier(), + SMTPConfigColumnSenderName.identifier(), + SMTPConfigColumnReplyToAddress.identifier(), + SMTPConfigColumnSMTPHost.identifier(), + SMTPConfigColumnSMTPUser.identifier(), + SMTPConfigColumnSMTPPassword.identifier(), + SMTPConfigColumnID.identifier(), + SMTPConfigColumnState.identifier(), + SMTPConfigColumnDescription.identifier(), + countColumn.identifier()). + From(smtpConfigsTable.identifier() + db.Timetravel(call.Took(ctx))). + PlaceholderFormat(sq.Dollar), + func(rows *sql.Rows) (*SMTPConfigs, error) { + configs := &SMTPConfigs{Configs: []*SMTPConfig{}} + for rows.Next() { + config := new(SMTPConfig) + err := rows.Scan( + &config.CreationDate, + &config.ChangeDate, + &config.ResourceOwner, + &config.Sequence, + &config.TLS, + &config.SenderAddress, + &config.SenderName, + &config.ReplyToAddress, + &config.Host, + &config.User, + &config.Password, + &config.ID, + &config.State, + &config.Description, + &configs.Count, + ) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, zerrors.ThrowNotFound(err, "QUERY-fwofw", "Errors.SMTPConfig.NotFound") + } + return nil, zerrors.ThrowInternal(err, "QUERY-9k87F", "Errors.Internal") + } + configs.Configs = append(configs.Configs, config) + } + return configs, nil + } +} + +func (q *Queries) SearchSMTPConfigs(ctx context.Context, queries *SMTPConfigsSearchQueries) (configs *SMTPConfigs, err error) { + ctx, span := tracing.NewSpan(ctx) + defer func() { span.EndWithError(err) }() + + query, scan := prepareSMTPConfigsQuery(ctx, q.client) + stmt, args, err := queries.toQuery(query). + Where(sq.Eq{ + SMTPConfigColumnInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(), + }).ToSql() + if err != nil { + return nil, zerrors.ThrowInvalidArgument(err, "QUERY-sZ7Cx", "Errors.Query.InvalidRequest") + } + + err = q.client.QueryContext(ctx, func(rows *sql.Rows) error { + configs, err = scan(rows) + return err + }, stmt, args...) + if err != nil { + return nil, zerrors.ThrowInternal(err, "QUERY-tOpKN", "Errors.Internal") + } + configs.State, err = q.latestState(ctx, smsConfigsTable) + return configs, err +} diff --git a/internal/query/smtp_test.go b/internal/query/smtp_test.go index 1e72fcdde3..e1824fd277 100644 --- a/internal/query/smtp_test.go +++ b/internal/query/smtp_test.go @@ -9,26 +9,28 @@ import ( "testing" "github.com/zitadel/zitadel/internal/crypto" + "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/zerrors" ) var ( - prepareSMTPConfigStmt = `SELECT projections.smtp_configs1.aggregate_id,` + - ` projections.smtp_configs1.creation_date,` + - ` projections.smtp_configs1.change_date,` + - ` projections.smtp_configs1.resource_owner,` + - ` projections.smtp_configs1.sequence,` + - ` projections.smtp_configs1.tls,` + - ` projections.smtp_configs1.sender_address,` + - ` projections.smtp_configs1.sender_name,` + - ` projections.smtp_configs1.reply_to_address,` + - ` projections.smtp_configs1.host,` + - ` projections.smtp_configs1.username,` + - ` projections.smtp_configs1.password` + - ` FROM projections.smtp_configs1` + + prepareSMTPConfigStmt = `SELECT projections.smtp_configs2.creation_date,` + + ` projections.smtp_configs2.change_date,` + + ` projections.smtp_configs2.resource_owner,` + + ` projections.smtp_configs2.sequence,` + + ` projections.smtp_configs2.tls,` + + ` projections.smtp_configs2.sender_address,` + + ` projections.smtp_configs2.sender_name,` + + ` projections.smtp_configs2.reply_to_address,` + + ` projections.smtp_configs2.host,` + + ` projections.smtp_configs2.username,` + + ` projections.smtp_configs2.password,` + + ` projections.smtp_configs2.id,` + + ` projections.smtp_configs2.state,` + + ` projections.smtp_configs2.description` + + ` FROM projections.smtp_configs2` + ` AS OF SYSTEM TIME '-1 ms'` prepareSMTPConfigCols = []string{ - "aggregate_id", "creation_date", "change_date", "resource_owner", @@ -40,6 +42,9 @@ var ( "smtp_host", "smtp_user", "smtp_password", + "id", + "state", + "description", } ) @@ -80,7 +85,6 @@ func Test_SMTPConfigsPrepares(t *testing.T) { regexp.QuoteMeta(prepareSMTPConfigStmt), prepareSMTPConfigCols, []driver.Value{ - "agg-id", testNow, testNow, "ro", @@ -92,11 +96,13 @@ func Test_SMTPConfigsPrepares(t *testing.T) { "host", "user", &crypto.CryptoValue{}, + "2232323", + domain.SMTPConfigStateActive, + "test", }, ), }, object: &SMTPConfig{ - AggregateID: "agg-id", CreationDate: testNow, ChangeDate: testNow, ResourceOwner: "ro", @@ -108,6 +114,93 @@ func Test_SMTPConfigsPrepares(t *testing.T) { Host: "host", User: "user", Password: &crypto.CryptoValue{}, + ID: "2232323", + State: domain.SMTPConfigStateActive, + Description: "test", + }, + }, + { + name: "prepareSMTPConfigQuery another config found", + prepare: prepareSMTPConfigQuery, + want: want{ + sqlExpectations: mockQuery( + regexp.QuoteMeta(prepareSMTPConfigStmt), + prepareSMTPConfigCols, + []driver.Value{ + testNow, + testNow, + "ro", + uint64(20211109), + true, + "sender2", + "name2", + "reply-to2", + "host2", + "user2", + &crypto.CryptoValue{}, + "44442323", + domain.SMTPConfigStateInactive, + "test2", + }, + ), + }, + object: &SMTPConfig{ + CreationDate: testNow, + ChangeDate: testNow, + ResourceOwner: "ro", + Sequence: 20211109, + TLS: true, + SenderAddress: "sender2", + SenderName: "name2", + ReplyToAddress: "reply-to2", + Host: "host2", + User: "user2", + Password: &crypto.CryptoValue{}, + ID: "44442323", + State: domain.SMTPConfigStateInactive, + Description: "test2", + }, + }, + { + name: "prepareSMTPConfigQuery yet another config found", + prepare: prepareSMTPConfigQuery, + want: want{ + sqlExpectations: mockQuery( + regexp.QuoteMeta(prepareSMTPConfigStmt), + prepareSMTPConfigCols, + []driver.Value{ + testNow, + testNow, + "ro", + uint64(20211109), + true, + "sender3", + "name3", + "reply-to3", + "host3", + "user3", + &crypto.CryptoValue{}, + "23234444", + domain.SMTPConfigStateInactive, + "test3", + }, + ), + }, + object: &SMTPConfig{ + CreationDate: testNow, + ChangeDate: testNow, + ResourceOwner: "ro", + Sequence: 20211109, + TLS: true, + SenderAddress: "sender3", + SenderName: "name3", + ReplyToAddress: "reply-to3", + Host: "host3", + User: "user3", + Password: &crypto.CryptoValue{}, + ID: "23234444", + State: domain.SMTPConfigStateInactive, + Description: "test3", }, }, { diff --git a/internal/repository/instance/eventstore.go b/internal/repository/instance/eventstore.go index 6b21ab6f29..d17dd2aa25 100644 --- a/internal/repository/instance/eventstore.go +++ b/internal/repository/instance/eventstore.go @@ -14,6 +14,8 @@ func init() { eventstore.RegisterFilterEventMapper(AggregateType, SecretGeneratorRemovedEventType, SecretGeneratorRemovedEventMapper) eventstore.RegisterFilterEventMapper(AggregateType, SMTPConfigAddedEventType, SMTPConfigAddedEventMapper) eventstore.RegisterFilterEventMapper(AggregateType, SMTPConfigChangedEventType, SMTPConfigChangedEventMapper) + eventstore.RegisterFilterEventMapper(AggregateType, SMTPConfigActivatedEventType, SMTPConfigActivatedEventMapper) + eventstore.RegisterFilterEventMapper(AggregateType, SMTPConfigDeactivatedEventType, SMTPConfigDeactivatedEventMapper) eventstore.RegisterFilterEventMapper(AggregateType, SMTPConfigPasswordChangedEventType, SMTPConfigPasswordChangedEventMapper) eventstore.RegisterFilterEventMapper(AggregateType, SMTPConfigRemovedEventType, SMTPConfigRemovedEventMapper) eventstore.RegisterFilterEventMapper(AggregateType, SMSConfigTwilioAddedEventType, SMSConfigTwilioAddedEventMapper) diff --git a/internal/repository/instance/smtp_config.go b/internal/repository/instance/smtp_config.go index b0da86cd2d..907375160b 100644 --- a/internal/repository/instance/smtp_config.go +++ b/internal/repository/instance/smtp_config.go @@ -4,6 +4,7 @@ import ( "context" "github.com/zitadel/zitadel/internal/crypto" + "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/eventstore" "github.com/zitadel/zitadel/internal/zerrors" ) @@ -14,23 +15,29 @@ const ( SMTPConfigChangedEventType = instanceEventTypePrefix + smtpConfigPrefix + "changed" SMTPConfigPasswordChangedEventType = instanceEventTypePrefix + smtpConfigPrefix + "password.changed" SMTPConfigRemovedEventType = instanceEventTypePrefix + smtpConfigPrefix + "removed" + SMTPConfigActivatedEventType = instanceEventTypePrefix + smtpConfigPrefix + "activated" + SMTPConfigDeactivatedEventType = instanceEventTypePrefix + smtpConfigPrefix + "deactivated" ) type SMTPConfigAddedEvent struct { eventstore.BaseEvent `json:"-"` - SenderAddress string `json:"senderAddress,omitempty"` - SenderName string `json:"senderName,omitempty"` - ReplyToAddress string `json:"replyToAddress,omitempty"` - TLS bool `json:"tls,omitempty"` - Host string `json:"host,omitempty"` - User string `json:"user,omitempty"` - Password *crypto.CryptoValue `json:"password,omitempty"` + ID string `json:"id,omitempty"` + Description string `json:"description,omitempty"` + SenderAddress string `json:"senderAddress,omitempty"` + SenderName string `json:"senderName,omitempty"` + ReplyToAddress string `json:"replyToAddress,omitempty"` + TLS bool `json:"tls,omitempty"` + Host string `json:"host,omitempty"` + User string `json:"user,omitempty"` + Password *crypto.CryptoValue `json:"password,omitempty"` + State domain.SMTPConfigState `json:"state,omitempty"` } func NewSMTPConfigAddedEvent( ctx context.Context, aggregate *eventstore.Aggregate, + id, description string, tls bool, senderAddress, senderName, @@ -45,6 +52,8 @@ func NewSMTPConfigAddedEvent( aggregate, SMTPConfigAddedEventType, ), + ID: id, + Description: description, TLS: tls, SenderAddress: senderAddress, SenderName: senderName, @@ -77,13 +86,15 @@ func SMTPConfigAddedEventMapper(event eventstore.Event) (eventstore.Event, error type SMTPConfigChangedEvent struct { eventstore.BaseEvent `json:"-"` - - FromAddress *string `json:"senderAddress,omitempty"` - FromName *string `json:"senderName,omitempty"` - ReplyToAddress *string `json:"replyToAddress,omitempty"` - TLS *bool `json:"tls,omitempty"` - Host *string `json:"host,omitempty"` - User *string `json:"user,omitempty"` + ID string `json:"id,omitempty"` + Description *string `json:"description,omitempty"` + FromAddress *string `json:"senderAddress,omitempty"` + FromName *string `json:"senderName,omitempty"` + ReplyToAddress *string `json:"replyToAddress,omitempty"` + TLS *bool `json:"tls,omitempty"` + Host *string `json:"host,omitempty"` + User *string `json:"user,omitempty"` + Password *crypto.CryptoValue `json:"password,omitempty"` } func (e *SMTPConfigChangedEvent) Payload() interface{} { @@ -97,6 +108,7 @@ func (e *SMTPConfigChangedEvent) UniqueConstraints() []*eventstore.UniqueConstra func NewSMTPConfigChangeEvent( ctx context.Context, aggregate *eventstore.Aggregate, + id string, changes []SMTPConfigChanges, ) (*SMTPConfigChangedEvent, error) { if len(changes) == 0 { @@ -108,6 +120,7 @@ func NewSMTPConfigChangeEvent( aggregate, SMTPConfigChangedEventType, ), + ID: id, } for _, change := range changes { change(changeEvent) @@ -117,6 +130,18 @@ func NewSMTPConfigChangeEvent( type SMTPConfigChanges func(event *SMTPConfigChangedEvent) +func ChangeSMTPConfigID(id string) func(event *SMTPConfigChangedEvent) { + return func(e *SMTPConfigChangedEvent) { + e.ID = id + } +} + +func ChangeSMTPConfigDescription(description string) func(event *SMTPConfigChangedEvent) { + return func(e *SMTPConfigChangedEvent) { + e.Description = &description + } +} + func ChangeSMTPConfigTLS(tls bool) func(event *SMTPConfigChangedEvent) { return func(e *SMTPConfigChangedEvent) { e.TLS = &tls @@ -153,6 +178,12 @@ func ChangeSMTPConfigSMTPUser(smtpUser string) func(event *SMTPConfigChangedEven } } +func ChangeSMTPConfigSMTPPassword(password *crypto.CryptoValue) func(event *SMTPConfigChangedEvent) { + return func(e *SMTPConfigChangedEvent) { + e.Password = password + } +} + func SMTPConfigChangedEventMapper(event eventstore.Event) (eventstore.Event, error) { e := &SMTPConfigChangedEvent{ BaseEvent: *eventstore.BaseEventFromRepo(event), @@ -168,13 +199,14 @@ func SMTPConfigChangedEventMapper(event eventstore.Event) (eventstore.Event, err type SMTPConfigPasswordChangedEvent struct { eventstore.BaseEvent `json:"-"` - - Password *crypto.CryptoValue `json:"password,omitempty"` + ID string `json:"id,omitempty"` + Password *crypto.CryptoValue `json:"password,omitempty"` } func NewSMTPConfigPasswordChangedEvent( ctx context.Context, aggregate *eventstore.Aggregate, + id string, password *crypto.CryptoValue, ) *SMTPConfigPasswordChangedEvent { return &SMTPConfigPasswordChangedEvent{ @@ -196,24 +228,106 @@ func (e *SMTPConfigPasswordChangedEvent) UniqueConstraints() []*eventstore.Uniqu } func SMTPConfigPasswordChangedEventMapper(event eventstore.Event) (eventstore.Event, error) { - smtpConfigPasswordChagned := &SMTPConfigPasswordChangedEvent{ + smtpConfigPasswordChanged := &SMTPConfigPasswordChangedEvent{ BaseEvent: *eventstore.BaseEventFromRepo(event), } - err := event.Unmarshal(smtpConfigPasswordChagned) + err := event.Unmarshal(smtpConfigPasswordChanged) if err != nil { return nil, zerrors.ThrowInternal(err, "IAM-99iNF", "unable to unmarshal smtp config password changed") } - return smtpConfigPasswordChagned, nil + return smtpConfigPasswordChanged, nil +} + +type SMTPConfigActivatedEvent struct { + eventstore.BaseEvent `json:"-"` + ID string `json:"id,omitempty"` +} + +func NewSMTPConfigActivatedEvent( + ctx context.Context, + aggregate *eventstore.Aggregate, + id string, +) *SMTPConfigActivatedEvent { + return &SMTPConfigActivatedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + SMTPConfigActivatedEventType, + ), + ID: id, + } +} + +func (e *SMTPConfigActivatedEvent) Payload() interface{} { + return e +} + +func (e *SMTPConfigActivatedEvent) UniqueConstraints() []*eventstore.UniqueConstraint { + return nil +} + +func SMTPConfigActivatedEventMapper(event eventstore.Event) (eventstore.Event, error) { + smtpConfigActivated := &SMTPConfigActivatedEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + } + err := event.Unmarshal(smtpConfigActivated) + if err != nil { + return nil, zerrors.ThrowInternal(err, "IAM-KPr5t", "unable to unmarshal smtp config removed") + } + + return smtpConfigActivated, nil +} + +type SMTPConfigDeactivatedEvent struct { + eventstore.BaseEvent `json:"-"` + ID string `json:"id,omitempty"` +} + +func NewSMTPConfigDeactivatedEvent( + ctx context.Context, + aggregate *eventstore.Aggregate, + id string, +) *SMTPConfigDeactivatedEvent { + return &SMTPConfigDeactivatedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + SMTPConfigDeactivatedEventType, + ), + ID: id, + } +} + +func (e *SMTPConfigDeactivatedEvent) Payload() interface{} { + return e +} + +func (e *SMTPConfigDeactivatedEvent) UniqueConstraints() []*eventstore.UniqueConstraint { + return nil +} + +func SMTPConfigDeactivatedEventMapper(event eventstore.Event) (eventstore.Event, error) { + smtpConfigDeactivated := &SMTPConfigDeactivatedEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + } + err := event.Unmarshal(smtpConfigDeactivated) + if err != nil { + return nil, zerrors.ThrowInternal(err, "IAM-KPr5t", "unable to unmarshal smtp config removed") + } + + return smtpConfigDeactivated, nil } type SMTPConfigRemovedEvent struct { eventstore.BaseEvent `json:"-"` + ID string `json:"id,omitempty"` } func NewSMTPConfigRemovedEvent( ctx context.Context, aggregate *eventstore.Aggregate, + id string, ) *SMTPConfigRemovedEvent { return &SMTPConfigRemovedEvent{ BaseEvent: *eventstore.NewBaseEventForPush( @@ -221,6 +335,7 @@ func NewSMTPConfigRemovedEvent( aggregate, SMTPConfigRemovedEventType, ), + ID: id, } } diff --git a/internal/static/i18n/bg.yaml b/internal/static/i18n/bg.yaml index e355256778..899fa9f0ce 100644 --- a/internal/static/i18n/bg.yaml +++ b/internal/static/i18n/bg.yaml @@ -56,6 +56,7 @@ Errors: SMTPConfig: NotFound: SMTP конфигурацията не е намерена AlreadyExists: SMTP конфигурация вече съществува + AlreadyDeactivated: SMTP конфигурацията вече е деактивирана SenderAdressNotCustomDomain: >- Адресът на изпращача трябва да бъде конфигуриран като персонализиран домейн в екземпляра. @@ -1151,6 +1152,9 @@ EventTypes: config: added: Добавена е SMTP конфигурация changed: SMTP конфигурацията е променена + activated: SMTP конфигурацията е активирана + deactivated: SMTP конфигурацията е деактивирана + removed: Премахната SMTP конфигурация password: changed: Тайната на конфигурацията на SMTP е променена sms: @@ -1305,6 +1309,8 @@ EventTypes: config: added: Добавена е SMTP конфигурация changed: SMTP конфигурацията е променена + activated: SMTP конфигурацията е активирана + deactivated: SMTP конфигурацията е деактивирана password: changed: Паролата на SMTP конфигурацията е променена removed: Премахната SMTP конфигурация diff --git a/internal/static/i18n/cs.yaml b/internal/static/i18n/cs.yaml index de02e20b27..b1e83a6d18 100644 --- a/internal/static/i18n/cs.yaml +++ b/internal/static/i18n/cs.yaml @@ -56,6 +56,7 @@ Errors: SMTPConfig: NotFound: Konfigurace SMTP nebyla nalezena AlreadyExists: Konfigurace SMTP již existuje + AlreadyDeactivated: Konfigurace SMTP je již deaktivována SenderAdressNotCustomDomain: Adresa odesílatele musí být nakonfigurována jako vlastní doména na instanci. Notification: NoDomain: Pro zprávu nebyla nalezena žádná doména @@ -1126,6 +1127,9 @@ EventTypes: config: added: Konfigurace SMTP přidána changed: Konfigurace SMTP změněna + activated: Konfigurace SMTP aktivována + deactivated: Konfigurace SMTP deaktivována + removed: Konfigurace SMTP odstraněna password: changed: Tajemství konfigurace SMTP změněno sms: @@ -1271,6 +1275,8 @@ EventTypes: config: added: Konfigurace SMTP přidána changed: Konfigurace SMTP změněna + activated: Konfigurace SMTP aktivována + deactivated: Konfigurace SMTP deaktivována password: changed: Heslo konfigurace SMTP změněno removed: Konfigurace SMTP odstraněna diff --git a/internal/static/i18n/de.yaml b/internal/static/i18n/de.yaml index 102892290a..12bd70bc40 100644 --- a/internal/static/i18n/de.yaml +++ b/internal/static/i18n/de.yaml @@ -56,6 +56,7 @@ Errors: SMTPConfig: NotFound: SMTP Konfiguration nicht gefunden AlreadyExists: SMTP Konfiguration existiert bereits + AlreadyDeactivated: SMTP-Konfiguration bereits deaktiviert SenderAdressNotCustomDomain: Die Sender Adresse muss als Custom Domain auf der Instanz registriert sein. Notification: NoDomain: Keine Domäne für Nachricht gefunden @@ -1128,6 +1129,9 @@ EventTypes: config: added: SMTP Konfiguration hinzugefügt changed: SMTP Konfiguration geändert + activated: SMTP Konfiguration aktiviert + deactivated: SMTP Konfiguration deaktiviert + removed: SMTP Konfiguration entfernt password: changed: SMTP Konfigurations Passwort geändert sms: @@ -1273,6 +1277,8 @@ EventTypes: config: added: SMTP Konfiguration hinzugefügt changed: SMTP Konfiguration geändert + activated: SMTP Konfiguration aktiviert + deactivated: SMTP Konfiguration deaktiviert password: changed: Passwort von SMTP Konfiguration geändert removed: SMTP Konfiguration gelöscht diff --git a/internal/static/i18n/en.yaml b/internal/static/i18n/en.yaml index 3d6a781412..511248da6e 100644 --- a/internal/static/i18n/en.yaml +++ b/internal/static/i18n/en.yaml @@ -56,6 +56,7 @@ Errors: SMTPConfig: NotFound: SMTP configuration not found AlreadyExists: SMTP configuration already exists + AlreadyDeactivated: SMTP configuration already deactivated SenderAdressNotCustomDomain: The sender address must be configured as custom domain on the instance. Notification: NoDomain: No Domain found for message @@ -787,7 +788,7 @@ EventTypes: code: added: Phone number code generated sent: Phone number code sent - removed: Phone number removed + profile: changed: User profile changed address: @@ -1128,6 +1129,9 @@ EventTypes: config: added: SMTP configuration added changed: SMTP configuration changed + activated: SMTP configuration activated + deactivated: SMTP configuration deactivated + removed: SMTP configuration removed password: changed: SMTP configuration secret changed sms: @@ -1273,6 +1277,8 @@ EventTypes: config: added: SMTP configuration added changed: SMTP configuration changed + activated: SMTP configuration activated + deactivated: SMTP configuration deactivated password: changed: Password of SMTP configuration changed removed: SMTP configuration removed diff --git a/internal/static/i18n/es.yaml b/internal/static/i18n/es.yaml index 620a5efd89..60115ca865 100644 --- a/internal/static/i18n/es.yaml +++ b/internal/static/i18n/es.yaml @@ -56,6 +56,7 @@ Errors: SMTPConfig: NotFound: configuración SMTP no encontrada AlreadyExists: la configuración SMTP ya existe + AlreadyDeactivated: la configuración SMTP ya está desactivada SenderAdressNotCustomDomain: La dirección del remitente debe configurarse como un dominio personalizado en la instancia. Notification: NoDomain: No se encontró el dominio para el mensaje @@ -1128,6 +1129,9 @@ EventTypes: config: added: Configuración SMTP añadida changed: Configuración SMTP modificada + activated: Configuración SMTP activada + deactivated: Configuración SMTP desactivada + removed: Configuración SMTP eliminada password: changed: Configuración de secreto SMTP modificada sms: @@ -1273,6 +1277,8 @@ EventTypes: config: added: Configuración SMTP añadida changed: Configuración SMTP modificada + activated: Configuración SMTP activada + deactivated: Configuración SMTP desactivada password: changed: Contraseña de configuración SMTP modificada removed: Configuración SMTP eliminada diff --git a/internal/static/i18n/fr.yaml b/internal/static/i18n/fr.yaml index cf0f944c97..8855ce5c46 100644 --- a/internal/static/i18n/fr.yaml +++ b/internal/static/i18n/fr.yaml @@ -56,6 +56,7 @@ Errors: SMTPConfig: NotFound: Configuration SMTP non trouvée AlreadyExists: La configuration SMTP existe déjà + AlreadyDeactivated: Configuration SMTP déjà désactivée SenderAdressNotCustomDomain: L'adresse de l'expéditeur doit être configurée comme un domaine personnalisé sur l'instance. Notification: NoDomain: Aucun domaine trouvé pour le message @@ -816,6 +817,12 @@ EventTypes: set: Ensemble de métadonnées de l'utilisateur removed: Métadonnées de l'utilisateur supprimées removed.all: Suppression de toutes les métadonnées utilisateur + domain: + claimed: Domaine revendiqué + claimed.sent: Notification de domaine revendiqué envoyée + pat: + added: Personal Access Token added + removed: Personal Access Token removed org: added: Organisation ajoutée changed: Organisation modifiée @@ -862,6 +869,10 @@ EventTypes: config: added: Configuration IDP SAML ajoutée changed: Modification de la configuration IDP SAML + jwt: + config: + added: Configuration JWT IDP ajoutée + changed: La configuration du fournisseur d'identité JWT a été modifiée customtext: set: Jeu de texte personnalisé removed: Texte personnalisé supprimé @@ -875,6 +886,8 @@ EventTypes: idpprovider: added: Fournisseur d'Idp ajouté à la politique de connexion removed: Idp Provider supprimé de la politique de connexion + cascade: + removed: Cascade de fournisseurs d'identité supprimée de la stratégie de connexion secondfactor: added: Second factor ajouté à la politique de connexion removed: Second facteur supprimé de la politique de connexion @@ -920,6 +933,14 @@ EventTypes: added: Politique de confidentialité et CGU ajoutés changed: Politique de confidentialité et CGU modifiées removed: Politique de confidentialité et conditions d'utilisation supprimées + domain: + added: Politique de domaine ajoutée + changed: Politique de domaine modifiée + removed: Politique de domaine supprimée + lockout: + added: Politique de verrouillage ajoutée + changed: La politique de verrouillage a été modifiée + removed: Politique de verrouillage supprimée notification: added: Politique de notification ajoutée changed: Politique de notification modifiée @@ -930,6 +951,20 @@ EventTypes: cascade: removed: Cascade d'actions supprimée removed: Actions supprimées + cleared: Flux effacé + mail: + template: + added: Modèle de courrier électronique ajouté + changed: Modèle d'e-mail modifié + removed: Modèle d'e-mail supprimé + text: + added: Texte de l'e-mail ajouté + changed: Le texte de l'e-mail a été modifié + removed: Texte de l'e-mail supprimé + metadata: + removed: Metadata removed + removed.all: All metadata removed + set: Metadata set project: added: Projet ajouté changed: Projet modifié @@ -1036,6 +1071,10 @@ EventTypes: saml: config: added: Ajout de la configuration SAML IDP + changed: La configuration SAML IDP a été modifiée + jwt: + config: + added: Configuration JWT du fournisseur d'identité ajoutée changed: Modification de la configuration de SAML IDP customtext: set: Le texte a été mis en place @@ -1085,6 +1124,9 @@ EventTypes: config: added: Ajout de la configuration SMTP changed: Modification de la configuration SMTP + activated: Configuration SMTP activée + deactivated: Configuration SMTP désactivée + removed: Configuration SMTP supprimée password: changed: Modification du secret de la configuration SMTP sms: @@ -1099,6 +1141,8 @@ EventTypes: deactivated: Fournisseur de SMS Twilio désactivé key_pair: added: Paire de clés ajoutée + certificate: + added: Certificat ajouté action: added: Action ajoutée changed: Action modifiée @@ -1111,7 +1155,134 @@ EventTypes: deactivated: Schéma utilisateur désactivé reactivated: Schéma utilisateur réactivé deleted: Schéma utilisateur supprimé +instance: + added: Instance ajoutée + changed: Instance modifiée + customtext: + removed: Texte personnalisé supprimé + set: Ensemble de texte personnalisé + template: + removed: Modèle de texte personnalisé supprimé + default: + language: + set: Langue par défaut définie + org: + set: Ensemble d'organisation par défaut + domain: + added: Domaine ajouté + primary: + set: Ensemble de domaines principal + removed: Domaine supprimé + iam: + console: + set: Ensemble d'applications Console ZITADEL + project: + set: ZITADEL project set + mail: + template: + added: Modèle de courrier électronique ajouté + changed: Modèle d'e-mail modifié + text: + added: Texte de l'e-mail ajouté + changed: Le texte de l'e-mail a été modifié + member: + added: Membre de l'instance ajouté + changed: Membre de l'instance modifié + removed: Membre de l'instance supprimé + cascade: + removed: Cascade de membres de l'instance supprimée + notification: + provider: + debug: + fileadded: Fournisseur de notification de débogage de fichiers ajouté + filechanged: Le fournisseur de notification de débogage de fichier a été modifié + fileremoved: Fournisseur de notification de débogage de fichier supprimé + logadded: Fournisseur de notification de débogage de journal ajouté + logchanged: Le fournisseur de notification de débogage du journal a été modifié + logremoved: Fournisseur de notification de débogage du journal supprimé + oidc: + settings: + added: Paramètres OIDC ajoutés + changed: Paramètres OIDC modifiés + policy: + domain: + added: Politique de domaine ajoutée + changed: Politique de domaine modifiée + label: + activated: Politique d'étiquetage activée + added: Politique d'étiquetage ajoutée + assets: + removed: L'élément de la stratégie d'étiquette a été supprimé + changed: Politique d'étiquetage modifiée + font: + added: Police ajoutée à la stratégie d'étiquette + removed: Police supprimée de la stratégie relative aux étiquettes + icon: + added: Icône ajoutée à la politique d'étiquetage + removed: Icône supprimée des règles relatives aux étiquettes + dark: + added: Icône ajoutée à la politique d'étiquette sombre + removed: Icône supprimée de la politique relative aux étiquettes sombres + logo: + added: Logo ajouté à la politique d'étiquetage + removed: Logo supprimé de la politique relative aux étiquettes + dark: + added: Logo ajouté à la politique relative aux étiquettes sombres + removed: Logo supprimé de la politique relative aux étiquettes sombres + lockout: + added: Politique de verrouillage ajoutée + changed: La politique de verrouillage a été modifiée + login: + added: Politique de connexion ajoutée + changed: Politique de connexion modifiée + idpprovider: + added: Fournisseur d'identité ajouté à la politique de connexion + cascade: + removed: Cascade de fournisseurs d'identité supprimée de la stratégie de connexion + removed: Fournisseur d'identité supprimé de la stratégie de connexion + multifactor: + added: Multifactor ajouté à la politique de connexion + removed: Multifactor supprimé de la politique de connexion + secondfactor: + added: Deuxième facteur ajouté à la politique de connexion + removed: Deuxième facteur supprimé de la politique de connexion + password: + age: + added: Politique d'âge du mot de passe ajoutée + changed: La politique relative à l'âge du mot de passe a été modifiée + complexity: + added: Politique de complexité des mots de passe ajoutée + changed: Politique de complexité des mots de passe supprimée + privacy: + added: Politique de confidentialité ajoutée + changed: Politique de confidentialité modifiée + security: + set: Ensemble de règles de sécurité + removed: Instance removed + secret: + generator: + added: Générateur de secrets ajouté + changed: Le générateur de secrets a changé + removed: Générateur de secrets supprimé + sms: + configtwilio: + activated: Configuration SMS Twilio activée + added: Configuration SMS Twilio ajoutée + changed: La configuration des SMS Twilio a été modifiée + deactivated: Configuration SMS Twilio désactivée + removed: Configuration SMS Twilio supprimée + token: + changed: Jeton de configuration SMS Twilio modifié + smtp: + config: + added: Configuration SMTP ajoutée + changed: Configuration SMTP modifiée + activated: Configuration SMTP activée + deactivated: Configuration SMTP désactivée + password: + changed: Mot de passe de configuration SMTP modifié + removed: Configuration SMTP supprimée Application: OIDC: UnsupportedVersion: Votre version de l'OIDC n'est pas prise en charge diff --git a/internal/static/i18n/it.yaml b/internal/static/i18n/it.yaml index a81121adf6..7005eaf311 100644 --- a/internal/static/i18n/it.yaml +++ b/internal/static/i18n/it.yaml @@ -56,6 +56,7 @@ Errors: SMTPConfig: NotFound: Configurazione SMTP non trovata AlreadyExists: La configurazione SMTP esiste già + AlreadyDeactivated: Configurazione SMTP già disattivata SenderAdressNotCustomDomain: L'indirizzo del mittente deve essere configurato come dominio personalizzato sull'istanza. Notification: NoDomain: Nessun dominio trovato per il messaggio @@ -218,7 +219,6 @@ Errors: EmptyString: I caratteri non numerici e alfabetici non validi sono stati sostituiti con spazi vuoti e il dominio risultante è una stringa vuota IDP: InvalidSearchQuery: Parametro di ricerca non valido - InvalidCharacter: Per un dominio sono ammessi solo caratteri alfanumerici, . e - ClientIDMissing: ClientID mancante TeamIDMissing: TeamID mancante KeyIDMissing: ID chiave mancante @@ -616,6 +616,7 @@ EventTypes: username: reserved: Nome utente riservato released: Nome utente rilasciato + changed: Nome utente cambiato email: reserved: Indirizzo e-mail riservato released: Indirizzo e-mail rilasciato @@ -786,6 +787,7 @@ EventTypes: code: added: Codice del numero di telefono generato sent: Codice del numero di telefono inviato + removed: Codice del numero di telefono rimosso profile: changed: Profilo utente cambiato address: @@ -799,7 +801,9 @@ EventTypes: succeeded: Controllo OTP riuscito failed: Controllo OTP fallito init: - skipped: Inizializzazione saltata + skipped: Inizializzazione OTP saltata + init: + skipped: Inizializzazione saltata signed: out: L'utente è uscito grant: @@ -817,6 +821,12 @@ EventTypes: set: Set di metadati utente removed: Metadati utente rimossi removed.all: Tutti i metadati utente rimossi + domain: + claimed: Dominio rivendicato + claimed.sent: Notifica di rivendicazione del dominio inviata + pat: + added: Aggiunto token di accesso personale + removed: Token di accesso personale rimosso org: added: Organizzazione aggiunta changed: Organizzazione cambiata @@ -863,6 +873,10 @@ EventTypes: config: added: Aggiunta la configurazione IDP SAML changed: Configurazione IDP SAML modificata + jwt: + config: + added: Aggiunta la configurazione IDP JWT + changed: La configurazione dell'IDP JWT è stata modificata customtext: set: Testo personalizzato salvato removed: Testo personalizzato rimosso @@ -876,6 +890,8 @@ EventTypes: idpprovider: added: IDP aggiunto alle impostazioni di accesso removed: IDP rimosso dalle impostazioni di accesso + cascade: + removed: Cascata di provider di identità rimossa dalla policy di accesso secondfactor: added: Secondo fattore aggiunto alle impostazioni di accesso removed: Secondo fattore rimosso dalle impostazioni di accesso @@ -921,6 +937,14 @@ EventTypes: added: Informativa sulla privacy e termini e condizioni aggiunti changed: Informativa sulla privacy e termini e condizioni cambiati removed: Informativa sulla privacy e termini e condizioni rimossi + domain: + added: Aggiunta politica di dominio + changed: La politica del dominio è cambiata + removed: Politica del dominio rimossa + lockout: + added: Lockout policy added + changed: Lockout policy changed + removed: Lockout policy removed notification: added: Impostazione di notifica creata changed: Impostazione di notifica cambiata @@ -931,6 +955,20 @@ EventTypes: cascade: removed: Azioni a cascata rimosse removed: Azioni rimosse + cleared: Il flusso è stato eliminato + mail: + template: + added: Aggiunto modello di posta elettronica + changed: Il modello di posta elettronica è stato modificato + removed: Modello di posta elettronica rimosso + text: + added: Aggiunto il testo dell'e-mail + changed: Il testo dell'e-mail è stato modificato + removed: Testo dell'e-mail rimosso + metadata: + removed: Metadati rimossi + removed.all: Tutti i metadati rimossi + set: Insieme di metadati project: added: Progetto aggiunto changed: Progetto cambiato @@ -1037,7 +1075,11 @@ EventTypes: saml: config: added: Aggiunta la configurazione IDP SAML - changed: Configurazione IDP SAML modificata + changed: La configurazione dell'IDP SAML è stata modificata + jwt: + config: + added: Aggiunta la configurazione JWT al provider di identità + changed: Configurazione JWT dal provider di identità rimossa customtext: set: Il testo è stato impostato removed: Il testo è stato rimosso @@ -1086,6 +1128,9 @@ EventTypes: config: added: SMTP configuration added changed: SMTP configuration changed + activated: Configurazione SMTP attivata + deactivated: Configurazione SMTP disattivata + removed: Configurazione SMTP rimossa password: changed: SMTP configuration secret changed sms: @@ -1100,6 +1145,8 @@ EventTypes: deactivated: Provider SMS Twilio disattivato key_pair: added: Keypair aggiunto + certificate: + added: Certificato aggiunto action: added: Azione aggiunta changed: Azione cambiata @@ -1112,6 +1159,134 @@ EventTypes: deactivated: Schema utente disattivato reactivated: Schema utente riattivato deleted: Schema utente eliminato + instance: + added: Istanza aggiunta + changed: L'istanza è cambiata + customtext: + removed: Testo personalizzato rimosso + set: Set di testo personalizzato + template: + removed: Modello di testo personalizzato rimosso + default: + language: + set: Lingua predefinita impostata + org: + set: Insieme di organizzazioni predefinito + domain: + added: Dominio aggiunto + primary: + set: Insieme di domini primari + removed: Dominio rimosso + iam: + console: + set: Set di applicazioni per console ZITADEL + project: + set: Set progetto ZITADEL + mail: + template: + added: Aggiunto modello di posta elettronica + changed: Il modello di posta elettronica è stato modificato + text: + added: Aggiunto il testo dell'e-mail + changed: Il testo dell'e-mail è stato modificato + member: + added: Membro dell'istanza aggiunto + changed: Il membro dell'istanza è cambiato + removed: Membro dell'istanza rimosso + cascade: + removed: Cascata di membri dell'istanza rimossa + notification: + provider: + debug: + fileadded: Aggiunto provider di notifiche di debug dei file + filechanged: Il provider delle notifiche di debug dei file è stato modificato + fileremoved: Provider di notifiche di debug del file rimosso + logadded: Aggiunto provider di notifiche di debug del registro + logchanged: Il provider delle notifiche di debug del registro è stato modificato + logremoved: Provider di notifiche di debug del registro rimosso + oidc: + settings: + added: Aggiunte impostazioni OIDC + changed: Le impostazioni OIDC sono state modificate + policy: + domain: + added: Aggiunta politica di dominio + changed: Domain policy changed + label: + activated: Criterio etichetta attivato + added: Aggiunta la politica sull'etichetta + assets: + removed: Risorsa dalla norma sull'etichetta rimossa + changed: La politica sull'etichetta è cambiata + font: + added: Carattere aggiunto ai criteri di etichetta + removed: Carattere rimosso dai criteri di etichetta + icon: + added: Icona aggiunta al criterio dell'etichetta + removed: Icona rimossa dal criterio di etichetta + dark: + added: Icona aggiunta al criterio dell'etichetta oscura + removed: Icona rimossa dal criterio dell'etichetta oscura + logo: + added: Logo aggiunto alla politica sull'etichetta + removed: Logo rimosso dalla politica sull'etichetta + dark: + added: Logo aggiunto alla politica delle etichette scure + removed: Logo rimosso dalla politica delle etichette scure + lockout: + added: Aggiunta politica di blocco + changed: La politica di blocco è cambiata + login: + added: Criteri di accesso aggiunti + changed: La politica di accesso è cambiata + idpprovider: + added: Provider di identità aggiunto alla policy di accesso + cascade: + removed: Cascata di provider di identità rimossa dalla policy di accesso + removed: Provider di identità rimosso dalla policy di accesso + multifactor: + added: Multifattore aggiunto alla policy di accesso + removed: Multifattore rimosso dalla policy di accesso + secondfactor: + added: Secondo fattore aggiunto alla politica di accesso + removed: Secondo fattore rimosso dalla politica di accesso + password: + age: + added: Aggiunta politica sull'età della password + changed: La politica di validità della password è cambiata + complexity: + added: Aggiunta policy sulla complessità della password + changed: Criterio di complessità della password rimosso + privacy: + added: Aggiunta informativa sulla privacy + changed: L'informativa sulla privacy è cambiata + security: + set: Insieme di politiche di sicurezza + + removed: Istanza rimossa + secret: + generator: + added: Aggiunto generatore segreto + changed: Il generatore segreto è cambiato + removed: Generatore segreto rimosso + sms: + configtwilio: + activated: Configurazione SMS Twilio attivata + added: Aggiunta la configurazione SMS di Twilio + changed: La configurazione SMS di Twilio è stata modificata + deactivated: Configurazione SMS Twilio disattivata + removed: Configurazione SMS di Twilio rimossa + token: + changed: La configurazione del token di Twilio SMS è stata modificata + smtp: + config: + added: Aggiunta configurazione SMTP + changed: La configurazione SMTP è stata modificata + activated: Configurazione SMTP attivata + deactivated: Configurazione SMTP disattivata + password: + changed: La password della configurazione SMTP è cambiata + removed: Configurazione SMTP rimossa Application: OIDC: diff --git a/internal/static/i18n/ja.yaml b/internal/static/i18n/ja.yaml index a86e272796..6eed3af3e7 100644 --- a/internal/static/i18n/ja.yaml +++ b/internal/static/i18n/ja.yaml @@ -56,6 +56,7 @@ Errors: SMTPConfig: NotFound: SMTP構成が見つかりません AlreadyExists: すでに存在するSMTP構成です + AlreadyDeactivated: SMTP設定はすでに無効化されています SenderAdressNotCustomDomain: 送信者アドレスは、インスタンスのカスタムドメインとして構成する必要があります。 Notification: NoDomain: メッセージのドメインが見つかりません @@ -1117,6 +1118,9 @@ EventTypes: config: added: SMTP構成の追加 changed: SMTP構成の変更 + activated: SMTP設定が有効化されました + deactivated: SMTP設定が無効化されました + removed: SMTP設定が削除されました password: changed: SMTP構成シークレットの変更 sms: @@ -1262,6 +1266,8 @@ EventTypes: config: added: SMTP構成の追加 changed: SMTP構成の変更 + activated: SMTP設定が有効化されました + deactivated: SMTP設定が無効化されました password: changed: SMTP構成パスワードの変更 removed: SMTP構成の削除 diff --git a/internal/static/i18n/mk.yaml b/internal/static/i18n/mk.yaml index 81a2f6a56e..f964ce2d71 100644 --- a/internal/static/i18n/mk.yaml +++ b/internal/static/i18n/mk.yaml @@ -56,6 +56,7 @@ Errors: SMTPConfig: NotFound: SMTP конфигурацијата не е пронајдена AlreadyExists: SMTP конфигурацијата веќе постои + AlreadyDeactivated: SMTP конфигурацијата е веќе деактивирана SenderAdressNotCustomDomain: Адресата на испраќачот мора да биде конфигурирана како прилагоден домен на инстанцата. Notification: NoDomain: Не е пронајден домен за пораката @@ -1127,6 +1128,9 @@ EventTypes: config: added: Додадена SMTP конфигурација changed: Променета SMTP конфигурација + activated: SMTP конфигурацијата е активирана + deactivated: SMTP конфигурацијата е деактивирана + removed: SMTP конфигурацијата е отстранета password: changed: Променена тајна на SMTP конфигурација sms: @@ -1271,6 +1275,8 @@ EventTypes: config: added: Додадена SMTP конфигурација changed: Променета SMTP конфигурација + activated: SMTP конфигурацијата е активирана + deactivated: SMTP конфигурацијата е деактивирана password: changed: Променета лозинка на SMTP конфигурацијата removed: Отстранета SMTP конфигурација diff --git a/internal/static/i18n/pl.yaml b/internal/static/i18n/pl.yaml index ed417ee6dc..33e7b77342 100644 --- a/internal/static/i18n/pl.yaml +++ b/internal/static/i18n/pl.yaml @@ -56,6 +56,7 @@ Errors: SMTPConfig: NotFound: Konfiguracja SMTP nie znaleziona AlreadyExists: Konfiguracja SMTP już istnieje + AlreadyDeactivated: Konfiguracja SMTP jest już dezaktywowana SenderAdressNotCustomDomain: Adres nadawcy musi być skonfigurowany jako domena niestandardowa na instancji. Notification: NoDomain: Nie znaleziono domeny dla wiadomości @@ -1128,6 +1129,9 @@ EventTypes: config: added: Dodano konfigurację SMTP changed: Zmieniono konfigurację SMTP + activated: Konfiguracja SMTP została aktywowana + deactivated: Konfiguracja SMTP dezaktywowana + removed: Konfiguracja SMTP została usunięta password: changed: Zmieniono sekret konfiguracji SMTP sms: @@ -1273,6 +1277,8 @@ EventTypes: config: added: Konfiguracja SMTP dodana changed: Konfiguracja SMTP zmieniona + activated: Konfiguracja SMTP została aktywowana + deactivated: Konfiguracja SMTP dezaktywowana password: changed: Hasło konfiguracji SMTP zmienione removed: Konfiguracja SMTP usunięta diff --git a/internal/static/i18n/pt.yaml b/internal/static/i18n/pt.yaml index f87ba02bac..89dab225c9 100644 --- a/internal/static/i18n/pt.yaml +++ b/internal/static/i18n/pt.yaml @@ -56,6 +56,7 @@ Errors: SMTPConfig: NotFound: Configuração de SMTP não encontrada AlreadyExists: Configuração de SMTP já existe + AlreadyDeactivated: Configuração SMTP já desativada SenderAdressNotCustomDomain: O endereço do remetente deve ser configurado como um domínio personalizado na instância. Notification: NoDomain: Nenhum domínio encontrado para a mensagem @@ -1122,6 +1123,9 @@ EventTypes: config: added: Configuração SMTP adicionada changed: Configuração SMTP alterada + activated: Configuração SMTP ativada + deactivated: Configuração SMTP desativada + removed: Configuração SMTP removida password: changed: Segredo da configuração SMTP alterado sms: @@ -1267,6 +1271,8 @@ EventTypes: config: added: Configuração SMTP adicionada changed: Configuração SMTP alterada + activated: Configuração SMTP ativada + deactivated: Configuração SMTP desativada password: changed: Senha da configuração SMTP alterada removed: Configuração SMTP removida diff --git a/internal/static/i18n/ru.yaml b/internal/static/i18n/ru.yaml index 5df3d13fca..3bb3cd64dc 100644 --- a/internal/static/i18n/ru.yaml +++ b/internal/static/i18n/ru.yaml @@ -56,7 +56,8 @@ Errors: SMTPConfig: NotFound: Конфигурация SMTP не найдена AlreadyExists: Конфигурация SMTP уже существует - SenderAdressNotCustomDomain: Адрес отправителя должен быть настроен как личный домен в экземпляре + AlreadyDeactivated: Конфигурация SMTP уже деактивирована + SenderAdressNotCustomDomain: Адрес отправителя должен быть настроен как личный домен на экземпляре. Notification: NoDomain: Домен не найден User: @@ -1117,6 +1118,9 @@ EventTypes: config: added: Конфигурация SMTP добавлена changed: Конфигурация SMTP изменена + activated: Конфигурация SMTP активирована + deactivated: Конфигурация SMTP деактивирована + removed: Конфигурация SMTP удалена. password: changed: Ключ конфигурации SMTP изменён sms: @@ -1262,6 +1266,8 @@ EventTypes: config: added: Конфигурация SMTP добавлена changed: Конфигурация SMTP изменена + activated: Конфигурация SMTP активирована + deactivated: Конфигурация SMTP деактивирована password: changed: Пароль конфигурации SMTP изменён removed: Конфигурация SMTP удалена diff --git a/internal/static/i18n/zh.yaml b/internal/static/i18n/zh.yaml index 65ac0dcea5..ee7bfec97c 100644 --- a/internal/static/i18n/zh.yaml +++ b/internal/static/i18n/zh.yaml @@ -56,6 +56,7 @@ Errors: SMTPConfig: NotFound: 未找到 SMTP 配置 AlreadyExists: SMTP 配置已存在 + AlreadyDeactivated: SMTP 配置已停用 SenderAdressNotCustomDomain: 发件人地址必须在在实例的域名设置中验证。 Notification: NoDomain: 未找到对应的域名 @@ -615,6 +616,7 @@ EventTypes: username: reserved: 保留用户名 released: 用户名已发布 + changed: 用户名已更改 email: reserved: 电子邮件地址已保留 released: 电子邮件地址已发布 @@ -670,6 +672,10 @@ EventTypes: check: succeeded: 密码检查成功 failed: 密码检查失败 + change: + sent: 密码更改已发送 + hash: + updated: 密码哈希已更新 externallogin: check: succeeded: 外部登录成功 @@ -773,10 +779,6 @@ EventTypes: check: succeeded: 密码检查成功 failed: 密码检查失败 - change: - sent: 密码更改已发送 - hash: - updated: 密码哈希已更新 phone: changed: 更改手机号码 verified: 验证手机号码 @@ -785,6 +787,7 @@ EventTypes: code: added: 生成的手机号码验证码 sent: 发送手机号码验证码 + removed: 电话号码已删除 profile: changed: 修改用户资料 address: @@ -797,8 +800,10 @@ EventTypes: check: succeeded: MFA OTP 验证成功 failed: MFA OTP 验证失败 + init: + skipped: 跳过 MFA 初始化 init: - skipped: 跳过 MFA 初始化 + skipped: 跳过多因素初始化 signed: out: 用户退出登录 grant: @@ -816,6 +821,12 @@ EventTypes: set: 用户元数据集 removed: 删除用户元数据 removed.all: 删除所有用户元数据 + domain: + claimed: 已认领域名 + claimed.sent: 已发送域声明通知 + pat: + added: 添加个人访问令牌 + removed: 个人访问令牌已删除 org: added: 添加组织 changed: 更改组织 @@ -862,6 +873,10 @@ EventTypes: config: added: 添加 SAML IDP 配置 changed: 更改 SAML IDP 配置 + jwt: + config: + added: 添加了 JWT IDP 配置 + changed: JWT IDP 配置已更改 customtext: set: 设置自定义文本 removed: 删除自定义文本 @@ -875,6 +890,8 @@ EventTypes: idpprovider: added: 添加 IDP 到登录策略 removed: 从登录策略删除 IDP + cascade: + removed: 从登录策略中删除了身份提供者级联 secondfactor: added: 添加两步认证到登录策略 removed: 删除两步认证到登录策略 @@ -918,6 +935,14 @@ EventTypes: removed: 从标签策略中删除的资产 privacy: added: 添加隐私政策和服务条款 + changed: 隐私政策和服务条款已更改 + removed: 隐私政策和 TOS 已删除 + domain: + added: 添加了域策略 + changed: 域策略已更改 + removed: 域策略已删除 + lockout: + added: 添加了锁定策略 changed: 更改隐私政策和服务条款 removed: 删除隐私政策和服务条款 notification: @@ -930,6 +955,20 @@ EventTypes: cascade: removed: 删除动作级联 removed: 删除动作 + cleared: 流量已清除 + mail: + template: + added: 添加了电子邮件模板 + changed: 电子邮件模板已更改 + removed: 电子邮件模板已删除 + text: + added: 添加了电子邮件文本 + changed: 电子邮件文本已更改 + removed: 电子邮件文本已删除 + metadata: + removed: 电子邮件文本已删除 + removed.all: 所有元数据已删除 + set: 元数据集 project: added: 添加项目 changed: 更改项目 @@ -1037,6 +1076,10 @@ EventTypes: config: added: 添加 SAML IDP 配置 changed: 更改 SAML IDP 配置 + jwt: + config: + added: 添加了身份提供者的 JWT 配置 + changed: 身份提供商的 JWT 配置已删除 customtext: set: 设置文本 removed: 删除文本 @@ -1085,6 +1128,9 @@ EventTypes: config: added: 添加 SMTP 配置 changed: 更改 SMTP 配置 + activated: SMTP 配置已激活 + deactivated: SMTP 配置已停用 + removed: SMTP 配置已删除 password: changed: 更改 SMTP 安全设置 sms: @@ -1099,6 +1145,8 @@ EventTypes: deactivated: 停用 Twilio SMS 提供者 key_pair: added: 添加密钥对 + certificate: + added: 证书已添加 action: added: 添加动作 changed: 更改动作 @@ -1111,6 +1159,134 @@ EventTypes: deactivated: 用户架构已停用 reactivated: 用户架构已重新激活 deleted: 用户架构已删除 + instance: + added: 实例已添加 + changed: 实例已更改 + customtext: + removed: 自定义文本已删除 + set: 自定义文本集 + template: + removed: 删除了自定义文本模板 + default: + language: + set: 默认语言设置 + org: + set: 默认组织集 + domain: + added: 已添加域名 + primary: + set: 主域集 + removed: 域名已删除 + iam: + console: + set: ZITADEL 控制台应用程序集 + project: + set: ZITADEL 项目集 + mail: + template: + added: 添加了电子邮件模板 + changed: 电子邮件模板已更改 + text: + added: 添加了电子邮件文本 + changed: 电子邮件文本已更改 + member: + added: 已添加实例成员 + changed: 实例成员发生变化 + removed: 实例成员已删除 + cascade: + removed: 实例成员级联已删除 + notification: + provider: + debug: + fileadded: 添加了文件调试通知提供程序 + filechanged: 文件调试通知提供程序已更改 + fileremoved: 删除文件调试通知提供程序 + logadded: 添加了日志调试通知提供程序 + logchanged: 日志调试通知提供程序已更改 + logremoved: 日志调试通知提供程序已删除 + oidc: + settings: + added: 添加了 OIDC 设置 + changed: OIDC 设置已更改 + policy: + domain: + added: 添加了域策略 + changed: 域策略已更改 + label: + activated: 标签政策已激活 + added: 添加了标签策略 + assets: + removed: 已删除标签政策中的资产 + changed: 标签政策已更改 + font: + added: 添加到标签政策的字体 + removed: 从标签政策中删除的字体 + icon: + added: 图标已添加到标签策略 + removed: 图标已从标签政策中删除 + dark: + added: 图标已添加到暗标签政策 + removed: 图标已从暗标签政策中删除 + logo: + added: 徽标已添加到标签政策中 + removed: 徽标已从标签政策中删除 + dark: + added: 徽标已添加到暗标签政策中 + removed: 徽标从暗标签政策中删除 + lockout: + added: 添加了锁定策略 + changed: 锁定政策已更改 + login: + added: 添加了登录策略 + changed: 登录政策已更改 + idpprovider: + added: 身份提供商已添加到登录策略中 + cascade: + removed: 身份提供者级联从登录策略中删除 + removed: 身份提供商已从登录策略中删除 + multifactor: + added: 登录策略中添加了多因素 + removed: 从登录策略中删除了多因素 + secondfactor: + added: 添加到登录策略的第二个因素 + removed: 从登录策略中删除了第二个因素 + password: + age: + added: 添加了密码年龄策略 + changed: 密码期限政策已更改 + complexity: + added: 添加了密码复杂性策略 + changed: 删除了密码复杂性策略 + privacy: + added: 添加了隐私政策 + changed: 隐私政策已更改 + security: + set: 安全策略集 + + removed: 实例已删除 + secret: + generator: + added: 添加了秘密生成器 + changed: 秘密生成器已更改 + removed: 秘密生成器已移除 + sms: + configtwilio: + activated: Twilio SMS 配置已激活 + added: 添加了 Twilio SMS 配置 + changed: Twilio SMS 配置已更改 + deactivated: Twilio SMS 配置已停用 + removed: Twilio SMS 配置已删除 + token: + changed: Twilio SMS 配置的令牌已更改 + smtp: + config: + added: 添加了 SMTP 配置 + changed: SMTP 配置已更改 + activated: SMTP 配置已激活 + deactivated: SMTP 配置已停用 + password: + changed: SMTP 配置密码已更改 + removed: SMTP 配置已删除 Application: OIDC: diff --git a/proto/zitadel/admin.proto b/proto/zitadel/admin.proto index b8a0d0290e..5f5639060a 100644 --- a/proto/zitadel/admin.proto +++ b/proto/zitadel/admin.proto @@ -381,8 +381,24 @@ service AdminService { option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { tags: "SMTP"; - summary: "Get SMTP Configuration"; - description: "Returns the SMTP configuration from the system. This is used to send E-Mails to the users." + summary: "Get active SMTP Configuration"; + description: "Returns the active SMTP configuration from the system. This is used to send E-Mails to the users." + }; + } + + rpc GetSMTPConfigById(GetSMTPConfigByIdRequest) returns (GetSMTPConfigByIdResponse) { + option (google.api.http) = { + get: "/smtp/{id}"; + }; + + option (zitadel.v1.auth_option) = { + permission: "iam.read"; + }; + + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + tags: "SMTP"; + summary: "Get SMTP provider configuration by its id"; + description: "Get a specific SMTP provider configuration by its ID."; }; } @@ -405,7 +421,7 @@ service AdminService { rpc UpdateSMTPConfig(UpdateSMTPConfigRequest) returns (UpdateSMTPConfigResponse) { option (google.api.http) = { - put: "/smtp"; + put: "/smtp/{id}"; body: "*" }; @@ -422,7 +438,7 @@ service AdminService { rpc UpdateSMTPConfigPassword(UpdateSMTPConfigPasswordRequest) returns (UpdateSMTPConfigPasswordResponse) { option (google.api.http) = { - put: "/smtp/password"; + put: "/smtp/{id}/password"; body: "*" }; @@ -437,9 +453,43 @@ service AdminService { }; } + rpc ActivateSMTPConfig(ActivateSMTPConfigRequest) returns (ActivateSMTPConfigResponse) { + option (google.api.http) = { + post: "/smtp/{id}/_activate"; + body: "*" + }; + + option (zitadel.v1.auth_option) = { + permission: "iam.write"; + }; + + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + tags: "SMTP Provider"; + summary: "Activate SMTP Provider"; + description: "Activate an SMTP provider." + }; + } + + rpc DeactivateSMTPConfig(DeactivateSMTPConfigRequest) returns (DeactivateSMTPConfigResponse) { + option (google.api.http) = { + post: "/smtp/{id}/_deactivate"; + body: "*" + }; + + option (zitadel.v1.auth_option) = { + permission: "iam.write"; + }; + + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + tags: "SMTP Provider"; + summary: "Deactivate SMTP Provider"; + description: "Deactivate an SMTP provider. After deactivating the provider, the users will not be able to receive SMTP notifications from that provider anymore." + }; + } + rpc RemoveSMTPConfig(RemoveSMTPConfigRequest) returns (RemoveSMTPConfigResponse) { option (google.api.http) = { - delete: "/smtp"; + delete: "/smtp/{id}"; }; option (zitadel.v1.auth_option) = { @@ -453,6 +503,23 @@ service AdminService { }; } + rpc ListSMTPConfigs(ListSMTPConfigsRequest) returns (ListSMTPConfigsResponse) { + option (google.api.http) = { + post: "/smtp/_search" + body: "*" + }; + + option (zitadel.v1.auth_option) = { + permission: "iam.read"; + }; + + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation) = { + tags: "SMTP Configs"; + summary: "List SMTP Configs"; + description: "Returns a list of SMTP configurations." + }; + } + rpc ListSMSProviders(ListSMSProvidersRequest) returns (ListSMSProvidersResponse) { option (google.api.http) = { post: "/sms/_search" @@ -4007,6 +4074,23 @@ message GetSMTPConfigResponse { zitadel.settings.v1.SMTPConfig smtp_config = 1; } +message GetSMTPConfigByIdRequest { + string id = 1 [(validate.rules).string = {min_len: 1, max_len: 100}]; +} + +message GetSMTPConfigByIdResponse { + zitadel.settings.v1.SMTPConfig smtp_config = 1; +} + +message ListSMTPConfigsRequest { + zitadel.v1.ListQuery query = 1; +} + +message ListSMTPConfigsResponse { + zitadel.v1.ListDetails details = 1; + repeated zitadel.settings.v1.SMTPConfig result = 2; +} + message AddSMTPConfigRequest { string sender_address = 1 [ (validate.rules).string = {min_len: 1, max_len: 200}, @@ -4051,7 +4135,15 @@ message AddSMTPConfigRequest { (validate.rules).string = {min_len: 0, max_len: 200}, (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { example: "\"replyto@m.zitadel.cloud\""; - min_length: 1; + min_length: 0; + max_length: 200; + } + ]; + string description = 8 [ + (validate.rules).string = {min_len: 0, max_len: 200}, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"provider description\""; + min_length: 0; max_length: 200; } ]; @@ -4059,6 +4151,7 @@ message AddSMTPConfigRequest { message AddSMTPConfigResponse { zitadel.v1.ObjectDetails details = 1; + string id = 2; } message UpdateSMTPConfigRequest { @@ -4104,6 +4197,20 @@ message UpdateSMTPConfigRequest { max_length: 200; } ]; + string password = 7 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"this-is-my-password\""; + } + ]; + string description = 8 [ + (validate.rules).string = {min_len: 0, max_len: 200}, + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"provider description\""; + min_length: 1; + max_length: 200; + } + ]; + string id = 9 [(validate.rules).string = {min_len: 1, max_len: 100}]; } message UpdateSMTPConfigResponse { @@ -4116,14 +4223,32 @@ message UpdateSMTPConfigPasswordRequest { example: "\"this-is-my-updated-password\""; } ]; + string id = 2 [(validate.rules).string = {min_len: 1, max_len: 100}]; } message UpdateSMTPConfigPasswordResponse { zitadel.v1.ObjectDetails details = 1; } -//this is an empty request -message RemoveSMTPConfigRequest {} +message ActivateSMTPConfigRequest { + string id = 1 [(validate.rules).string = {min_len: 1, max_len: 200}]; +} + +message ActivateSMTPConfigResponse { + zitadel.v1.ObjectDetails details = 1; +} + +message DeactivateSMTPConfigRequest { + string id = 1 [(validate.rules).string = {min_len: 1, max_len: 200}]; +} + +message DeactivateSMTPConfigResponse { + zitadel.v1.ObjectDetails details = 1; +} + +message RemoveSMTPConfigRequest { + string id = 1 [(validate.rules).string = {min_len: 1, max_len: 100}]; +} message RemoveSMTPConfigResponse { zitadel.v1.ObjectDetails details = 1; diff --git a/proto/zitadel/settings.proto b/proto/zitadel/settings.proto index ffb2dd9da8..18b343df08 100644 --- a/proto/zitadel/settings.proto +++ b/proto/zitadel/settings.proto @@ -40,6 +40,12 @@ message SecretGeneratorTypeQuery { SecretGeneratorType generator_type = 1; } +enum SMTPConfigState { + SMTP_CONFIG_STATE_UNSPECIFIED = 0; + SMTP_CONFIG_ACTIVE = 1; + SMTP_CONFIG_INACTIVE = 2; +} + enum SecretGeneratorType { SECRET_GENERATOR_TYPE_UNSPECIFIED = 0; SECRET_GENERATOR_TYPE_INIT_CODE = 1; @@ -80,6 +86,13 @@ message SMTPConfig { example: "\"replyto@m.zitadel.cloud\""; } ]; + SMTPConfigState state = 8; + string description = 9 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "\"Mailjet\""; + } + ]; + string id = 10; } message SMSProvider {