diff --git a/e2e/global-setup.ts b/e2e/global-setup.ts index 36a73b47db..9217ded795 100644 --- a/e2e/global-setup.ts +++ b/e2e/global-setup.ts @@ -36,13 +36,18 @@ const globalSetup = async (config: FullConfig): Promise => { process.env.NODE_ENV = 'test'; console.log(`Running tests with ${config.workers} workers`); - // Build plugins before starting tests (skip if already built in CI) + // Build plugins before starting tests (skip if already built) + // Check both the dev path (src/assets/) and the CI pre-built path (.tmp/angular-dist/) const pluginManifestPath = path.join( process.cwd(), 'src/assets/bundled-plugins/api-test-plugin/manifest.json', ); + const ciBuildManifestPath = path.join( + process.cwd(), + '.tmp/angular-dist/browser/assets/bundled-plugins/api-test-plugin/manifest.json', + ); - if (fs.existsSync(pluginManifestPath)) { + if (fs.existsSync(pluginManifestPath) || fs.existsSync(ciBuildManifestPath)) { console.log('Plugins already built, skipping...'); } else { console.log('Building bundled plugins...'); diff --git a/e2e/pages/supersync.page.ts b/e2e/pages/supersync.page.ts index 24fe37ad19..b6d1bcccbe 100644 --- a/e2e/pages/supersync.page.ts +++ b/e2e/pages/supersync.page.ts @@ -345,6 +345,12 @@ export class SuperSyncPage extends BasePage { decryptErrorDialog .waitFor({ state: 'visible', timeout: encSyncTimeout }) .then(() => 'decrypt_error_dialog' as const), + // Mandatory encryption dialog (disableClose:true) opened by sync wrapper + // after successful sync when SuperSync has no encryption configured + enableEncryptionDialog + .first() + .waitFor({ state: 'visible', timeout: encSyncTimeout }) + .then(() => 'enable_encryption_dialog' as const), // Sync error icon indicates encrypted data received but no password this.syncErrorIcon .waitFor({ state: 'visible', timeout: encSyncTimeout }) @@ -369,6 +375,16 @@ export class SuperSyncPage extends BasePage { // Decryption error - this shouldn't happen with correct password console.log('[SuperSyncPage] Decrypt error dialog appeared - unexpected'); throw new Error('Decrypt error dialog appeared - password may be incorrect'); + } else if (outcome === 'enable_encryption_dialog') { + // Mandatory encryption dialog appeared (disableClose:true) - Client A + // Handle it directly since ensureOverlaysClosed cannot dismiss it + console.log( + '[SuperSyncPage] Mandatory encryption dialog appeared - handling directly', + ); + await this._fillAndConfirmEncryptionDialog( + enableEncryptionDialog, + config.password!, + ); } else if (outcome === 'fresh_client_dialog') { // Fresh client dialog - server has no encrypted data yet // This means we're Client A (first client) @@ -863,6 +879,25 @@ export class SuperSyncPage extends BasePage { * Prerequisites: SuperSync must already be configured without encryption */ async enableEncryption(password: string): Promise { + const enableEncryptionDialog = this.page.locator('dialog-enable-encryption'); + + // Check if the mandatory encryption dialog is already open. + // The sync wrapper opens this dialog with disableClose:true when SuperSync + // is configured without encryption, so ensureOverlaysClosed() cannot dismiss it. + const isEncDialogAlreadyOpen = await enableEncryptionDialog + .isVisible() + .catch(() => false); + + if (isEncDialogAlreadyOpen) { + console.log( + '[SuperSyncPage] Mandatory encryption dialog already open - handling directly', + ); + await this._fillAndConfirmEncryptionDialog(enableEncryptionDialog, password); + await this._waitForEncryptionSyncComplete(); + return; + } + + // No encryption dialog open - open settings and enable encryption manually // Open sync settings via right-click // Use noWaitAfter to prevent blocking on Angular hash navigation await this.syncBtn.click({ button: 'right', noWaitAfter: true }); @@ -876,20 +911,7 @@ export class SuperSyncPage extends BasePage { // The listener is async and needs time to load provider config and update the form await this.page.waitForTimeout(1000); - // Expand "Advanced settings" collapsible to access encryption fields - const advancedCollapsible = this.page.locator( - '.collapsible-header:has-text("Advanced")', - ); - await advancedCollapsible.waitFor({ state: 'visible', timeout: 5000 }); - - // Check if already expanded - const isExpanded = await this.enableEncryptionBtn.isVisible().catch(() => false); - if (!isExpanded) { - await advancedCollapsible.click(); - await this.enableEncryptionBtn.waitFor({ state: 'visible', timeout: 3000 }); - } - - // Check if already enabled + // Check if already enabled (button is visible at top level for SuperSync, not inside Advanced) const isEnabled = await this.disableEncryptionBtn.isVisible().catch(() => false); if (isEnabled) { // Already enabled - just close the dialog @@ -900,38 +922,50 @@ export class SuperSyncPage extends BasePage { return; } + // Check if the enable encryption button is visible (for SuperSync it's at the top level) + let enableBtnVisible = await this.enableEncryptionBtn.isVisible().catch(() => false); + + if (!enableBtnVisible) { + // Try expanding "Advanced settings" collapsible + const advancedCollapsible = this.page.locator( + '.collapsible-header:has-text("Advanced")', + ); + const advancedExists = await advancedCollapsible.isVisible().catch(() => false); + if (advancedExists) { + await advancedCollapsible.click(); + enableBtnVisible = await this.enableEncryptionBtn + .waitFor({ state: 'visible', timeout: 3000 }) + .then(() => true) + .catch(() => false); + } + } + + if (!enableBtnVisible) { + throw new Error( + 'Enable encryption button not visible after checking top level and Advanced section', + ); + } + // Enable encryption by clicking the "Enable Encryption" button which opens a dialog - await this.enableEncryptionBtn.waitFor({ state: 'visible', timeout: 5000 }); await this.enableEncryptionBtn.click(); // Wait for the Enable Encryption dialog to appear - const enableEncryptionDialog = this.page.locator('dialog-enable-encryption'); await enableEncryptionDialog.waitFor({ state: 'visible', timeout: 5000 }); - // Fill in the password fields - const passwordInput = enableEncryptionDialog - .locator('input[type="password"]') - .first(); - const confirmPasswordInput = enableEncryptionDialog - .locator('input[type="password"]') - .nth(1); - await passwordInput.fill(password); - await confirmPasswordInput.fill(password); + await this._fillAndConfirmEncryptionDialog(enableEncryptionDialog, password); - // Click the confirm button (has mat-flat-button and text includes "Enable") - const confirmBtn = enableEncryptionDialog.locator( - 'button[mat-flat-button]:has-text("Enable")', - ); - await confirmBtn.click(); + // Close the "Configure Sync" dialog if still open + const configDialogCount = await this.page.locator('mat-dialog-container').count(); + if (configDialogCount > 0) { + const configDialog = this.page.locator('mat-dialog-container').first(); + const cancelBtn = configDialog.locator('button').filter({ hasText: /cancel/i }); + const hasCancelBtn = await cancelBtn.isVisible().catch(() => false); + if (hasCancelBtn) { + await cancelBtn.click(); + } + } - await this.page.waitForTimeout(500); - - // Close the "Configure Sync" dialog - const configDialog = this.page.locator('mat-dialog-container').first(); - const cancelBtn = configDialog.locator('button').filter({ hasText: /cancel/i }); - await cancelBtn.click(); - - // Wait for dialog to close + // Wait for all dialogs to close await expect(this.page.locator('mat-dialog-container')).toHaveCount(0, { timeout: 10000, }); @@ -940,7 +974,44 @@ export class SuperSyncPage extends BasePage { // This handles backdrop removal and any lingering dialogs await this.ensureOverlaysClosed(); - // Wait for clean slate sync to complete + await this._waitForEncryptionSyncComplete(); + } + + /** + * Fill in the encryption dialog password fields and click confirm. + */ + private async _fillAndConfirmEncryptionDialog( + dialog: Locator, + password: string, + ): Promise { + const passwordInput = dialog.locator('input[type="password"]').first(); + const confirmPasswordInput = dialog.locator('input[type="password"]').nth(1); + await passwordInput.fill(password); + await confirmPasswordInput.fill(password); + + // Click the confirm button (has mat-flat-button and text includes "Enable") + const confirmBtn = dialog.locator('button[mat-flat-button]:has-text("Enable")'); + await confirmBtn.click(); + + await this.page.waitForTimeout(500); + + // Wait for the encryption dialog to close + await dialog.waitFor({ state: 'hidden', timeout: 15000 }).catch(() => {}); + + // Wait for any remaining dialogs to close + await expect(this.page.locator('mat-dialog-container')) + .toHaveCount(0, { + timeout: 10000, + }) + .catch(() => {}); + + await this.ensureOverlaysClosed(); + } + + /** + * Wait for the clean slate sync to complete after enabling/disabling encryption. + */ + private async _waitForEncryptionSyncComplete(): Promise { const spinnerAppeared = await this.syncSpinner .waitFor({ state: 'visible', timeout: 5000 }) .then(() => true) diff --git a/package-lock.json b/package-lock.json index 1b7ccdbe91..07f322682e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -442,6 +442,40 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/@angular-devkit/architect/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@angular-devkit/architect/node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@angular-devkit/build-angular": { "version": "21.2.0", "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-21.2.0.tgz", @@ -1233,6 +1267,102 @@ "node": ">=18" } }, + "node_modules/@angular-devkit/build-angular/node_modules/@vitest/expect": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz", + "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "chai": "^6.2.1", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@vitest/pretty-format": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz", + "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@vitest/runner": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz", + "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@vitest/utils": "4.0.18", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@vitest/snapshot": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz", + "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@vitest/pretty-format": "4.0.18", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@vitest/spy": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz", + "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@vitest/utils": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz", + "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@vitest/pretty-format": "4.0.18", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/@angular-devkit/build-angular/node_modules/ajv": { "version": "8.18.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", @@ -1263,6 +1393,18 @@ "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, + "node_modules/@angular-devkit/build-angular/node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=18" + } + }, "node_modules/@angular-devkit/build-angular/node_modules/chalk": { "version": "5.6.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", @@ -1276,6 +1418,24 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/@angular-devkit/build-angular/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@angular-devkit/build-angular/node_modules/cli-spinners": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-3.4.0.tgz", @@ -1412,6 +1572,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@angular-devkit/build-angular/node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@angular-devkit/build-angular/node_modules/semver": { "version": "7.7.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", @@ -1458,6 +1634,18 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "node_modules/@angular-devkit/build-angular/node_modules/tinyexec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=18" + } + }, "node_modules/@angular-devkit/build-angular/node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -1475,6 +1663,127 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/@angular-devkit/build-angular/node_modules/tinyrainbow": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", + "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/vitest": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", + "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@vitest/expect": "4.0.18", + "@vitest/mocker": "4.0.18", + "@vitest/pretty-format": "4.0.18", + "@vitest/runner": "4.0.18", + "@vitest/snapshot": "4.0.18", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "es-module-lexer": "^1.7.0", + "expect-type": "^1.2.2", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^3.10.0", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3", + "vite": "^6.0.0 || ^7.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.0.18", + "@vitest/browser-preview": "4.0.18", + "@vitest/browser-webdriverio": "4.0.18", + "@vitest/ui": "4.0.18", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/vitest/node_modules/@vitest/mocker": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz", + "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@vitest/spy": "4.0.18", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, "node_modules/@angular-devkit/build-webpack": { "version": "0.2102.0", "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.2102.0.tgz", @@ -1585,6 +1894,24 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/@angular-devkit/schematics/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@angular-devkit/schematics/node_modules/cli-spinners": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-3.4.0.tgz", @@ -1664,6 +1991,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@angular-devkit/schematics/node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@angular-devkit/schematics/node_modules/string-width": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.0.tgz", @@ -1979,6 +2322,24 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/@angular/cli/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@angular/cli/node_modules/cliui": { "version": "9.0.1", "dev": true, @@ -2005,6 +2366,22 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/@angular/cli/node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@angular/cli/node_modules/semver": { "version": "7.7.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", @@ -5416,6 +5793,17 @@ "node": ">=10.12.0" } }, + "node_modules/@electron/asar/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/@electron/asar/node_modules/commander": { "version": "5.1.0", "dev": true, @@ -5444,19 +5832,16 @@ } }, "node_modules/@electron/asar/node_modules/minimatch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", - "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "ISC", "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" + "brace-expansion": "^1.1.7" }, "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": "*" } }, "node_modules/@electron/fuses": { @@ -5776,6 +6161,7 @@ "os": [ "aix" ], + "peer": true, "engines": { "node": ">=18" } @@ -5793,6 +6179,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -5810,6 +6197,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -5827,6 +6215,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -5844,6 +6233,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=18" } @@ -5861,6 +6251,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=18" } @@ -5878,6 +6269,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -5895,6 +6287,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -5912,6 +6305,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -5929,6 +6323,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -5946,6 +6341,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -5963,6 +6359,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -5980,6 +6377,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -5997,6 +6395,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -6014,6 +6413,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -6031,6 +6431,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -6046,6 +6447,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -6063,6 +6465,7 @@ "os": [ "netbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -6080,6 +6483,7 @@ "os": [ "netbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -6097,6 +6501,7 @@ "os": [ "openbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -6114,6 +6519,7 @@ "os": [ "openbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -6131,6 +6537,7 @@ "os": [ "openharmony" ], + "peer": true, "engines": { "node": ">=18" } @@ -6148,6 +6555,7 @@ "os": [ "sunos" ], + "peer": true, "engines": { "node": ">=18" } @@ -6165,6 +6573,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -6182,6 +6591,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -6199,6 +6609,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -6627,27 +7038,6 @@ "glob": "^11.0.0" } }, - "node_modules/@fastify/static/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@fastify/static/node_modules/brace-expansion": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", - "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, "node_modules/@fastify/static/node_modules/content-disposition": { "version": "0.5.4", "license": "MIT", @@ -10580,6 +10970,40 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/@schematics/angular/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@schematics/angular/node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@sigstore/bundle": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-4.0.0.tgz", @@ -13866,7 +14290,6 @@ "version": "5.0.4", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" @@ -13879,7 +14302,6 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, "license": "MIT", "engines": { "node": "18 || 20 || >=22" @@ -18217,20 +18639,27 @@ "minimatch": "^5.0.1" } }, - "node_modules/filelist/node_modules/minimatch": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", - "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" }, "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=10" } }, "node_modules/fill-range": { @@ -22244,29 +22673,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/minimatch/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/minimatch/node_modules/brace-expansion": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.3.tgz", - "integrity": "sha512-fy6KJm2RawA5RcHkLa1z/ScpBeA762UF9KmZQxwIbDtRJrgLzM10depAiEQ+CXYcoiqW1/m96OAAoke2nE9EeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, "node_modules/minimist": { "version": "1.2.8", "license": "MIT", @@ -23448,6 +23854,19 @@ "dev": true, "license": "MIT" }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/on-exit-leak-free": { "version": "2.1.2", "license": "MIT", @@ -24565,6 +24984,7 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -29224,6 +29644,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": "^8.16.0 || ^10.6.0 || >=11.0.0" }