Claude/fix failing e2e tests ov lxs (#6721)

* test(e2e): fix SuperSync encryption overlay and plugin build in CI

Two root causes for failing e2e tests:

1. Plugin build failure in global-setup.ts: The plugin manifest check
   only looked at the dev path (src/assets/bundled-plugins/) but not the
   CI pre-built path (.tmp/angular-dist/browser/assets/bundled-plugins/).
   In CI, the frontend is pre-built and downloaded as an artifact, so the
   dev path doesn't exist. This caused all WebDAV tests to fail.

2. SuperSync enableEncryption overlay blocking: The sync wrapper opens
   a mandatory encryption dialog with disableClose:true after a successful
   sync when encryption is not yet configured. ensureOverlaysClosed()
   uses Escape key which cannot dismiss disableClose dialogs.

   Fixes:
   - Add enableEncryptionDialog to the sync outcome race so the mandatory
     dialog is detected immediately instead of waiting for a 30s timeout
   - enableEncryption() now checks if the dialog is already open and
     handles it directly instead of trying to right-click the sync button
   - Extract _fillAndConfirmEncryptionDialog() and
     _waitForEncryptionSyncComplete() helpers for reuse
   - Improve enable encryption button lookup to check both top-level
     (SuperSync) and Advanced collapsible positions

https://claude.ai/code/session_01CnQXCAB3WYnYdKPbNEqUS3

* chore: update package-lock.json after npm install

Regenerated lock file to resolve workspace dependencies including
vite-plugin's devDependencies (@types/node, vite, typescript).

https://claude.ai/code/session_01CnQXCAB3WYnYdKPbNEqUS3

---------

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Johannes Millan 2026-03-04 00:59:02 +01:00 committed by GitHub
parent af373e4e5b
commit 6394fa4363
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 603 additions and 106 deletions

View file

@ -36,13 +36,18 @@ const globalSetup = async (config: FullConfig): Promise<void> => {
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...');

View file

@ -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<void> {
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<void> {
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<void> {
const spinnerAppeared = await this.syncSpinner
.waitFor({ state: 'visible', timeout: 5000 })
.then(() => true)

551
package-lock.json generated
View file

@ -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"
}