diff --git a/.gitignore b/.gitignore index 7f5dce7e..85ce3a4f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,9 @@ .vscode .idea .claude +.angular dist +dist-demo build coverage node_modules diff --git a/.npmrc b/.npmrc index ec422f31..d408b358 100644 --- a/.npmrc +++ b/.npmrc @@ -3,3 +3,6 @@ auto-install-peers=true # Strict peer dependencies strict-peer-dependencies=false + +# Angular library compilation imports TypeScript helpers from tslib implicitly. +public-hoist-pattern[]=tslib diff --git a/README.md b/README.md index f4772c2a..4174a707 100644 --- a/README.md +++ b/README.md @@ -108,19 +108,21 @@ Ready-made plugins for your stack: - ✅ **Nuxt** — Auto-imported, SSR-compatible - ✅ **React** — Component & hook with modern React patterns - ✅ **Svelte** — Component, composable, action, and attachment for Svelte 5 +- ✅ **Angular** — Standalone component, directive, pipe, and service - ✅ **TypeScript/Vanilla JS** — Framework-agnostic core --- ## 📦 Packages -| Package | Version | Description | -| ----------------------------------------------------------- | --------------------------------------------------------------------------------------- | ----------------------------------------------------- | -| [@desource/phone-mask](./packages/phone-mask) | ![npm](https://img.shields.io/npm/v/@desource/phone-mask?color=blue&logo=typescript) | Core library — TypeScript/JS | -| [@desource/phone-mask-react](./packages/phone-mask-react) | ![npm](https://img.shields.io/npm/v/@desource/phone-mask-react?color=blue&logo=react) | React component + hook | -| [@desource/phone-mask-vue](./packages/phone-mask-vue) | ![npm](https://img.shields.io/npm/v/@desource/phone-mask-vue?color=blue&logo=vuedotjs) | Vue 3 component + composable + directive | -| [@desource/phone-mask-svelte](./packages/phone-mask-svelte) | ![npm](https://img.shields.io/npm/v/@desource/phone-mask-svelte?color=blue&logo=svelte) | Svelte 5 component + composable + action + attachment | -| [@desource/phone-mask-nuxt](./packages/phone-mask-nuxt) | ![npm](https://img.shields.io/npm/v/@desource/phone-mask-nuxt?color=blue&logo=nuxt) | Nuxt module | +| Package | Version | Description | +| ------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------- | +| [@desource/phone-mask](./packages/phone-mask) | ![npm](https://img.shields.io/npm/v/@desource/phone-mask?color=blue&logo=typescript) | Core library — TypeScript/JS | +| [@desource/phone-mask-react](./packages/phone-mask-react) | ![npm](https://img.shields.io/npm/v/@desource/phone-mask-react?color=blue&logo=react) | React component + hook | +| [@desource/phone-mask-vue](./packages/phone-mask-vue) | ![npm](https://img.shields.io/npm/v/@desource/phone-mask-vue?color=blue&logo=vuedotjs) | Vue 3 component + composable + directive | +| [@desource/phone-mask-svelte](./packages/phone-mask-svelte) | ![npm](https://img.shields.io/npm/v/@desource/phone-mask-svelte?color=blue&logo=svelte) | Svelte 5 component + composable + action + attachment | +| [@desource/phone-mask-angular](./packages/phone-mask-angular) | ![npm](https://img.shields.io/npm/v/@desource/phone-mask-angular?color=blue&logo=angular) | Angular component + directive + pipe + service | +| [@desource/phone-mask-nuxt](./packages/phone-mask-nuxt) | ![npm](https://img.shields.io/npm/v/@desource/phone-mask-nuxt?color=blue&logo=nuxt) | Nuxt module | --- @@ -181,6 +183,27 @@ npm install @desource/phone-mask-svelte ``` +### Angular + +```bash +npm install @desource/phone-mask-angular +``` + +```ts +import { Component, signal } from '@angular/core'; +import { PhoneInputComponent } from '@desource/phone-mask-angular'; + +@Component({ + selector: 'app-phone', + standalone: true, + imports: [PhoneInputComponent], + template: `` +}) +export class PhoneComponent { + readonly phone = signal(''); +} +``` + ### Nuxt ```bash diff --git a/common/tests/unit/setup/tools.ts b/common/tests/unit/setup/tools.ts index b231461e..f149f690 100644 --- a/common/tests/unit/setup/tools.ts +++ b/common/tests/unit/setup/tools.ts @@ -7,7 +7,7 @@ */ type FireEventReturn = Promise | Promise | boolean; -export type MaybeRef = T | { value: T }; +export type MaybeRef = T | { value: T } | (() => T); export interface TestTools { toValue: (val: MaybeRef) => T; diff --git a/eslint.config.js b/eslint.config.js index 1e717ede..59afabad 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -7,6 +7,7 @@ import svelte from 'eslint-plugin-svelte'; import svelteParser from 'svelte-eslint-parser'; import react from 'eslint-plugin-react'; import reactHooks from 'eslint-plugin-react-hooks'; +import angular from 'angular-eslint'; import prettier from 'eslint-config-prettier'; import globals from 'globals'; @@ -14,6 +15,8 @@ const TS_FILES = ['**/*.ts', '**/*.tsx', '**/*.mts', '**/*.cts']; const JS_FILES = ['**/*.js', '**/*.mjs', '**/*.cjs', '**/*.jsx']; const REACT_FILES = ['packages/phone-mask-react/**/*.{ts,tsx,js,jsx}']; +const ANGULAR_TS_FILES = ['packages/phone-mask-angular/**/*.ts']; +const ANGULAR_TEMPLATE_FILES = ['packages/phone-mask-angular/**/*.html']; const VUE_SFC_FILES = ['packages/phone-mask-vue/**/*.vue', 'packages/phone-mask-nuxt/**/*.vue', 'demo/**/*.vue']; const VUE_TS_FILES = [ 'packages/phone-mask-vue/**/*.{ts,mts,cts}', @@ -31,6 +34,7 @@ const BROWSER_FILES = [ 'packages/phone-mask-react/**/*.{ts,tsx,js,jsx}', 'packages/phone-mask-vue/**/*.{ts,js,mts,cts,vue}', 'packages/phone-mask-svelte/**/*.{ts,js,mts,cts,svelte}', + 'packages/phone-mask-angular/**/*.{ts,js,mts,cts}', 'demo/**/*.{ts,tsx,js,jsx,vue}' ]; @@ -56,6 +60,7 @@ export default [ ignores: [ '**/node_modules/**', '**/dist/**', + '**/dist-demo/**', '**/.nuxt/**', '**/.output/**', '**/.svelte-kit/**', @@ -149,6 +154,31 @@ export default [ } }, + ...angular.configs.tsRecommended.map((config) => ({ + ...config, + files: ANGULAR_TS_FILES + })), + + { + files: ANGULAR_TS_FILES, + processor: angular.processInlineTemplates, + rules: { + '@angular-eslint/no-input-rename': 'off', + '@angular-eslint/no-output-native': 'off', + '@angular-eslint/no-output-rename': 'off' + } + }, + + ...angular.configs.templateRecommended.map((config) => ({ + ...config, + files: ANGULAR_TEMPLATE_FILES + })), + + ...angular.configs.templateAccessibility.map((config) => ({ + ...config, + files: ANGULAR_TEMPLATE_FILES + })), + { files: VUE_TS_FILES, languageOptions: { diff --git a/package.json b/package.json index b2fab01f..cf7dc652 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "@typescript-eslint/eslint-plugin": "^8.59.2", "@typescript-eslint/parser": "^8.59.2", "@vitest/coverage-v8": "^4.1.5", + "angular-eslint": "^21.3.1", "eslint": "^9.39.4", "eslint-config-prettier": "^10.1.8", "eslint-plugin-react": "^7.37.5", diff --git a/packages/phone-mask-angular/CHANGELOG.md b/packages/phone-mask-angular/CHANGELOG.md new file mode 100644 index 00000000..93c3322a --- /dev/null +++ b/packages/phone-mask-angular/CHANGELOG.md @@ -0,0 +1,5 @@ +# @desource/phone-mask-angular + +## 1.4.0 + +- Initial Angular package with standalone component, directive, pipe, service, and provider APIs. diff --git a/packages/phone-mask-angular/README.md b/packages/phone-mask-angular/README.md new file mode 100644 index 00000000..b52324db --- /dev/null +++ b/packages/phone-mask-angular/README.md @@ -0,0 +1,153 @@ +# @desource/phone-mask-angular + +> Angular phone input component, directive, pipe, and service API with smart masking and Google libphonenumber data + +[![npm version](https://img.shields.io/npm/v/@desource/phone-mask-angular?color=blue&logo=angular)](https://www.npmjs.com/package/@desource/phone-mask-angular) +[![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/DeSource-Labs/phone-mask/blob/main/LICENSE) + +Beautiful, accessible, tree-shakeable Angular phone input with auto-formatting, country selector, validation, forms support, and signal-first APIs. + +## Features + +- Standalone Angular component, directive, pipe, and `UsePhoneMaskService` +- Signal inputs and `model()` two-way value binding +- Works with Angular forms through `ControlValueAccessor` +- Smart country search with keyboard navigation +- As-you-type formatting with stable caret handling +- Optional GeoIP and locale country detection +- APF package output with partial compilation +- Core mask data and kit utilities re-exported from `@desource/phone-mask-angular/core` + +## Installation + +```bash +npm install @desource/phone-mask-angular +# or +pnpm add @desource/phone-mask-angular +``` + +## Quick Start + +```ts +import { Component, signal } from '@angular/core'; +import { PhoneInputComponent, type PMaskPhoneNumber } from '@desource/phone-mask-angular'; + +@Component({ + selector: 'app-checkout-phone', + standalone: true, + imports: [PhoneInputComponent], + template: ` + + + @if (isValid()) { +

Valid phone number

+ } + ` +}) +export class CheckoutPhoneComponent { + readonly phoneDigits = signal(''); + readonly isValid = signal(false); + + onPhoneChange(phone: PMaskPhoneNumber): void { + console.log(phone.digits, phone.full, phone.fullFormatted); + } +} +``` + +The component also works as an Angular form control: + +```html + +``` + +## Directive Mode + +Use the directive when you want to own the input markup and styling: + +```ts +import { Component, signal } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { PhoneMaskDirective, type PMaskPhoneNumber } from '@desource/phone-mask-angular'; + +@Component({ + selector: 'app-custom-phone', + standalone: true, + imports: [FormsModule, PhoneMaskDirective], + template: ` + + ` +}) +export class CustomPhoneComponent { + readonly country = signal('US'); + digits = ''; + + onPhoneChange(phone: PMaskPhoneNumber): void { + console.log(phone.fullFormatted); + } +} +``` + +You can also bind directive options directly: + +```html + +``` + +## Pipe + +```ts +import { Component } from '@angular/core'; +import { PhoneMaskPipe } from '@desource/phone-mask-angular'; + +@Component({ + selector: 'app-phone-summary', + standalone: true, + imports: [PhoneMaskPipe], + template: ` +

{{ '2025551234' | phoneMask }}

+

{{ '2025551234' | phoneMask: { mode: 'fullFormatted' } }}

+ ` +}) +export class PhoneSummaryComponent {} +``` + +## Custom Templates + +```html + + + {{ country.id }} + + + + + + +``` + +Available template refs are `#flag`, `#actionsBefore`, `#copySvg`, and `#clearSvg`. + +## Core Utilities + +```ts +import { getFlagEmoji, formatDigitsWithMap } from '@desource/phone-mask-angular/core'; +``` + +## Styles + +The component ships its default styles with the component. A compiled stylesheet is also available for manual use: + +```ts +import '@desource/phone-mask-angular/assets/lib.css'; +``` diff --git a/packages/phone-mask-angular/angular.json b/packages/phone-mask-angular/angular.json new file mode 100644 index 00000000..8333b9e5 --- /dev/null +++ b/packages/phone-mask-angular/angular.json @@ -0,0 +1,59 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "phone-mask-angular": { + "projectType": "library", + "root": ".", + "sourceRoot": ".", + "prefix": "desource", + "architect": { + "build": { + "builder": "@angular/build:ng-packagr", + "options": { + "project": "ng-package.json" + } + }, + "test": { + "builder": "@angular/build:unit-test", + "options": { + "buildTarget": "phone-mask-angular:build", + "tsConfig": "tsconfig.spec.json", + "runner": "vitest", + "runnerConfig": "vitest.angular.config.ts", + "setupFiles": ["tests/unit/setup/angular.ts"], + "include": ["tests/unit/**/*.test.ts"], + "coverageInclude": ["src/**/*.ts"], + "coverageExclude": ["src/**/*.d.ts"], + "coverageReporters": ["lcov"] + } + } + } + }, + "demo": { + "projectType": "application", + "root": "demo", + "sourceRoot": "demo/src", + "prefix": "demo", + "architect": { + "build": { + "builder": "@angular/build:application", + "options": { + "browser": "demo/src/main.ts", + "index": "demo/src/index.html", + "outputPath": "dist-demo", + "tsConfig": "demo/tsconfig.json", + "styles": [] + } + }, + "serve": { + "builder": "@angular/build:dev-server", + "options": { + "buildTarget": "demo:build" + } + } + } + } + } +} diff --git a/packages/phone-mask-angular/core/ng-package.json b/packages/phone-mask-angular/core/ng-package.json new file mode 100644 index 00000000..139198bd --- /dev/null +++ b/packages/phone-mask-angular/core/ng-package.json @@ -0,0 +1,6 @@ +{ + "$schema": "../node_modules/ng-packagr/ng-entrypoint.schema.json", + "lib": { + "entryFile": "src/public-api.ts" + } +} diff --git a/packages/phone-mask-angular/core/src/public-api.ts b/packages/phone-mask-angular/core/src/public-api.ts new file mode 100644 index 00000000..8bee598d --- /dev/null +++ b/packages/phone-mask-angular/core/src/public-api.ts @@ -0,0 +1,2 @@ +export * from '@desource/phone-mask'; +export * from '@desource/phone-mask/kit'; diff --git a/packages/phone-mask-angular/demo/src/app.component.ts b/packages/phone-mask-angular/demo/src/app.component.ts new file mode 100644 index 00000000..f4a308a7 --- /dev/null +++ b/packages/phone-mask-angular/demo/src/app.component.ts @@ -0,0 +1,474 @@ +import { + ChangeDetectorRef, + Component, + ElementRef, + ViewEncapsulation, + inject, + signal, + viewChild, + type AfterViewInit, + type OnDestroy +} from '@angular/core'; +import type { CountryKey, MaskFull } from '@desource/phone-mask'; +import { + PhoneInputComponent, + UsePhoneMaskService, + type PhoneInputSize, + type PhoneInputTheme +} from '../../src/public-api'; + +function isPhoneInputSize(value: string): value is PhoneInputSize { + return value === 'compact' || value === 'normal' || value === 'large'; +} + +function isPhoneInputTheme(value: string): value is PhoneInputTheme { + return value === 'auto' || value === 'light' || value === 'dark'; +} + +@Component({ + selector: 'demo-hook', + standalone: true, + template: ` +
+

UsePhoneMask Service

+
+ + + + +
+
+
Digits: {{ mask.digits() || '—' }}
+
Full: {{ mask.full() || '—' }}
+
Formatted: {{ mask.fullFormatted() || '—' }}
+
Valid: {{ mask.isComplete() ? 'Yes' : 'No' }}
+
+
+ `, + providers: [UsePhoneMaskService] +}) +class DemoHookComponent implements AfterViewInit, OnDestroy { + protected readonly mask = inject(UsePhoneMaskService); + private readonly inputRef = viewChild>('phoneInput'); + private readonly value = signal(''); + + constructor() { + this.mask.configure({ + value: this.value, + detect: () => false, + onChange: (digits) => this.value.set(digits) + }); + this.mask.setCountry('GB'); + } + + ngAfterViewInit(): void { + queueMicrotask(() => this.mask.connect(this.inputRef()?.nativeElement ?? null)); + } + + ngOnDestroy(): void { + this.mask.connect(null); + } + + protected setCountry(country: CountryKey): void { + this.mask.setCountry(country); + } + + protected clear(): void { + this.mask.clear(); + this.value.set(''); + } +} + +@Component({ + selector: 'demo-root', + standalone: true, + imports: [PhoneInputComponent, DemoHookComponent], + encapsulation: ViewEncapsulation.None, + template: ` +
+
+

@desource/phone-mask-angular

+

Interactive component and service playground

+
+ +
+

Component Playground

+
+
+

Preview

+
+ +
+
Value: {{ digits() || '—' }}
+
+
+
+ +
+

Props

+
+ + + + + + + +
+ +
+ + + + + + + +
+ +
+ + + + + + + +
+
+
+
+ + +
+ `, + styles: [ + ` + :host { + display: block; + } + + * { + box-sizing: border-box; + } + + body { + margin: 0; + } + + .app-main { + min-height: 100vh; + width: 100vw; + background: #101014; + color: #ffffff; + font-family: Arial, sans-serif; + padding: 40px 20px; + } + + .app-header, + .section { + max-width: 1200px; + margin: 0 auto 24px; + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 16px; + background: rgba(255, 255, 255, 0.06); + padding: 28px; + } + + .app-header { + text-align: center; + } + + h1, + h2, + h3, + p { + margin-top: 0; + } + + .grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 24px; + } + + .panel, + .preview, + .meta { + border: 1px solid rgba(255, 255, 255, 0.08); + border-radius: 8px; + background: rgba(0, 0, 0, 0.18); + padding: 20px; + } + + .meta { + display: grid; + gap: 6px; + margin-top: 16px; + font-size: 14px; + } + + .control-group, + .controls { + display: flex; + flex-direction: column; + gap: 12px; + margin-bottom: 16px; + } + + .row { + flex-direction: row; + flex-wrap: wrap; + } + + .label { + display: flex; + flex-direction: column; + gap: 6px; + font-size: 14px; + font-weight: 600; + } + + .checkbox-label { + display: flex; + align-items: center; + gap: 8px; + font-size: 14px; + } + + .select, + .input, + .btn { + border: 1px solid rgba(255, 255, 255, 0.2); + border-radius: 8px; + background: rgba(255, 255, 255, 0.08); + color: #ffffff; + font: inherit; + padding: 9px 12px; + } + + .select option { + color: #000000; + } + + .input::placeholder { + color: rgba(255, 255, 255, 0.45); + } + + .btn { + cursor: pointer; + font-weight: 600; + } + ` + ] +}) +export class AppComponent { + private readonly changeDetector = inject(ChangeDetectorRef); + private readonly playgroundPhone = viewChild('playgroundPhone'); + + protected readonly digits = signal(''); + protected readonly country = signal(undefined); + protected readonly locale = signal(undefined); + protected readonly detect = signal(true); + protected readonly showCopy = signal(true); + protected readonly showClear = signal(true); + protected readonly size = signal('normal'); + protected readonly theme = signal('dark'); + protected readonly withValidity = signal(true); + protected readonly disabled = signal(false); + protected readonly readonly = signal(false); + protected readonly searchPlaceholder = signal(''); + protected readonly noResultsText = signal(''); + protected readonly clearButtonLabel = signal(''); + protected readonly dropdownClass = signal(''); + protected readonly disableDefaultStyles = signal(false); + + protected setDetect(event: Event): void { + const checked = (event.target as HTMLInputElement).checked; + this.detect.set(checked); + if (checked) this.country.set(undefined); + } + + protected setDisabled(event: Event): void { + const checked = (event.target as HTMLInputElement).checked; + this.disabled.set(checked); + this.playgroundPhone()?.setDisabledState(checked); + this.changeDetector.detectChanges(); + } + + protected setReadonly(event: Event): void { + this.readonly.set((event.target as HTMLInputElement).checked); + this.changeDetector.detectChanges(); + } + + protected setCountryOption(event: Event): void { + const value = (event.target as HTMLSelectElement).value; + this.country.set((value as CountryKey) || undefined); + } + + protected setLocaleOption(event: Event): void { + this.locale.set((event.target as HTMLSelectElement).value || undefined); + } + + protected setSizeOption(event: Event): void { + const value = (event.target as HTMLSelectElement).value; + if (isPhoneInputSize(value)) this.size.set(value); + } + + protected setThemeOption(event: Event): void { + const value = (event.target as HTMLSelectElement).value; + if (isPhoneInputTheme(value)) this.theme.set(value); + } + + protected onCountryChange(_country: MaskFull): void {} + + protected onValidationChange(_valid: boolean): void {} +} diff --git a/packages/phone-mask-angular/demo/src/index.html b/packages/phone-mask-angular/demo/src/index.html new file mode 100644 index 00000000..1607259b --- /dev/null +++ b/packages/phone-mask-angular/demo/src/index.html @@ -0,0 +1,12 @@ + + + + + @desource/phone-mask-angular + + + + + + + diff --git a/packages/phone-mask-angular/demo/src/main.ts b/packages/phone-mask-angular/demo/src/main.ts new file mode 100644 index 00000000..b1d670b5 --- /dev/null +++ b/packages/phone-mask-angular/demo/src/main.ts @@ -0,0 +1,4 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { AppComponent } from './app.component'; + +bootstrapApplication(AppComponent); diff --git a/packages/phone-mask-angular/demo/tsconfig.json b/packages/phone-mask-angular/demo/tsconfig.json new file mode 100644 index 00000000..a4e41d46 --- /dev/null +++ b/packages/phone-mask-angular/demo/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "composite": false, + "declaration": false, + "declarationMap": false, + "emitDeclarationOnly": false, + "outDir": "../dist/out-tsc/demo", + "types": [] + }, + "angularCompilerOptions": { + "compilationMode": "full", + "strictTemplates": true + }, + "include": ["src/**/*.ts"] +} diff --git a/packages/phone-mask-angular/ng-package.json b/packages/phone-mask-angular/ng-package.json new file mode 100644 index 00000000..86182c36 --- /dev/null +++ b/packages/phone-mask-angular/ng-package.json @@ -0,0 +1,9 @@ +{ + "$schema": "./node_modules/ng-packagr/ng-package.schema.json", + "dest": "dist", + "assets": ["CHANGELOG.md"], + "allowedNonPeerDependencies": ["@desource/phone-mask", "tslib"], + "lib": { + "entryFile": "src/public-api.ts" + } +} diff --git a/packages/phone-mask-angular/package.json b/packages/phone-mask-angular/package.json new file mode 100644 index 00000000..3d9f6b9b --- /dev/null +++ b/packages/phone-mask-angular/package.json @@ -0,0 +1,80 @@ +{ + "name": "@desource/phone-mask-angular", + "version": "1.4.0", + "description": "📱 Angular component, directive, pipe, and service for international phone number masking. Powered by @desource/phone-mask and Google libphonenumber.", + "keywords": [ + "angular", + "phone", + "phone-input", + "phone-mask", + "phone-number", + "international-phone", + "libphonenumber", + "angular-component", + "angular-directive", + "angular-pipe", + "input-mask", + "validation", + "tel", + "telephone", + "country-code", + "formatting" + ], + "author": "Stefan Popov ", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/DeSource-Labs/phone-mask.git", + "directory": "packages/phone-mask-angular" + }, + "bugs": { + "url": "https://github.com/DeSource-Labs/phone-mask/issues" + }, + "homepage": "https://github.com/DeSource-Labs/phone-mask/tree/main/packages/phone-mask-angular#readme", + "private": false, + "publishConfig": { + "access": "public", + "directory": "dist" + }, + "sideEffects": false, + "type": "module", + "exports": { + "./assets/lib.css": "./assets/lib.css" + }, + "scripts": { + "clean": "rimraf dist dist-demo test-results coverage tsconfig.tsbuildinfo", + "clean:modules": "rimraf node_modules", + "dev": "ng serve demo --port 5173", + "build:demo": "ng build demo", + "build": "pnpm clean && pnpm build:lib && pnpm build:styles", + "build:lib": "ng-packagr -p ng-package.json", + "build:styles": "sass src/components/phone-input/phone-input.component.scss dist/assets/lib.css --style=compressed --no-source-map", + "lint": "eslint .", + "typecheck": "ngc -p tsconfig.json --noEmit", + "test:unit": "ng test phone-mask-angular --watch=false", + "test:unit:coverage": "ng test phone-mask-angular --watch=false --coverage", + "test:e2e": "playwright test" + }, + "peerDependencies": { + "@angular/common": "^19.0.0 || ^20.0.0 || ^21.0.0", + "@angular/core": "^19.0.0 || ^20.0.0 || ^21.0.0", + "@angular/forms": "^19.0.0 || ^20.0.0 || ^21.0.0" + }, + "dependencies": { + "@desource/phone-mask": "workspace:*", + "tslib": "^2.8.1" + }, + "devDependencies": { + "@angular/build": "^21.2.10", + "@angular/cli": "^21.2.10", + "@angular/common": "^21.2.12", + "@angular/compiler": "^21.2.12", + "@angular/compiler-cli": "^21.2.12", + "@angular/core": "^21.2.12", + "@angular/forms": "^21.2.12", + "@angular/platform-browser": "^21.2.12", + "@testing-library/angular": "^19.2.1", + "ng-packagr": "^21.2.3", + "sass": "^1.99.0" + } +} diff --git a/packages/phone-mask-angular/playwright.config.ts b/packages/phone-mask-angular/playwright.config.ts new file mode 100644 index 00000000..2d7a3f34 --- /dev/null +++ b/packages/phone-mask-angular/playwright.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from '@playwright/test'; + +export default defineConfig({ + testDir: './tests/e2e', + use: { + baseURL: 'http://localhost:5173' + }, + webServer: { + command: 'pnpm dev', + url: 'http://localhost:5173', + reuseExistingServer: !process.env.CI + } +}); diff --git a/packages/phone-mask-angular/src/components/phone-input/phone-input.component.html b/packages/phone-mask-angular/src/components/phone-input/phone-input.component.html new file mode 100644 index 00000000..b26535ee --- /dev/null +++ b/packages/phone-mask-angular/src/components/phone-input/phone-input.component.html @@ -0,0 +1,187 @@ +
+
+ +
+ +
+ + + +
+
+ +@if (renderDropdown()) { +
+ @if (dropdownOpen()) { +
+ +
+
    + @for (c of filteredCountries(); track c.id; let idx = $index) { +
  • + + @if (flagTemplate(); as flagTpl) { + + } @else { + {{ c.flag }} + } + + {{ c.name }} + {{ c.code }} +
  • + } @empty { +
  • {{ noResultsText() }}
  • + } +
+ } +
+} + +
diff --git a/packages/phone-mask-angular/src/components/phone-input/phone-input.component.scss b/packages/phone-mask-angular/src/components/phone-input/phone-input.component.scss new file mode 100644 index 00000000..85febefc --- /dev/null +++ b/packages/phone-mask-angular/src/components/phone-input/phone-input.component.scss @@ -0,0 +1,450 @@ +// Global styles and CSS variables +.phone-input, +.phone-dropdown { + // CSS custom properties + --pi-bg: #ffffff; + --pi-fg: #111827; + --pi-muted: #6b7280; + --pi-border: #e5e7eb; + --pi-border-hover: #d1d5db; + --pi-border-focus: #3b82f6; + --pi-radius: 8px; + --pi-padding: 12px; + --pi-font-size: 16px; + --pi-height: 44px; + --pi-actions-size: 32px; + --pi-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); + --pi-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -2px rgb(0 0 0 / 0.05); + --pi-warning: #f59e0b; + --pi-warning-light: #fbbf24; + --pi-success: #10b981; + --pi-focus-ring: 3px solid rgb(59 130 246 / 0.15); + --pi-focus-ring-warning: 3px solid rgb(245 158 11 / 0.15); + --pi-focus-ring-success: 3px solid rgb(16 185 129 / 0.15); + --pi-disabled-bg: #f9fafb; + --pi-disabled-fg: #9ca3af; + + // Theme variants + &.theme-dark { + --pi-bg: #1f2937; + --pi-fg: #f9fafb; + --pi-muted: #9ca3af; + --pi-border: #374151; + --pi-border-hover: #4b5563; + --pi-border-focus: #60a5fa; + --pi-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.3); + --pi-shadow-lg: 0 20px 25px -5px rgb(0 0 0 / 0.3), 0 10px 10px -5px rgb(0 0 0 / 0.2); + --pi-warning: #fbbf24; + --pi-warning-light: #fcd34d; + --pi-focus-ring: 3px solid rgb(96 165 250 / 0.2); + --pi-focus-ring-warning: 3px solid rgb(251 191 24 / 0.2); + --pi-focus-ring-success: 3px solid rgb(16 185 129 / 0.2); + --pi-disabled-bg: #374151; + } + + // Shared styles used by both the field and the top-layer dropdown. + font-size: var(--pi-font-size); + background: var(--pi-bg); + color: var(--pi-fg); + border-radius: var(--pi-radius); + border: 1px solid var(--pi-border); + + // Reset styles + *, + *::before, + *::after { + box-sizing: border-box; + } + + button, + input { + margin: 0; + padding: 0; + border: none; + background: none; + font: inherit; + color: inherit; + } + + button { + cursor: pointer; + &:disabled { + cursor: not-allowed; + } + } + + input { + outline: none; + &::placeholder { + opacity: 0.5; + } + &:disabled { + cursor: not-allowed; + } + } +} + +.phone-input { + position: relative; + display: flex; + align-items: stretch; + width: 100%; + + &:focus-within { + outline: var(--pi-focus-ring); + } + + &.is-incomplete { + border-color: var(--pi-warning); + &:focus-within { + outline: var(--pi-focus-ring-warning); + } + } + + &.is-complete { + border-color: var(--pi-success); + &:focus-within { + outline: var(--pi-focus-ring-success); + } + } + + &.is-disabled { + background: var(--pi-disabled-bg); + color: var(--pi-disabled-fg); + } + + &.is-readonly { + cursor: default; + } + + // Size variants + &.size-compact { + --pi-font-size: 14px; + --pi-height: 36px; + --pi-padding: 10px; + --pi-actions-size: 24px; + } + + &.size-large { + --pi-font-size: 18px; + --pi-height: 52px; + --pi-padding: 16px; + --pi-actions-size: 32px; + } + + &.is-unstyled { + all: initial; + display: block; + } + + // Selector + .pi-selector { + flex-shrink: 0; + } + + .pi-selector-btn { + display: flex; + align-items: center; + gap: 6px; + padding-left: var(--pi-padding); + padding-right: 0; + min-height: var(--pi-height); + border: 1px solid transparent; + border-radius: var(--pi-radius) 0 0 var(--pi-radius); + transition: all 150ms cubic-bezier(0.4, 0, 0.2, 1); + + &.no-dropdown { + cursor: default; + } + + &:focus-visible { + border-color: var(--pi-border-focus); + outline: none; + } + + &:disabled > .pi-flag { + opacity: 0.5; + } + } + + .pi-flag { + font-size: 1.25em; + line-height: 1; + display: inline-flex; + } + + .pi-code { + color: var(--pi-fg); + } + + .pi-chevron { + margin-left: 2px; + color: var(--pi-muted); + transition: transform 200ms ease; + + &.is-open { + transform: rotate(180deg); + } + } + + // Input wrap + .pi-input-wrap { + flex: 1; + position: relative; + display: flex; + align-items: center; + } + + // Input + .pi-input { + flex: 1; + width: 100%; + padding-left: var(--pi-padding); + // Calc right padding based on number of action buttons + 2px gaps + base padding + padding-right: calc((var(--pi-actions-size) + 2px) * var(--pi-actions-count) + var(--pi-padding)); + min-height: var(--pi-height); + border-radius: 0 var(--pi-radius) var(--pi-radius) 0; + transition: all 150ms cubic-bezier(0.4, 0, 0.2, 1); + + &:hover:not(:disabled):not(:read-only) { + border-color: var(--pi-border-hover); + } + + &:focus { + border-color: var(--pi-border-focus); + position: relative; + } + + &:-webkit-autofill, + &:-webkit-autofill:hover, + &:-webkit-autofill:focus, + &:-webkit-autofill:active { + -webkit-text-fill-color: var(--pi-fg); + caret-color: var(--pi-fg); + -webkit-box-shadow: 0 0 0 1000px var(--pi-bg) inset; + box-shadow: 0 0 0 1000px var(--pi-bg) inset; + transition: + background-color 9999s ease-out, + color 9999s ease-out; + } + &:-moz-autofill { + -moz-text-fill-color: var(--pi-fg); + box-shadow: 0 0 0 1000px var(--pi-bg) inset; + } + } + + // Actions + .pi-actions { + position: absolute; + right: 2px; + top: 50%; + transform: translateY(-50%); + display: inline-flex; + align-items: center; + gap: 2px; + } + + .pi-btn { + display: flex; + align-items: center; + justify-content: center; + width: var(--pi-actions-size); + height: var(--pi-actions-size); + background: transparent; + color: var(--pi-muted); + border: none; + border-radius: 9999px; + transition: all 150ms cubic-bezier(0.4, 0, 0.2, 1); + + &:hover { + background: var(--pi-disabled-bg); + color: var(--pi-fg); + } + + &:active:not(:disabled) { + transform: scale(0.95); + } + + &:focus { + outline: 1px solid var(--pi-border-focus); + outline-offset: -1px; + } + + &.is-copied { + color: var(--pi-success); + border-color: var(--pi-success); + } + + svg { + flex-shrink: 0; + } + } +} + +.phone-dropdown { + position: fixed; + top: var(--pi-dd-top, 0); + left: var(--pi-dd-left, 0); + margin: 0; + width: var(--pi-dd-width, 0); + max-width: calc(100vw - 16px); + display: flex; + flex-direction: column; + box-shadow: var(--pi-shadow-lg); + overflow: hidden; + opacity: 0; + visibility: hidden; + pointer-events: none; + transform: scale(0.98); + transform-origin: top center; + will-change: opacity, transform; + z-index: 1000; + transition: none; + + &.is-open { + opacity: 1; + visibility: visible; + pointer-events: auto; + transform: scale(1); + transition: + opacity 160ms cubic-bezier(0.4, 0, 0.2, 1), + transform 160ms cubic-bezier(0.4, 0, 0.2, 1); + } + + &[data-placement='top'] { + transform-origin: bottom center; + } + + .pi-search-wrap { + padding: 8px; + border-bottom: 1px solid var(--pi-border); + } + + .pi-search { + width: 100%; + padding: 8px 12px; + font-size: 16px; + border: 1px solid var(--pi-border); + border-radius: calc(var(--pi-radius) - 2px); + background: var(--pi-bg); + transition: border-color 150ms ease; + + &:focus { + border-color: var(--pi-border-focus); + } + } + + .pi-options { + max-height: var(--pi-dd-max-height, 300px); + min-height: 0; + flex: 1 1 auto; + overflow-y: auto; + padding: 4px 0; + margin: 0; + list-style: none; + + &::-webkit-scrollbar { + width: 8px; + } + + &::-webkit-scrollbar-track { + background: transparent; + } + + &::-webkit-scrollbar-thumb { + background: var(--pi-border); + border-radius: 4px; + + &:hover { + background: var(--pi-border-hover); + } + } + } + + .pi-option { + display: flex; + align-items: center; + gap: 8px; + padding: 8px 12px; + cursor: pointer; + transition: background-color 100ms ease; + + &:hover, + &.is-focused { + background: var(--pi-disabled-bg); + } + + &.is-selected { + background: var(--pi-border); + font-weight: 500; + } + } + + .pi-opt-name { + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .pi-opt-code { + color: var(--pi-muted); + font-size: 0.875em; + } + + .pi-empty { + padding: 12px; + text-align: center; + color: var(--pi-muted); + font-size: 0.875em; + } +} + +@keyframes fade-scale-in { + from { + opacity: 0; + transform: scale(0.8); + } + to { + opacity: 1; + transform: scale(1); + } +} + +.pi-actions .pi-btn { + animation: fade-scale-in 200ms cubic-bezier(0.4, 0, 0.2, 1) both; +} + +// Screen reader only +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +// Responsive +@media (max-width: 480px) { + .phone-input { + --pi-padding: 8px; + --pi-actions-size: 24px; + } + + .size-compact { + --pi-actions-size: 20px; + } +} + +// Reduced motion +@media (prefers-reduced-motion: reduce) { + * { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } +} diff --git a/packages/phone-mask-angular/src/components/phone-input/phone-input.component.ts b/packages/phone-mask-angular/src/components/phone-input/phone-input.component.ts new file mode 100644 index 00000000..f5115a5b --- /dev/null +++ b/packages/phone-mask-angular/src/components/phone-input/phone-input.component.ts @@ -0,0 +1,382 @@ +import { NgTemplateOutlet } from '@angular/common'; +import { + ChangeDetectionStrategy, + Component, + ElementRef, + TemplateRef, + ViewEncapsulation, + booleanAttribute, + computed, + contentChild, + effect, + forwardRef, + inject, + input, + model, + output, + signal, + untracked, + viewChild +} from '@angular/core'; +import { NG_VALUE_ACCESSOR, type ControlValueAccessor } from '@angular/forms'; +import type { CountryKey, MaskFull } from '@desource/phone-mask'; +import { extractDigits } from '@desource/phone-mask/kit'; +import { UseCopyActionService } from '../../services/internal/useCopyAction.service'; +import { UseCountryService } from '../../services/internal/useCountry.service'; +import { UseCountrySelectorService } from '../../services/internal/useCountrySelector.service'; +import { UseFormatterService } from '../../services/internal/useFormatter.service'; +import { UseInputHandlersService } from '../../services/internal/useInputHandlers.service'; +import { UseThemeService } from '../../services/internal/useTheme.service'; +import { UseValidationHintService } from '../../services/internal/useValidationHint.service'; +import { UseClipboardService } from '../../services/utility/useClipboard.service'; +import type { PhoneInputRef, PhoneNumber, Size, Theme } from '../../types'; + +let nextDropdownId = 0; + +@Component({ + selector: 'desource-phone-input', + standalone: true, + imports: [NgTemplateOutlet], + templateUrl: './phone-input.component.html', + styleUrl: './phone-input.component.scss', + encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.OnPush, + providers: [ + UseClipboardService, + UseCopyActionService, + UseCountryService, + UseCountrySelectorService, + UseFormatterService, + UseInputHandlersService, + UseThemeService, + UseValidationHintService, + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => PhoneInputComponent), + multi: true + } + ] +}) +export class PhoneInputComponent implements ControlValueAccessor, PhoneInputRef { + readonly value = model(''); + + readonly id = input(); + readonly name = input(); + readonly countryInput = input(undefined, { alias: 'country' }); + readonly detectInput = input(true, { + alias: 'detect', + transform: booleanAttribute + }); + readonly localeInput = input(undefined, { alias: 'locale' }); + readonly size = input('normal'); + readonly theme = input('auto'); + readonly disabledInput = input(false, { alias: 'disabled', transform: booleanAttribute }); + readonly readOnlyInput = input(false, { alias: 'readonly', transform: booleanAttribute }); + readonly showCopy = input(true, { transform: booleanAttribute }); + readonly showClear = input(false, { transform: booleanAttribute }); + readonly withValidity = input(true, { transform: booleanAttribute }); + readonly searchPlaceholder = input('Search country or code...'); + readonly noResultsText = input('No countries found'); + readonly clearButtonLabel = input('Clear phone number'); + readonly dropdownClass = input(''); + readonly disableDefaultStyles = input(false, { transform: booleanAttribute }); + + readonly phoneChange = output(); + readonly countryChange = output(); + readonly validationChange = output(); + readonly focused = output({ alias: 'focus' }); + readonly blurred = output({ alias: 'blur' }); + readonly copiedValue = output({ alias: 'copy' }); + readonly cleared = output({ alias: 'clear' }); + + readonly actionsBeforeTemplate = contentChild>('actionsBefore'); + readonly flagTemplate = contentChild>('flag'); + readonly copySvgTemplate = contentChild>('copySvg'); + readonly clearSvgTemplate = contentChild>('clearSvg'); + + private readonly rootRef = viewChild>('root'); + private readonly telRef = viewChild>('telInput'); + private readonly liveRef = viewChild>('live'); + private readonly dropdownRef = viewChild>('dropdown'); + private readonly searchRef = viewChild>('searchInput'); + private readonly selectorRef = viewChild>('selectorButton'); + + private readonly countryState = inject(UseCountryService); + private readonly formatterState = inject(UseFormatterService); + private readonly inputHandlers = inject(UseInputHandlersService); + private readonly validationHint = inject(UseValidationHintService); + private readonly countrySelector = inject(UseCountrySelectorService); + private readonly copyAction = inject(UseCopyActionService); + private readonly themeState = inject(UseThemeService); + + private readonly formDisabled = signal(false); + private onTouched: () => void = () => {}; + private onChange: (value: string) => void = () => {}; + + readonly locale = this.countryState.locale; + readonly country = this.countryState.country; + readonly formatter = this.formatterState.formatter; + readonly digits = this.formatterState.digits; + readonly displayPlaceholder = this.formatterState.displayPlaceholder; + readonly displayValue = this.formatterState.displayValue; + readonly phoneData = this.formatterState.phoneData; + readonly full = this.formatterState.full; + readonly fullFormatted = this.formatterState.fullFormatted; + readonly isCompleteSignal = this.formatterState.isComplete; + readonly isEmpty = this.formatterState.isEmpty; + readonly shouldShowWarn = this.formatterState.shouldShowWarn; + readonly showValidationHint = this.validationHint.showValidationHint; + readonly dropdownOpen = this.countrySelector.dropdownOpen; + readonly search = this.countrySelector.search; + readonly focusedIndex = this.countrySelector.focusedIndex; + readonly filteredCountries = this.countrySelector.filteredCountries; + readonly hasDropdown = this.countrySelector.hasDropdown; + readonly themeClass = this.themeState.themeClass; + readonly copied = this.copyAction.copied; + readonly copyAriaLabel = this.copyAction.copyAriaLabel; + readonly copyButtonTitle = this.copyAction.copyButtonTitle; + + readonly dropdownId = ++nextDropdownId; + readonly dropdownElementId = `pi-dropdown-${this.dropdownId}`; + readonly listboxId = `pi-options-${this.dropdownId}`; + + readonly isDisabled = computed(() => this.disabledInput() || this.formDisabled()); + readonly isReadOnly = computed(() => this.readOnlyInput()); + readonly inactive = computed(() => this.isDisabled() || this.isReadOnly()); + readonly incomplete = computed(() => this.showValidationHint() && this.shouldShowWarn()); + readonly showCopyButton = computed(() => this.showCopy() && !this.isEmpty() && !this.isDisabled()); + readonly showClearButton = computed(() => this.showClear() && !this.isEmpty() && !this.inactive()); + readonly canOpenDropdown = computed(() => this.hasDropdown() && !this.inactive()); + readonly renderDropdown = computed(() => this.hasDropdown() && (!this.inactive() || this.dropdownOpen())); + readonly activeOptionId = computed(() => + this.dropdownOpen() && this.filteredCountries()[this.focusedIndex()] + ? this.getOptionId(this.focusedIndex()) + : undefined + ); + readonly rootClasses = computed(() => + [ + 'phone-input', + `size-${this.size()}`, + this.themeClass(), + this.isDisabled() && 'is-disabled', + this.isReadOnly() && 'is-readonly', + this.disableDefaultStyles() && 'is-unstyled', + this.withValidity() && this.incomplete() && 'is-incomplete', + this.withValidity() && this.isCompleteSignal() && 'is-complete' + ] + .filter(Boolean) + .join(' ') + ); + readonly dropdownClasses = computed(() => + ['phone-dropdown', this.dropdownOpen() && 'is-open', this.dropdownClass(), this.themeClass()] + .filter(Boolean) + .join(' ') + ); + readonly actionsCount = computed( + () => +this.showCopyButton() + +this.showClearButton() + (this.actionsBeforeTemplate() ? 1 : 0) + ); + + constructor() { + this.countryState.configure({ + country: this.countryInput, + locale: this.localeInput, + detect: this.detectInput, + onCountryChange: (country) => this.countryChange.emit(country) + }); + + this.formatterState.configure({ + country: this.country, + value: this.value, + onChange: (digits) => this.setValue(digits, true), + onPhoneChange: (phone) => this.phoneChange.emit(phone), + onValidationChange: (isComplete) => this.validationChange.emit(isComplete) + }); + + this.inputHandlers.configure({ + formatter: this.formatter, + digits: this.digits, + inactive: this.inactive, + onChange: (digits) => this.setValue(digits, true), + scheduleValidationHint: (delay) => this.validationHint.scheduleValidationHint(delay) + }); + + this.countrySelector.configure({ + rootElement: () => this.rootRef()?.nativeElement, + dropdownElement: () => this.dropdownRef()?.nativeElement, + searchElement: () => this.searchRef()?.nativeElement, + selectorElement: () => this.selectorRef()?.nativeElement, + locale: this.locale, + inactive: this.inactive, + countryOption: this.countryInput, + onSelectCountry: (country) => this.selectCountry(country), + onAfterSelect: () => this.focus() + }); + + this.copyAction.configure({ + fullFormatted: this.fullFormatted, + liveElement: () => this.liveRef()?.nativeElement, + onCopy: (value) => this.copiedValue.emit(value) + }); + + this.themeState.configure({ theme: this.theme }); + + effect((onCleanup) => { + if (typeof document === 'undefined') return; + + const dropdown = this.dropdownRef()?.nativeElement; + if (!dropdown || dropdown.parentElement === document.body) return; + + const placeholder = document.createComment('phone-input-dropdown'); + const parent = dropdown.parentNode; + parent?.insertBefore(placeholder, dropdown); + document.body.appendChild(dropdown); + + onCleanup(() => { + if (placeholder.parentNode && dropdown.isConnected) { + placeholder.parentNode.insertBefore(dropdown, placeholder); + } + placeholder.remove(); + }); + }); + } + + writeValue(value: string | number | null | undefined): void { + this.setValue(String(value ?? ''), false); + } + + registerOnChange(fn: (value: string) => void): void { + this.onChange = fn; + } + + registerOnTouched(fn: () => void): void { + this.onTouched = fn; + } + + setDisabledState(isDisabled: boolean): void { + this.formDisabled.set(isDisabled); + } + + focus(): void { + setTimeout(() => this.telRef()?.nativeElement.focus()); + } + + blur(): void { + this.telRef()?.nativeElement.blur(); + } + + clear(): void { + this.setValue('', true); + this.validationHint.clearValidationHint(); + this.cleared.emit(); + } + + selectCountry(country: CountryKey | string): boolean { + return this.countryState.setCountry(country); + } + + getFullNumber(): string { + return this.full(); + } + + getFullFormattedNumber(): string { + return this.fullFormatted(); + } + + getDigits(): string { + return this.digits(); + } + + isValid(): boolean { + return this.isComplete(); + } + + isComplete(): boolean { + return this.isCompleteSignal(); + } + + getOptionId(index: number): string { + return `pi-option-${this.dropdownId}-${index}`; + } + + flagContext(country: MaskFull): { $implicit: MaskFull; country: MaskFull } { + return { $implicit: country, country }; + } + + copyContext(): { copied: boolean } { + return { copied: this.copied() }; + } + + handleBeforeInput(event: InputEvent): void { + this.inputHandlers.handleBeforeInput(event); + } + + handleInput(event: Event): void { + this.inputHandlers.handleInput(event); + } + + handleKeydown(event: KeyboardEvent): void { + this.inputHandlers.handleKeydown(event); + } + + handlePaste(event: ClipboardEvent): void { + this.inputHandlers.handlePaste(event); + } + + handleFocus(event: FocusEvent): void { + this.validationHint.clearValidationHint(false); + this.countrySelector.closeDropdown(); + this.focused.emit(event); + } + + handleBlur(event: FocusEvent): void { + this.onTouched(); + this.blurred.emit(event); + } + + handleSelectorPointerDown(event: PointerEvent): void { + this.countrySelector.handleSelectorPointerDown(event); + } + + handleSelectorKeydown(event: KeyboardEvent): void { + this.countrySelector.handleSelectorKeydown(event); + } + + handleSearchChange(event: Event): void { + this.countrySelector.handleSearchChange(event); + } + + handleSearchKeydown(event: KeyboardEvent): void { + this.countrySelector.handleSearchKeydown(event); + } + + toggleDropdown(): void { + this.countrySelector.toggleDropdown(); + } + + setFocusedIndex(index: number): void { + this.countrySelector.setFocusedIndex(index); + } + + selectDropdownCountry(country: CountryKey): void { + this.countrySelector.selectCountry(country); + } + + onClearClick(): void { + this.clear(); + this.focus(); + } + + async onCopyClick(): Promise { + await this.copyAction.onCopyClick(); + } + + private setValue(value: string, emit: boolean): void { + const nextDigits = extractDigits(value, this.formatter().getMaxDigits()); + + untracked(() => this.value.set(nextDigits)); + + if (emit) { + this.onChange(nextDigits); + } + } +} diff --git a/packages/phone-mask-angular/src/core.ts b/packages/phone-mask-angular/src/core.ts new file mode 100644 index 00000000..8bee598d --- /dev/null +++ b/packages/phone-mask-angular/src/core.ts @@ -0,0 +1,2 @@ +export * from '@desource/phone-mask'; +export * from '@desource/phone-mask/kit'; diff --git a/packages/phone-mask-angular/src/phone-mask.directive.ts b/packages/phone-mask-angular/src/phone-mask.directive.ts new file mode 100644 index 00000000..3e6c6c2b --- /dev/null +++ b/packages/phone-mask-angular/src/phone-mask.directive.ts @@ -0,0 +1,234 @@ +import { + Directive, + DestroyRef, + ElementRef, + booleanAttribute, + effect, + forwardRef, + inject, + input, + model, + output, + untracked +} from '@angular/core'; +import { NG_VALUE_ACCESSOR, type ControlValueAccessor } from '@angular/forms'; +import type { CountryKey, MaskFull } from '@desource/phone-mask'; +import { extractDigits } from '@desource/phone-mask/kit'; +import { UseCountryService } from './services/internal/useCountry.service'; +import { UseFormatterService } from './services/internal/useFormatter.service'; +import { UseInputHandlersService } from './services/internal/useInputHandlers.service'; +import type { + DirectiveHTMLInputElement, + PhoneMaskDirectiveInput, + PhoneMaskDirectiveOptions, + PhoneNumber +} from './types'; + +function parseOptions(value: PhoneMaskDirectiveInput): PhoneMaskDirectiveOptions { + if (typeof value === 'string') return { country: value }; + if (value && typeof value === 'object') return value; + return {}; +} + +@Directive({ + selector: '[phoneMask]', + standalone: true, + exportAs: 'phoneMask', + providers: [ + UseCountryService, + UseFormatterService, + UseInputHandlersService, + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => PhoneMaskDirective), + multi: true + } + ] +}) +export class PhoneMaskDirective implements ControlValueAccessor { + readonly phoneMask = input(undefined); + readonly countryInput = input(undefined, { alias: 'phoneMaskCountry' }); + readonly localeInput = input(undefined, { alias: 'phoneMaskLocale' }); + readonly detectInput = input(true, { + alias: 'phoneMaskDetect', + transform: booleanAttribute + }); + readonly value = model('', { alias: 'phoneMaskValue' }); + + readonly phoneChange = output({ alias: 'phoneMaskChange' }); + readonly countryChange = output({ alias: 'phoneMaskCountryChange' }); + + private readonly elementRef = inject>(ElementRef); + private readonly destroyRef = inject(DestroyRef); + private readonly countryState = inject(UseCountryService); + private readonly formatterState = inject(UseFormatterService); + private readonly inputHandlers = inject(UseInputHandlersService); + + private readonly inputElement = this.elementRef.nativeElement as DirectiveHTMLInputElement; + private readonly isInput = this.inputElement.tagName === 'INPUT'; + private onTouched: () => void = () => {}; + private onChange: (value: string) => void = () => {}; + + private readonly options = () => { + const parsed = parseOptions(this.phoneMask()); + + return { + ...parsed, + country: this.countryInput() ?? parsed.country, + locale: this.localeInput() ?? parsed.locale, + detect: parsed.detect ?? this.detectInput() + }; + }; + + readonly locale = this.countryState.locale; + readonly country = this.countryState.country; + readonly formatter = this.formatterState.formatter; + readonly digits = this.formatterState.digits; + readonly full = this.formatterState.full; + readonly fullFormatted = this.formatterState.fullFormatted; + + constructor() { + if (!this.isInput) { + console.warn('[phoneMask] Directive can only be used on input elements'); + return; + } + + this.inputElement.setAttribute('type', 'tel'); + this.inputElement.setAttribute('inputmode', 'tel'); + this.inputElement.setAttribute('placeholder', ''); + + this.countryState.configure({ + country: () => this.options().country, + locale: () => this.options().locale, + detect: () => this.options().detect, + onCountryChange: (country) => { + this.countryChange.emit(country); + this.options().onCountryChange?.(country); + } + }); + + this.formatterState.configure({ + country: this.country, + value: this.value, + onChange: (digits) => this.setValue(digits, true), + onPhoneChange: (phone) => { + this.phoneChange.emit(phone); + this.options().onChange?.(phone); + } + }); + + this.inputHandlers.configure({ + formatter: this.formatter, + digits: this.digits, + onChange: (digits) => this.setValue(digits, true) + }); + + const beforeInputHandler = (event: InputEvent) => this.inputHandlers.handleBeforeInput(event); + const inputHandler = (event: Event) => this.inputHandlers.handleInput(event); + const keydownHandler = (event: KeyboardEvent) => this.inputHandlers.handleKeydown(event); + const pasteHandler = (event: ClipboardEvent) => this.inputHandlers.handlePaste(event); + const blurHandler = () => this.onTouched(); + + this.inputElement.addEventListener('beforeinput', beforeInputHandler); + this.inputElement.addEventListener('input', inputHandler); + this.inputElement.addEventListener('keydown', keydownHandler); + this.inputElement.addEventListener('paste', pasteHandler); + this.inputElement.addEventListener('blur', blurHandler); + + this.destroyRef.onDestroy(() => { + this.inputElement.removeEventListener('beforeinput', beforeInputHandler); + this.inputElement.removeEventListener('input', inputHandler); + this.inputElement.removeEventListener('keydown', keydownHandler); + this.inputElement.removeEventListener('paste', pasteHandler); + this.inputElement.removeEventListener('blur', blurHandler); + delete this.inputElement.__phoneMaskState; + }); + + effect(() => { + this.inputElement.value = this.formatterState.displayValue(); + this.inputElement.placeholder = this.formatterState.displayPlaceholder(); + + const state = (this.inputElement.__phoneMaskState ??= { + country: this.country(), + formatter: this.formatter(), + digits: this.digits(), + locale: this.locale(), + options: this.options(), + setCountry: (code) => { + const updated = this.selectCountry(code); + if (!updated || !this.inputElement.__phoneMaskState) return false; + + this.inputElement.__phoneMaskState.country = this.country(); + this.inputElement.__phoneMaskState.formatter = this.formatter(); + this.inputElement.__phoneMaskState.digits = this.digits(); + this.inputElement.__phoneMaskState.locale = this.locale(); + this.inputElement.__phoneMaskState.options = this.options(); + return true; + } + }); + + state.country = this.country(); + state.formatter = this.formatter(); + state.digits = this.digits(); + state.locale = this.locale(); + state.options = this.options(); + this.inputElement.__phoneMaskState = state; + }); + } + + writeValue(value: string | number | null | undefined): void { + if (!this.isInput) return; + this.setValue(String(value ?? ''), false); + } + + registerOnChange(fn: (value: string) => void): void { + this.onChange = fn; + } + + registerOnTouched(fn: () => void): void { + this.onTouched = fn; + } + + setDisabledState(isDisabled: boolean): void { + if (!this.isInput) return; + this.inputElement.disabled = isDisabled; + } + + clear(): void { + this.setValue('', true); + } + + selectCountry(country: CountryKey | string): boolean { + return this.countryState.setCountry(country); + } + + getDigits(): string { + return this.digits(); + } + + getFullNumber(): string { + return this.full(); + } + + getFullFormattedNumber(): string { + return this.fullFormatted(); + } + + isComplete(): boolean { + return this.formatter().isComplete(this.digits()); + } + + isValid(): boolean { + return this.isComplete(); + } + + private setValue(value: string, emit: boolean): void { + const nextDigits = extractDigits(value, this.formatter().getMaxDigits()); + + untracked(() => this.value.set(nextDigits)); + + if (emit) { + this.onChange(nextDigits); + } + } +} diff --git a/packages/phone-mask-angular/src/phone-mask.pipe.ts b/packages/phone-mask-angular/src/phone-mask.pipe.ts new file mode 100644 index 00000000..b2fa22b4 --- /dev/null +++ b/packages/phone-mask-angular/src/phone-mask.pipe.ts @@ -0,0 +1,50 @@ +import { Pipe, type PipeTransform } from '@angular/core'; +import type { CountryKey } from '@desource/phone-mask'; +import { + createPhoneFormatter, + extractDigits, + getCountry, + getNavigatorLang, + parseCountryCode +} from '@desource/phone-mask/kit'; +import type { PhoneMaskFormatMode, PhoneMaskFormatOptions } from './types'; + +const DEFAULT_COUNTRY = 'US'; + +function isFormatOptions(value: unknown): value is PhoneMaskFormatOptions { + return !!value && typeof value === 'object'; +} + +function formatPhoneValue(value: string | number | null | undefined, options: PhoneMaskFormatOptions): string { + const mode: PhoneMaskFormatMode = options.mode ?? 'display'; + const country = getCountry(parseCountryCode(options.country, DEFAULT_COUNTRY), options.locale || getNavigatorLang()); + const formatter = createPhoneFormatter(country); + const digits = extractDigits(String(value ?? ''), formatter.getMaxDigits()); + const displayValue = formatter.formatDisplay(digits); + + if (mode === 'placeholder') return formatter.getPlaceholder(); + if (mode === 'full') return digits ? `${country.code}${digits}` : ''; + if (mode === 'fullFormatted') return displayValue ? `${country.code} ${displayValue}` : ''; + + return displayValue; +} + +@Pipe({ + name: 'phoneMask', + standalone: true, + pure: true +}) +export class PhoneMaskPipe implements PipeTransform { + transform( + value: string | number | null | undefined, + countryOrOptions?: CountryKey | string | PhoneMaskFormatOptions, + mode: PhoneMaskFormatMode = 'display', + locale?: string + ): string { + const options: PhoneMaskFormatOptions = isFormatOptions(countryOrOptions) + ? countryOrOptions + : { country: countryOrOptions, mode, locale }; + + return formatPhoneValue(value, options); + } +} diff --git a/packages/phone-mask-angular/src/public-api.ts b/packages/phone-mask-angular/src/public-api.ts new file mode 100644 index 00000000..72dbbed0 --- /dev/null +++ b/packages/phone-mask-angular/src/public-api.ts @@ -0,0 +1,31 @@ +export { PhoneInputComponent } from './components/phone-input/phone-input.component'; +export { PhoneMaskDirective } from './phone-mask.directive'; +export { PhoneMaskPipe } from './phone-mask.pipe'; +export { UsePhoneMaskService } from './services/usePhoneMask.service'; + +export type { + DirectiveHTMLInputElement, + PhoneInputRef, + PhoneMaskDirectiveInput, + PhoneMaskDirectiveOptions, + PhoneMaskDirectiveState, + PhoneMaskFormatMode, + PhoneMaskFormatOptions, + PhoneNumber as PMaskPhoneNumber, + Size as PhoneInputSize, + Theme as PhoneInputTheme +} from './types'; + +export type { UsePhoneMaskOptions } from './services/usePhoneMask.service'; + +export type { + CountryKey as PCountryKey, + MaskBase as PMaskBase, + MaskBaseMap as PMaskBaseMap, + Mask as PMask, + MaskMap as PMaskMap, + MaskWithFlag as PMaskWithFlag, + MaskWithFlagMap as PMaskWithFlagMap, + MaskFull as PMaskFull, + MaskFullMap as PMaskFullMap +} from '@desource/phone-mask'; diff --git a/packages/phone-mask-angular/src/services/internal/useCopyAction.service.ts b/packages/phone-mask-angular/src/services/internal/useCopyAction.service.ts new file mode 100644 index 00000000..4e6239e8 --- /dev/null +++ b/packages/phone-mask-angular/src/services/internal/useCopyAction.service.ts @@ -0,0 +1,57 @@ +import { DestroyRef, Injectable, computed, inject } from '@angular/core'; +import { UseClipboardService } from '../utility/useClipboard.service'; + +interface UseCopyActionOptions { + fullFormatted: () => string; + liveElement?: () => HTMLElement | null | undefined; + onCopy?: (value: string) => void; +} + +const DELAY = 1_800; + +@Injectable() +export class UseCopyActionService { + private readonly clipboard = inject(UseClipboardService); + private readonly destroyRef = inject(DestroyRef); + private fullFormattedGetter = () => ''; + private liveElementGetter: () => HTMLElement | null | undefined = () => undefined; + private onCopy: ((value: string) => void) | undefined; + private liveTimer: ReturnType | undefined; + + readonly copied = this.clipboard.copied; + readonly copyAriaLabel = computed(() => (this.copied() ? 'Copied' : `Copy ${this.fullFormattedGetter()}`)); + readonly copyButtonTitle = computed(() => (this.copied() ? 'Copied' : 'Copy phone number')); + + constructor() { + this.destroyRef.onDestroy(() => { + if (this.liveTimer) clearTimeout(this.liveTimer); + }); + } + + configure(options: UseCopyActionOptions): void { + this.fullFormattedGetter = options.fullFormatted; + this.liveElementGetter = options.liveElement ?? this.liveElementGetter; + this.onCopy = options.onCopy; + } + + async onCopyClick(): Promise { + const value = this.fullFormattedGetter().trim(); + const success = await this.clipboard.copy(value, DELAY); + + if (!success) return; + + this.onCopy?.(value); + this.announceToScreenReader('Phone number copied to clipboard'); + } + + private announceToScreenReader(message: string): void { + const live = this.liveElementGetter(); + if (!live) return; + + live.textContent = message; + if (this.liveTimer) clearTimeout(this.liveTimer); + this.liveTimer = setTimeout(() => { + live.textContent = ''; + }, DELAY); + } +} diff --git a/packages/phone-mask-angular/src/services/internal/useCountry.service.ts b/packages/phone-mask-angular/src/services/internal/useCountry.service.ts new file mode 100644 index 00000000..50876dfd --- /dev/null +++ b/packages/phone-mask-angular/src/services/internal/useCountry.service.ts @@ -0,0 +1,114 @@ +import { Injectable, InjectionToken, Injector, computed, effect, inject, signal, untracked } from '@angular/core'; +import type { CountryKey, MaskFull } from '@desource/phone-mask'; +import { + detectByGeoIp, + detectCountryFromLocale, + getCountry, + getNavigatorLang, + parseCountryCode +} from '@desource/phone-mask/kit'; + +interface UseCountryOptions { + country?: () => CountryKey | string | null | undefined; + locale?: () => string | undefined; + detect?: () => boolean | undefined; + onCountryChange?: (country: MaskFull) => void; +} + +interface CountryDetection { + detectByGeoIp: typeof detectByGeoIp; + detectCountryFromLocale: typeof detectCountryFromLocale; +} + +/** + * Injection token for country detection methods. + * This allows for custom implementations to be provided if needed. + * It's designed for testing and flexibility. + */ +export const COUNTRY_DETECTION = new InjectionToken('COUNTRY_DETECTION', { + providedIn: 'root', + factory: () => ({ + detectByGeoIp, + detectCountryFromLocale + }) +}); + +@Injectable() +export class UseCountryService { + private readonly injector = inject(Injector); + private readonly detection = inject(COUNTRY_DETECTION); + private countryOption: () => CountryKey | string | null | undefined = () => undefined; + private localeOption: () => string | undefined = () => undefined; + private detectOption: () => boolean | undefined = () => undefined; + private onCountryChange: ((country: MaskFull) => void) | undefined; + private detectionKey = ''; + private configured = false; + + readonly countryCode = signal('US'); + readonly locale = computed(() => this.localeOption() || getNavigatorLang()); + readonly detect = computed(() => this.detectOption() ?? true); + readonly country = computed(() => getCountry(this.countryCode(), this.locale())); + + configure(options: UseCountryOptions = {}): void { + if (this.configured) return; + this.configured = true; + + this.countryOption = options.country ?? this.countryOption; + this.localeOption = options.locale ?? this.localeOption; + this.detectOption = options.detect ?? this.detectOption; + this.onCountryChange = options.onCountryChange; + + const initialCountry = parseCountryCode(this.countryOption()); + if (initialCountry) { + this.countryCode.set(initialCountry); + } + + effect( + () => { + const parsed = parseCountryCode(this.countryOption()); + + if (parsed && parsed !== this.countryCode()) { + queueMicrotask(() => this.setCountry(parsed)); + } + }, + { injector: this.injector } + ); + + effect( + () => { + if (!this.detect() || this.countryOption()) return; + + const key = `${this.locale()}:${this.detect()}`; + if (this.detectionKey === key) return; + + this.detectionKey = key; + void this.detectCountry(); + }, + { injector: this.injector } + ); + + effect( + () => { + this.onCountryChange?.(this.country()); + }, + { injector: this.injector } + ); + } + + setCountry(countryCode?: CountryKey | string | null): boolean { + const parsed = parseCountryCode(countryCode); + + if (!parsed) return false; + + untracked(() => this.countryCode.set(parsed)); + return true; + } + + private async detectCountry(): Promise { + const geoCountry = parseCountryCode(await this.detection.detectByGeoIp()); + + if (geoCountry && this.setCountry(geoCountry)) return; + + this.setCountry(this.detection.detectCountryFromLocale()); + } +} diff --git a/packages/phone-mask-angular/src/services/internal/useCountrySelector.service.ts b/packages/phone-mask-angular/src/services/internal/useCountrySelector.service.ts new file mode 100644 index 00000000..aa55fcea --- /dev/null +++ b/packages/phone-mask-angular/src/services/internal/useCountrySelector.service.ts @@ -0,0 +1,174 @@ +import { Injectable, Injector, afterNextRender, computed, effect, inject, signal } from '@angular/core'; +import { MasksFull, type CountryKey, type MaskFull } from '@desource/phone-mask'; +import { + bindCountryDropdownListeners, + filterCountries, + handleCountryButtonKeydown, + handleCountrySearchKeydown, + positionCountryDropdown, + scrollCountryOptionIntoView +} from '@desource/phone-mask/kit'; + +type IndexUpdate = number | ((index: number) => number); + +interface UseCountrySelectorOptions { + rootElement: () => HTMLElement | null | undefined; + dropdownElement: () => HTMLElement | null | undefined; + searchElement: () => HTMLInputElement | null | undefined; + selectorElement: () => HTMLButtonElement | null | undefined; + locale: () => string; + inactive?: () => boolean; + countryOption?: () => string | undefined; + onSelectCountry: (code: CountryKey) => void; + onAfterSelect?: () => void; +} + +@Injectable() +export class UseCountrySelectorService { + private readonly injector = inject(Injector); + private rootElementGetter: () => HTMLElement | null | undefined = () => undefined; + private dropdownElementGetter: () => HTMLElement | null | undefined = () => undefined; + private searchElementGetter: () => HTMLInputElement | null | undefined = () => undefined; + private selectorElementGetter: () => HTMLButtonElement | null | undefined = () => undefined; + private localeGetter = () => 'en'; + private inactiveGetter = () => false; + private countryOptionGetter: () => string | undefined = () => undefined; + private onSelectCountry: (code: CountryKey) => void = () => {}; + private onAfterSelect: (() => void) | undefined; + private openByKeyboard = false; + private configured = false; + + readonly dropdownOpen = signal(false); + readonly search = signal(''); + readonly focusedIndex = signal(0); + readonly countries = computed(() => MasksFull(this.localeGetter())); + readonly filteredCountries = computed(() => filterCountries(this.countries(), this.search())); + readonly hasDropdown = computed(() => !this.countryOptionGetter() && this.countries().length > 1); + + configure(options: UseCountrySelectorOptions): void { + if (this.configured) return; + this.configured = true; + + this.rootElementGetter = options.rootElement; + this.dropdownElementGetter = options.dropdownElement; + this.searchElementGetter = options.searchElement; + this.selectorElementGetter = options.selectorElement; + this.localeGetter = options.locale; + this.inactiveGetter = options.inactive ?? this.inactiveGetter; + this.countryOptionGetter = options.countryOption ?? this.countryOptionGetter; + this.onSelectCountry = options.onSelectCountry; + this.onAfterSelect = options.onAfterSelect; + + effect( + () => { + if ((this.inactiveGetter() || !this.hasDropdown()) && this.dropdownOpen()) { + this.closeDropdown(); + } + }, + { injector: this.injector } + ); + + effect( + (onCleanup) => { + if (!this.dropdownOpen()) return; + + queueMicrotask(() => { + this.updateDropdownPosition(); + if (this.openByKeyboard) this.focusSearch(); + }); + + onCleanup( + bindCountryDropdownListeners( + () => this.dropdownElementGetter(), + () => this.selectorElementGetter(), + () => this.closeDropdown(), + () => this.updateDropdownPosition() + ) + ); + }, + { injector: this.injector } + ); + } + + openDropdown(): void { + if (this.inactiveGetter() || !this.hasDropdown() || this.dropdownOpen()) return; + if (!this.dropdownElementGetter() || !this.selectorElementGetter()) return; + + this.updateDropdownPosition(); + this.focusedIndex.set(0); + this.dropdownOpen.set(true); + } + + closeDropdown(): void { + this.dropdownOpen.set(false); + this.resetDropdownState(); + } + + toggleDropdown(): void { + if (this.inactiveGetter() || !this.hasDropdown()) return; + if (this.dropdownOpen()) this.closeDropdown(); + else this.openDropdown(); + } + + selectCountry(code: CountryKey): void { + this.onSelectCountry(code); + this.closeDropdown(); + this.onAfterSelect?.(); + } + + setFocusedIndex(index: IndexUpdate): void { + this.focusedIndex.update((current) => (typeof index === 'function' ? index(current) : index)); + } + + handleSearchChange(event: Event): void { + this.search.set((event.target as HTMLInputElement).value); + this.focusedIndex.set(0); + } + + handleSearchKeydown(event: KeyboardEvent): void { + handleCountrySearchKeydown( + event, + this.focusedIndex(), + this.filteredCountries(), + (index) => this.setFocusedIndex(index), + (index) => this.scrollFocusedIntoView(index), + (country: MaskFull) => this.selectCountry(country.id) + ); + } + + handleSelectorPointerDown(event: PointerEvent): void { + this.openByKeyboard = event.pointerType === 'mouse'; + } + + handleSelectorKeydown(event: KeyboardEvent): void { + handleCountryButtonKeydown( + event, + this.dropdownOpen(), + () => { + this.openByKeyboard = true; + }, + () => this.focusSearch(), + () => this.openDropdown() + ); + } + + private resetDropdownState(): void { + this.search.set(''); + this.focusedIndex.set(0); + this.openByKeyboard = false; + } + + private updateDropdownPosition(): void { + positionCountryDropdown(this.rootElementGetter() ?? null, this.dropdownElementGetter() ?? null); + } + + private focusSearch(): void { + afterNextRender(() => this.searchElementGetter()?.focus({ preventScroll: true }), { injector: this.injector }); + } + + private scrollFocusedIntoView(index: number): void { + afterNextRender(() => scrollCountryOptionIntoView(this.dropdownElementGetter(), index), { + injector: this.injector + }); + } +} diff --git a/packages/phone-mask-angular/src/services/internal/useFormatter.service.ts b/packages/phone-mask-angular/src/services/internal/useFormatter.service.ts new file mode 100644 index 00000000..094aae7d --- /dev/null +++ b/packages/phone-mask-angular/src/services/internal/useFormatter.service.ts @@ -0,0 +1,103 @@ +import { Injectable, Injector, computed, effect, inject } from '@angular/core'; +import type { MaskFull } from '@desource/phone-mask'; +import { createPhoneFormatter, extractDigits } from '@desource/phone-mask/kit'; +import type { PhoneNumber } from '../../types'; + +interface UseFormatterOptions { + country: () => MaskFull; + value: () => string; + onChange: (digits: string) => void; + onPhoneChange?: (phone: PhoneNumber) => void; + onValidationChange?: (isComplete: boolean) => void; +} + +@Injectable() +export class UseFormatterService { + private readonly injector = inject(Injector); + private countryGetter: () => MaskFull = () => ({ + id: 'US', + code: '+1', + name: 'United States', + flag: '🇺🇸', + mask: ['###-###-####'] + }); + private valueGetter = () => ''; + private onChange: (digits: string) => void = () => {}; + private onPhoneChange: ((phone: PhoneNumber) => void) | undefined; + private onValidationChange: ((isComplete: boolean) => void) | undefined; + private configured = false; + private clampedValueKey = ''; + + readonly country = computed(() => this.countryGetter()); + readonly formatter = computed(() => createPhoneFormatter(this.country())); + readonly digits = computed(() => extractDigits(this.valueGetter(), this.formatter().getMaxDigits())); + readonly displayPlaceholder = computed(() => this.formatter().getPlaceholder()); + readonly displayValue = computed(() => this.formatter().formatDisplay(this.digits())); + readonly phoneData = computed(() => ({ + full: this.digits() ? `${this.country().code}${this.digits()}` : '', + fullFormatted: this.displayValue() ? `${this.country().code} ${this.displayValue()}` : '', + digits: this.digits() + })); + readonly full = computed(() => this.phoneData().full); + readonly fullFormatted = computed(() => this.phoneData().fullFormatted); + readonly isComplete = computed(() => this.formatter().isComplete(this.digits())); + readonly isEmpty = computed(() => this.digits().length === 0); + readonly shouldShowWarn = computed(() => !this.isEmpty() && !this.isComplete()); + + configure(options: UseFormatterOptions): void { + if (this.configured) return; + this.configured = true; + + this.countryGetter = options.country; + this.valueGetter = options.value; + this.onChange = options.onChange; + this.onPhoneChange = options.onPhoneChange; + this.onValidationChange = options.onValidationChange; + + this.emitClampedValue(); + + effect( + () => { + const value = this.valueGetter(); + const digits = this.digits(); + + if (value === digits) { + this.clampedValueKey = ''; + } else { + queueMicrotask(() => this.emitClampedValue()); + } + }, + { injector: this.injector } + ); + + effect( + () => { + this.onPhoneChange?.(this.phoneData()); + }, + { injector: this.injector } + ); + + effect( + () => { + this.onValidationChange?.(this.isComplete()); + }, + { injector: this.injector } + ); + } + + private emitClampedValue(): void { + const value = this.valueGetter(); + const digits = this.digits(); + + if (value === digits) { + this.clampedValueKey = ''; + return; + } + + const key = `${value}\u0000${digits}`; + if (key === this.clampedValueKey) return; + + this.clampedValueKey = key; + this.onChange(digits); + } +} diff --git a/packages/phone-mask-angular/src/services/internal/useInputHandlers.service.ts b/packages/phone-mask-angular/src/services/internal/useInputHandlers.service.ts new file mode 100644 index 00000000..c5b74090 --- /dev/null +++ b/packages/phone-mask-angular/src/services/internal/useInputHandlers.service.ts @@ -0,0 +1,92 @@ +import { Injectable } from '@angular/core'; +import { + processBeforeInput, + processInput, + processKeydown, + processPaste, + setCaret, + type FormatterHelpers +} from '@desource/phone-mask/kit'; + +interface UseInputHandlersOptions { + formatter: () => FormatterHelpers; + digits: () => string; + inactive?: () => boolean; + onChange?: (digits: string) => void; + scheduleValidationHint?: (delay: number) => void; +} + +const HINT_DELAY_INPUT = 500; +const HINT_DELAY_ACTION = 300; + +@Injectable() +export class UseInputHandlersService { + private formatterGetter!: () => FormatterHelpers; + private digitsGetter = () => ''; + private inactiveGetter = () => false; + private onChange: ((digits: string) => void) | undefined; + private scheduleValidationHint: ((delay: number) => void) | undefined; + + configure(options: UseInputHandlersOptions): void { + this.formatterGetter = options.formatter; + this.digitsGetter = options.digits; + this.inactiveGetter = options.inactive ?? this.inactiveGetter; + this.onChange = options.onChange; + this.scheduleValidationHint = options.scheduleValidationHint; + } + + handleBeforeInput(event: InputEvent): void { + if (this.inactiveGetter()) { + event.preventDefault(); + return; + } + + processBeforeInput(event); + } + + handleInput(event: Event): void { + if (this.inactiveGetter()) return; + + const result = processInput(event, { formatter: this.formatterGetter() }); + if (!result) return; + + this.onChange?.(result.newDigits); + this.scheduleCaretUpdate(event.target as HTMLInputElement | null, result.caretDigitIndex); + this.scheduleValidationHint?.(HINT_DELAY_INPUT); + } + + handleKeydown(event: KeyboardEvent): void { + if (this.inactiveGetter()) { + event.preventDefault(); + return; + } + + const result = processKeydown(event, { digits: this.digitsGetter(), formatter: this.formatterGetter() }); + if (!result) return; + + this.onChange?.(result.newDigits); + this.scheduleCaretUpdate(event.target as HTMLInputElement | null, result.caretDigitIndex); + this.scheduleValidationHint?.(HINT_DELAY_ACTION); + } + + handlePaste(event: ClipboardEvent): void { + if (this.inactiveGetter()) { + event.preventDefault(); + return; + } + + const result = processPaste(event, { digits: this.digitsGetter(), formatter: this.formatterGetter() }); + if (!result) return; + + this.onChange?.(result.newDigits); + this.scheduleCaretUpdate(event.target as HTMLInputElement | null, result.caretDigitIndex); + this.scheduleValidationHint?.(HINT_DELAY_ACTION); + } + + private scheduleCaretUpdate(el: HTMLInputElement | null, digitIndex: number): void { + setTimeout(() => { + const position = this.formatterGetter().getCaretPosition(digitIndex); + setCaret(el, position); + }); + } +} diff --git a/packages/phone-mask-angular/src/services/internal/useTheme.service.ts b/packages/phone-mask-angular/src/services/internal/useTheme.service.ts new file mode 100644 index 00000000..c8774192 --- /dev/null +++ b/packages/phone-mask-angular/src/services/internal/useTheme.service.ts @@ -0,0 +1,37 @@ +import { ChangeDetectorRef, DestroyRef, Injectable, computed, inject, signal } from '@angular/core'; +import type { Theme } from '../../types'; + +@Injectable() +export class UseThemeService { + private readonly cdr = inject(ChangeDetectorRef); + private readonly destroyRef = inject(DestroyRef); + private readonly systemDark = signal(false); + private readonly mediaQuery = globalThis.matchMedia?.('(prefers-color-scheme: dark)') ?? undefined; + private themeGetter: () => Theme = () => 'auto'; + + readonly themeClass = computed(() => { + const theme = this.themeGetter(); + if (theme === 'auto') return this.systemDark() ? 'theme-dark' : 'theme-light'; + return `theme-${theme}`; + }); + + constructor() { + if (this.mediaQuery) { + this.systemDark.set(this.mediaQuery.matches); + this.mediaQuery.addEventListener('change', this.handleThemeChange); + } + + this.destroyRef.onDestroy(() => { + this.mediaQuery?.removeEventListener('change', this.handleThemeChange); + }); + } + + configure(options: { theme: () => Theme }): void { + this.themeGetter = options.theme; + } + + private readonly handleThemeChange = (event: MediaQueryListEvent) => { + this.systemDark.set(event.matches); + this.cdr.markForCheck(); + }; +} diff --git a/packages/phone-mask-angular/src/services/internal/useValidationHint.service.ts b/packages/phone-mask-angular/src/services/internal/useValidationHint.service.ts new file mode 100644 index 00000000..d7f3c0b2 --- /dev/null +++ b/packages/phone-mask-angular/src/services/internal/useValidationHint.service.ts @@ -0,0 +1,30 @@ +import { ChangeDetectorRef, DestroyRef, Injectable, inject, signal } from '@angular/core'; + +@Injectable() +export class UseValidationHintService { + private readonly cdr = inject(ChangeDetectorRef); + private readonly destroyRef = inject(DestroyRef); + + readonly showValidationHint = signal(false); + + private validationTimer: ReturnType | undefined; + + constructor() { + this.destroyRef.onDestroy(() => this.clearValidationHint()); + } + + clearValidationHint(hideHint = true): void { + if (hideHint) this.showValidationHint.set(false); + if (this.validationTimer) clearTimeout(this.validationTimer); + this.validationTimer = undefined; + } + + scheduleValidationHint(delay: number): void { + this.showValidationHint.set(false); + if (this.validationTimer) clearTimeout(this.validationTimer); + this.validationTimer = setTimeout(() => { + this.showValidationHint.set(true); + this.cdr.markForCheck(); + }, delay); + } +} diff --git a/packages/phone-mask-angular/src/services/usePhoneMask.service.ts b/packages/phone-mask-angular/src/services/usePhoneMask.service.ts new file mode 100644 index 00000000..a1f6d3d0 --- /dev/null +++ b/packages/phone-mask-angular/src/services/usePhoneMask.service.ts @@ -0,0 +1,154 @@ +import { DestroyRef, Injectable, Injector, computed, effect, inject, signal, untracked } from '@angular/core'; +import type { CountryKey, MaskFull } from '@desource/phone-mask'; +import type { FormatterHelpers } from '@desource/phone-mask/kit'; +import { UseCountryService } from './internal/useCountry.service'; +import { UseFormatterService } from './internal/useFormatter.service'; +import { UseInputHandlersService } from './internal/useInputHandlers.service'; +import type { PhoneNumber } from '../types'; + +export interface UsePhoneMaskOptions { + /** Controlled value: digits only, without country code. */ + value: () => string; + /** Called when digits change. */ + onChange: (digits: string) => void; + /** Country ISO 3166-1 alpha-2 code. */ + country?: () => CountryKey | string | undefined; + /** Locale for country names. */ + locale?: () => string | undefined; + /** Auto-detect country via GeoIP/locale. */ + detect?: () => boolean | undefined; + /** Called on every phone number update. */ + onPhoneChange?: (phone: PhoneNumber) => void; + /** Called when country changes. */ + onCountryChange?: (country: MaskFull) => void; +} + +@Injectable() +export class UsePhoneMaskService { + private readonly injector = inject(Injector); + private readonly destroyRef = inject(DestroyRef); + private readonly stateInjector = Injector.create({ + providers: [UseCountryService, UseFormatterService, UseInputHandlersService], + parent: this.injector, + name: 'UsePhoneMaskService' + }); + private readonly countryState = this.stateInjector.get(UseCountryService); + private readonly formatterState = this.stateInjector.get(UseFormatterService); + private readonly inputHandlers = this.stateInjector.get(UseInputHandlersService); + private readonly inputElement = signal(null); + private onChange: (digits: string) => void = () => {}; + private configured = false; + + readonly country = this.countryState.country; + readonly locale = this.countryState.locale; + readonly digits = this.formatterState.digits; + readonly formatter = this.formatterState.formatter; + readonly full = this.formatterState.full; + readonly fullFormatted = this.formatterState.fullFormatted; + readonly isComplete = this.formatterState.isComplete; + readonly isEmpty = this.formatterState.isEmpty; + readonly shouldShowWarn = this.formatterState.shouldShowWarn; + readonly inputRef = computed(() => this.inputElement()); + + constructor() { + this.destroyRef.onDestroy(() => { + this.connect(null); + this.stateInjector.destroy(); + }); + } + + configure(options: UsePhoneMaskOptions): void { + if (this.configured) return; + this.configured = true; + this.onChange = options.onChange; + + this.countryState.configure({ + country: options.country, + locale: options.locale, + detect: options.detect, + onCountryChange: options.onCountryChange + }); + + this.formatterState.configure({ + country: this.country, + value: options.value, + onChange: options.onChange, + onPhoneChange: options.onPhoneChange + }); + + this.inputHandlers.configure({ + formatter: this.formatter, + digits: this.digits, + onChange: options.onChange + }); + + effect( + () => { + const el = this.inputElement(); + if (!el) return; + + this.syncInputElement(el); + }, + { injector: this.injector } + ); + + effect( + (onCleanup) => { + const el = this.inputElement(); + if (!el) return; + + const beforeInputHandler = (event: InputEvent) => this.inputHandlers.handleBeforeInput(event); + const inputHandler = (event: Event) => this.inputHandlers.handleInput(event); + const keydownHandler = (event: KeyboardEvent) => this.inputHandlers.handleKeydown(event); + const pasteHandler = (event: ClipboardEvent) => this.inputHandlers.handlePaste(event); + + el.addEventListener('beforeinput', beforeInputHandler); + el.addEventListener('input', inputHandler); + el.addEventListener('keydown', keydownHandler); + el.addEventListener('paste', pasteHandler); + + onCleanup(() => { + el.removeEventListener('beforeinput', beforeInputHandler); + el.removeEventListener('input', inputHandler); + el.removeEventListener('keydown', keydownHandler); + el.removeEventListener('paste', pasteHandler); + }); + }, + { injector: this.injector } + ); + } + + connect(inputElement: HTMLInputElement | null): void { + untracked(() => this.inputElement.set(inputElement)); + } + + setCountry(countryCode?: CountryKey | string | null): boolean { + const updated = this.countryState.setCountry(countryCode); + if (updated) this.syncInputElement(); + + return updated; + } + + clear(): void { + const el = this.inputElement(); + if (el) el.value = ''; + this.onChange(''); + } + + getDigits(): string { + return this.digits(); + } + + getFormatter(): FormatterHelpers { + return this.formatter(); + } + + private syncInputElement(inputElement = this.inputElement()): void { + if (!inputElement) return; + + inputElement.setAttribute('type', 'tel'); + inputElement.setAttribute('inputmode', 'tel'); + inputElement.value = this.formatterState.displayValue(); + inputElement.setAttribute('placeholder', this.formatterState.displayPlaceholder()); + } +} diff --git a/packages/phone-mask-angular/src/services/utility/useClipboard.service.ts b/packages/phone-mask-angular/src/services/utility/useClipboard.service.ts new file mode 100644 index 00000000..7baa511f --- /dev/null +++ b/packages/phone-mask-angular/src/services/utility/useClipboard.service.ts @@ -0,0 +1,72 @@ +import { DOCUMENT } from '@angular/common'; +import { ChangeDetectorRef, DestroyRef, Injectable, inject, signal } from '@angular/core'; + +@Injectable() +export class UseClipboardService { + private readonly cdr = inject(ChangeDetectorRef); + private readonly destroyRef = inject(DestroyRef); + private readonly document = inject(DOCUMENT, { optional: true }); + + readonly copied = signal(false); + readonly isCopying = signal(false); + + private resetTimer: ReturnType | undefined; + + constructor() { + this.destroyRef.onDestroy(() => { + if (this.resetTimer) clearTimeout(this.resetTimer); + }); + } + + async copy(value: string, resetDelay = 1_800): Promise { + if (this.isCopying()) return false; + + const text = value.trim(); + if (!text) return false; + + this.isCopying.set(true); + + try { + const success = await this.writeText(text); + if (!success) return false; + + this.copied.set(true); + + if (this.resetTimer) clearTimeout(this.resetTimer); + this.resetTimer = setTimeout(() => { + this.copied.set(false); + this.cdr.markForCheck(); + }, resetDelay); + + return true; + } finally { + this.isCopying.set(false); + } + } + + private async writeText(value: string): Promise { + try { + if (globalThis.navigator?.clipboard?.writeText) { + await globalThis.navigator.clipboard.writeText(value); + return true; + } + + if (!this.document?.body) return false; + + const textarea = this.document.createElement('textarea'); + textarea.value = value; + textarea.setAttribute('readonly', ''); + textarea.style.position = 'fixed'; + textarea.style.opacity = '0'; + this.document.body.appendChild(textarea); + textarea.select(); + const copied = this.document.execCommand('copy'); + textarea.remove(); + + return copied; + } catch (err) { + console.warn('Copy failed', err); + return false; + } + } +} diff --git a/packages/phone-mask-angular/src/services/utility/useTimer.service.ts b/packages/phone-mask-angular/src/services/utility/useTimer.service.ts new file mode 100644 index 00000000..3e7c9a6b --- /dev/null +++ b/packages/phone-mask-angular/src/services/utility/useTimer.service.ts @@ -0,0 +1,22 @@ +import { DestroyRef, Injectable, inject } from '@angular/core'; + +@Injectable() +export class UseTimerService { + private readonly destroyRef = inject(DestroyRef); + private timer: ReturnType | undefined; + + constructor() { + this.destroyRef.onDestroy(() => this.clear()); + } + + set(callback: () => void, delay: number): void { + this.clear(); + this.timer = setTimeout(callback, delay); + } + + clear(): void { + if (!this.timer) return; + clearTimeout(this.timer); + this.timer = undefined; + } +} diff --git a/packages/phone-mask-angular/src/types.ts b/packages/phone-mask-angular/src/types.ts new file mode 100644 index 00000000..8c96b7aa --- /dev/null +++ b/packages/phone-mask-angular/src/types.ts @@ -0,0 +1,70 @@ +import type { CountryKey, MaskFull } from '@desource/phone-mask'; +import type { FormatterHelpers } from '@desource/phone-mask/kit'; + +export type Size = 'compact' | 'normal' | 'large'; +export type Theme = 'auto' | 'light' | 'dark'; +export type PhoneMaskFormatMode = 'display' | 'full' | 'fullFormatted' | 'placeholder'; + +export interface PhoneNumber { + full: string; + fullFormatted: string; + digits: string; +} + +export interface PhoneMaskFormatOptions { + /** ISO 3166-1 alpha-2 country code. */ + country?: CountryKey | string; + /** Locale for country names. */ + locale?: string; + /** Returned formatting mode. */ + mode?: PhoneMaskFormatMode; +} + +export interface PhoneMaskDirectiveOptions { + /** Country ISO code (e.g. US, DE, GB). */ + country?: CountryKey | string; + /** Locale for country names. */ + locale?: string; + /** Auto-detect country from GeoIP/locale. */ + detect?: boolean; + /** Called when formatted phone data changes. */ + onChange?: (phone: PhoneNumber) => void; + /** Called when selected country changes. */ + onCountryChange?: (country: MaskFull) => void; +} + +export type PhoneMaskDirectiveInput = CountryKey | string | PhoneMaskDirectiveOptions | null | undefined; + +export interface PhoneMaskDirectiveState { + country: MaskFull; + formatter: FormatterHelpers; + digits: string; + locale: string; + options: PhoneMaskDirectiveOptions; + setCountry?: (code: string) => boolean; +} + +export interface DirectiveHTMLInputElement extends HTMLInputElement { + __phoneMaskState?: PhoneMaskDirectiveState; +} + +export interface PhoneInputRef { + /** Focus the phone input. */ + focus: () => void; + /** Blur the phone input. */ + blur: () => void; + /** Clear the phone input. */ + clear: () => void; + /** Select a country by its ISO 3166-1 alpha-2 code. */ + selectCountry: (country: CountryKey | string) => boolean; + /** Get the full phone number with country code (e.g. +1234567890). */ + getFullNumber: () => string; + /** Get the full phone number formatted according to country rules (e.g. +1 234-567-890). */ + getFullFormattedNumber: () => string; + /** Get only the digits of the phone number without country code (e.g. 234567890). */ + getDigits: () => string; + /** Check if the current phone number is valid. */ + isValid: () => boolean; + /** Check if the current phone number is complete. */ + isComplete: () => boolean; +} diff --git a/packages/phone-mask-angular/tests/e2e/PhoneInput.spec.ts b/packages/phone-mask-angular/tests/e2e/PhoneInput.spec.ts new file mode 100644 index 00000000..0bc27329 --- /dev/null +++ b/packages/phone-mask-angular/tests/e2e/PhoneInput.spec.ts @@ -0,0 +1,37 @@ +import { testPhoneInput } from '@common/tests/e2e/PhoneInput'; + +const PLAYGROUND_SELECTOR = '[data-testid="playground"]'; + +const COUNTRY_SELECTOR = '[data-testid="props-country"]'; +const READONLY_SELECTOR = '[data-testid="props-readonly"] input[type="checkbox"]'; +const DISABLED_SELECTOR = '[data-testid="props-disabled"] input[type="checkbox"]'; +const SHOW_COPY_SELECTOR = '[data-testid="props-show-copy"] input[type="checkbox"]'; +const SHOW_CLEAR_SELECTOR = '[data-testid="props-show-clear"] input[type="checkbox"]'; +const WITH_VALIDITY_SELECTOR = '[data-testid="props-with-validity"] input[type="checkbox"]'; +const DETECT_SELECTOR = '[data-testid="props-detect"] input[type="checkbox"]'; +const LOCALE_SELECTOR = '[data-testid="props-locale"]'; +const SIZE_SELECTOR = '[data-testid="props-size"]'; +const THEME_SELECTOR = '[data-testid="props-theme"]'; +const SEARCH_PLACEHOLDER_SELECTOR = '[data-testid="props-search-placeholder"]'; +const NO_RESULTS_TEXT_SELECTOR = '[data-testid="props-no-results-text"]'; +const CLEAR_BUTTON_LABEL_SELECTOR = '[data-testid="props-clear-button-label"]'; +const DROPDOWN_CLASS_SELECTOR = '[data-testid="props-dropdown-class"]'; +const DISABLE_DEFAULT_STYLES_SELECTOR = '[data-testid="props-disable-default-styles"] input[type="checkbox"]'; + +testPhoneInput(PLAYGROUND_SELECTOR, { + country: COUNTRY_SELECTOR, + readonly: READONLY_SELECTOR, + disabled: DISABLED_SELECTOR, + showCopy: SHOW_COPY_SELECTOR, + showClear: SHOW_CLEAR_SELECTOR, + withValidity: WITH_VALIDITY_SELECTOR, + detect: DETECT_SELECTOR, + locale: LOCALE_SELECTOR, + size: SIZE_SELECTOR, + theme: THEME_SELECTOR, + searchPlaceholder: SEARCH_PLACEHOLDER_SELECTOR, + noResultsText: NO_RESULTS_TEXT_SELECTOR, + clearButtonLabel: CLEAR_BUTTON_LABEL_SELECTOR, + dropdownClass: DROPDOWN_CLASS_SELECTOR, + disableDefaultStyles: DISABLE_DEFAULT_STYLES_SELECTOR +}); diff --git a/packages/phone-mask-angular/tests/e2e/UsePhoneMask.spec.ts b/packages/phone-mask-angular/tests/e2e/UsePhoneMask.spec.ts new file mode 100644 index 00000000..6cccab00 --- /dev/null +++ b/packages/phone-mask-angular/tests/e2e/UsePhoneMask.spec.ts @@ -0,0 +1,27 @@ +import { testUsePhoneMask } from '@common/tests/e2e/UsePhoneMask'; + +const HOOK_SELECTOR = '[data-testid="hook"]'; + +const SET_COUNTRY_US_SELECTOR = '[data-testid="control-country-us"]'; +const SET_COUNTRY_DE_SELECTOR = '[data-testid="control-country-de"]'; +const CLEAR_SELECTOR = '[data-testid="control-clear"]'; + +const META_DIGITS_SELECTOR = '[data-testid="meta-digits"]'; +const META_FULL_SELECTOR = '[data-testid="meta-full"]'; +const META_FORMATTED_SELECTOR = '[data-testid="meta-formatted"]'; +const META_VALID_SELECTOR = '[data-testid="meta-valid"]'; + +testUsePhoneMask( + HOOK_SELECTOR, + { + setCountryUs: SET_COUNTRY_US_SELECTOR, + setCountryDe: SET_COUNTRY_DE_SELECTOR, + clear: CLEAR_SELECTOR + }, + { + digits: META_DIGITS_SELECTOR, + full: META_FULL_SELECTOR, + formatted: META_FORMATTED_SELECTOR, + valid: META_VALID_SELECTOR + } +); diff --git a/packages/phone-mask-angular/tests/tsconfig.json b/packages/phone-mask-angular/tests/tsconfig.json new file mode 100644 index 00000000..bd758ea2 --- /dev/null +++ b/packages/phone-mask-angular/tests/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "composite": false, + "declaration": false, + "declarationMap": false, + "emitDeclarationOnly": false, + "paths": { + "@common/*": ["../../../common/*"], + "@src/*": ["../src/*"] + }, + "types": ["vitest/globals"] + }, + "include": ["unit/**/*.ts", "e2e/**/*.ts", "../src/**/*.ts", "../../common/tests/**/*.ts"], + "exclude": [] +} diff --git a/packages/phone-mask-angular/tests/unit/PhoneInput.test.ts b/packages/phone-mask-angular/tests/unit/PhoneInput.test.ts new file mode 100644 index 00000000..5bed7d1f --- /dev/null +++ b/packages/phone-mask-angular/tests/unit/PhoneInput.test.ts @@ -0,0 +1,238 @@ +/// +import { Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { By } from '@angular/platform-browser'; +import { render } from '@testing-library/angular'; +import type { CountryKey, MaskFull } from '@desource/phone-mask'; +import { testPhoneInput, type SetupFn } from '@common/tests/unit/PhoneInput'; +import { PhoneInputComponent } from '@src/components/phone-input/phone-input.component'; +import type { Size, Theme } from '@src/types'; +import { tools } from './setup/tools'; + +@Component({ + standalone: true, + imports: [PhoneInputComponent], + template: ` + + @if (withCustomRenderers) { + + Before + + + {{ country.id }} + + + {{ copied ? 'copied' : 'copy' }} + + + clear + + } + + ` +}) +class PhoneInputHostComponent { + value = ''; + id?: string; + name?: string; + detect = false; + showClear = false; + showCopy = true; + disabled = false; + readonly = false; + country?: CountryKey | string; + size: Size = 'normal'; + theme: Theme = 'auto'; + disableDefaultStyles = false; + withCustomRenderers = false; + dropdownClass = ''; + + onChange = vi.fn(); + onCountryChange = vi.fn(); + onCopy = vi.fn(); + onFocus = vi.fn(); + onBlur = vi.fn(); + + handleValueChange(value: string): void { + this.value = value; + this.onChange(value); + } + + handleCountryChange(country: MaskFull): void { + this.onCountryChange(country); + } +} + +@Component({ + standalone: true, + imports: [PhoneInputComponent, ReactiveFormsModule], + template: '' +}) +class PhoneInputFormHostComponent { + readonly control = new FormControl(''); +} + +const setup: SetupFn = async ({ + value = '', + id, + name, + detect = false, + showClear = false, + showCopy = true, + disabled = false, + readonly = false, + country, + disableDefaultStyles = false, + withCustomRenderers = false +} = {}) => { + const result = await render(PhoneInputHostComponent, { + componentProperties: { + value, + id, + name, + detect, + showClear, + showCopy, + disabled, + readonly, + country, + disableDefaultStyles, + withCustomRenderers, + dropdownClass: withCustomRenderers ? 'custom-dropdown' : '' + } + }); + + const host = result.fixture.componentInstance; + const ref = result.debugElement.query(By.directive(PhoneInputComponent))?.componentInstance as PhoneInputComponent; + if (!ref) throw new Error('PhoneInput ref is not created'); + + return { + ref, + onChange: host.onChange, + onCountryChange: host.onCountryChange, + onCopy: host.onCopy, + onFocus: host.onFocus, + onBlur: host.onBlur, + container: result.container, + unmount: () => result.fixture.destroy() + }; +}; + +testPhoneInput(setup, tools); + +const renderComponent = async (componentProperties: Partial = {}) => { + const result = await render(PhoneInputHostComponent, { + componentProperties + }); + const ref = result.debugElement.query(By.directive(PhoneInputComponent))?.componentInstance as PhoneInputComponent; + const input = result.container.querySelector('input') as HTMLInputElement; + if (!ref || !input) throw new Error('PhoneInput component is not rendered'); + + return { + result, + ref, + input, + root: result.container.querySelector('.phone-input') as HTMLDivElement, + unmount: () => result.fixture.destroy() + }; +}; + +describe('PhoneInputComponent Angular API', () => { + it('supports ControlValueAccessor writeValue, change, touched, and disabled APIs', async () => { + const { result, ref, input, root, unmount } = await renderComponent(); + const onChange = vi.fn(); + const onTouched = vi.fn(); + + ref.registerOnChange(onChange); + ref.registerOnTouched(onTouched); + + ref.writeValue(2025550199); + result.detectChanges(); + + expect(ref.getDigits()).toBe('2025550199'); + expect(ref.getFullNumber()).toBe('+12025550199'); + expect(input.value).toBe('202-555-0199'); + expect(onChange).not.toHaveBeenCalled(); + + input.dispatchEvent(new FocusEvent('blur')); + expect(onTouched).toHaveBeenCalledOnce(); + + ref.setDisabledState(true); + result.detectChanges(); + expect(input.disabled).toBe(true); + expect(root.className).toContain('is-disabled'); + + ref.setDisabledState(false); + result.detectChanges(); + expect(input.disabled).toBe(false); + + ref.clear(); + expect(onChange).toHaveBeenCalledWith(''); + + unmount(); + }); + + it('works as an Angular reactive forms value accessor', async () => { + const result = await render(PhoneInputFormHostComponent); + const host = result.fixture.componentInstance; + const input = result.container.querySelector('input') as HTMLInputElement; + + host.control.setValue('2025550199'); + result.detectChanges(); + + expect(input.value).toBe('202-555-0199'); + expect(host.control.value).toBe('2025550199'); + + result.fixture.destroy(); + }); + + it('rejects invalid country selections and truncates when country max digits shrink', async () => { + const { result, ref, unmount } = await renderComponent({ value: '2025550199' }); + const onChange = vi.fn(); + + ref.registerOnChange(onChange); + expect(ref.selectCountry('INVALID')).toBe(false); + expect(ref.getFullNumber()).toBe('+12025550199'); + + await tools.act(async () => { + expect(ref.selectCountry('AD')).toBe(true); + result.detectChanges(); + }); + + expect(ref.getFullNumber()).toMatch(/^\+376/); + expect(ref.getDigits().length).toBeLessThan(10); + expect(onChange).toHaveBeenCalledWith(ref.getDigits()); + + unmount(); + }); + + it('clears nullish values written through ControlValueAccessor', async () => { + const { result, ref, input, unmount } = await renderComponent({ value: '2025550199' }); + + ref.writeValue(null); + result.detectChanges(); + + expect(ref.getDigits()).toBe(''); + expect(ref.getFullNumber()).toBe(''); + expect(input.value).toBe(''); + + unmount(); + }); +}); diff --git a/packages/phone-mask-angular/tests/unit/index.test.ts b/packages/phone-mask-angular/tests/unit/index.test.ts new file mode 100644 index 00000000..61b1ee23 --- /dev/null +++ b/packages/phone-mask-angular/tests/unit/index.test.ts @@ -0,0 +1,12 @@ +/// +import { testIndexImports } from '@common/tests/unit/index'; +import * as indexModule from '@src/public-api'; +import * as coreModule from '@src/core'; + +testIndexImports({ + suiteName: 'angular', + indexModule, + coreModule, + expectedDefinedExports: ['PhoneInputComponent', 'PhoneMaskDirective', 'PhoneMaskPipe', 'UsePhoneMaskService'], + expectedFunctionExports: [] +}); diff --git a/packages/phone-mask-angular/tests/unit/phoneMaskDirective.test.ts b/packages/phone-mask-angular/tests/unit/phoneMaskDirective.test.ts new file mode 100644 index 00000000..5effd472 --- /dev/null +++ b/packages/phone-mask-angular/tests/unit/phoneMaskDirective.test.ts @@ -0,0 +1,241 @@ +/// +import { Component } from '@angular/core'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { By } from '@angular/platform-browser'; +import { render } from '@testing-library/angular'; +import { detectCountryFromLocale } from '@desource/phone-mask/kit'; +import { testPhoneMaskBinding } from '@common/tests/unit/phoneMaskBinding'; +import { PhoneMaskDirective } from '@src/phone-mask.directive'; +import { COUNTRY_DETECTION } from '@src/services/internal/useCountry.service'; +import type { DirectiveHTMLInputElement, PhoneMaskDirectiveInput, PhoneMaskDirectiveOptions } from '@src/types'; +import { tools } from './setup/tools'; + +const countryDetection = { + detectByGeoIp: vi.fn().mockResolvedValue(null), + detectCountryFromLocale +}; + +@Component({ + standalone: true, + imports: [PhoneMaskDirective], + template: ` + @if (tag === 'input') { + + } @else { +
+ } + ` +}) +class PhoneMaskDirectiveHostComponent { + tag: 'input' | 'div' = 'input'; + value = ''; + options?: PhoneMaskDirectiveInput; +} + +@Component({ + standalone: true, + imports: [PhoneMaskDirective, ReactiveFormsModule], + template: '' +}) +class PhoneMaskDirectiveFormHostComponent { + readonly control = new FormControl(''); +} + +const flushAngular = async (detectChanges: () => void) => { + await Promise.resolve(); + await Promise.resolve(); + detectChanges(); +}; + +const setup = + (elTag: 'input' | 'div' = 'input', elValue?: string) => + async (options?: string | PhoneMaskDirectiveOptions) => { + const onChange = vi.fn(); + const onCountryChange = vi.fn(); + + const mergeOptions = (opts?: string | PhoneMaskDirectiveOptions): string | PhoneMaskDirectiveOptions | undefined => + typeof opts === 'object' ? { ...opts, onChange, onCountryChange } : opts; + + const result = await render(PhoneMaskDirectiveHostComponent, { + imports: [PhoneMaskDirective], + providers: [{ provide: COUNTRY_DETECTION, useValue: countryDetection }], + componentProperties: { + tag: elTag, + value: elValue ?? '', + options: mergeOptions(options) + } + }); + + await flushAngular(result.detectChanges); + + const el = result.container.querySelector(elTag) as DirectiveHTMLInputElement; + + const update = async (newOptions?: string | PhoneMaskDirectiveOptions) => { + const host = result.fixture.componentInstance; + if (elTag === 'input') host.value = el.value; + host.options = mergeOptions(newOptions); + await flushAngular(result.detectChanges); + }; + + return { + el, + onChange, + onCountryChange, + update, + unmount: () => result.fixture.destroy() + }; + }; + +describe('PhoneMaskDirective', () => { + testPhoneMaskBinding( + setup, + { + warnMessage: '[phoneMask] Directive can only be used on input elements', + detectByGeoIpMock: countryDetection.detectByGeoIp + }, + tools + ); + + const renderDirective = async (value = '', options?: PhoneMaskDirectiveInput, tag: 'input' | 'div' = 'input') => { + const result = await render(PhoneMaskDirectiveHostComponent, { + imports: [PhoneMaskDirective], + providers: [{ provide: COUNTRY_DETECTION, useValue: countryDetection }], + componentProperties: { + tag, + value, + options + } + }); + + await flushAngular(result.detectChanges); + + const el = result.container.querySelector(tag) as DirectiveHTMLInputElement; + const directive = result.debugElement.query(By.directive(PhoneMaskDirective)).injector.get(PhoneMaskDirective); + + return { + el, + directive, + unmount: () => result.fixture.destroy() + }; + }; + + it('keeps defensive ControlValueAccessor methods inert on non-input hosts', async () => { + const warn = vi.spyOn(console, 'warn').mockImplementation(() => {}); + const { directive, unmount } = await renderDirective('', undefined, 'div'); + + expect(() => directive.writeValue('2025550199')).not.toThrow(); + expect(() => directive.setDisabledState(true)).not.toThrow(); + + unmount(); + warn.mockRestore(); + }); + + it('uses default touched callback until ControlValueAccessor registers one', async () => { + const { el, unmount } = await renderDirective(); + + expect(() => el.dispatchEvent(new Event('blur'))).not.toThrow(); + + unmount(); + }); + + it('supports ControlValueAccessor change, touched, and disabled APIs', async () => { + const { el, directive, unmount } = await renderDirective('2025550199', { country: 'US' }); + const onChange = vi.fn(); + const onTouched = vi.fn(); + + directive.registerOnChange(onChange); + directive.registerOnTouched(onTouched); + + directive.setDisabledState(true); + expect(el.disabled).toBe(true); + + directive.setDisabledState(false); + expect(el.disabled).toBe(false); + + directive.writeValue(null); + expect(el.value).toBe(''); + + el.dispatchEvent(new Event('blur')); + expect(onTouched).toHaveBeenCalledOnce(); + + const beforeInput = new InputEvent('beforeinput', { + data: '7', + inputType: 'insertText', + bubbles: true, + cancelable: true + }); + + el.dispatchEvent(beforeInput); + expect(beforeInput.defaultPrevented).toBe(false); + + directive.clear(); + expect(onChange).toHaveBeenCalledWith(''); + expect(directive.getDigits()).toBe(''); + + unmount(); + }); + + it('works as an Angular reactive forms value accessor', async () => { + const result = await render(PhoneMaskDirectiveFormHostComponent, { + providers: [{ provide: COUNTRY_DETECTION, useValue: countryDetection }] + }); + const host = result.fixture.componentInstance; + const el = result.container.querySelector('input') as HTMLInputElement; + + host.control.setValue('2025550199'); + await flushAngular(result.detectChanges); + + expect(el.value).toBe('202-555-0199'); + expect(host.control.value).toBe('2025550199'); + + result.fixture.destroy(); + }); + + it('supports writeValue, getters, and invalid country handling', async () => { + const { el, directive, unmount } = await renderDirective('', { country: 'US' }); + const onChange = vi.fn(); + + directive.registerOnChange(onChange); + directive.writeValue(2025550199); + + expect(directive.getDigits()).toBe('2025550199'); + expect(directive.getFullNumber()).toBe('+12025550199'); + expect(directive.getFullFormattedNumber()).toBe('+1 202-555-0199'); + expect(directive.isComplete()).toBe(true); + expect(directive.isValid()).toBe(true); + expect(el.value).toBe('202-555-0199'); + expect(onChange).not.toHaveBeenCalled(); + + expect(directive.selectCountry('INVALID')).toBe(false); + expect(directive.getFullNumber()).toBe('+12025550199'); + + unmount(); + }); + + it('truncates digits when selecting a country with a shorter mask', async () => { + const { directive, unmount } = await renderDirective('2025550199'); + const onChange = vi.fn(); + + directive.registerOnChange(onChange); + await tools.act(async () => { + expect(directive.selectCountry('AD')).toBe(true); + }); + + expect(directive.getDigits().length).toBeLessThan(10); + expect(onChange).toHaveBeenCalledWith(directive.getDigits()); + expect(directive.getFullNumber()).toMatch(/^\+376/); + + unmount(); + }); + + it('binding state setCountry returns false when state is removed before update finishes', async () => { + const { el, unmount } = await setup('input')({ country: 'US' }); + const setCountry = el.__phoneMaskState?.setCountry; + + delete el.__phoneMaskState; + + expect(setCountry?.('GB')).toBe(false); + + unmount(); + }); +}); diff --git a/packages/phone-mask-angular/tests/unit/service-pipe.test.ts b/packages/phone-mask-angular/tests/unit/service-pipe.test.ts new file mode 100644 index 00000000..acda30cb --- /dev/null +++ b/packages/phone-mask-angular/tests/unit/service-pipe.test.ts @@ -0,0 +1,31 @@ +import { describe, expect, it } from 'vitest'; +import { TestBed } from '@angular/core/testing'; +import { PhoneMaskPipe } from '@src/phone-mask.pipe'; + +describe('PhoneMaskPipe', () => { + const setup = () => { + return TestBed.runInInjectionContext(() => new PhoneMaskPipe()); + }; + + it('supports display, full, fullFormatted, and placeholder modes', () => { + const pipe = setup(); + expect(pipe.transform('2025551234')).toBe('202-555-1234'); + expect(pipe.transform('2025551234', { mode: 'full' })).toBe('+12025551234'); + expect(pipe.transform('2025551234', { mode: 'fullFormatted' })).toBe('+1 202-555-1234'); + expect(pipe.transform('', { mode: 'placeholder' })).toBe('###-###-####'); + }); + + it('accepts country, mode, and locale shorthand arguments', () => { + const pipe = setup(); + expect(pipe.transform('442071234567', 'GB', 'fullFormatted', 'en')).toMatch(/^\+44 /); + }); + + it('formats number, null, and invalid-country inputs through fallback paths', () => { + const pipe = setup(); + + expect(pipe.transform(2025551234, { country: 'US' })).toBe('202-555-1234'); + expect(pipe.transform(null, { country: 'US', mode: 'full' })).toBe(''); + expect(pipe.transform(undefined, { country: 'US', mode: 'fullFormatted' })).toBe(''); + expect(pipe.transform('2025551234', { country: 'INVALID', mode: 'full' })).toBe('+12025551234'); + }); +}); diff --git a/packages/phone-mask-angular/tests/unit/setup/angular.ts b/packages/phone-mask-angular/tests/unit/setup/angular.ts new file mode 100644 index 00000000..4653e1a7 --- /dev/null +++ b/packages/phone-mask-angular/tests/unit/setup/angular.ts @@ -0,0 +1,11 @@ +import '@angular/compiler'; +import { getTestBed } from '@angular/core/testing'; +import { BrowserTestingModule, platformBrowserTesting } from '@angular/platform-browser/testing'; + +const testBed = getTestBed(); + +if (!testBed.platform) { + testBed.initTestEnvironment(BrowserTestingModule, platformBrowserTesting(), { + teardown: { destroyAfterEach: true } + }); +} diff --git a/packages/phone-mask-angular/tests/unit/setup/tools.ts b/packages/phone-mask-angular/tests/unit/setup/tools.ts new file mode 100644 index 00000000..63ed91ac --- /dev/null +++ b/packages/phone-mask-angular/tests/unit/setup/tools.ts @@ -0,0 +1,21 @@ +import { TestBed } from '@angular/core/testing'; +import { fireEvent, screen, waitFor } from '@testing-library/angular'; +import type { MaybeRef, TestTools } from '@common/tests/unit/setup/tools'; + +export const act = async (callback: () => void | Promise): Promise => { + await callback(); + TestBed.tick(); + await Promise.resolve(); +}; + +export const tools: TestTools = { + toValue: (val: MaybeRef) => { + if (typeof val === 'function') return (val as () => T)(); + if (val && typeof val === 'object' && 'value' in val) return val.value; + return val; + }, + act, + waitFor, + fireEvent, + screen +}; diff --git a/packages/phone-mask-angular/tests/unit/useClipboard.test.ts b/packages/phone-mask-angular/tests/unit/useClipboard.test.ts new file mode 100644 index 00000000..cb41dbb6 --- /dev/null +++ b/packages/phone-mask-angular/tests/unit/useClipboard.test.ts @@ -0,0 +1,106 @@ +/// +import { Component, inject } from '@angular/core'; +import { TestBed } from '@angular/core/testing'; +import { testUseClipboard, type SetupOptions } from '@common/tests/unit/useClipboard'; +import { UseClipboardService } from '@src/services/utility/useClipboard.service'; +import { tools } from './setup/tools'; + +let initialOptions: SetupOptions = {}; + +@Component({ + standalone: true, + template: '', + providers: [UseClipboardService] +}) +class UseClipboardHostComponent { + readonly service = inject(UseClipboardService); +} + +function setup(options: SetupOptions = {}) { + initialOptions = options; + TestBed.configureTestingModule({ imports: [UseClipboardHostComponent] }); + const fixture = TestBed.createComponent(UseClipboardHostComponent); + fixture.detectChanges(); + TestBed.tick(); + + const host = fixture.componentInstance; + + return { + result: { + copied: host.service.copied, + isCopying: host.service.isCopying, + copy: (text: string) => host.service.copy(text, initialOptions.delay) + }, + service: host.service, + unmount: () => fixture.destroy() + }; +} + +testUseClipboard(setup, tools); + +describe('UseClipboardService Angular fallback', () => { + beforeEach(() => { + Object.defineProperty(navigator, 'clipboard', { + value: undefined, + writable: true, + configurable: true + }); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + it('uses textarea fallback when navigator.clipboard is unavailable', async () => { + const execCommand = vi.fn(() => true); + Object.defineProperty(document, 'execCommand', { + value: execCommand, + configurable: true + }); + + const { result, unmount } = setup(); + + await tools.act(async () => { + await result.copy(' +1 234-567-8901 '); + }); + + expect(execCommand).toHaveBeenCalledWith('copy'); + expect(document.querySelector('textarea')).toBeNull(); + expect(tools.toValue(result.copied)).toBe(true); + unmount(); + }); + + it('returns false when textarea fallback cannot copy', async () => { + const execCommand = vi.fn(() => false); + Object.defineProperty(document, 'execCommand', { + value: execCommand, + configurable: true + }); + + const { result, unmount } = setup(); + let copied = true; + + await tools.act(async () => { + copied = await result.copy('+1 234-567-8901'); + }); + + expect(copied).toBe(false); + expect(tools.toValue(result.copied)).toBe(false); + unmount(); + }); + + it('returns false when neither clipboard API nor document body is available', async () => { + const { result, service, unmount } = setup(); + let copied = true; + + (service as unknown as { document: Document | null }).document = null; + + await tools.act(async () => { + copied = await result.copy('+1 234-567-8901'); + }); + + expect(copied).toBe(false); + expect(tools.toValue(result.copied)).toBe(false); + unmount(); + }); +}); diff --git a/packages/phone-mask-angular/tests/unit/useCopyAction.test.ts b/packages/phone-mask-angular/tests/unit/useCopyAction.test.ts new file mode 100644 index 00000000..6b819395 --- /dev/null +++ b/packages/phone-mask-angular/tests/unit/useCopyAction.test.ts @@ -0,0 +1,146 @@ +/// +import { Component, ElementRef, inject, signal, viewChild } from '@angular/core'; +import { TestBed } from '@angular/core/testing'; +import { DELAY, PHONE, testUseCopyAction, type SetupOptions } from '@common/tests/unit/useCopyAction'; +import { UseCopyActionService } from '@src/services/internal/useCopyAction.service'; +import { UseClipboardService } from '@src/services/utility/useClipboard.service'; +import { tools } from './setup/tools'; + +let initialOptions: SetupOptions = { fullFormatted: '' }; + +@Component({ + selector: 'test-use-copy-action-host', + standalone: true, + template: '
', + providers: [UseClipboardService, UseCopyActionService] +}) +class UseCopyActionHostComponent { + readonly service = inject(UseCopyActionService); + readonly fullFormatted = signal(initialOptions.fullFormatted); + readonly liveRef = viewChild>('live'); + readonly onCopy = vi.fn(); + disableLiveRef = initialOptions.disableLiveRef ?? false; + + constructor() { + this.service.configure({ + fullFormatted: this.fullFormatted, + liveElement: () => (this.disableLiveRef ? null : this.liveRef()?.nativeElement), + onCopy: (value) => this.onCopy(value) + }); + } +} + +@Component({ + selector: 'test-unconfigured-use-copy-action-host', + standalone: true, + template: '', + providers: [UseClipboardService, UseCopyActionService] +}) +class UnconfiguredUseCopyActionHostComponent { + readonly service = inject(UseCopyActionService); +} + +@Component({ + selector: 'test-use-copy-action-without-live-host', + standalone: true, + template: '', + providers: [UseClipboardService, UseCopyActionService] +}) +class UseCopyActionWithoutLiveHostComponent { + readonly service = inject(UseCopyActionService); + readonly fullFormatted = signal(PHONE); + + constructor() { + this.service.configure({ fullFormatted: this.fullFormatted }); + } +} + +function setup(options: SetupOptions) { + initialOptions = options; + TestBed.configureTestingModule({ imports: [UseCopyActionHostComponent] }); + const fixture = TestBed.createComponent(UseCopyActionHostComponent); + fixture.detectChanges(); + TestBed.tick(); + + const host = fixture.componentInstance; + const el = fixture.nativeElement.querySelector('div') as HTMLDivElement; + + return { + result: { + copied: host.service.copied, + copyAriaLabel: host.service.copyAriaLabel, + copyButtonTitle: host.service.copyButtonTitle, + onCopyClick: () => host.service.onCopyClick() + }, + unmount: () => fixture.destroy(), + rerender: ({ fullFormatted }: { fullFormatted: string }) => { + host.fullFormatted.set(fullFormatted); + fixture.detectChanges(); + }, + el, + onCopy: host.onCopy + }; +} + +testUseCopyAction(setup, tools); + +describe('UseCopyActionService Angular live region timer', () => { + it('keeps default copy state inert before configure is called', async () => { + TestBed.configureTestingModule({ imports: [UnconfiguredUseCopyActionHostComponent] }); + const fixture = TestBed.createComponent(UnconfiguredUseCopyActionHostComponent); + fixture.detectChanges(); + TestBed.tick(); + const { service } = fixture.componentInstance; + + expect(service.copyAriaLabel()).toBe('Copy '); + expect(service.copyButtonTitle()).toBe('Copy phone number'); + + await tools.act(async () => { + await service.onCopyClick(); + }); + + expect(service.copied()).toBe(false); + fixture.destroy(); + }); + + it('copies without optional live region and copy callback hooks', async () => { + TestBed.configureTestingModule({ imports: [UseCopyActionWithoutLiveHostComponent] }); + const fixture = TestBed.createComponent(UseCopyActionWithoutLiveHostComponent); + fixture.detectChanges(); + TestBed.tick(); + const { service } = fixture.componentInstance; + + await tools.act(async () => { + await service.onCopyClick(); + }); + + expect(service.copied()).toBe(true); + fixture.destroy(); + }); + + it('replaces the pending live-region clear timer on repeated successful copy', async () => { + const { result, el, unmount } = setup({ fullFormatted: PHONE }); + + await tools.act(async () => { + await result.onCopyClick(); + }); + + await tools.act(async () => { + vi.advanceTimersByTime(DELAY - 1); + await result.onCopyClick(); + }); + + await tools.act(async () => { + vi.advanceTimersByTime(DELAY - 1); + }); + + expect(el.textContent).toBe('Phone number copied to clipboard'); + + await tools.act(async () => { + vi.advanceTimersByTime(1); + }); + + expect(el.textContent).toBe(''); + unmount(); + }); +}); diff --git a/packages/phone-mask-angular/tests/unit/useCountry.test.ts b/packages/phone-mask-angular/tests/unit/useCountry.test.ts new file mode 100644 index 00000000..44d2e3f1 --- /dev/null +++ b/packages/phone-mask-angular/tests/unit/useCountry.test.ts @@ -0,0 +1,123 @@ +/// +import { Component, inject, signal } from '@angular/core'; +import { TestBed } from '@angular/core/testing'; +import type { Mock } from 'vitest'; +import { testUseCountry, type CountrySetupOptions } from '@common/tests/unit/useCountry'; +import { COUNTRY_DETECTION, UseCountryService } from '@src/services/internal/useCountry.service'; +import { tools } from './setup/tools'; + +const countryDetection = { + detectByGeoIp: vi.fn(), + detectCountryFromLocale: vi.fn() +}; + +let initialOptions: CountrySetupOptions = {}; + +@Component({ + standalone: true, + template: '', + providers: [UseCountryService] +}) +class UseCountryHostComponent { + readonly service = inject(UseCountryService); + readonly countryOption = signal(initialOptions.countryOption); + readonly locale = signal(initialOptions.locale); + readonly detect = signal(initialOptions.detect ?? false); + readonly onCountryChange = vi.fn(); + + constructor() { + this.service.configure({ + country: this.countryOption, + locale: this.locale, + detect: this.detect, + onCountryChange: (country) => this.onCountryChange(country) + }); + } +} + +function setup(options: CountrySetupOptions = {}) { + initialOptions = options; + TestBed.configureTestingModule({ + imports: [UseCountryHostComponent], + providers: [{ provide: COUNTRY_DETECTION, useValue: countryDetection }] + }); + const fixture = TestBed.createComponent(UseCountryHostComponent); + fixture.detectChanges(); + TestBed.tick(); + + const host = fixture.componentInstance; + + return { + result: { + country: host.service.country, + setCountry: (code?: string | null) => host.service.setCountry(code), + locale: host.service.locale + }, + unmount: () => fixture.destroy(), + rerender: (newProps: Partial) => { + if ('countryOption' in newProps) host.countryOption.set(newProps.countryOption); + if ('locale' in newProps) host.locale.set(newProps.locale); + if ('detect' in newProps) host.detect.set(newProps.detect); + fixture.detectChanges(); + }, + onCountryChange: host.onCountryChange + }; +} + +const mocks = { + detectByGeoIp: countryDetection.detectByGeoIp as Mock, + detectCountryFromLocale: countryDetection.detectCountryFromLocale as Mock +}; + +testUseCountry(setup, tools, mocks); + +describe('UseCountryService Angular scheduling', () => { + it('keeps the first configuration when configure is called again', () => { + TestBed.configureTestingModule({ + providers: [UseCountryService, { provide: COUNTRY_DETECTION, useValue: countryDetection }] + }); + + const service = TestBed.inject(UseCountryService); + service.configure({ country: () => 'US', detect: () => false }); + service.configure({ country: () => 'GB', detect: () => false }); + + expect(service.country().id).toBe('US'); + }); + + it('uses detect=true as the service default when no detect option is configured', async () => { + mocks.detectByGeoIp.mockResolvedValue(null); + mocks.detectCountryFromLocale.mockReturnValue(null); + + TestBed.configureTestingModule({ + providers: [UseCountryService, { provide: COUNTRY_DETECTION, useValue: countryDetection }] + }); + + const service = TestBed.inject(UseCountryService); + service.configure(); + + await tools.act(async () => {}); + + expect(service.detect()).toBe(true); + expect(mocks.detectByGeoIp).toHaveBeenCalledOnce(); + }); + + it('does not repeat detection for the same locale and detect key', async () => { + mocks.detectByGeoIp.mockResolvedValue(null); + mocks.detectCountryFromLocale.mockReturnValue(null); + + const { rerender, unmount } = setup({ detect: true, locale: 'en' }); + + await tools.act(async () => {}); + expect(mocks.detectByGeoIp).toHaveBeenCalledTimes(1); + + rerender({ locale: 'en' }); + await tools.act(async () => {}); + expect(mocks.detectByGeoIp).toHaveBeenCalledTimes(1); + + rerender({ locale: 'de' }); + await tools.act(async () => {}); + expect(mocks.detectByGeoIp).toHaveBeenCalledTimes(2); + + unmount(); + }); +}); diff --git a/packages/phone-mask-angular/tests/unit/useCountrySelector.test.ts b/packages/phone-mask-angular/tests/unit/useCountrySelector.test.ts new file mode 100644 index 00000000..c73f633d --- /dev/null +++ b/packages/phone-mask-angular/tests/unit/useCountrySelector.test.ts @@ -0,0 +1,168 @@ +/// +import { Component, inject, signal } from '@angular/core'; +import { TestBed } from '@angular/core/testing'; +import { + createKeyboardOpenCountrySelectorSetupResult, + testUseCountrySelector, + type SetupOptions +} from '@common/tests/unit/useCountrySelector'; +import { testUseCountrySelectorDomBehavior } from '@common/tests/unit/useCountrySelectorDom'; +import { + createCountrySelectorDomFixture, + createCountrySelectorDomSetupResult, + type CountrySelectorDomFixture +} from '@common/tests/unit/setup/countrySelectorDom'; +import { UseCountrySelectorService } from '@src/services/internal/useCountrySelector.service'; +import { tools } from './setup/tools'; + +interface CountrySelectorContext { + dom: CountrySelectorDomFixture; + countryOption?: string; + inactive?: boolean; +} + +let context: CountrySelectorContext; + +@Component({ + standalone: true, + template: '', + providers: [UseCountrySelectorService] +}) +class UseCountrySelectorHostComponent { + readonly service = inject(UseCountrySelectorService); + readonly countryOption = signal(context.countryOption); + readonly inactive = signal(context.inactive ?? false); + readonly rootElement = signal(context.dom.rootEl); + readonly dropdownElement = signal(context.dom.dropdownEl); + readonly searchElement = signal(context.dom.searchEl); + readonly selectorElement = signal(context.dom.selectorEl); + readonly onSelectCountry = vi.fn(); + readonly onAfterSelect = vi.fn(); + + constructor() { + this.service.configure({ + rootElement: this.rootElement, + dropdownElement: this.dropdownElement, + searchElement: this.searchElement, + selectorElement: this.selectorElement, + locale: () => 'en', + inactive: this.inactive, + countryOption: this.countryOption, + onSelectCountry: (code) => this.onSelectCountry(code), + onAfterSelect: () => this.onAfterSelect() + }); + } +} + +function createHost(options: SetupOptions = {}) { + context = { + dom: createCountrySelectorDomFixture(), + countryOption: options.countryOption, + inactive: options.inactive + }; + + TestBed.configureTestingModule({ imports: [UseCountrySelectorHostComponent] }); + const fixture = TestBed.createComponent(UseCountrySelectorHostComponent); + fixture.detectChanges(); + TestBed.tick(); + + return { + fixture, + host: fixture.componentInstance, + dom: context.dom + }; +} + +function setup(options: SetupOptions = {}) { + const { fixture, host, dom } = createHost(options); + + return createKeyboardOpenCountrySelectorSetupResult( + host.service, + dom.cleanup, + () => fixture.destroy(), + host.onSelectCountry, + host.onAfterSelect, + dom.searchEl + ); +} + +afterEach(() => { + vi.restoreAllMocks(); + document.body.innerHTML = ''; +}); + +testUseCountrySelector(setup, tools); + +function setupWithDom(initialCountryOption?: string) { + const { fixture, host, dom } = createHost({ countryOption: initialCountryOption }); + + return createCountrySelectorDomSetupResult(dom, () => fixture.destroy(), { + result: host.service, + flushAsync: async () => { + TestBed.tick(); + await Promise.resolve(); + }, + setCountryOptionFixed: () => { + host.countryOption.set('US'); + fixture.detectChanges(); + }, + setInactive: () => { + host.inactive.set(true); + fixture.detectChanges(); + }, + setRootUnavailable: () => { + host.rootElement.set(null); + fixture.detectChanges(); + globalThis.dispatchEvent(new Event('resize')); + }, + setDropdownUnavailable: () => { + host.dropdownElement.set(null); + fixture.detectChanges(); + }, + setSelectorUnavailable: () => { + host.selectorElement.set(null); + fixture.detectChanges(); + } + }); +} + +describe('useCountrySelector DOM behavior (Angular)', () => { + testUseCountrySelectorDomBehavior(setupWithDom, tools); +}); + +describe('UseCountrySelectorService Angular defaults', () => { + it('keeps the first configuration when configure is called again', () => { + const { fixture, host, dom } = createHost(); + const ignoredSelect = vi.fn(); + + host.service.configure({ + rootElement: host.rootElement, + dropdownElement: host.dropdownElement, + searchElement: host.searchElement, + selectorElement: host.selectorElement, + locale: () => 'de', + onSelectCountry: ignoredSelect + }); + + host.service.selectCountry('GB'); + + expect(host.onSelectCountry).toHaveBeenCalledWith('GB'); + expect(ignoredSelect).not.toHaveBeenCalled(); + + dom.cleanup(); + fixture.destroy(); + }); + + it('is inert before configure is called', () => { + TestBed.configureTestingModule({ providers: [UseCountrySelectorService] }); + const service = TestBed.inject(UseCountrySelectorService); + + expect(service.hasDropdown()).toBe(true); + + service.openDropdown(); + expect(service.dropdownOpen()).toBe(false); + + service.selectCountry('US'); + expect(service.dropdownOpen()).toBe(false); + }); +}); diff --git a/packages/phone-mask-angular/tests/unit/useFormatter.test.ts b/packages/phone-mask-angular/tests/unit/useFormatter.test.ts new file mode 100644 index 00000000..d9cb1bb8 --- /dev/null +++ b/packages/phone-mask-angular/tests/unit/useFormatter.test.ts @@ -0,0 +1,114 @@ +/// +import { Component, inject, signal } from '@angular/core'; +import { TestBed } from '@angular/core/testing'; +import { getCountry } from '@desource/phone-mask/kit'; +import { testUseFormatter, type SetupOptions } from '@common/tests/unit/useFormatter'; +import { UseFormatterService } from '@src/services/internal/useFormatter.service'; +import { tools } from './setup/tools'; + +let initialOptions: SetupOptions = {}; + +@Component({ + standalone: true, + template: '', + providers: [UseFormatterService] +}) +class UseFormatterHostComponent { + readonly service = inject(UseFormatterService); + readonly countryCode = signal(initialOptions.countryCode ?? 'US'); + readonly value = signal(initialOptions.value ?? ''); + readonly onChange = vi.fn(); + readonly onPhoneChange = vi.fn(); + readonly onValidationChange = vi.fn(); + + constructor() { + this.service.configure({ + country: () => getCountry(this.countryCode(), 'en'), + value: this.value, + onChange: (digits) => this.onChange(digits), + onPhoneChange: (phone) => this.onPhoneChange(phone), + onValidationChange: (isComplete) => this.onValidationChange(isComplete) + }); + } +} + +function setup(options: SetupOptions = {}) { + initialOptions = options; + TestBed.configureTestingModule({ imports: [UseFormatterHostComponent] }); + const fixture = TestBed.createComponent(UseFormatterHostComponent); + fixture.detectChanges(); + TestBed.tick(); + + const host = fixture.componentInstance; + + return { + result: { + digits: host.service.digits, + displayPlaceholder: host.service.displayPlaceholder, + displayValue: host.service.displayValue, + full: host.service.full, + fullFormatted: host.service.fullFormatted, + isComplete: host.service.isComplete, + isEmpty: host.service.isEmpty, + shouldShowWarn: host.service.shouldShowWarn + }, + unmount: () => fixture.destroy(), + rerender: ({ value, countryCode }: SetupOptions) => { + if (value !== undefined) host.value.set(value); + if (countryCode !== undefined) host.countryCode.set(countryCode); + fixture.detectChanges(); + }, + onChange: host.onChange, + onPhoneChange: host.onPhoneChange, + onValidationChange: host.onValidationChange + }; +} + +testUseFormatter(setup, tools); + +describe('UseFormatterService Angular scheduling', () => { + it('keeps the first configuration when configure is called again', () => { + initialOptions = { value: '2025550199', countryCode: 'US' }; + TestBed.configureTestingModule({ imports: [UseFormatterHostComponent] }); + const fixture = TestBed.createComponent(UseFormatterHostComponent); + fixture.detectChanges(); + TestBed.tick(); + const host = fixture.componentInstance; + const ignoredOnChange = vi.fn(); + + host.service.configure({ + country: () => getCountry('GB', 'en'), + value: () => '777', + onChange: ignoredOnChange + }); + + expect(host.service.full()).toBe('+12025550199'); + expect(ignoredOnChange).not.toHaveBeenCalled(); + fixture.destroy(); + }); + + it('exposes safe default formatter state before configure is called', () => { + TestBed.configureTestingModule({ providers: [UseFormatterService] }); + const service = TestBed.inject(UseFormatterService); + + expect(service.country().id).toBe('US'); + expect(service.digits()).toBe(''); + expect(service.displayPlaceholder()).toBe('###-###-####'); + expect(service.full()).toBe(''); + expect(service.isEmpty()).toBe(true); + }); + + it('does not emit duplicate clamped values for the same raw and clamped pair', async () => { + const { onChange, rerender, unmount } = setup({ value: '23456789011' }); + + expect(onChange).toHaveBeenCalledTimes(1); + expect(onChange).toHaveBeenCalledWith('2345678901'); + + await tools.act(async () => { + rerender({ value: '23456789011' }); + }); + + expect(onChange).toHaveBeenCalledTimes(1); + unmount(); + }); +}); diff --git a/packages/phone-mask-angular/tests/unit/useInputHandlers.test.ts b/packages/phone-mask-angular/tests/unit/useInputHandlers.test.ts new file mode 100644 index 00000000..f05f6f55 --- /dev/null +++ b/packages/phone-mask-angular/tests/unit/useInputHandlers.test.ts @@ -0,0 +1,96 @@ +/// +import { createPhoneFormatter, getCountry } from '@desource/phone-mask/kit'; +import { testUseInputHandlers, type SetupOptions } from '@common/tests/unit/useInputHandlers'; +import { UseInputHandlersService } from '@src/services/internal/useInputHandlers.service'; +import { tools } from './setup/tools'; + +function setup(options: SetupOptions = {}) { + let digits = options.digits ?? ''; + let inactive = options.inactive ?? false; + + const onChange = vi.fn(); + const scheduleValidationHint = vi.fn(); + const formatter = createPhoneFormatter(getCountry('US', 'en')); + const service = new UseInputHandlersService(); + const inputEl = document.createElement('input'); + + document.body.appendChild(inputEl); + + service.configure({ + formatter: () => formatter, + digits: () => digits, + inactive: () => inactive, + onChange, + scheduleValidationHint + }); + + const beforeInputHandler = (event: InputEvent) => service.handleBeforeInput(event); + const inputHandler = (event: Event) => service.handleInput(event); + const keydownHandler = (event: KeyboardEvent) => service.handleKeydown(event); + const pasteHandler = (event: ClipboardEvent) => service.handlePaste(event); + + inputEl.addEventListener('beforeinput', beforeInputHandler); + inputEl.addEventListener('input', inputHandler); + inputEl.addEventListener('keydown', keydownHandler); + inputEl.addEventListener('paste', pasteHandler); + + return { + unmount: () => { + inputEl.removeEventListener('beforeinput', beforeInputHandler); + inputEl.removeEventListener('input', inputHandler); + inputEl.removeEventListener('keydown', keydownHandler); + inputEl.removeEventListener('paste', pasteHandler); + inputEl.remove(); + }, + rerender: (newProps: SetupOptions) => { + if (newProps.digits !== undefined) digits = newProps.digits; + if (newProps.inactive !== undefined) inactive = newProps.inactive; + }, + onChange, + scheduleValidationHint, + inputEl, + invokeInputWithoutTarget: () => { + service.handleInput({ target: null } as unknown as Event); + } + }; +} + +testUseInputHandlers(setup, tools); + +describe('UseInputHandlersService Angular edges', () => { + it('prevents beforeinput when inactive', async () => { + const { inputEl, unmount } = setup({ inactive: true }); + const event = new InputEvent('beforeinput', { + bubbles: true, + cancelable: true, + inputType: 'insertText', + data: '5' + }); + const preventDefault = vi.spyOn(event, 'preventDefault'); + + await tools.act(async () => { + inputEl.dispatchEvent(event); + }); + + expect(preventDefault).toHaveBeenCalledOnce(); + unmount(); + }); + + it('handles valid input without optional callbacks', async () => { + const formatter = createPhoneFormatter(getCountry('US', 'en')); + const service = new UseInputHandlersService(); + const inputEl = document.createElement('input'); + + service.configure({ + formatter: () => formatter, + digits: () => '' + }); + + await tools.act(async () => { + inputEl.value = '202-555-0199'; + service.handleInput({ target: inputEl } as unknown as Event); + }); + + expect(inputEl.value).toBe('202-555-0199'); + }); +}); diff --git a/packages/phone-mask-angular/tests/unit/usePhoneMask.test.ts b/packages/phone-mask-angular/tests/unit/usePhoneMask.test.ts new file mode 100644 index 00000000..7a3059f6 --- /dev/null +++ b/packages/phone-mask-angular/tests/unit/usePhoneMask.test.ts @@ -0,0 +1,154 @@ +/// +import { Component, ElementRef, inject, signal, viewChild, type AfterViewInit, type OnDestroy } from '@angular/core'; +import { render } from '@testing-library/angular'; +import { testUsePhoneMask, type UsePhoneMaskSetupOptions } from '@common/tests/unit/usePhoneMask'; +import { UsePhoneMaskService } from '@src/services/usePhoneMask.service'; +import { tools } from './setup/tools'; + +@Component({ + standalone: true, + template: '', + providers: [UsePhoneMaskService] +}) +class UsePhoneMaskHostComponent implements AfterViewInit, OnDestroy { + readonly mask = inject(UsePhoneMaskService); + readonly value = signal(''); + attachRef = true; + onChange = vi.fn(); + private readonly inputRef = viewChild>('phoneInput'); + + constructor() { + this.mask.configure({ + value: this.value, + detect: () => false, + onChange: (digits) => { + this.value.set(digits); + this.onChange(digits); + } + }); + } + + ngAfterViewInit(): void { + if (this.attachRef) { + this.mask.connect(this.inputRef()?.nativeElement ?? null); + } + } + + ngOnDestroy(): void { + this.mask.connect(null); + } +} + +@Component({ + standalone: true, + template: '', + providers: [UsePhoneMaskService] +}) +class UnconfiguredUsePhoneMaskHostComponent { + readonly mask = inject(UsePhoneMaskService); +} + +async function setup(initialValue = '', options: UsePhoneMaskSetupOptions = {}) { + const attachRef = options.attachRef ?? true; + const result = await render(UsePhoneMaskHostComponent, { + detectChangesOnRender: false, + componentProperties: { attachRef } + }); + + const host = result.fixture.componentInstance; + host.value.set(initialValue); + result.detectChanges(); + if (attachRef) host.mask.connect(result.container.querySelector('input')); + await tools.act(async () => {}); + + const inputEl = result.container.querySelector('input') as HTMLInputElement; + + return { + inputEl, + onChange: host.onChange, + getValue: () => host.value(), + unmount: () => result.fixture.destroy(), + api: { + getDigits: () => host.mask.getDigits(), + getFull: () => host.mask.full(), + getFullFormatted: () => host.mask.fullFormatted(), + isEmpty: () => host.mask.isEmpty(), + shouldShowWarn: () => host.mask.shouldShowWarn(), + getInputRef: () => host.mask.inputRef(), + getFormatter: () => host.mask.getFormatter(), + configureAgain: (onChange: (digits: string) => void) => + host.mask.configure({ + value: () => '999', + onChange + }), + setCountry: (countryCode: string) => host.mask.setCountry(countryCode), + clear: () => host.mask.clear() + } + }; +} + +testUsePhoneMask(setup, tools); + +describe('UsePhoneMaskService Angular API', () => { + it('exposes formatter helper and rejects invalid countries without resyncing input', async () => { + const { api, inputEl, onChange, unmount } = await setup('2025550199'); + const ignoredOnChange = vi.fn(); + + expect(api.getInputRef()).toBe(inputEl); + expect(api.getFormatter().getPlaceholder()).toBe('###-###-####'); + expect(api.setCountry('INVALID')).toBe(false); + expect(inputEl.value).toBe('202-555-0199'); + + api.configureAgain(ignoredOnChange); + api.clear(); + expect(onChange).toHaveBeenCalledWith(''); + expect(ignoredOnChange).not.toHaveBeenCalled(); + + unmount(); + }); + + it('keeps imperative helpers safe before configure is called', async () => { + const { fixture } = await render(UnconfiguredUsePhoneMaskHostComponent, { detectChangesOnRender: false }); + const { mask } = fixture.componentInstance; + + expect(mask.inputRef()).toBeNull(); + mask.clear(); + + fixture.destroy(); + }); + + it('wires beforeinput, keydown, and paste listeners to the connected input', async () => { + const { inputEl, onChange, unmount } = await setup('2025550199'); + + await tools.act(async () => { + inputEl.setSelectionRange(inputEl.value.length, inputEl.value.length); + inputEl.dispatchEvent(new KeyboardEvent('keydown', { key: 'Backspace', bubbles: true, cancelable: true })); + }); + + expect(onChange).toHaveBeenCalledWith('202555019'); + + await tools.act(async () => { + inputEl.setSelectionRange(inputEl.value.length, inputEl.value.length); + const paste = new Event('paste', { bubbles: true, cancelable: true }) as ClipboardEvent; + Object.defineProperty(paste, 'clipboardData', { + value: { getData: () => '88' }, + configurable: true + }); + inputEl.dispatchEvent(paste); + }); + + expect(onChange).toHaveBeenCalledWith('2025550198'); + + const beforeInput = new InputEvent('beforeinput', { + data: '7', + inputType: 'insertText', + bubbles: true, + cancelable: true + }); + + inputEl.dispatchEvent(beforeInput); + expect(beforeInput.defaultPrevented).toBe(false); + + unmount(); + }); +}); diff --git a/packages/phone-mask-angular/tests/unit/useTheme.test.ts b/packages/phone-mask-angular/tests/unit/useTheme.test.ts new file mode 100644 index 00000000..805205f2 --- /dev/null +++ b/packages/phone-mask-angular/tests/unit/useTheme.test.ts @@ -0,0 +1,69 @@ +/// +import { Component, inject, signal } from '@angular/core'; +import { TestBed } from '@angular/core/testing'; +import { testUseTheme, type SetupOptions } from '@common/tests/unit/useTheme'; +import { UseThemeService } from '@src/services/internal/useTheme.service'; +import type { Theme } from '@src/types'; +import { tools } from './setup/tools'; + +let initialOptions: SetupOptions = { theme: 'auto' }; + +@Component({ + selector: 'test-use-theme-host', + standalone: true, + template: '', + providers: [UseThemeService] +}) +class UseThemeHostComponent { + readonly service = inject(UseThemeService); + readonly theme = signal(initialOptions.theme); + + constructor() { + this.service.configure({ theme: this.theme }); + } +} + +@Component({ + selector: 'test-unconfigured-use-theme-host', + standalone: true, + template: '', + providers: [UseThemeService] +}) +class UnconfiguredUseThemeHostComponent { + readonly service = inject(UseThemeService); +} + +function setup(options: SetupOptions) { + initialOptions = options; + TestBed.configureTestingModule({ imports: [UseThemeHostComponent] }); + const fixture = TestBed.createComponent(UseThemeHostComponent); + fixture.detectChanges(); + TestBed.tick(); + + const host = fixture.componentInstance; + + return { + result: { + themeClass: host.service.themeClass + }, + unmount: () => fixture.destroy(), + rerender: ({ theme }: SetupOptions) => { + host.theme.set(theme); + fixture.detectChanges(); + } + }; +} + +testUseTheme(setup, tools); + +describe('UseThemeService Angular defaults', () => { + it('uses auto theme before configure is called', () => { + TestBed.configureTestingModule({ imports: [UnconfiguredUseThemeHostComponent] }); + const fixture = TestBed.createComponent(UnconfiguredUseThemeHostComponent); + fixture.detectChanges(); + TestBed.tick(); + + expect(fixture.componentInstance.service.themeClass()).toBe('theme-light'); + fixture.destroy(); + }); +}); diff --git a/packages/phone-mask-angular/tests/unit/useTimer.test.ts b/packages/phone-mask-angular/tests/unit/useTimer.test.ts new file mode 100644 index 00000000..b0a97baf --- /dev/null +++ b/packages/phone-mask-angular/tests/unit/useTimer.test.ts @@ -0,0 +1,29 @@ +/// +import { Component, inject } from '@angular/core'; +import { TestBed } from '@angular/core/testing'; +import { testUseTimer } from '@common/tests/unit/useTimer'; +import { UseTimerService } from '@src/services/utility/useTimer.service'; +import { tools } from './setup/tools'; + +@Component({ + standalone: true, + template: '', + providers: [UseTimerService] +}) +class UseTimerHostComponent { + readonly service = inject(UseTimerService); +} + +function setup() { + TestBed.configureTestingModule({ imports: [UseTimerHostComponent] }); + const fixture = TestBed.createComponent(UseTimerHostComponent); + fixture.detectChanges(); + TestBed.tick(); + + return { + result: fixture.componentInstance.service, + unmount: () => fixture.destroy() + }; +} + +testUseTimer(setup, tools); diff --git a/packages/phone-mask-angular/tests/unit/useValidationHint.test.ts b/packages/phone-mask-angular/tests/unit/useValidationHint.test.ts new file mode 100644 index 00000000..c7e1a21d --- /dev/null +++ b/packages/phone-mask-angular/tests/unit/useValidationHint.test.ts @@ -0,0 +1,29 @@ +/// +import { Component, inject } from '@angular/core'; +import { TestBed } from '@angular/core/testing'; +import { testUseValidationHint } from '@common/tests/unit/useValidationHint'; +import { UseValidationHintService } from '@src/services/internal/useValidationHint.service'; +import { tools } from './setup/tools'; + +@Component({ + standalone: true, + template: '', + providers: [UseValidationHintService] +}) +class UseValidationHintHostComponent { + readonly service = inject(UseValidationHintService); +} + +function setup() { + TestBed.configureTestingModule({ imports: [UseValidationHintHostComponent] }); + const fixture = TestBed.createComponent(UseValidationHintHostComponent); + fixture.detectChanges(); + TestBed.tick(); + + return { + result: fixture.componentInstance.service, + unmount: () => fixture.destroy() + }; +} + +testUseValidationHint(setup, tools); diff --git a/packages/phone-mask-angular/tsconfig.json b/packages/phone-mask-angular/tsconfig.json new file mode 100644 index 00000000..acfce103 --- /dev/null +++ b/packages/phone-mask-angular/tsconfig.json @@ -0,0 +1,26 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "target": "ES2022", + "module": "ES2022", + "moduleResolution": "bundler", + "composite": false, + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": false, + "experimentalDecorators": true, + "inlineSources": true, + "outDir": "dist/out-tsc", + "rootDir": ".", + "skipLibCheck": true, + "types": [] + }, + "angularCompilerOptions": { + "compilationMode": "partial", + "strictTemplates": true, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true + }, + "include": ["src/**/*.ts", "core/src/**/*.ts"], + "exclude": ["dist", "tests/**/*.ts"] +} diff --git a/packages/phone-mask-angular/tsconfig.spec.json b/packages/phone-mask-angular/tsconfig.spec.json new file mode 100644 index 00000000..54e06d68 --- /dev/null +++ b/packages/phone-mask-angular/tsconfig.spec.json @@ -0,0 +1,9 @@ +{ + "extends": "./tests/tsconfig.json", + "compilerOptions": { + "target": "ES2022", + "types": ["vitest/globals", "node"] + }, + "include": ["src/**/*.ts", "core/src/**/*.ts", "tests/**/*.ts", "../../common/tests/**/*.ts"], + "exclude": [] +} diff --git a/packages/phone-mask-angular/vitest.angular.config.ts b/packages/phone-mask-angular/vitest.angular.config.ts new file mode 100644 index 00000000..6622188b --- /dev/null +++ b/packages/phone-mask-angular/vitest.angular.config.ts @@ -0,0 +1,20 @@ +import { defineConfig } from 'vitest/config'; +import { fileURLToPath } from 'node:url'; + +export default defineConfig({ + resolve: { + alias: { + '@common': fileURLToPath(new URL('../../common', import.meta.url)), + '@src': fileURLToPath(new URL('./src', import.meta.url)) + } + }, + test: { + environment: 'jsdom', + globals: true, + coverage: { + include: ['src/**/*.ts'], + exclude: ['src/**/*.d.ts'], + reportsDirectory: 'coverage' + } + } +}); diff --git a/packages/phone-mask-react/tests/e2e/PhoneInput.spec.ts b/packages/phone-mask-react/tests/e2e/PhoneInput.spec.ts index cff6821f..0bc27329 100644 --- a/packages/phone-mask-react/tests/e2e/PhoneInput.spec.ts +++ b/packages/phone-mask-react/tests/e2e/PhoneInput.spec.ts @@ -1,4 +1,4 @@ -import { testPhoneInput } from '../../../../common/tests/e2e/PhoneInput'; +import { testPhoneInput } from '@common/tests/e2e/PhoneInput'; const PLAYGROUND_SELECTOR = '[data-testid="playground"]'; diff --git a/packages/phone-mask-react/tests/e2e/UsePhoneMask.spec.ts b/packages/phone-mask-react/tests/e2e/UsePhoneMask.spec.ts index bd118897..6cccab00 100644 --- a/packages/phone-mask-react/tests/e2e/UsePhoneMask.spec.ts +++ b/packages/phone-mask-react/tests/e2e/UsePhoneMask.spec.ts @@ -1,4 +1,4 @@ -import { testUsePhoneMask } from '../../../../common/tests/e2e/UsePhoneMask'; +import { testUsePhoneMask } from '@common/tests/e2e/UsePhoneMask'; const HOOK_SELECTOR = '[data-testid="hook"]'; diff --git a/packages/phone-mask-react/tests/unit/PhoneInput.test.tsx b/packages/phone-mask-react/tests/unit/PhoneInput.test.tsx index 37021b7b..937c43e9 100644 --- a/packages/phone-mask-react/tests/unit/PhoneInput.test.tsx +++ b/packages/phone-mask-react/tests/unit/PhoneInput.test.tsx @@ -1,8 +1,8 @@ /// import { createRef, type RefObject } from 'react'; import { render } from '@testing-library/react'; -import { PhoneInput } from '../../src/components/PhoneInput'; -import type { PhoneInputRef } from '../../src/types'; +import { PhoneInput } from '@src/components/PhoneInput'; +import type { PhoneInputRef } from '@src/types'; import { testPhoneInput } from '@common/tests/unit/PhoneInput'; import { tools, createResultProxy } from './setup/tools'; import type { SetupFn } from '@common/tests/unit/PhoneInput'; diff --git a/packages/phone-mask-react/tests/unit/index.test.ts b/packages/phone-mask-react/tests/unit/index.test.ts index d2278b70..f4c797e0 100644 --- a/packages/phone-mask-react/tests/unit/index.test.ts +++ b/packages/phone-mask-react/tests/unit/index.test.ts @@ -1,7 +1,7 @@ /// import { testIndexImports } from '@common/tests/unit/index'; -import * as indexModule from '../../src/index'; -import * as coreModule from '../../src/core'; +import * as indexModule from '@src/index'; +import * as coreModule from '@src/core'; testIndexImports({ suiteName: 'react', diff --git a/packages/phone-mask-react/tests/unit/usePhoneMask.test.tsx b/packages/phone-mask-react/tests/unit/usePhoneMask.test.tsx index 29428b5d..488968c3 100644 --- a/packages/phone-mask-react/tests/unit/usePhoneMask.test.tsx +++ b/packages/phone-mask-react/tests/unit/usePhoneMask.test.tsx @@ -1,7 +1,7 @@ /// import { useState } from 'react'; import { render } from '@testing-library/react'; -import { usePhoneMask } from '../../src/hooks/usePhoneMask'; +import { usePhoneMask } from '@src/hooks/usePhoneMask'; import { testUsePhoneMask, type UsePhoneMaskSetupOptions } from '@common/tests/unit/usePhoneMask'; import { tools } from './setup/tools'; diff --git a/packages/phone-mask-svelte/tests/e2e/PhoneInput.spec.ts b/packages/phone-mask-svelte/tests/e2e/PhoneInput.spec.ts index cff6821f..0bc27329 100644 --- a/packages/phone-mask-svelte/tests/e2e/PhoneInput.spec.ts +++ b/packages/phone-mask-svelte/tests/e2e/PhoneInput.spec.ts @@ -1,4 +1,4 @@ -import { testPhoneInput } from '../../../../common/tests/e2e/PhoneInput'; +import { testPhoneInput } from '@common/tests/e2e/PhoneInput'; const PLAYGROUND_SELECTOR = '[data-testid="playground"]'; diff --git a/packages/phone-mask-svelte/tests/e2e/UsePhoneMask.spec.ts b/packages/phone-mask-svelte/tests/e2e/UsePhoneMask.spec.ts index bd118897..6cccab00 100644 --- a/packages/phone-mask-svelte/tests/e2e/UsePhoneMask.spec.ts +++ b/packages/phone-mask-svelte/tests/e2e/UsePhoneMask.spec.ts @@ -1,4 +1,4 @@ -import { testUsePhoneMask } from '../../../../common/tests/e2e/UsePhoneMask'; +import { testUsePhoneMask } from '@common/tests/e2e/UsePhoneMask'; const HOOK_SELECTOR = '[data-testid="hook"]'; diff --git a/packages/phone-mask-svelte/tests/unit/index.test.ts b/packages/phone-mask-svelte/tests/unit/index.test.ts index d96889fa..4e6cde44 100644 --- a/packages/phone-mask-svelte/tests/unit/index.test.ts +++ b/packages/phone-mask-svelte/tests/unit/index.test.ts @@ -1,7 +1,7 @@ /// import { testIndexImports } from '@common/tests/unit/index'; -import * as indexModule from '../../src/index'; -import * as coreModule from '../../src/core'; +import * as indexModule from '@src/index'; +import * as coreModule from '@src/core'; testIndexImports({ suiteName: 'svelte', diff --git a/packages/phone-mask-svelte/tests/unit/useCopyAction.test.ts b/packages/phone-mask-svelte/tests/unit/useCopyAction.test.ts index 7707835d..75d47b6f 100644 --- a/packages/phone-mask-svelte/tests/unit/useCopyAction.test.ts +++ b/packages/phone-mask-svelte/tests/unit/useCopyAction.test.ts @@ -1,5 +1,5 @@ /// -import { useCopyAction } from '../../src/composables/internal/useCopyAction.svelte'; +import { useCopyAction } from '@src/composables/internal/useCopyAction.svelte'; import { testUseCopyAction, type SetupOptions } from '@common/tests/unit/useCopyAction'; import { tools, withSetup, createState } from './setup/tools.svelte'; diff --git a/packages/phone-mask-svelte/tests/unit/usePhoneMask.test.ts b/packages/phone-mask-svelte/tests/unit/usePhoneMask.test.ts index 54c9cd3b..d4f46294 100644 --- a/packages/phone-mask-svelte/tests/unit/usePhoneMask.test.ts +++ b/packages/phone-mask-svelte/tests/unit/usePhoneMask.test.ts @@ -1,5 +1,5 @@ /// -import { usePhoneMask } from '../../src/composables/usePhoneMask.svelte'; +import { usePhoneMask } from '@src/composables/usePhoneMask.svelte'; import { testUsePhoneMask, type UsePhoneMaskSetupOptions } from '@common/tests/unit/usePhoneMask'; import { createState, tools, withSetup } from './setup/tools.svelte'; diff --git a/packages/phone-mask-vue/tests/e2e/PhoneInput.spec.ts b/packages/phone-mask-vue/tests/e2e/PhoneInput.spec.ts index cff6821f..0bc27329 100644 --- a/packages/phone-mask-vue/tests/e2e/PhoneInput.spec.ts +++ b/packages/phone-mask-vue/tests/e2e/PhoneInput.spec.ts @@ -1,4 +1,4 @@ -import { testPhoneInput } from '../../../../common/tests/e2e/PhoneInput'; +import { testPhoneInput } from '@common/tests/e2e/PhoneInput'; const PLAYGROUND_SELECTOR = '[data-testid="playground"]'; diff --git a/packages/phone-mask-vue/tests/e2e/UsePhoneMask.spec.ts b/packages/phone-mask-vue/tests/e2e/UsePhoneMask.spec.ts index bd118897..6cccab00 100644 --- a/packages/phone-mask-vue/tests/e2e/UsePhoneMask.spec.ts +++ b/packages/phone-mask-vue/tests/e2e/UsePhoneMask.spec.ts @@ -1,4 +1,4 @@ -import { testUsePhoneMask } from '../../../../common/tests/e2e/UsePhoneMask'; +import { testUsePhoneMask } from '@common/tests/e2e/UsePhoneMask'; const HOOK_SELECTOR = '[data-testid="hook"]'; diff --git a/packages/phone-mask-vue/tests/unit/PhoneInput.test.ts b/packages/phone-mask-vue/tests/unit/PhoneInput.test.ts index ce44ef25..73ea80d2 100644 --- a/packages/phone-mask-vue/tests/unit/PhoneInput.test.ts +++ b/packages/phone-mask-vue/tests/unit/PhoneInput.test.ts @@ -1,8 +1,8 @@ /// import { defineComponent, shallowRef, h } from 'vue'; import { render } from '@testing-library/vue'; -import { PhoneInput } from '../../src/index'; -import type { PhoneInputExposed } from '../../src/types'; +import { PhoneInput } from '@src/index'; +import type { PhoneInputExposed } from '@src/types'; import { testPhoneInput } from '@common/tests/unit/PhoneInput'; import { tools } from './setup/tools'; import type { SetupFn } from '@common/tests/unit/PhoneInput'; diff --git a/packages/phone-mask-vue/tests/unit/index.test.ts b/packages/phone-mask-vue/tests/unit/index.test.ts index cc6542b1..0edba58c 100644 --- a/packages/phone-mask-vue/tests/unit/index.test.ts +++ b/packages/phone-mask-vue/tests/unit/index.test.ts @@ -1,7 +1,7 @@ /// import { testIndexImports } from '@common/tests/unit/index'; -import * as indexModule from '../../src/index'; -import * as coreModule from '../../src/core'; +import * as indexModule from '@src/index'; +import * as coreModule from '@src/core'; const { default: defaultExport, install } = indexModule; diff --git a/packages/phone-mask-vue/tests/unit/usePhoneMask.test.ts b/packages/phone-mask-vue/tests/unit/usePhoneMask.test.ts index 99c3bf13..e74ab52a 100644 --- a/packages/phone-mask-vue/tests/unit/usePhoneMask.test.ts +++ b/packages/phone-mask-vue/tests/unit/usePhoneMask.test.ts @@ -1,7 +1,7 @@ /// import { defineComponent, h, nextTick, ref } from 'vue'; import { render } from '@testing-library/vue'; -import { usePhoneMask } from '../../src/composables/usePhoneMask'; +import { usePhoneMask } from '@src/composables/usePhoneMask'; import { testUsePhoneMask, type UsePhoneMaskSetupOptions } from '@common/tests/unit/usePhoneMask'; import { tools, withSetup } from './setup/tools'; diff --git a/packages/phone-mask/tests/tsconfig.json b/packages/phone-mask/tests/tsconfig.json index 8902769b..dad8c982 100644 --- a/packages/phone-mask/tests/tsconfig.json +++ b/packages/phone-mask/tests/tsconfig.json @@ -3,7 +3,11 @@ "compilerOptions": { "composite": false, "noEmit": true, - "lib": ["ES2020", "DOM", "DOM.Iterable"] + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "paths": { + "@common/*": ["../../../common/*"], + "@src/*": ["../src/*"] + } }, "include": ["./**/*", "../src/**/*"] } diff --git a/packages/phone-mask/tests/unit/country-code-emodji.test.ts b/packages/phone-mask/tests/unit/country-code-emodji.test.ts index 2f26361b..15b63639 100644 --- a/packages/phone-mask/tests/unit/country-code-emodji.test.ts +++ b/packages/phone-mask/tests/unit/country-code-emodji.test.ts @@ -1,6 +1,6 @@ /// import { describe, expect, it, vi } from 'vitest'; -import { countryCodeEmoji } from '../../src/country-code-emodji'; +import { countryCodeEmoji } from '@src/country-code-emodji'; describe('countryCodeEmoji', () => { it('converts a valid country code to a flag emoji', () => { diff --git a/packages/phone-mask/tests/unit/country-selector.test.ts b/packages/phone-mask/tests/unit/country-selector.test.ts index fe14f370..f95f05b6 100644 --- a/packages/phone-mask/tests/unit/country-selector.test.ts +++ b/packages/phone-mask/tests/unit/country-selector.test.ts @@ -5,8 +5,8 @@ import { handleCountrySearchKeydown, positionCountryDropdown, scrollCountryOptionIntoView -} from '../../src/country-selector'; -import { createRect } from '../../../../common/tests/unit/setup/domRect'; +} from '@src/country-selector'; +import { createRect } from '@common/tests/unit/setup/domRect'; describe('country selector DOM helpers', () => { let originalInnerHeight = globalThis.innerHeight; diff --git a/packages/phone-mask/tests/unit/data-min.test.ts b/packages/phone-mask/tests/unit/data-min.test.ts index 60969cae..31b60d8f 100644 --- a/packages/phone-mask/tests/unit/data-min.test.ts +++ b/packages/phone-mask/tests/unit/data-min.test.ts @@ -1,9 +1,9 @@ /// import { describe, expect, it } from 'vitest'; -import dataJson from '../../src/data.json'; -import { countryCodeEmoji } from '../../src/country-code-emodji'; -import { Masks, MasksBase, MasksBaseMap, MasksMap, MasksWithFlag, MasksWithFlagMap } from '../../src/entries'; -import type { CountryKey } from '../../src/data-types'; +import dataJson from '@src/data.json'; +import { countryCodeEmoji } from '@src/country-code-emodji'; +import { Masks, MasksBase, MasksBaseMap, MasksMap, MasksWithFlag, MasksWithFlagMap } from '@src/entries'; +import type { CountryKey } from '@src/data-types'; function splitBaseMask(baseMask: string) { const splitAt = baseMask.indexOf(' '); diff --git a/packages/phone-mask/tests/unit/entries.test.ts b/packages/phone-mask/tests/unit/entries.test.ts index 2971e82d..20c7fe50 100644 --- a/packages/phone-mask/tests/unit/entries.test.ts +++ b/packages/phone-mask/tests/unit/entries.test.ts @@ -1,7 +1,7 @@ /// import { describe, expect, it, vi } from 'vitest'; -import { countryCodeEmoji } from '../../src/country-code-emodji'; -import { MasksFull, MasksFullMap } from '../../src/entries'; +import { countryCodeEmoji } from '@src/country-code-emodji'; +import { MasksFull, MasksFullMap } from '@src/entries'; describe('entries helpers', () => { it('throws for invalid country code inputs', () => { diff --git a/packages/phone-mask/tests/unit/exports.test.ts b/packages/phone-mask/tests/unit/exports.test.ts index 8031cc23..16f1e2d9 100644 --- a/packages/phone-mask/tests/unit/exports.test.ts +++ b/packages/phone-mask/tests/unit/exports.test.ts @@ -1,6 +1,6 @@ /// -import * as root from '../../src'; -import * as kit from '../../src/kit'; +import * as root from '@src/index'; +import * as kit from '@src/kit'; describe('public exports', () => { it('keeps the root entry focused on mask data', () => { diff --git a/packages/phone-mask/tests/unit/formatter.test.ts b/packages/phone-mask/tests/unit/formatter.test.ts index 8072626d..5a61f40d 100644 --- a/packages/phone-mask/tests/unit/formatter.test.ts +++ b/packages/phone-mask/tests/unit/formatter.test.ts @@ -1,7 +1,7 @@ /// import { describe, expect, it } from 'vitest'; -import { createPhoneFormatter } from '../../src/formatter'; -import type { MaskFull } from '../../src/entries'; +import { createPhoneFormatter } from '@src/formatter'; +import type { MaskFull } from '@src/entries'; const countryWithMultipleMasks: MaskFull = { id: 'AC', diff --git a/packages/phone-mask/tests/unit/geoip.test.ts b/packages/phone-mask/tests/unit/geoip.test.ts index 81ace507..af65d914 100644 --- a/packages/phone-mask/tests/unit/geoip.test.ts +++ b/packages/phone-mask/tests/unit/geoip.test.ts @@ -1,7 +1,7 @@ /// import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { CACHE_EXPIRY_MS, CACHE_KEY } from '../../src/services/geoip/consts'; -import { detectByGeoIp, detectCountryFromGeoIP } from '../../src/services/geoip'; +import { CACHE_EXPIRY_MS, CACHE_KEY } from '@src/services/geoip/consts'; +import { detectByGeoIp, detectCountryFromGeoIP } from '@src/services/geoip'; function createMockStorage() { const store = new Map(); diff --git a/packages/phone-mask/tests/unit/handlers.test.ts b/packages/phone-mask/tests/unit/handlers.test.ts index f093f7c4..c3be4040 100644 --- a/packages/phone-mask/tests/unit/handlers.test.ts +++ b/packages/phone-mask/tests/unit/handlers.test.ts @@ -8,9 +8,9 @@ import { processInput, processKeydown, processPaste -} from '../../src/handlers'; -import { createPhoneFormatter } from '../../src/formatter'; -import type { CountryKey } from '../../src/entries'; +} from '@src/handlers'; +import { createPhoneFormatter } from '@src/formatter'; +import type { CountryKey } from '@src/entries'; const createFormatter = () => createPhoneFormatter({ diff --git a/packages/phone-mask/tests/unit/utils.test.ts b/packages/phone-mask/tests/unit/utils.test.ts index cb2e496b..1f5dc918 100644 --- a/packages/phone-mask/tests/unit/utils.test.ts +++ b/packages/phone-mask/tests/unit/utils.test.ts @@ -1,6 +1,6 @@ /// import { beforeEach, describe, expect, it } from 'vitest'; -import { countryCodeEmoji } from '../../src/country-code-emodji'; +import { countryCodeEmoji } from '@src/country-code-emodji'; import { getCountry, parseCountryCode, @@ -12,9 +12,9 @@ import { hasCountry, pickMaskVariant, removeCountryCodePrefix -} from '../../src/utils'; -import { getFlagEmoji } from '../../src/entries'; -import type { MaskFull } from '../../src/entries'; +} from '@src/utils'; +import { getFlagEmoji } from '@src/entries'; +import type { MaskFull } from '@src/entries'; const sampleCountries: MaskFull[] = [ { diff --git a/packages/phone-mask/vitest.config.ts b/packages/phone-mask/vitest.config.ts index aadca86b..b9aeace6 100644 --- a/packages/phone-mask/vitest.config.ts +++ b/packages/phone-mask/vitest.config.ts @@ -1,6 +1,13 @@ import { defineConfig } from 'vitest/config'; +import { fileURLToPath } from 'node:url'; export default defineConfig({ + resolve: { + alias: { + '@common': fileURLToPath(new URL('../../common', import.meta.url)), + '@src': fileURLToPath(new URL('./src', import.meta.url)) + } + }, test: { environment: 'jsdom', globals: true, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cd56a3ce..2469ac55 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -36,6 +36,9 @@ importers: '@vitest/coverage-v8': specifier: ^4.1.5 version: 4.1.5(vitest@4.1.5) + angular-eslint: + specifier: ^21.3.1 + version: 21.3.1(@angular/cli@21.2.10(@types/node@25.6.2)(chokidar@5.0.0))(chokidar@5.0.0)(eslint@9.39.4(jiti@2.6.1))(typescript-eslint@8.59.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(typescript@5.9.3) eslint: specifier: ^9.39.4 version: 9.39.4(jiti@2.6.1) @@ -125,6 +128,50 @@ importers: specifier: ^1.0.0 version: 1.0.0(rollup@4.60.3) + packages/phone-mask-angular: + dependencies: + '@desource/phone-mask': + specifier: workspace:* + version: link:../phone-mask + tslib: + specifier: ^2.8.1 + version: 2.8.1 + devDependencies: + '@angular/build': + specifier: ^21.2.10 + version: 21.2.10(@angular/compiler-cli@21.2.12(@angular/compiler@21.2.12)(typescript@5.9.3))(@angular/compiler@21.2.12)(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(@angular/platform-browser@21.2.12(@angular/common@21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2))(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2)))(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.6.2)(chokidar@5.0.0)(jiti@2.6.1)(less@4.6.4)(ng-packagr@21.2.3(@angular/compiler-cli@21.2.12(@angular/compiler@21.2.12)(typescript@5.9.3))(tslib@2.8.1)(typescript@5.9.3))(postcss@8.5.14)(terser@5.46.0)(tslib@2.8.1)(typescript@5.9.3)(vitest@4.1.5)(yaml@2.8.4) + '@angular/cli': + specifier: ^21.2.10 + version: 21.2.10(@types/node@25.6.2)(chokidar@5.0.0) + '@angular/common': + specifier: ^21.2.12 + version: 21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2) + '@angular/compiler': + specifier: ^21.2.12 + version: 21.2.12 + '@angular/compiler-cli': + specifier: ^21.2.12 + version: 21.2.12(@angular/compiler@21.2.12)(typescript@5.9.3) + '@angular/core': + specifier: ^21.2.12 + version: 21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2) + '@angular/forms': + specifier: ^21.2.12 + version: 21.2.12(@angular/common@21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2))(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(@angular/platform-browser@21.2.12(@angular/common@21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2))(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2)))(rxjs@7.8.2) + '@angular/platform-browser': + specifier: ^21.2.12 + version: 21.2.12(@angular/common@21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2))(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2)) + '@testing-library/angular': + specifier: ^19.2.1 + version: 19.2.1(@angular/common@21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2))(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(@angular/platform-browser@21.2.12(@angular/common@21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2))(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2)))(@angular/router@21.2.12(@angular/common@21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2))(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(@angular/platform-browser@21.2.12(@angular/common@21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2))(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2)))(rxjs@7.8.2))(@testing-library/dom@10.4.1) + ng-packagr: + specifier: ^21.2.3 + version: 21.2.3(@angular/compiler-cli@21.2.12(@angular/compiler@21.2.12)(typescript@5.9.3))(tslib@2.8.1)(typescript@5.9.3) + sass: + specifier: ^1.99.0 + version: 1.99.0 + publishDirectory: dist + packages/phone-mask-nuxt: dependencies: '@desource/phone-mask-vue': @@ -212,6 +259,243 @@ importers: packages: + '@algolia/abtesting@1.14.1': + resolution: {integrity: sha512-Dkj0BgPiLAaim9sbQ97UKDFHJE/880wgStAM18U++NaJ/2Cws34J5731ovJifr6E3Pv4T2CqvMXf8qLCC417Ew==} + engines: {node: '>= 14.0.0'} + + '@algolia/client-abtesting@5.48.1': + resolution: {integrity: sha512-LV5qCJdj+/m9I+Aj91o+glYszrzd7CX6NgKaYdTOj4+tUYfbS62pwYgUfZprYNayhkQpVFcrW8x8ZlIHpS23Vw==} + engines: {node: '>= 14.0.0'} + + '@algolia/client-analytics@5.48.1': + resolution: {integrity: sha512-/AVoMqHhPm14CcHq7mwB+bUJbfCv+jrxlNvRjXAuO+TQa+V37N8k1b0ijaRBPdmSjULMd8KtJbQyUyabXOu6Kg==} + engines: {node: '>= 14.0.0'} + + '@algolia/client-common@5.48.1': + resolution: {integrity: sha512-VXO+qu2Ep6ota28ktvBm3sG53wUHS2n7bgLWmce5jTskdlCD0/JrV4tnBm1l7qpla1CeoQb8D7ShFhad+UoSOw==} + engines: {node: '>= 14.0.0'} + + '@algolia/client-insights@5.48.1': + resolution: {integrity: sha512-zl+Qyb0nLg+Y5YvKp1Ij+u9OaPaKg2/EPzTwKNiVyOHnQJlFxmXyUZL1EInczAZsEY8hVpPCLtNfhMhfxluXKQ==} + engines: {node: '>= 14.0.0'} + + '@algolia/client-personalization@5.48.1': + resolution: {integrity: sha512-r89Qf9Oo9mKWQXumRu/1LtvVJAmEDpn8mHZMc485pRfQUMAwSSrsnaw1tQ3sszqzEgAr1c7rw6fjBI+zrAXTOw==} + engines: {node: '>= 14.0.0'} + + '@algolia/client-query-suggestions@5.48.1': + resolution: {integrity: sha512-TPKNPKfghKG/bMSc7mQYD9HxHRUkBZA4q1PEmHgICaSeHQscGqL4wBrKkhfPlDV1uYBKW02pbFMUhsOt7p4ZpA==} + engines: {node: '>= 14.0.0'} + + '@algolia/client-search@5.48.1': + resolution: {integrity: sha512-4Fu7dnzQyQmMFknYwTiN/HxPbH4DyxvQ1m+IxpPp5oslOgz8m6PG5qhiGbqJzH4HiT1I58ecDiCAC716UyVA8Q==} + engines: {node: '>= 14.0.0'} + + '@algolia/ingestion@1.48.1': + resolution: {integrity: sha512-/RFq3TqtXDUUawwic/A9xylA2P3LDMO8dNhphHAUOU51b1ZLHrmZ6YYJm3df1APz7xLY1aht6okCQf+/vmrV9w==} + engines: {node: '>= 14.0.0'} + + '@algolia/monitoring@1.48.1': + resolution: {integrity: sha512-Of0jTeAZRyRhC7XzDSjJef0aBkgRcvRAaw0ooYRlOw57APii7lZdq+layuNdeL72BRq1snaJhoMMwkmLIpJScw==} + engines: {node: '>= 14.0.0'} + + '@algolia/recommend@5.48.1': + resolution: {integrity: sha512-bE7JcpFXzxF5zHwj/vkl2eiCBvyR1zQ7aoUdO+GDXxGp0DGw7nI0p8Xj6u8VmRQ+RDuPcICFQcCwRIJT5tDJFw==} + engines: {node: '>= 14.0.0'} + + '@algolia/requester-browser-xhr@5.48.1': + resolution: {integrity: sha512-MK3wZ2koLDnvH/AmqIF1EKbJlhRS5j74OZGkLpxI4rYvNi9Jn/C7vb5DytBnQ4KUWts7QsmbdwHkxY5txQHXVw==} + engines: {node: '>= 14.0.0'} + + '@algolia/requester-fetch@5.48.1': + resolution: {integrity: sha512-2oDT43Y5HWRSIQMPQI4tA/W+TN/N2tjggZCUsqQV440kxzzoPGsvv9QP1GhQ4CoDa+yn6ygUsGp6Dr+a9sPPSg==} + engines: {node: '>= 14.0.0'} + + '@algolia/requester-node-http@5.48.1': + resolution: {integrity: sha512-xcaCqbhupVWhuBP1nwbk1XNvwrGljozutEiLx06mvqDf3o8cHyEgQSHS4fKJM+UAggaWVnnFW+Nne5aQ8SUJXg==} + engines: {node: '>= 14.0.0'} + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@angular-devkit/architect@0.2102.10': + resolution: {integrity: sha512-deiDH9ug1//eAM6IcyFT5T3eDDAudZex7F1K6lJkVUsjic/DwLU/KabvqF/i+PM05YmxMwLZsGNN0oj0qCxP8A==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + hasBin: true + + '@angular-devkit/core@21.2.10': + resolution: {integrity: sha512-LMpwxn2PsIdFEZCJJpaym7B2MSuMvo2BUfEl+EZwJT7Zk4RdIMP9eTFOP7JTz9Mis+ODQWO4ei0nqGDE/UanQg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + peerDependencies: + chokidar: ^5.0.0 + peerDependenciesMeta: + chokidar: + optional: true + + '@angular-devkit/schematics@21.2.10': + resolution: {integrity: sha512-ydmYDqbX7c2yZl25MDzeKKH+Sy9x3qq5AdWhXJh2SsqbQWp88DgrYNV315nznZONukLkg7eSNyWbweuBcIHmKA==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + + '@angular-eslint/builder@21.3.1': + resolution: {integrity: sha512-1f1Lyp5e7OH6txiV224HaY3G1uRCj91OSKq7hT2Vw9NRw6zWFc1anBpDeLVjpL9ptUxzUGIQR5jEV54hOPayoQ==} + peerDependencies: + '@angular/cli': '>= 21.0.0 < 22.0.0' + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '*' + + '@angular-eslint/bundled-angular-compiler@21.3.1': + resolution: {integrity: sha512-jjbnJPUXQeQBJ8RM+ahlbt4GH2emVN8JvG3AhFbPci1FrqXi9cOOfkbwLmvpoyTli4LF8gy7g4ctFqnlRgqryw==} + + '@angular-eslint/eslint-plugin-template@21.3.1': + resolution: {integrity: sha512-ndPWJodkcEOu2PVUxlUwyz4D2u3r9KO7veWmStVNOLeNrICJA+nQvrz2BWCu0l48rO0K5ezsy0JFcQDVwE/5mw==} + peerDependencies: + '@angular-eslint/template-parser': 21.3.1 + '@typescript-eslint/types': ^7.11.0 || ^8.0.0 + '@typescript-eslint/utils': ^7.11.0 || ^8.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '*' + + '@angular-eslint/eslint-plugin@21.3.1': + resolution: {integrity: sha512-08NNTxwawRLTWPLl8dg1BnXMwimx93y4wMEwx2aWQpJbIt4pmNvwJzd+NgoD/Ag2VdLS/gOMadhJH5fgaYKsPQ==} + peerDependencies: + '@typescript-eslint/utils': ^7.11.0 || ^8.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '*' + + '@angular-eslint/schematics@21.3.1': + resolution: {integrity: sha512-1U2u4ZsZvwT30aXRLsIJf6tULIiioo9BtASNsldpYecU3/m/1+F61lCYG79qt7YWbif9KABPYZlFTJUFGN8HWA==} + peerDependencies: + '@angular/cli': '>= 21.0.0 < 22.0.0' + + '@angular-eslint/template-parser@21.3.1': + resolution: {integrity: sha512-moERVCTekQKOvR8RMuEOtWSO3VS1qrzA3keI1dPto/JVB8Nqp9w3R5ZpEoXHzh4zgEryosxmPgdi6UczJe2ouQ==} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '*' + + '@angular-eslint/utils@21.3.1': + resolution: {integrity: sha512-Q3SGA1/36phZhmsp1mYrKzp/jcmqofRr861MYn46FaWIKSYXBYRzl+H3FIJKBu5CE36Bggu6hbNpwGPuUp+MCg==} + peerDependencies: + '@typescript-eslint/utils': ^7.11.0 || ^8.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '*' + + '@angular/build@21.2.10': + resolution: {integrity: sha512-jnFN56y9tyqsZbbDueEzITYAfug7bSF9KcOi9fhPppbmTdjSN5xrXXltDSqwgRdvGtcctZ55NunT7sGF7+ubXQ==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + peerDependencies: + '@angular/compiler': ^21.0.0 + '@angular/compiler-cli': ^21.0.0 + '@angular/core': ^21.0.0 + '@angular/localize': ^21.0.0 + '@angular/platform-browser': ^21.0.0 + '@angular/platform-server': ^21.0.0 + '@angular/service-worker': ^21.0.0 + '@angular/ssr': ^21.2.10 + karma: ^6.4.0 + less: ^4.2.0 + ng-packagr: ^21.0.0 + postcss: ^8.4.0 + tailwindcss: ^2.0.0 || ^3.0.0 || ^4.0.0 + tslib: ^2.3.0 + typescript: '>=5.9 <6.0' + vitest: ^4.0.8 + peerDependenciesMeta: + '@angular/core': + optional: true + '@angular/localize': + optional: true + '@angular/platform-browser': + optional: true + '@angular/platform-server': + optional: true + '@angular/service-worker': + optional: true + '@angular/ssr': + optional: true + karma: + optional: true + less: + optional: true + ng-packagr: + optional: true + postcss: + optional: true + tailwindcss: + optional: true + vitest: + optional: true + + '@angular/cli@21.2.10': + resolution: {integrity: sha512-ezf9LM0GgexG2l8ae/uN4fUyxGqeFEH9iu30mUMU5dwow76aK+b4Abuf5eSuR0F8zTLEA3ZUEYywI+gajbAUuA==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + hasBin: true + + '@angular/common@21.2.12': + resolution: {integrity: sha512-b7IRSM9fWPmZ1SLN0utVcW87IkhiRte3Wsnwr2nEsjum2soRMfvKqHwtEFGfCztlwOmZLgKiGW9pqKpzBkIjnQ==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@angular/core': 21.2.12 + rxjs: ^6.5.3 || ^7.4.0 + + '@angular/compiler-cli@21.2.12': + resolution: {integrity: sha512-YQ15Yp2OWBS1NnzZH77HLH1ZDn+/A5Mc1EobKl4CX8dYUEPIB/KwmGKLaKtbJ0KNcVsDlmsTTWodRgqe2n5erw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@angular/compiler': 21.2.12 + typescript: '>=5.9 <6.1' + peerDependenciesMeta: + typescript: + optional: true + + '@angular/compiler@21.2.12': + resolution: {integrity: sha512-246iBwMAVGzrYPqu/Wwzb9L/kt+dkT12Hllr/dYZu6aHeIxaHPRZoPBKSweAgOPXeOl+q+nlPtK34glsMb1CRw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + '@angular/core@21.2.12': + resolution: {integrity: sha512-wcD6tzE30nwg58KmAU19347Jf/1F/vFg2CEd9Qcu5cA1Z4s3umzvaqs/7988ne4HaS4iJEpvTbRvGss7EYZEfA==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@angular/compiler': 21.2.12 + rxjs: ^6.5.3 || ^7.4.0 + zone.js: ~0.15.0 || ~0.16.0 + peerDependenciesMeta: + '@angular/compiler': + optional: true + zone.js: + optional: true + + '@angular/forms@21.2.12': + resolution: {integrity: sha512-jhHaIgMWcgPcVFEPwhjLhByvA2xou6Th5PR6iC3H0YeLQyRmOFPWdczszytlWB1CeJ0UT9epxzOZT25zNcGSfg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@angular/common': 21.2.12 + '@angular/core': 21.2.12 + '@angular/platform-browser': 21.2.12 + rxjs: ^6.5.3 || ^7.4.0 + + '@angular/platform-browser@21.2.12': + resolution: {integrity: sha512-P4MVColcYgBPmHyQ9nPVw9NjWPNxkC++N2Bjh3kOUFflC/6D/ufYJytsI/y1WQ8dtoHPHxiuRf3xHvcwUMPgEQ==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@angular/animations': 21.2.12 + '@angular/common': 21.2.12 + '@angular/core': 21.2.12 + peerDependenciesMeta: + '@angular/animations': + optional: true + + '@angular/router@21.2.12': + resolution: {integrity: sha512-2/RDHt3GdW2ABNRVrgLX7IxgJLdF7u8Sbh11kAUn04QhNI/GObxIV4M5Hm/NTeDoi+hCXavkaHVBlj/dG5ANbw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@angular/common': 21.2.12 + '@angular/core': 21.2.12 + '@angular/platform-browser': 21.2.12 + rxjs: ^6.5.3 || ^7.4.0 + '@asamuzakjp/css-color@5.1.11': resolution: {integrity: sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} @@ -293,6 +577,10 @@ packages: resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} engines: {node: '>=6.9.0'} + '@babel/helper-split-export-declaration@7.24.7': + resolution: {integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==} + engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.27.1': resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} @@ -507,6 +795,18 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.27.3': + resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/aix-ppc64@0.28.0': resolution: {integrity: sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==} engines: {node: '>=18'} @@ -519,6 +819,18 @@ packages: cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.27.3': + resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm64@0.28.0': resolution: {integrity: sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==} engines: {node: '>=18'} @@ -531,6 +843,18 @@ packages: cpu: [arm] os: [android] + '@esbuild/android-arm@0.27.3': + resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-arm@0.28.0': resolution: {integrity: sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==} engines: {node: '>=18'} @@ -543,6 +867,18 @@ packages: cpu: [x64] os: [android] + '@esbuild/android-x64@0.27.3': + resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/android-x64@0.28.0': resolution: {integrity: sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==} engines: {node: '>=18'} @@ -555,6 +891,18 @@ packages: cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.27.3': + resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-arm64@0.28.0': resolution: {integrity: sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==} engines: {node: '>=18'} @@ -567,6 +915,18 @@ packages: cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.27.3': + resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/darwin-x64@0.28.0': resolution: {integrity: sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==} engines: {node: '>=18'} @@ -579,6 +939,18 @@ packages: cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.27.3': + resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-arm64@0.28.0': resolution: {integrity: sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==} engines: {node: '>=18'} @@ -591,6 +963,18 @@ packages: cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.27.3': + resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/freebsd-x64@0.28.0': resolution: {integrity: sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==} engines: {node: '>=18'} @@ -603,6 +987,18 @@ packages: cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.27.3': + resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm64@0.28.0': resolution: {integrity: sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==} engines: {node: '>=18'} @@ -615,6 +1011,18 @@ packages: cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.27.3': + resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-arm@0.28.0': resolution: {integrity: sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==} engines: {node: '>=18'} @@ -627,6 +1035,18 @@ packages: cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.27.3': + resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-ia32@0.28.0': resolution: {integrity: sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==} engines: {node: '>=18'} @@ -639,6 +1059,18 @@ packages: cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.27.3': + resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-loong64@0.28.0': resolution: {integrity: sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==} engines: {node: '>=18'} @@ -651,6 +1083,18 @@ packages: cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.27.3': + resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-mips64el@0.28.0': resolution: {integrity: sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==} engines: {node: '>=18'} @@ -663,6 +1107,18 @@ packages: cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.27.3': + resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-ppc64@0.28.0': resolution: {integrity: sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==} engines: {node: '>=18'} @@ -675,6 +1131,18 @@ packages: cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.27.3': + resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-riscv64@0.28.0': resolution: {integrity: sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==} engines: {node: '>=18'} @@ -687,6 +1155,18 @@ packages: cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.27.3': + resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-s390x@0.28.0': resolution: {integrity: sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==} engines: {node: '>=18'} @@ -699,6 +1179,18 @@ packages: cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.27.3': + resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/linux-x64@0.28.0': resolution: {integrity: sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==} engines: {node: '>=18'} @@ -711,6 +1203,18 @@ packages: cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-arm64@0.27.3': + resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-arm64@0.28.0': resolution: {integrity: sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==} engines: {node: '>=18'} @@ -723,18 +1227,42 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.28.0': - resolution: {integrity: sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==} + '@esbuild/netbsd-x64@0.27.3': + resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.12': - resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.28.0': + resolution: {integrity: sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-arm64@0.27.3': + resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-arm64@0.28.0': resolution: {integrity: sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==} engines: {node: '>=18'} @@ -747,6 +1275,18 @@ packages: cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.27.3': + resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openbsd-x64@0.28.0': resolution: {integrity: sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==} engines: {node: '>=18'} @@ -759,6 +1299,18 @@ packages: cpu: [arm64] os: [openharmony] + '@esbuild/openharmony-arm64@0.27.3': + resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/openharmony-arm64@0.28.0': resolution: {integrity: sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==} engines: {node: '>=18'} @@ -771,6 +1323,18 @@ packages: cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.27.3': + resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/sunos-x64@0.28.0': resolution: {integrity: sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==} engines: {node: '>=18'} @@ -783,6 +1347,18 @@ packages: cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.27.3': + resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-arm64@0.28.0': resolution: {integrity: sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==} engines: {node: '>=18'} @@ -795,6 +1371,18 @@ packages: cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.27.3': + resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-ia32@0.28.0': resolution: {integrity: sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==} engines: {node: '>=18'} @@ -807,6 +1395,18 @@ packages: cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.27.3': + resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@esbuild/win32-x64@0.28.0': resolution: {integrity: sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==} engines: {node: '>=18'} @@ -883,6 +1483,19 @@ packages: '@fastify/accept-negotiator@2.0.1': resolution: {integrity: sha512-/c/TW2bO/v9JeEgoD/g1G5GxGeCF1Hafdf79WPmUlgYiBXummY0oX3VVq4yFkKKVBKDNlaDUYoab7g38RpPqCQ==} + '@gar/promise-retry@1.0.3': + resolution: {integrity: sha512-GmzA9ckNokPypTg10pgpeHNQe7ph+iIKKmhKu3Ob9ANkswreCx7R3cKmY781K8QK3AqVL3xVh9A42JvIAbkkSA==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@harperfast/extended-iterable@1.0.3': + resolution: {integrity: sha512-sSAYhQca3rDWtQUHSAPeO7axFIUJOI6hn1gjRC5APVE1a90tuyT8f5WIgRsFhhWA7htNkju2veB9eWL6YHi/Lw==} + + '@hono/node-server@1.19.14': + resolution: {integrity: sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -895,218 +1508,542 @@ packages: resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} - '@humanwhocodes/retry@0.4.3': - resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} - engines: {node: '>=18.18'} + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@inquirer/ansi@1.0.2': + resolution: {integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==} + engines: {node: '>=18'} + + '@inquirer/checkbox@4.3.2': + resolution: {integrity: sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/confirm@5.1.21': + resolution: {integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/core@10.3.2': + resolution: {integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/editor@4.2.23': + resolution: {integrity: sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/expand@4.0.23': + resolution: {integrity: sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/external-editor@1.0.3': + resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/figures@1.0.15': + resolution: {integrity: sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==} + engines: {node: '>=18'} + + '@inquirer/input@4.3.1': + resolution: {integrity: sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/number@3.0.23': + resolution: {integrity: sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/password@4.0.23': + resolution: {integrity: sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/prompts@7.10.1': + resolution: {integrity: sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/rawlist@4.1.11': + resolution: {integrity: sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/search@3.2.2': + resolution: {integrity: sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/select@4.4.2': + resolution: {integrity: sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/type@3.0.10': + resolution: {integrity: sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@ioredis/commands@1.5.1': + resolution: {integrity: sha512-JH8ZL/ywcJyR9MmJ5BNqZllXNZQqQbnVZOqpPQqE1vHiFgAw4NHbvE0FOduNU8IX9babitBT46571OnPTT0Zcw==} + + '@isaacs/cliui@9.0.0': + resolution: {integrity: sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==} + engines: {node: '>=18'} + + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + + '@istanbuljs/schema@0.1.6': + resolution: {integrity: sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==} + engines: {node: '>=8'} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@kwsites/file-exists@1.1.1': + resolution: {integrity: sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==} + + '@kwsites/promise-deferred@1.1.1': + resolution: {integrity: sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==} - '@img/colour@1.0.0': - resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} - engines: {node: '>=18'} + '@listr2/prompt-adapter-inquirer@3.0.5': + resolution: {integrity: sha512-WELs+hj6xcilkloBXYf9XXK8tYEnKsgLj01Xl5ONUJpKjmT5hGVUzNUS5tooUxs7pGMrw+jFD/41WpqW4V3LDA==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@inquirer/prompts': '>= 3 < 8' + listr2: 9.0.5 - '@img/sharp-darwin-arm64@0.34.5': - resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@lmdb/lmdb-darwin-arm64@3.5.1': + resolution: {integrity: sha512-tpfN4kKrrMpQ+If1l8bhmoNkECJi0iOu6AEdrTJvWVC+32sLxTARX5Rsu579mPImRP9YFWfWgeRQ5oav7zApQQ==} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.34.5': - resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@lmdb/lmdb-darwin-x64@3.5.1': + resolution: {integrity: sha512-+a2tTfc3rmWhLAolFUWRgJtpSuu+Fw/yjn4rF406NMxhfjbMuiOUTDRvRlMFV+DzyjkwnokisskHbCWkS3Ly5w==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.2.4': - resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + '@lmdb/lmdb-linux-arm64@3.5.1': + resolution: {integrity: sha512-aoERa5B6ywXdyFeYGQ1gbQpkMkDbEo45qVoXE5QpIRavqjnyPwjOulMkmkypkmsbJ5z4Wi0TBztON8agCTG0Vg==} + cpu: [arm64] + os: [linux] + + '@lmdb/lmdb-linux-arm@3.5.1': + resolution: {integrity: sha512-0EgcE6reYr8InjD7V37EgXcYrloqpxVPINy3ig1MwDSbl6LF/vXTYRH9OE1Ti1D8YZnB35ZH9aTcdfSb5lql2A==} + cpu: [arm] + os: [linux] + + '@lmdb/lmdb-linux-x64@3.5.1': + resolution: {integrity: sha512-SqNDY1+vpji7bh0sFH5wlWyFTOzjbDOl0/kB5RLLYDAFyd/uw3n7wyrmas3rYPpAW7z18lMOi1yKlTPv967E3g==} + cpu: [x64] + os: [linux] + + '@lmdb/lmdb-win32-arm64@3.5.1': + resolution: {integrity: sha512-50v0O1Lt37cwrmR9vWZK5hRW0Aw+KEmxJJ75fge/zIYdvNKB/0bSMSVR5Uc2OV9JhosIUyklOmrEvavwNJ8D6w==} + cpu: [arm64] + os: [win32] + + '@lmdb/lmdb-win32-x64@3.5.1': + resolution: {integrity: sha512-qwosvPyl+zpUlp3gRb7UcJ3H8S28XHCzkv0Y0EgQToXjQP91ZD67EHSCDmaLjtKhe+GVIW5om1KUpzVLA0l6pg==} + cpu: [x64] + os: [win32] + + '@manypkg/find-root@1.1.0': + resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} + + '@manypkg/get-packages@1.1.3': + resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} + + '@mapbox/node-pre-gyp@2.0.3': + resolution: {integrity: sha512-uwPAhccfFJlsfCxMYTwOdVfOz3xqyj8xYL3zJj8f0pb30tLohnnFPhLuqp4/qoEz8sNxe4SESZedcBojRefIzg==} + engines: {node: '>=18'} + hasBin: true + + '@modelcontextprotocol/sdk@1.26.0': + resolution: {integrity: sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==} + engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true + + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': + resolution: {integrity: sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.2.4': - resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3': + resolution: {integrity: sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.2.4': - resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3': + resolution: {integrity: sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==} cpu: [arm64] os: [linux] - libc: [glibc] - '@img/sharp-libvips-linux-arm@1.2.4': - resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3': + resolution: {integrity: sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==} cpu: [arm] os: [linux] - libc: [glibc] - '@img/sharp-libvips-linux-ppc64@1.2.4': - resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} - cpu: [ppc64] + '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3': + resolution: {integrity: sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==} + cpu: [x64] os: [linux] - libc: [glibc] - '@img/sharp-libvips-linux-riscv64@1.2.4': - resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} - cpu: [riscv64] - os: [linux] - libc: [glibc] + '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3': + resolution: {integrity: sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==} + cpu: [x64] + os: [win32] - '@img/sharp-libvips-linux-s390x@1.2.4': - resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} - cpu: [s390x] - os: [linux] - libc: [glibc] + '@napi-rs/nice-android-arm-eabi@1.1.1': + resolution: {integrity: sha512-kjirL3N6TnRPv5iuHw36wnucNqXAO46dzK9oPb0wj076R5Xm8PfUVA9nAFB5ZNMmfJQJVKACAPd/Z2KYMppthw==} + engines: {node: '>= 10'} + cpu: [arm] + os: [android] - '@img/sharp-libvips-linux-x64@1.2.4': - resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} - cpu: [x64] - os: [linux] - libc: [glibc] + '@napi-rs/nice-android-arm64@1.1.1': + resolution: {integrity: sha512-blG0i7dXgbInN5urONoUCNf+DUEAavRffrO7fZSeoRMJc5qD+BJeNcpr54msPF6qfDD6kzs9AQJogZvT2KD5nw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': - resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + '@napi-rs/nice-darwin-arm64@1.1.1': + resolution: {integrity: sha512-s/E7w45NaLqTGuOjC2p96pct4jRfo61xb9bU1unM/MJ/RFkKlJyJDx7OJI/O0ll/hrfpqKopuAFDV8yo0hfT7A==} + engines: {node: '>= 10'} cpu: [arm64] - os: [linux] - libc: [musl] + os: [darwin] - '@img/sharp-libvips-linuxmusl-x64@1.2.4': - resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + '@napi-rs/nice-darwin-x64@1.1.1': + resolution: {integrity: sha512-dGoEBnVpsdcC+oHHmW1LRK5eiyzLwdgNQq3BmZIav+9/5WTZwBYX7r5ZkQC07Nxd3KHOCkgbHSh4wPkH1N1LiQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@napi-rs/nice-freebsd-x64@1.1.1': + resolution: {integrity: sha512-kHv4kEHAylMYmlNwcQcDtXjklYp4FCf0b05E+0h6nDHsZ+F0bDe04U/tXNOqrx5CmIAth4vwfkjjUmp4c4JktQ==} + engines: {node: '>= 10'} cpu: [x64] + os: [freebsd] + + '@napi-rs/nice-linux-arm-gnueabihf@1.1.1': + resolution: {integrity: sha512-E1t7K0efyKXZDoZg1LzCOLxgolxV58HCkaEkEvIYQx12ht2pa8hoBo+4OB3qh7e+QiBlp1SRf+voWUZFxyhyqg==} + engines: {node: '>= 10'} + cpu: [arm] os: [linux] - libc: [musl] - '@img/sharp-linux-arm64@0.34.5': - resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@napi-rs/nice-linux-arm64-gnu@1.1.1': + resolution: {integrity: sha512-CIKLA12DTIZlmTaaKhQP88R3Xao+gyJxNWEn04wZwC2wmRapNnxCUZkVwggInMJvtVElA+D4ZzOU5sX4jV+SmQ==} + engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [glibc] - '@img/sharp-linux-arm@0.34.5': - resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm] + '@napi-rs/nice-linux-arm64-musl@1.1.1': + resolution: {integrity: sha512-+2Rzdb3nTIYZ0YJF43qf2twhqOCkiSrHx2Pg6DJaCPYhhaxbLcdlV8hCRMHghQ+EtZQWGNcS2xF4KxBhSGeutg==} + engines: {node: '>= 10'} + cpu: [arm64] os: [linux] - libc: [glibc] + libc: [musl] - '@img/sharp-linux-ppc64@0.34.5': - resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@napi-rs/nice-linux-ppc64-gnu@1.1.1': + resolution: {integrity: sha512-4FS8oc0GeHpwvv4tKciKkw3Y4jKsL7FRhaOeiPei0X9T4Jd619wHNe4xCLmN2EMgZoeGg+Q7GY7BsvwKpL22Tg==} + engines: {node: '>= 10'} cpu: [ppc64] os: [linux] libc: [glibc] - '@img/sharp-linux-riscv64@0.34.5': - resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@napi-rs/nice-linux-riscv64-gnu@1.1.1': + resolution: {integrity: sha512-HU0nw9uD4FO/oGCCk409tCi5IzIZpH2agE6nN4fqpwVlCn5BOq0MS1dXGjXaG17JaAvrlpV5ZeyZwSon10XOXw==} + engines: {node: '>= 10'} cpu: [riscv64] os: [linux] libc: [glibc] - '@img/sharp-linux-s390x@0.34.5': - resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@napi-rs/nice-linux-s390x-gnu@1.1.1': + resolution: {integrity: sha512-2YqKJWWl24EwrX0DzCQgPLKQBxYDdBxOHot1KWEq7aY2uYeX+Uvtv4I8xFVVygJDgf6/92h9N3Y43WPx8+PAgQ==} + engines: {node: '>= 10'} cpu: [s390x] os: [linux] libc: [glibc] - '@img/sharp-linux-x64@0.34.5': - resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@napi-rs/nice-linux-x64-gnu@1.1.1': + resolution: {integrity: sha512-/gaNz3R92t+dcrfCw/96pDopcmec7oCcAQ3l/M+Zxr82KT4DljD37CpgrnXV+pJC263JkW572pdbP3hP+KjcIg==} + engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [glibc] - '@img/sharp-linuxmusl-arm64@0.34.5': - resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@img/sharp-linuxmusl-x64@0.34.5': - resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@napi-rs/nice-linux-x64-musl@1.1.1': + resolution: {integrity: sha512-xScCGnyj/oppsNPMnevsBe3pvNaoK7FGvMjT35riz9YdhB2WtTG47ZlbxtOLpjeO9SqqQ2J2igCmz6IJOD5JYw==} + engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [musl] - '@img/sharp-wasm32@0.34.5': - resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [wasm32] + '@napi-rs/nice-openharmony-arm64@1.1.1': + resolution: {integrity: sha512-6uJPRVwVCLDeoOaNyeiW0gp2kFIM4r7PL2MczdZQHkFi9gVlgm+Vn+V6nTWRcu856mJ2WjYJiumEajfSm7arPQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [openharmony] - '@img/sharp-win32-arm64@0.34.5': - resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@napi-rs/nice-win32-arm64-msvc@1.1.1': + resolution: {integrity: sha512-uoTb4eAvM5B2aj/z8j+Nv8OttPf2m+HVx3UjA5jcFxASvNhQriyCQF1OB1lHL43ZhW+VwZlgvjmP5qF3+59atA==} + engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@img/sharp-win32-ia32@0.34.5': - resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@napi-rs/nice-win32-ia32-msvc@1.1.1': + resolution: {integrity: sha512-CNQqlQT9MwuCsg1Vd/oKXiuH+TcsSPJmlAFc5frFyX/KkOh0UpBLEj7aoY656d5UKZQMQFP7vJNa1DNUNORvug==} + engines: {node: '>= 10'} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.34.5': - resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@napi-rs/nice-win32-x64-msvc@1.1.1': + resolution: {integrity: sha512-vB+4G/jBQCAh0jelMTY3+kgFy00Hlx2f2/1zjMoH821IbplbWZOkLiTYXQkygNTzQJTq5cvwBDgn2ppHD+bglQ==} + engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@inquirer/external-editor@1.0.3': - resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} - engines: {node: '>=18'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@ioredis/commands@1.5.1': - resolution: {integrity: sha512-JH8ZL/ywcJyR9MmJ5BNqZllXNZQqQbnVZOqpPQqE1vHiFgAw4NHbvE0FOduNU8IX9babitBT46571OnPTT0Zcw==} - - '@isaacs/cliui@9.0.0': - resolution: {integrity: sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==} - engines: {node: '>=18'} - - '@isaacs/fs-minipass@4.0.1': - resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} - engines: {node: '>=18.0.0'} - - '@jridgewell/gen-mapping@0.3.13': - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - - '@jridgewell/remapping@2.3.5': - resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} - - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - - '@jridgewell/source-map@0.3.11': - resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} - - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - - '@jridgewell/trace-mapping@0.3.31': - resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - - '@kwsites/file-exists@1.1.1': - resolution: {integrity: sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==} - - '@kwsites/promise-deferred@1.1.1': - resolution: {integrity: sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==} - - '@manypkg/find-root@1.1.0': - resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} - - '@manypkg/get-packages@1.1.3': - resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} - - '@mapbox/node-pre-gyp@2.0.3': - resolution: {integrity: sha512-uwPAhccfFJlsfCxMYTwOdVfOz3xqyj8xYL3zJj8f0pb30tLohnnFPhLuqp4/qoEz8sNxe4SESZedcBojRefIzg==} - engines: {node: '>=18'} - hasBin: true + '@napi-rs/nice@1.1.1': + resolution: {integrity: sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==} + engines: {node: '>= 10'} '@napi-rs/wasm-runtime@1.1.4': resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} @@ -1130,6 +2067,43 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@npmcli/agent@4.0.0': + resolution: {integrity: sha512-kAQTcEN9E8ERLVg5AsGwLNoFb+oEG6engbqAU2P43gD4JEIkNGMHdVQ096FsOAAYpZPB0RSt0zgInKIAS1l5QA==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@npmcli/fs@5.0.0': + resolution: {integrity: sha512-7OsC1gNORBEawOa5+j2pXN9vsicaIOH5cPXxoR6fJOmH6/EXpJB2CajXOu1fPRFun2m1lktEFX11+P89hqO/og==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@npmcli/git@7.0.2': + resolution: {integrity: sha512-oeolHDjExNAJAnlYP2qzNjMX/Xi9bmu78C9dIGr4xjobrSKbuMYCph8lTzn4vnW3NjIqVmw/f8BCfouqyJXlRg==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@npmcli/installed-package-contents@4.0.0': + resolution: {integrity: sha512-yNyAdkBxB72gtZ4GrwXCM0ZUedo9nIbOMKfGjt6Cu6DXf0p8y1PViZAKDC8q8kv/fufx0WTjRBdSlyrvnP7hmA==} + engines: {node: ^20.17.0 || >=22.9.0} + hasBin: true + + '@npmcli/node-gyp@5.0.0': + resolution: {integrity: sha512-uuG5HZFXLfyFKqg8QypsmgLQW7smiRjVc45bqD/ofZZcR/uxEjgQU8qDPv0s9TEeMUiAAU/GC5bR6++UdTirIQ==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@npmcli/package-json@7.0.5': + resolution: {integrity: sha512-iVuTlG3ORq2iaVa1IWUxAO/jIp77tUKBhoMjuzYW2kL4MLN1bi/ofqkZ7D7OOwh8coAx1/S2ge0rMdGv8sLSOQ==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@npmcli/promise-spawn@9.0.1': + resolution: {integrity: sha512-OLUaoqBuyxeTqUvjA3FZFiXUfYC1alp3Sa99gW3EUDz3tZ3CbXDdcZ7qWKBzicrJleIgucoWamWH1saAmH/l2Q==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@npmcli/redact@4.0.0': + resolution: {integrity: sha512-gOBg5YHMfZy+TfHArfVogwgfBeQnKbbGo3pSUyK/gSI0AVu+pEiDVcKlQb0D8Mg1LNRZILZ6XG8I5dJ4KuAd9Q==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@npmcli/run-script@10.0.4': + resolution: {integrity: sha512-mGUWr1uMnf0le2TwfOZY4SFxZGXGfm4Jtay/nwAa2FLNAKXUoUwaGwBMNH36UHPtinWfTSJ3nqFQr0091CxVGg==} + engines: {node: ^20.17.0 || >=22.9.0} + '@nuxt/cli@3.35.1': resolution: {integrity: sha512-nX9XO+e3l9pnhHL2zsbnBmQb/nsOQYhGz2XiqE8X962QN9ufc1ZSuDZoTmQVv/ymkbYNR6hpNWW8RZQhuhzadw==} engines: {node: ^16.14.0 || >=18.0.0} @@ -1537,6 +2511,9 @@ packages: cpu: [x64] os: [win32] + '@oxc-project/types@0.113.0': + resolution: {integrity: sha512-Tp3XmgxwNQ9pEN9vxgJBAqdRamHibi76iowQ38O2I4PMpcvNRQNVsU2n1x1nv9yh0XoTrGFzf7cZSGxmixxrhA==} + '@oxc-project/types@0.128.0': resolution: {integrity: sha512-huv1Y/LzBJkBVHt3OlC7u0zHBW9qXf1FdD7sGmc1rXc2P1mTwHssYv7jyGx5KAACSCH+9B3Bhn6Z9luHRvf7pQ==} @@ -1784,30 +2761,60 @@ packages: cpu: [arm64] os: [android] + '@rolldown/binding-android-arm64@1.0.0-rc.4': + resolution: {integrity: sha512-vRq9f4NzvbdZavhQbjkJBx7rRebDKYR9zHfO/Wg486+I7bSecdUapzCm5cyXoK+LHokTxgSq7A5baAXUZkIz0w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + '@rolldown/binding-darwin-arm64@1.0.0-rc.18': resolution: {integrity: sha512-apJq2ktnGp27nSInMR5Vcj8kY6xJzDAvfdIFlpDcAK/w4cDO58qVoi1YQsES/SKiFNge/6e4CUzgjfHduYqWpQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] + '@rolldown/binding-darwin-arm64@1.0.0-rc.4': + resolution: {integrity: sha512-kFgEvkWLqt3YCgKB5re9RlIrx9bRsvyVUnaTakEpOPuLGzLpLapYxE9BufJNvPg8GjT6mB1alN4yN1NjzoeM8Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + '@rolldown/binding-darwin-x64@1.0.0-rc.18': resolution: {integrity: sha512-5Ofot8xbs+pxRHJqm9/9N/4sTQOvdrwEsmPE9pdLEEoAbdZtG6F2LMDfO1sp6ZAtXJuJV/21ew2srq3W8NXB5g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] + '@rolldown/binding-darwin-x64@1.0.0-rc.4': + resolution: {integrity: sha512-JXmaOJGsL/+rsmMfutcDjxWM2fTaVgCHGoXS7nE8Z3c9NAYjGqHvXrAhMUZvMpHS/k7Mg+X7n/MVKb7NYWKKww==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + '@rolldown/binding-freebsd-x64@1.0.0-rc.18': resolution: {integrity: sha512-7h8eeOTT1eyqJyx64BFCnWZpNm486hGWt2sqeLLgDxA0xI1oGZ9H7gK1S85uNGmBhkdPwa/6reTxfFFKvIsebw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] + '@rolldown/binding-freebsd-x64@1.0.0-rc.4': + resolution: {integrity: sha512-ep3Catd6sPnHTM0P4hNEvIv5arnDvk01PfyJIJ+J3wVCG1eEaPo09tvFqdtcaTrkwQy0VWR24uz+cb4IsK53Qw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.18': resolution: {integrity: sha512-eRcm/HVt9U/JFu5RKAEKwGQYtDCKWLiaH6wOnsSEp6NMBb/3Os8LgHZlNyzMpFVNmiiMFlfb2zEnebfzJrHFmg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.4': + resolution: {integrity: sha512-LwA5ayKIpnsgXJEwWc3h8wPiS33NMIHd9BhsV92T8VetVAbGe2qXlJwNVDGHN5cOQ22R9uYvbrQir2AB+ntT2w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.18': resolution: {integrity: sha512-SOrT/cT4ukTmgnrEz/Hg3m7LBnuCLW9psDeMKrimRWY4I8DmnO7Lco8W2vtqPmMkbVu8iJ+g4GFLVLLOVjJ9DQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1815,6 +2822,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.4': + resolution: {integrity: sha512-AC1WsGdlV1MtGay/OQ4J9T7GRadVnpYRzTcygV1hKnypbYN20Yh4t6O1Sa2qRBMqv1etulUknqXjc3CTIsBu6A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.18': resolution: {integrity: sha512-QWjdxN1HJCpBTAcZ5N5F7wju3gVPzRzSpmGzx7na0c/1qpN9CFil+xt+l9lV/1M6/gqHSNXCiqPfwhVJPeLnug==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1822,6 +2836,13 @@ packages: os: [linux] libc: [musl] + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.4': + resolution: {integrity: sha512-lU+6rgXXViO61B4EudxtVMXSOfiZONR29Sys5VGSetUY7X8mg9FCKIIjcPPj8xNDeYzKl+H8F/qSKOBVFJChCQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.18': resolution: {integrity: sha512-ugCOyj7a4d9h3q9B+wXmf6g3a68UsjGh6dob5DHevHGMwDUbhsYNbSPxJsENcIttJZ9jv7qGM2UesLw5jqIhdg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1843,6 +2864,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.4': + resolution: {integrity: sha512-DZaN1f0PGp/bSvKhtw50pPsnln4T13ycDq1FrDWRiHmWt1JeW+UtYg9touPFf8yt993p8tS2QjybpzKNTxYEwg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-x64-musl@1.0.0-rc.18': resolution: {integrity: sha512-XNOQZtuE6yUIvx4rwGemwh8kpL1xvU41FXy/s9K7T/3JVcqGzo3NfKM2HrbrGgfPYGFW42f07Wk++aOC6B9NWA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1850,35 +2878,68 @@ packages: os: [linux] libc: [musl] + '@rolldown/binding-linux-x64-musl@1.0.0-rc.4': + resolution: {integrity: sha512-RnGxwZLN7fhMMAItnD6dZ7lvy+TI7ba+2V54UF4dhaWa/p8I/ys1E73KO6HmPmgz92ZkfD8TXS1IMV8+uhbR9g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + '@rolldown/binding-openharmony-arm64@1.0.0-rc.18': resolution: {integrity: sha512-tSn/kzrfa7tNOXr7sEacDBN4YsIqTyLqh45IO0nHDwtpKIDNDJr+VFojt+4klSpChxB29JLyduSsE0MKEwa65A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] + '@rolldown/binding-openharmony-arm64@1.0.0-rc.4': + resolution: {integrity: sha512-6lcI79+X8klGiGd8yHuTgQRjuuJYNggmEml+RsyN596P23l/zf9FVmJ7K0KVKkFAeYEdg0iMUKyIxiV5vebDNQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + '@rolldown/binding-wasm32-wasi@1.0.0-rc.18': resolution: {integrity: sha512-+J9YGmc+czgqlhYmwun3S3O0FIZhsH8ep2456xwjAdIOmuJxM7xz4P4PtrxU+Bz17a/5bqPA8o3HAAoX0teUdg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] + '@rolldown/binding-wasm32-wasi@1.0.0-rc.4': + resolution: {integrity: sha512-wz7ohsKCAIWy91blZ/1FlpPdqrsm1xpcEOQVveWoL6+aSPKL4VUcoYmmzuLTssyZxRpEwzuIxL/GDsvpjaBtOw==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.18': resolution: {integrity: sha512-zsu47DgU0FQzSwi6sU9dZoEdUv7pc1AptSEz/Z8HBg54sV0Pbs3N0+CrIbTsgiu6EyoaNN9CHboqbLaz9lhOyQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.4': + resolution: {integrity: sha512-cfiMrfuWCIgsFmcVG0IPuO6qTRHvF7NuG3wngX1RZzc6dU8FuBFb+J3MIR5WrdTNozlumfgL4cvz+R4ozBCvsQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.18': resolution: {integrity: sha512-7H+3yqGgmnlDTRRhw/xpYY9J1kf4GC681nVc4GqKhExZTDrVVrV2tsOR9kso0fvgBdcTCcQShx4SLLoHgaLwhg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.4': + resolution: {integrity: sha512-p6UeR9y7ht82AH57qwGuFYn69S6CZ7LLKdCKy/8T3zS9VTrJei2/CGsTUV45Da4Z9Rbhc7G4gyWQ/Ioamqn09g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + '@rolldown/pluginutils@1.0.0-rc.13': resolution: {integrity: sha512-3ngTAv6F/Py35BsYbeeLeecvhMKdsKm4AoOETVhAA+Qc8nrA2I0kF7oa93mE9qnIurngOSpMnQ0x2nQY2FPviA==} '@rolldown/pluginutils@1.0.0-rc.18': resolution: {integrity: sha512-CUY5Mnhe64xQBGZEEXQ5WyZwsc1JU3vAZLIxtrsBt3LO6UOb+C8GunVKqe9sT8NeWb4lqSaoJtp2xo6GxT1MNw==} + '@rolldown/pluginutils@1.0.0-rc.4': + resolution: {integrity: sha512-1BrrmTu0TWfOP1riA8uakjFc9bpIUGzVKETsOtzY39pPga8zELGDl8eu1Dx7/gjM5CAz14UknsUMpBO8L+YntQ==} + '@rolldown/pluginutils@1.0.0-rc.7': resolution: {integrity: sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==} @@ -2110,6 +3171,39 @@ packages: cpu: [x64] os: [win32] + '@rollup/wasm-node@4.60.3': + resolution: {integrity: sha512-SVhQ4TJk0BvnJKwceVsCWHtmquucfjU0eu+Bonrjb6W3zombkA/tqw1efaqT2BONX/TJniqkzumF6Sz/sXMJ2w==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + '@schematics/angular@21.2.10': + resolution: {integrity: sha512-RWoD2iARXfHmMkAzmAsefj5rcyihhVPW4OY7+pdpfFYCHdGPreSbEAhCcTF2dJjJA/71N5qj5bFdSIJhO2aZ1A==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0, npm: ^6.11.0 || ^7.5.6 || >=8.0.0, yarn: '>= 1.13.0'} + + '@sigstore/bundle@4.0.0': + resolution: {integrity: sha512-NwCl5Y0V6Di0NexvkTqdoVfmjTaQwoLM236r89KEojGmq/jMls8S+zb7yOwAPdXvbwfKDlP+lmXgAL4vKSQT+A==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@sigstore/core@3.2.0': + resolution: {integrity: sha512-kxHrDQ9YgfrWUSXU0cjsQGv8JykOFZQ9ErNKbFPWzk3Hgpwu8x2hHrQ9IdA8yl+j9RTLTC3sAF3Tdq1IQCP4oA==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@sigstore/protobuf-specs@0.5.1': + resolution: {integrity: sha512-/ScWUhhoFasJsSRGTVBwId1loQjjnjAfE4djL6ZhrXRpNCmPTnUKF5Jokd58ILseOMjzET3UrMOtJPS9sYeI0g==} + engines: {node: ^18.17.0 || >=20.5.0} + + '@sigstore/sign@4.1.1': + resolution: {integrity: sha512-Hf4xglukg0XXQ2RiD5vSoLjdPe8OBUPA8XeVjUObheuDcWdYWrnH/BNmxZCzkAy68MzmNCxXLeurJvs6hcP2OQ==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@sigstore/tuf@4.0.2': + resolution: {integrity: sha512-TCAzTy0xzdP79EnxSjq9KQ3eaR7+FmudLC6eRKknVKZbV7ZNlGLClAAQb/HMNJ5n2OBNk2GT1tEmU0xuPr+SLQ==} + engines: {node: ^20.17.0 || >=22.9.0} + + '@sigstore/verify@3.1.0': + resolution: {integrity: sha512-mNe0Iigql08YupSOGv197YdHpPPr+EzDZmfCgMc7RPNaZTw5aLN01nBl6CHJOh3BGtnMIj83EeN4butBchc8Ag==} + engines: {node: ^20.17.0 || >=22.9.0} + '@sindresorhus/is@7.2.0': resolution: {integrity: sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==} engines: {node: '>=18'} @@ -2136,6 +3230,15 @@ packages: svelte: ^5.46.4 vite: ^8.0.11 + '@testing-library/angular@19.2.1': + resolution: {integrity: sha512-COWnkcTKFwb4fReLlInNATH1cPYmujWINnVMXdy0oJHidz0XIrdJopx/jwCBDIAgD4qtz+wEDsUWM4gI78Hakw==} + peerDependencies: + '@angular/common': '>= 21.0.0' + '@angular/core': '>= 21.0.0' + '@angular/platform-browser': '>= 21.0.0' + '@angular/router': '>= 21.0.0' + '@testing-library/dom': ^10.0.0 + '@testing-library/dom@10.4.1': resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} engines: {node: '>=18'} @@ -2188,6 +3291,14 @@ packages: '@vue/compiler-sfc': optional: true + '@tufjs/canonical-json@2.0.0': + resolution: {integrity: sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==} + engines: {node: ^16.14.0 || >=18.0.0} + + '@tufjs/models@4.1.0': + resolution: {integrity: sha512-Y8cK9aggNRsqJVaKUlEYs4s7CvQ1b1ta2DVPyAimb0I2qhzjNk+A+mxvll/klL0RlfuIUei8BF7YWiua4kQqww==} + engines: {node: ^20.17.0 || >=22.9.0} + '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} @@ -2298,6 +3409,12 @@ packages: engines: {node: '>=20'} hasBin: true + '@vitejs/plugin-basic-ssl@2.1.4': + resolution: {integrity: sha512-HXciTXN/sDBYWgeAD4V4s0DN0g72x5mlxQhHxtYu3Tt8BLa6MzcJZUyDVFCdtjNs3bfENVHVzOsmooTVuNgAAw==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + peerDependencies: + vite: ^8.0.11 + '@vitejs/plugin-react@6.0.1': resolution: {integrity: sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -2446,6 +3563,9 @@ packages: '@vue/test-utils@2.4.6': resolution: {integrity: sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==} + '@yarnpkg/lockfile@1.1.0': + resolution: {integrity: sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==} + abbrev@2.0.0: resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -2454,10 +3574,18 @@ packages: resolution: {integrity: sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==} engines: {node: ^18.17.0 || >=20.5.0} + abbrev@4.0.0: + resolution: {integrity: sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA==} + engines: {node: ^20.17.0 || >=22.9.0} + abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + acorn-import-attributes@1.9.5: resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} peerDependencies: @@ -2477,12 +3605,38 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + ajv@6.14.0: resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} + ajv@8.18.0: + resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + + algoliasearch@5.48.1: + resolution: {integrity: sha512-Rf7xmeuIo7nb6S4mp4abW2faW8DauZyE2faBIKFaUfP3wnpOvNSbiI5AwVhqBNj0jPgBWEvhyCu0sLjN2q77Rg==} + engines: {node: '>= 14.0.0'} + alien-signals@3.1.2: resolution: {integrity: sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw==} + angular-eslint@21.3.1: + resolution: {integrity: sha512-VGQWTyuPAEO/AnZuqHxGBJMYSiZ0tbrHx/OgPCRTKHfbrFU4x+zivS84h9UWoDpDtius1RyD+ZReFjTAEWptiA==} + peerDependencies: + '@angular/cli': '>= 21.0.0 < 22.0.0' + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '*' + typescript-eslint: ^8.0.0 + ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} @@ -2543,6 +3697,10 @@ packages: resolution: {integrity: sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==} engines: {node: '>= 0.4'} + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + array-buffer-byte-length@1.0.2: resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} engines: {node: '>= 0.4'} @@ -2646,6 +3804,10 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + beasties@0.4.1: + resolution: {integrity: sha512-2Imdcw3LznDuxAbJM26RHniOLAzE6WgrK8OuvVXCQtNBS8rsnD9zsSEa3fHl4hHpUY7BYTlrpvtPVbvu9G6neg==} + engines: {node: '>=18.0.0'} + better-path-resolve@1.0.0: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} @@ -2662,6 +3824,10 @@ packages: birpc@4.0.0: resolution: {integrity: sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==} + body-parser@2.2.2: + resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} + engines: {node: '>=18'} + boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} @@ -2698,6 +3864,10 @@ packages: resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} engines: {node: '>=18'} + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + c12@3.3.4: resolution: {integrity: sha512-cM0ApFQSBXuourJejzwv/AuPRvAxordTyParRVcHjjtXirtkzM0uK2L9TTn9s0cXZbG7E55jCivRQzoxYmRAlA==} peerDependencies: @@ -2710,6 +3880,10 @@ packages: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} + cacache@20.0.4: + resolution: {integrity: sha512-M3Lab8NPYlZU2exsL3bMVvMrMqgwCnMWfdZbK28bn3pK6APT/Te/I8hjRPNu1uwORY9a1eEQoifXbKPQMfMTOA==} + engines: {node: ^20.17.0 || >=22.9.0} + call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} @@ -2769,10 +3943,18 @@ packages: resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} engines: {node: '>=18'} + cli-spinners@3.4.0: + resolution: {integrity: sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw==} + engines: {node: '>=18.20'} + cli-truncate@5.2.0: resolution: {integrity: sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==} engines: {node: '>=20'} + cli-width@4.1.0: + resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} + engines: {node: '>= 12'} + cliui@9.0.1: resolution: {integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==} engines: {node: '>=20'} @@ -2792,6 +3974,9 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + commander@10.0.1: resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} engines: {node: '>=14'} @@ -2800,9 +3985,16 @@ packages: resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} engines: {node: '>=16'} + commander@14.0.3: + resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} + engines: {node: '>=20'} + commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + common-path-prefix@3.0.0: + resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==} + commondir@1.0.1: resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} @@ -2829,6 +4021,17 @@ packages: resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} engines: {node: ^14.18.0 || >=16.10.0} + content-disposition@1.1.0: + resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} + engines: {node: '>=18'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + convert-source-map@1.9.0: + resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -2841,6 +4044,14 @@ packages: cookie-es@3.1.1: resolution: {integrity: sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==} + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + copy-anything@3.0.5: resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} engines: {node: '>=12.13'} @@ -2848,6 +4059,10 @@ packages: core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} + engines: {node: '>= 0.10'} + crc-32@1.2.2: resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} engines: {node: '>=0.8'} @@ -2877,6 +4092,9 @@ packages: css-select@5.2.2: resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} + css-select@6.0.0: + resolution: {integrity: sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw==} + css-tree@2.2.1: resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} @@ -2889,6 +4107,10 @@ packages: resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} engines: {node: '>= 6'} + css-what@7.0.0: + resolution: {integrity: sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==} + engines: {node: '>= 6'} + cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} @@ -3018,6 +4240,10 @@ packages: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} + dependency-graph@1.0.0: + resolution: {integrity: sha512-cW3gggJ28HZ/LExwxP2B++aiKxhJXMSIt9K48FOXQkm+vuG5gyatXnLsONRJdzO/7VfjDIiaOOa/bs4l464Lwg==} + engines: {node: '>=4'} + dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -3097,6 +4323,9 @@ packages: emoji-regex@10.6.0: resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + encodeurl@2.0.0: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} @@ -3109,6 +4338,10 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + entities@7.0.1: resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} engines: {node: '>=0.12'} @@ -3117,10 +4350,17 @@ packages: resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==} engines: {node: '>=20.19.0'} + env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + environment@1.1.0: resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} engines: {node: '>=18'} + err-code@2.0.3: + resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} + errno@0.1.8: resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} hasBin: true @@ -3174,6 +4414,16 @@ packages: engines: {node: '>=18'} hasBin: true + esbuild@0.27.3: + resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} + engines: {node: '>=18'} + hasBin: true + + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} + engines: {node: '>=18'} + hasBin: true + esbuild@0.28.0: resolution: {integrity: sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==} engines: {node: '>=18'} @@ -3335,6 +4585,14 @@ packages: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} + eventsource-parser@3.0.8: + resolution: {integrity: sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ==} + engines: {node: '>=18.0.0'} + + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} + execa@8.0.1: resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} engines: {node: '>=16.17'} @@ -3343,6 +4601,19 @@ packages: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} + exponential-backoff@3.1.3: + resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} + + express-rate-limit@8.5.1: + resolution: {integrity: sha512-5O6KYmyJEpuPJV5hNTXKbAHWRqrzyu+OI3vUnSd2kXFubIVpG7ezpgxQy76Zo5GQZtrQBg86hF+CM/NX+cioiQ==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + exsolve@1.0.8: resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} @@ -3379,6 +4650,9 @@ packages: fast-string-width@1.1.0: resolution: {integrity: sha512-O3fwIVIH5gKB38QNbdg+3760ZmGz0SZMgvwJbA1b2TGXceKE6A2cOlfogh1iw8lr049zPyd7YADHy+B7U4W9bQ==} + fast-uri@3.1.2: + resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} + fast-wrap-ansi@0.1.6: resolution: {integrity: sha512-HlUwET7a5gqjURj70D5jl7aC3Zmy4weA1SHUfM0JFI0Ptq987NH2TwbBFLoERhfwk+E+eaq4EK3jXoT+R3yp3w==} @@ -3412,6 +4686,18 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} + + find-cache-directory@6.0.0: + resolution: {integrity: sha512-CvFd5ivA6HcSHbD+59P7CyzINHXzwhuQK8RY7CxJZtgDSAtRlHiCaQpZQ2lMR/WRyUIEmzUvL6G2AGurMfegZA==} + engines: {node: '>=20'} + + find-up-simple@1.0.1: + resolution: {integrity: sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==} + engines: {node: '>=18'} + find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} @@ -3434,6 +4720,10 @@ packages: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + fraction.js@5.3.4: resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} @@ -3449,6 +4739,10 @@ packages: resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} engines: {node: '>=6 <7 || >=8'} + fs-minipass@3.0.3: + resolution: {integrity: sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + fsevents@2.3.2: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -3523,6 +4817,9 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} + glob-to-regexp@0.4.1: + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + glob@13.0.6: resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} engines: {node: 18 || 20 || >=22} @@ -3609,12 +4906,20 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + hono@4.12.18: + resolution: {integrity: sha512-RWzP96k/yv0PQfyXnWjs6zot20TqfpfsNXhOnev8d1InAxubW93L11/oNUc3tQqn2G0bSdAOBpX+2uDFHV7kdQ==} + engines: {node: '>=16.9.0'} + hookable@5.5.3: resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} hookable@6.1.1: resolution: {integrity: sha512-U9LYDy1CwhMCnprUfeAZWZGByVbhd54hwepegYTK7Pi5NvqEj63ifz5z+xukznehT7i6NIZRu89Ay1AZmRsLEQ==} + hosted-git-info@9.0.3: + resolution: {integrity: sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg==} + engines: {node: ^20.17.0 || >=22.9.0} + html-encoding-sniffer@6.0.0: resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} @@ -3622,10 +4927,20 @@ packages: html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + htmlparser2@10.1.0: + resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} + + http-cache-semantics@4.2.0: + resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} + http-errors@2.0.1: resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} engines: {node: '>= 0.8'} + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + http-shutdown@1.2.2: resolution: {integrity: sha512-S9wWkJ/VSY9/k4qcjG318bqJNruzE4HySUhFYknwmu6LBP97KLLfwNf+n4V1BHurvFNkSKLFnK/RsuUnRTf9Vw==} engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} @@ -3661,6 +4976,10 @@ packages: ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + ignore-walk@8.0.0: + resolution: {integrity: sha512-FCeMZT4NiRQGh+YkeKMtWrOmBgWjHjMJ26WQWrRQyoyzqevdaGSakUaJW5xQYmjLlUVk2qUnCjYVBax9EKKg8A==} + engines: {node: ^20.17.0 || >=22.9.0} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -3701,6 +5020,13 @@ packages: resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + ini@6.0.0: + resolution: {integrity: sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==} + engines: {node: ^20.17.0 || >=22.9.0} + + injection-js@2.6.1: + resolution: {integrity: sha512-dbR5bdhi7TWDoCye9cByZqeg/gAfamm8Vu3G1KZOTYkOif8WkuM8CD0oeDPtZYMzT5YH76JAFB7bkmyY9OJi2A==} + internal-slot@1.1.0: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} @@ -3709,6 +5035,14 @@ packages: resolution: {integrity: sha512-HuEDBTI70aYdx1v6U97SbNx9F1+svQKBDo30o0b9fw055LMepzpOOd0Ccg9Q6tbqmBSJaMuY0fB7yw9/vjBYCA==} engines: {node: '>=12.22.0'} + ip-address@10.2.0: + resolution: {integrity: sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==} + engines: {node: '>= 12'} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + ipx@3.1.1: resolution: {integrity: sha512-7Xnt54Dco7uYkfdAw0r2vCly3z0rSaVhEXMzPvl3FndsTVm5p26j+PO+gyinkYmcsEUvX2Rh7OGK7KzYWRu6BA==} hasBin: true @@ -3765,6 +5099,10 @@ packages: resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} engines: {node: '>= 0.4'} + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + is-fullwidth-code-point@5.1.0: resolution: {integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==} engines: {node: '>=18'} @@ -3790,6 +5128,10 @@ packages: resolution: {integrity: sha512-K55T22lfpQ63N4KEN57jZUAaAYqYHEe8veb/TycJRk9DdSCLLcovXz/mL6mOnhQaZsQGwPhuFopdQIlqGSEjiQ==} engines: {node: '>=18'} + is-interactive@2.0.0: + resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} + engines: {node: '>=12'} + is-map@2.0.3: resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} engines: {node: '>= 0.4'} @@ -3816,6 +5158,9 @@ packages: is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-reference@1.2.1: resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} @@ -3858,6 +5203,10 @@ packages: resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} engines: {node: '>= 0.4'} + is-unicode-supported@2.1.0: + resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} + engines: {node: '>=18'} + is-weakmap@2.0.2: resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} engines: {node: '>= 0.4'} @@ -3899,6 +5248,10 @@ packages: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} + istanbul-lib-instrument@6.0.3: + resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} + engines: {node: '>=10'} + istanbul-lib-report@3.0.1: resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} engines: {node: '>=10'} @@ -3923,6 +5276,9 @@ packages: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true + jose@6.2.3: + resolution: {integrity: sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==} + js-beautify@1.15.4: resolution: {integrity: sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==} engines: {node: '>=14'} @@ -3966,9 +5322,19 @@ packages: json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + json-parse-even-better-errors@5.0.0: + resolution: {integrity: sha512-ZF1nxZ28VhQouRWhUcVlUIN3qwSgPuswK05s/HIaoetAoE/9tngVmCHjSxmSQPav1nd+lPtTL0YZ/2AFdR/iYQ==} + engines: {node: ^20.17.0 || >=22.9.0} + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-schema-typed@8.0.2: + resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} + json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} @@ -3977,9 +5343,16 @@ packages: engines: {node: '>=6'} hasBin: true + jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + jsonparse@1.3.1: + resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} + engines: {'0': node >= 0.2.0} + jsx-ast-utils@3.3.5: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} @@ -4112,6 +5485,14 @@ packages: resolution: {integrity: sha512-7I5knELsJKTUjXG+A6BkKAiGkW1i25fNa/xlUl9hFtk15WbE9jndA89xu5FzQKrY5llajE1hfZZFMILXkDHk/Q==} engines: {node: '>=22.13.0'} + listr2@9.0.5: + resolution: {integrity: sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==} + engines: {node: '>=20.0.0'} + + lmdb@3.5.1: + resolution: {integrity: sha512-NYHA0MRPjvNX+vSw8Xxg6FLKxzAG+e7Pt8RqAQA/EehzHVXq9SxDqJIN3JL1hK0dweb884y8kIh6rkWvPyg9Wg==} + hasBin: true + local-pkg@1.1.2: resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==} engines: {node: '>=14'} @@ -4148,6 +5529,10 @@ packages: lodash@4.17.23: resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==} + log-symbols@7.0.1: + resolution: {integrity: sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==} + engines: {node: '>=18'} + log-update@6.1.0: resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} engines: {node: '>=18'} @@ -4188,6 +5573,10 @@ packages: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} + make-fetch-happen@15.0.5: + resolution: {integrity: sha512-uCbIa8jWWmQZt4dSnEStkVC6gdakiinAm4PiGsywIkguF0eWMdcjDz0ECYhUolFU3pFLOev9VNPCEygydXnddg==} + engines: {node: ^20.17.0 || >=22.9.0} + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -4198,10 +5587,18 @@ packages: mdn-data@2.27.1: resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + meow@13.2.0: resolution: {integrity: sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==} engines: {node: '>=18'} + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -4254,6 +5651,30 @@ packages: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} + minipass-collect@2.0.1: + resolution: {integrity: sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==} + engines: {node: '>=16 || 14 >=14.17'} + + minipass-fetch@5.0.2: + resolution: {integrity: sha512-2d0q2a8eCi2IRg/IGubCNRJoYbA1+YPXAzQVRFmB45gdGZafyivnZ5YSEfo3JikbjGxOdntGFvBQGqaSMXlAFQ==} + engines: {node: ^20.17.0 || >=22.9.0} + + minipass-flush@1.0.7: + resolution: {integrity: sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA==} + engines: {node: '>= 8'} + + minipass-pipeline@1.2.4: + resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==} + engines: {node: '>=8'} + + minipass-sized@2.0.0: + resolution: {integrity: sha512-zSsHhto5BcUVM2m1LurnXY6M//cGhVaegT71OfOXoprxT6o780GZd792ea6FfrQkuU4usHZIUczAQMRUE2plzA==} + engines: {node: '>=8'} + + minipass@3.3.6: + resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} + engines: {node: '>=8'} + minipass@7.1.3: resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} @@ -4300,9 +5721,20 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + msgpackr-extract@3.0.3: + resolution: {integrity: sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==} + hasBin: true + + msgpackr@1.11.12: + resolution: {integrity: sha512-RBdJ1Un7yGlXWajrkxcSa93nvQ0w4zBf60c0yYv7YtBelP8H2FA7XsfBbMHtXKXUMUxH7zV3Zuozh+kUQWhHvg==} + muggle-string@0.4.1: resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + mute-stream@2.0.0: + resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} + engines: {node: ^18.17.0 || >=20.5.0} + nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -4319,6 +5751,23 @@ packages: engines: {node: '>= 4.4.x'} hasBin: true + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + + ng-packagr@21.2.3: + resolution: {integrity: sha512-jGq6yu0G6KReVK0i5RYVoV9HDL0mU626HrLBu5xvc8ZJ92n/+rLrFJuXdCnkroB9um+FBTQe/or6/A/2GAKhLw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@angular/compiler-cli': ^21.0.0 || ^21.2.0-next + tailwindcss: ^2.0.0 || ^3.0.0 || ^4.0.0 + tslib: ^2.3.0 + typescript: '>=5.9 <6.0' + peerDependenciesMeta: + tailwindcss: + optional: true + nitropack@2.13.4: resolution: {integrity: sha512-tX7bT6zxNeMwkc6hxHiZeUoTOjVrcjoh1Z3cmxOlodIqjl4HISgqfGOmkWSayky3Nv9Z5+KQH52F8nmXJY5AAA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -4329,6 +5778,9 @@ packages: xml2js: optional: true + node-addon-api@6.1.0: + resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==} + node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} @@ -4352,10 +5804,19 @@ packages: resolution: {integrity: sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==} engines: {node: '>= 6.13.0'} + node-gyp-build-optional-packages@5.2.2: + resolution: {integrity: sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==} + hasBin: true + node-gyp-build@4.8.4: resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} hasBin: true + node-gyp@12.3.0: + resolution: {integrity: sha512-QNcUWM+HgJplcPzBvFBZ9VXacyGZ4+VTOb80PwWR+TlVzoHbRKULNEzpRsnaoxG3Wzr7Qh7BYxGDU3CbKib2Yg==} + engines: {node: ^20.17.0 || >=22.9.0} + hasBin: true + node-mock-http@1.0.4: resolution: {integrity: sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==} @@ -4372,10 +5833,43 @@ packages: engines: {node: ^18.17.0 || >=20.5.0} hasBin: true + nopt@9.0.0: + resolution: {integrity: sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw==} + engines: {node: ^20.17.0 || >=22.9.0} + hasBin: true + normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} + npm-bundled@5.0.0: + resolution: {integrity: sha512-JLSpbzh6UUXIEoqPsYBvVNVmyrjVZ1fzEFbqxKkTJQkWBO3xFzFT+KDnSKQWwOQNbuWRwt5LSD6HOTLGIWzfrw==} + engines: {node: ^20.17.0 || >=22.9.0} + + npm-install-checks@8.0.0: + resolution: {integrity: sha512-ScAUdMpyzkbpxoNekQ3tNRdFI8SJ86wgKZSQZdUxT+bj0wVFpsEMWnkXP0twVe1gJyNF5apBWDJhhIbgrIViRA==} + engines: {node: ^20.17.0 || >=22.9.0} + + npm-normalize-package-bin@5.0.0: + resolution: {integrity: sha512-CJi3OS4JLsNMmr2u07OJlhcrPxCeOeP/4xq67aWNai6TNWWbTrlNDgl8NcFKVlcBKp18GPj+EzbNIgrBfZhsag==} + engines: {node: ^20.17.0 || >=22.9.0} + + npm-package-arg@13.0.2: + resolution: {integrity: sha512-IciCE3SY3uE84Ld8WZU23gAPPV9rIYod4F+rc+vJ7h7cwAJt9Vk6TVsK60ry7Uj3SRS3bqRRIGuTp9YVlk6WNA==} + engines: {node: ^20.17.0 || >=22.9.0} + + npm-packlist@10.0.4: + resolution: {integrity: sha512-uMW73iajD8hiH4ZBxEV3HC+eTnppIqwakjOYuvgddnalIw2lJguKviK1pcUJDlIWm1wSJkchpDZDSVVsZEYRng==} + engines: {node: ^20.17.0 || >=22.9.0} + + npm-pick-manifest@11.0.3: + resolution: {integrity: sha512-buzyCfeoGY/PxKqmBqn1IUJrZnUi1VVJTdSSRPGI60tJdUhUoSQFhs0zycJokDdOznQentgrpf8LayEHyyYlqQ==} + engines: {node: ^20.17.0 || >=22.9.0} + + npm-registry-fetch@19.1.1: + resolution: {integrity: sha512-TakBap6OM1w0H73VZVDf44iFXsOS3h+L4wVMXmbWOQroZgFhMch0juN6XSzBNlD965yIKvWg2dfu7NSiaYLxtw==} + engines: {node: ^20.17.0 || >=22.9.0} + npm-run-path@5.3.0: resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -4466,6 +5960,9 @@ packages: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + onetime@6.0.0: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} engines: {node: '>=12'} @@ -4486,6 +5983,17 @@ packages: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} + ora@9.3.0: + resolution: {integrity: sha512-lBX72MWFduWEf7v7uWf5DHp9Jn5BI8bNPGuFgtXMmr2uDz2Gz2749y3am3agSDdkhHPHYmmxEGSKH85ZLGzgXw==} + engines: {node: '>=20'} + + ora@9.4.0: + resolution: {integrity: sha512-84cglkRILFxdtA8hAvLNdMrtBpPNBTrQ9/ulg0FA7xLMnD6mifv+enAIeRmvtv+WgdCE+LPGOfQmtJRrVaIVhQ==} + engines: {node: '>=20'} + + ordered-binary@1.6.1: + resolution: {integrity: sha512-QkCdPooczexPLiXIrbVOPYkR3VO3T6v2OyKRkR1Xbhpy7/LAVXwahnRCgRp78Oe/Ehf0C/HATAxfSr6eA1oX+w==} + outdent@0.5.0: resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} @@ -4534,6 +6042,10 @@ packages: resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} engines: {node: '>=6'} + p-map@7.0.4: + resolution: {integrity: sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==} + engines: {node: '>=18'} + p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} @@ -4544,6 +6056,11 @@ packages: package-manager-detector@0.2.11: resolution: {integrity: sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==} + pacote@21.3.1: + resolution: {integrity: sha512-O0EDXi85LF4AzdjG74GUwEArhdvawi/YOHcsW6IijKNj7wm8IvEWNF5GnfuxNpQ/ZpO3L37+v8hqdVh8GgWYhg==} + engines: {node: ^20.17.0 || >=22.9.0} + hasBin: true + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -4552,6 +6069,12 @@ packages: resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} engines: {node: '>= 0.10'} + parse5-html-rewriting-stream@8.0.0: + resolution: {integrity: sha512-wzh11mj8KKkno1pZEu+l2EVeWsuKDfR5KNWZOTsslfUX8lPDZx77m9T0kIoAVkFtD1nx6YF8oh4BnPHvxMtNMw==} + + parse5-sax-parser@8.0.0: + resolution: {integrity: sha512-/dQ8UzHZwnrzs3EvDj6IkKrD/jIZyTlB+8XrHJvcjNgRdmWruNdN9i9RK/JtxakmlUdPwKubKPTCqvbTgzGhrw==} + parse5@8.0.1: resolution: {integrity: sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==} @@ -4585,6 +6108,9 @@ packages: resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} engines: {node: 18 || 20 || >=22} + path-to-regexp@8.4.2: + resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -4613,6 +6139,18 @@ packages: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} + piscina@5.1.4: + resolution: {integrity: sha512-7uU4ZnKeQq22t9AsmHGD2w4OYQGonwFnTypDypaWi7Qr2EvQIFVtG8J5D/3bE7W123Wdc9+v4CZDu5hJXVCtBg==} + engines: {node: '>=20.x'} + + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + + pkg-dir@8.0.0: + resolution: {integrity: sha512-4peoBq4Wks0riS0z8741NVv+/8IiTvqnZAr8QGgtdifrtpdXbNw/FxRS1l6NFqm4EMzuS0EDqNNx4XGaz8cuyQ==} + engines: {node: '>=18'} + pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} @@ -4687,6 +6225,9 @@ packages: ts-node: optional: true + postcss-media-query-parser@0.2.3: + resolution: {integrity: sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==} + postcss-merge-longhand@7.0.7: resolution: {integrity: sha512-b3mfYUxR388u5Pt0HPcVIUtUDn/k15UfTY9M+ORW+meCR6JLNxoZffiYvXyOYQoRYQNZyX/UFkMCM/mNHxe1qA==} engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} @@ -4868,6 +6409,10 @@ packages: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + proc-log@6.1.0: + resolution: {integrity: sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==} + engines: {node: ^20.17.0 || >=22.9.0} + process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} @@ -4875,6 +6420,10 @@ packages: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} + promise-retry@2.0.1: + resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} + engines: {node: '>=10'} + prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} @@ -4884,6 +6433,10 @@ packages: proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + prr@1.0.1: resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} @@ -4891,6 +6444,10 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + qs@6.15.1: + resolution: {integrity: sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==} + engines: {node: '>=0.6'} + quansync@0.2.11: resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} @@ -4904,6 +6461,10 @@ packages: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} + rc9@3.0.1: resolution: {integrity: sha512-gMDyleLWVE+i6Sgtc0QbbY6pEKqYs97NGi6isHQPqYlLemPoO8dxQ3uGi0f4NiP98c+jMW6cG1Kx9dDwfvqARQ==} @@ -4952,6 +6513,9 @@ packages: resolution: {integrity: sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==} engines: {node: '>=4'} + reflect-metadata@0.2.2: + resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} + reflect.getprototypeof@1.0.10: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} @@ -5011,12 +6575,17 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - rollup-plugin-dts@6.3.0: - resolution: {integrity: sha512-d0UrqxYd8KyZ6i3M2Nx7WOMy708qsV/7fTHMHxCMCBOAe3V/U7OMPu5GkX8hC+cmkHhzGnfeYongl1IgiooddA==} - engines: {node: '>=16'} + rolldown@1.0.0-rc.4: + resolution: {integrity: sha512-V2tPDUrY3WSevrvU2E41ijZlpF+5PbZu4giH+VpNraaadsJGHa4fR6IFwsocVwEXDoAdIv5qgPPxgrvKAOIPtA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + rollup-plugin-dts@6.4.1: + resolution: {integrity: sha512-l//F3Zf7ID5GoOfLfD8kroBjQKEKpy1qfhtAdnpibFZMffPaylrg1CoDC2vGkPeTeyxUe4bVFCln2EFuL7IGGg==} + engines: {node: '>=20'} peerDependencies: rollup: ^3.29.4 || ^4 - typescript: ^4.5 || ^5.0 + typescript: ^4.5 || ^5.0 || ^6.0 rollup-plugin-visualizer@7.0.1: resolution: {integrity: sha512-UJUT4+1Ho4OcWmPYU3sYXgUqI8B8Ayfe06MX7y0qCJ1K8aGoKtR/NDd/2nZqM7ADkrzny+I99Ul7GgyoiVNAgg==} @@ -5039,6 +6608,10 @@ packages: rou3@0.8.1: resolution: {integrity: sha512-ePa+XGk00/3HuCqrEnK3LxJW7I0SdNg6EFzKUJG73hMAdDcOUC/i/aSz7LSDwLrGr33kal/rqOGydzwl6U7zBA==} + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + run-applescript@7.1.0: resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} engines: {node: '>=18'} @@ -5046,6 +6619,9 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + sade@1.8.1: resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} engines: {node: '>=6'} @@ -5071,6 +6647,11 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + sass@1.97.3: + resolution: {integrity: sha512-fDz1zJpd5GycprAbu4Q2PV/RprsRtKC/0z82z0JLgdytmcq0+ujJbJ/09bPGDxCLkKY3Np5cRAOcWiVkLXJURg==} + engines: {node: '>=14.0.0'} + hasBin: true + sass@1.99.0: resolution: {integrity: sha512-kgW13M54DUB7IsIRM5LvJkNlpH+WhMpooUcaWGFARkF1Tc82v9mIWkCbCYf+MBvpIUBSeSOTilpZjEPr2VYE6Q==} engines: {node: '>=14.0.0'} @@ -5179,6 +6760,10 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} + sigstore@4.1.0: + resolution: {integrity: sha512-/fUgUhYghuLzVT/gaJoeVehLCgZiUxPCPMcyVNY0lIf/cTCz58K/WTI7PefDarXxp9nUKpEwg1yyz3eSBMTtgA==} + engines: {node: ^20.17.0 || >=22.9.0} + simple-git@3.33.0: resolution: {integrity: sha512-D4V/tGC2sjsoNhoMybKyGoE+v8A60hRawKQ1iFRA1zwuDgGZCBJ4ByOzZ5J8joBbi4Oam0qiPH+GhzmSBwbJng==} @@ -5210,10 +6795,22 @@ packages: resolution: {integrity: sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==} engines: {node: '>=20'} + smart-buffer@4.2.0: + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + smob@1.6.1: resolution: {integrity: sha512-KAkBqZl3c2GvNgNhcoyJae1aKldDW0LO279wF9bk1PnluRTETKBq0WyzRXxEhoQLk56yHaOY4JCBEKDuJIET5g==} engines: {node: '>=20.0.0'} + socks-proxy-agent@8.0.5: + resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==} + engines: {node: '>= 14'} + + socks@2.8.9: + resolution: {integrity: sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==} + engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -5232,6 +6829,15 @@ packages: spawndamnit@3.0.1: resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==} + spdx-exceptions@2.5.0: + resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} + + spdx-expression-parse@4.0.0: + resolution: {integrity: sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==} + + spdx-license-ids@3.0.23: + resolution: {integrity: sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==} + sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} @@ -5240,6 +6846,10 @@ packages: engines: {node: '>=20.16.0'} hasBin: true + ssri@13.0.1: + resolution: {integrity: sha512-QUiRf1+u9wPTL/76GTYlKttDEBWV1ga9ZXW8BG6kfdeyyM8LGPix9gROyg9V2+P0xNyF3X2Go526xKFdMZrHSQ==} + engines: {node: ^20.17.0 || >=22.9.0} + stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -5256,6 +6866,10 @@ packages: std-env@4.1.0: resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} + stdin-discarder@0.3.2: + resolution: {integrity: sha512-eCPu1qRxPVkl5605OTWF8Wz40b4Mf45NY5LQmVPQ599knfs5QhASUm9GbJ5BDMDOXgrnh0wyEdvzmL//YMlw0A==} + engines: {node: '>=18'} + stop-iteration-iterator@1.1.0: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} @@ -5267,6 +6881,10 @@ packages: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + string-width@7.2.0: resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} engines: {node: '>=18'} @@ -5413,6 +7031,10 @@ packages: resolution: {integrity: sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==} engines: {node: '>=18'} + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + tinyglobby@0.2.16: resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} engines: {node: '>=12.0.0'} @@ -5470,6 +7092,10 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tuf-js@4.1.0: + resolution: {integrity: sha512-50QV99kCKH5P/Vs4E2Gzp7BopNV+KzTXqWeaxrfu5IQJBOULRsTIS9seSsOVT8ZnGXzCyx55nYWAi4qJzpZKEQ==} + engines: {node: ^20.17.0 || >=22.9.0} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -5478,6 +7104,10 @@ packages: resolution: {integrity: sha512-JnTrzGu+zPV3aXIUhnyWJj4z/wigMsdYajGLIYakqyOW1nPllzXEJee0QQbHj+CTIQtXGlAjuK0UY+2xTyjVAw==} engines: {node: '>=20'} + type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} + type-level-regexp@0.1.17: resolution: {integrity: sha512-wTk4DH3cxwk196uGLK/E9pE45aLfeKJacKmcEgEOA/q5dnPGNxXt0cfYdFxb57L+sEpf1oJH4Dnx/pnRcku9jg==} @@ -5497,6 +7127,13 @@ packages: resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} + typescript-eslint@8.59.2: + resolution: {integrity: sha512-pJw051uomb3ZeCzGTpRb8RbEqB5Y4WWet8gl/GcTlU35BSx0PVdZ86/bqkQCyKKuraVQEK7r6kBHQXF+fBhkoQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} @@ -5530,6 +7167,14 @@ packages: undici-types@7.19.2: resolution: {integrity: sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==} + undici@6.25.0: + resolution: {integrity: sha512-ZgpWDC5gmNiuY9CnLVXEH8rl50xhRCuLNA97fAUnKi8RRuV4E6KG31pDTsLVUKnohJE0I3XDrTeEydAXRw47xg==} + engines: {node: '>=18.17'} + + undici@7.24.4: + resolution: {integrity: sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w==} + engines: {node: '>=20.18.1'} + undici@7.25.0: resolution: {integrity: sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==} engines: {node: '>=20.18.1'} @@ -5561,6 +7206,10 @@ packages: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + unplugin-utils@0.3.1: resolution: {integrity: sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==} engines: {node: '>=20.19.0'} @@ -5664,6 +7313,14 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + validate-npm-package-name@7.0.2: + resolution: {integrity: sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==} + engines: {node: ^20.17.0 || >=22.9.0} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + vite-dev-rpc@1.1.0: resolution: {integrity: sha512-pKXZlgoXGoE8sEKiKJSng4hI1sQ4wi5YT24FCrwrLt6opmkjlqPPVmiPWWJn8M8byMxRGzp1CrFuqQs4M/Z39A==} peerDependencies: @@ -5886,6 +7543,13 @@ packages: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} + watchpack@2.5.1: + resolution: {integrity: sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==} + engines: {node: '>=10.13.0'} + + weak-lru-cache@1.2.2: + resolution: {integrity: sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==} + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -5946,10 +7610,17 @@ packages: resolution: {integrity: sha512-SGcvg80f0wUy2/fXES19feHMz8E0JoXv2uNgHOu4Dgi2OrCy1lqwFYEJz1BLbDI0exjPMe/ZdzZ/YpGECBG/aQ==} engines: {node: '>=20'} + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + wrap-ansi@9.0.2: resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} engines: {node: '>=18'} + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + ws@8.19.0: resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} engines: {node: '>=10.0.0'} @@ -5993,6 +7664,9 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + yallist@5.0.0: resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} engines: {node: '>=18'} @@ -6018,6 +7692,14 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + yoctocolors-cjs@2.1.3: + resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} + engines: {node: '>=18'} + + yoctocolors@2.1.2: + resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==} + engines: {node: '>=18'} + youch-core@0.3.3: resolution: {integrity: sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==} @@ -6031,11 +7713,340 @@ packages: resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} engines: {node: '>= 14'} + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} + peerDependencies: + zod: ^3.25.28 || ^4 + zod@4.3.6: resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} + zone.js@0.16.2: + resolution: {integrity: sha512-Eky7p2Z1Ig3NnbfodSPoARCjKBSTFMnE/ACsP1L/XJEfY4SdOFce19BsUCWVwL6K5ABZFy5J3bjcMWffX+YM3Q==} + snapshots: + '@algolia/abtesting@1.14.1': + dependencies: + '@algolia/client-common': 5.48.1 + '@algolia/requester-browser-xhr': 5.48.1 + '@algolia/requester-fetch': 5.48.1 + '@algolia/requester-node-http': 5.48.1 + + '@algolia/client-abtesting@5.48.1': + dependencies: + '@algolia/client-common': 5.48.1 + '@algolia/requester-browser-xhr': 5.48.1 + '@algolia/requester-fetch': 5.48.1 + '@algolia/requester-node-http': 5.48.1 + + '@algolia/client-analytics@5.48.1': + dependencies: + '@algolia/client-common': 5.48.1 + '@algolia/requester-browser-xhr': 5.48.1 + '@algolia/requester-fetch': 5.48.1 + '@algolia/requester-node-http': 5.48.1 + + '@algolia/client-common@5.48.1': {} + + '@algolia/client-insights@5.48.1': + dependencies: + '@algolia/client-common': 5.48.1 + '@algolia/requester-browser-xhr': 5.48.1 + '@algolia/requester-fetch': 5.48.1 + '@algolia/requester-node-http': 5.48.1 + + '@algolia/client-personalization@5.48.1': + dependencies: + '@algolia/client-common': 5.48.1 + '@algolia/requester-browser-xhr': 5.48.1 + '@algolia/requester-fetch': 5.48.1 + '@algolia/requester-node-http': 5.48.1 + + '@algolia/client-query-suggestions@5.48.1': + dependencies: + '@algolia/client-common': 5.48.1 + '@algolia/requester-browser-xhr': 5.48.1 + '@algolia/requester-fetch': 5.48.1 + '@algolia/requester-node-http': 5.48.1 + + '@algolia/client-search@5.48.1': + dependencies: + '@algolia/client-common': 5.48.1 + '@algolia/requester-browser-xhr': 5.48.1 + '@algolia/requester-fetch': 5.48.1 + '@algolia/requester-node-http': 5.48.1 + + '@algolia/ingestion@1.48.1': + dependencies: + '@algolia/client-common': 5.48.1 + '@algolia/requester-browser-xhr': 5.48.1 + '@algolia/requester-fetch': 5.48.1 + '@algolia/requester-node-http': 5.48.1 + + '@algolia/monitoring@1.48.1': + dependencies: + '@algolia/client-common': 5.48.1 + '@algolia/requester-browser-xhr': 5.48.1 + '@algolia/requester-fetch': 5.48.1 + '@algolia/requester-node-http': 5.48.1 + + '@algolia/recommend@5.48.1': + dependencies: + '@algolia/client-common': 5.48.1 + '@algolia/requester-browser-xhr': 5.48.1 + '@algolia/requester-fetch': 5.48.1 + '@algolia/requester-node-http': 5.48.1 + + '@algolia/requester-browser-xhr@5.48.1': + dependencies: + '@algolia/client-common': 5.48.1 + + '@algolia/requester-fetch@5.48.1': + dependencies: + '@algolia/client-common': 5.48.1 + + '@algolia/requester-node-http@5.48.1': + dependencies: + '@algolia/client-common': 5.48.1 + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@angular-devkit/architect@0.2102.10(chokidar@5.0.0)': + dependencies: + '@angular-devkit/core': 21.2.10(chokidar@5.0.0) + rxjs: 7.8.2 + transitivePeerDependencies: + - chokidar + + '@angular-devkit/core@21.2.10(chokidar@5.0.0)': + dependencies: + ajv: 8.18.0 + ajv-formats: 3.0.1(ajv@8.18.0) + jsonc-parser: 3.3.1 + picomatch: 4.0.4 + rxjs: 7.8.2 + source-map: 0.7.6 + optionalDependencies: + chokidar: 5.0.0 + + '@angular-devkit/schematics@21.2.10(chokidar@5.0.0)': + dependencies: + '@angular-devkit/core': 21.2.10(chokidar@5.0.0) + jsonc-parser: 3.3.1 + magic-string: 0.30.21 + ora: 9.3.0 + rxjs: 7.8.2 + transitivePeerDependencies: + - chokidar + + '@angular-eslint/builder@21.3.1(@angular/cli@21.2.10(@types/node@25.6.2)(chokidar@5.0.0))(chokidar@5.0.0)(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@angular-devkit/architect': 0.2102.10(chokidar@5.0.0) + '@angular-devkit/core': 21.2.10(chokidar@5.0.0) + '@angular/cli': 21.2.10(@types/node@25.6.2)(chokidar@5.0.0) + eslint: 9.39.4(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - chokidar + + '@angular-eslint/bundled-angular-compiler@21.3.1': {} + + '@angular-eslint/eslint-plugin-template@21.3.1(@angular-eslint/template-parser@21.3.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(@typescript-eslint/types@8.59.2)(@typescript-eslint/utils@8.59.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@angular-eslint/bundled-angular-compiler': 21.3.1 + '@angular-eslint/template-parser': 21.3.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@angular-eslint/utils': 21.3.1(@typescript-eslint/utils@8.59.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/types': 8.59.2 + '@typescript-eslint/utils': 8.59.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + aria-query: 5.3.2 + axobject-query: 4.1.0 + eslint: 9.39.4(jiti@2.6.1) + typescript: 5.9.3 + + '@angular-eslint/eslint-plugin@21.3.1(@typescript-eslint/utils@8.59.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@angular-eslint/bundled-angular-compiler': 21.3.1 + '@angular-eslint/utils': 21.3.1(@typescript-eslint/utils@8.59.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.4(jiti@2.6.1) + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + + '@angular-eslint/schematics@21.3.1(@angular-eslint/template-parser@21.3.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(@angular/cli@21.2.10(@types/node@25.6.2)(chokidar@5.0.0))(@typescript-eslint/types@8.59.2)(@typescript-eslint/utils@8.59.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(chokidar@5.0.0)(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@angular-devkit/core': 21.2.10(chokidar@5.0.0) + '@angular-devkit/schematics': 21.2.10(chokidar@5.0.0) + '@angular-eslint/eslint-plugin': 21.3.1(@typescript-eslint/utils@8.59.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@angular-eslint/eslint-plugin-template': 21.3.1(@angular-eslint/template-parser@21.3.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(@typescript-eslint/types@8.59.2)(@typescript-eslint/utils@8.59.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@angular/cli': 21.2.10(@types/node@25.6.2)(chokidar@5.0.0) + ignore: 7.0.5 + semver: 7.7.4 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - '@angular-eslint/template-parser' + - '@typescript-eslint/types' + - '@typescript-eslint/utils' + - chokidar + - eslint + - typescript + + '@angular-eslint/template-parser@21.3.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@angular-eslint/bundled-angular-compiler': 21.3.1 + eslint: 9.39.4(jiti@2.6.1) + eslint-scope: 9.1.2 + typescript: 5.9.3 + + '@angular-eslint/utils@21.3.1(@typescript-eslint/utils@8.59.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@angular-eslint/bundled-angular-compiler': 21.3.1 + '@typescript-eslint/utils': 8.59.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.4(jiti@2.6.1) + typescript: 5.9.3 + + '@angular/build@21.2.10(@angular/compiler-cli@21.2.12(@angular/compiler@21.2.12)(typescript@5.9.3))(@angular/compiler@21.2.12)(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(@angular/platform-browser@21.2.12(@angular/common@21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2))(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2)))(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(@types/node@25.6.2)(chokidar@5.0.0)(jiti@2.6.1)(less@4.6.4)(ng-packagr@21.2.3(@angular/compiler-cli@21.2.12(@angular/compiler@21.2.12)(typescript@5.9.3))(tslib@2.8.1)(typescript@5.9.3))(postcss@8.5.14)(terser@5.46.0)(tslib@2.8.1)(typescript@5.9.3)(vitest@4.1.5)(yaml@2.8.4)': + dependencies: + '@ampproject/remapping': 2.3.0 + '@angular-devkit/architect': 0.2102.10(chokidar@5.0.0) + '@angular/compiler': 21.2.12 + '@angular/compiler-cli': 21.2.12(@angular/compiler@21.2.12)(typescript@5.9.3) + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-split-export-declaration': 7.24.7 + '@inquirer/confirm': 5.1.21(@types/node@25.6.2) + '@vitejs/plugin-basic-ssl': 2.1.4(vite@8.0.11(@types/node@25.6.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.6.4)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.4)) + beasties: 0.4.1 + browserslist: 4.28.2 + esbuild: 0.27.3 + https-proxy-agent: 7.0.6 + istanbul-lib-instrument: 6.0.3 + jsonc-parser: 3.3.1 + listr2: 9.0.5 + magic-string: 0.30.21 + mrmime: 2.0.1 + parse5-html-rewriting-stream: 8.0.0 + picomatch: 4.0.4 + piscina: 5.1.4 + rolldown: 1.0.0-rc.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + sass: 1.97.3 + semver: 7.7.4 + source-map-support: 0.5.21 + tinyglobby: 0.2.15 + tslib: 2.8.1 + typescript: 5.9.3 + undici: 7.24.4 + vite: 8.0.11(@types/node@25.6.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.6.4)(sass@1.99.0)(terser@5.46.0)(yaml@2.8.4) + watchpack: 2.5.1 + optionalDependencies: + '@angular/core': 21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2) + '@angular/platform-browser': 21.2.12(@angular/common@21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2))(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2)) + less: 4.6.4 + lmdb: 3.5.1 + ng-packagr: 21.2.3(@angular/compiler-cli@21.2.12(@angular/compiler@21.2.12)(typescript@5.9.3))(tslib@2.8.1)(typescript@5.9.3) + postcss: 8.5.14 + vitest: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.2)(@vitest/coverage-v8@4.1.5)(jsdom@29.1.1(@noble/hashes@1.8.0))(vite@8.0.11(@types/node@25.6.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.6.4)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.4)) + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + - '@types/node' + - '@vitejs/devtools' + - chokidar + - jiti + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + '@angular/cli@21.2.10(@types/node@25.6.2)(chokidar@5.0.0)': + dependencies: + '@angular-devkit/architect': 0.2102.10(chokidar@5.0.0) + '@angular-devkit/core': 21.2.10(chokidar@5.0.0) + '@angular-devkit/schematics': 21.2.10(chokidar@5.0.0) + '@inquirer/prompts': 7.10.1(@types/node@25.6.2) + '@listr2/prompt-adapter-inquirer': 3.0.5(@inquirer/prompts@7.10.1(@types/node@25.6.2))(@types/node@25.6.2)(listr2@9.0.5) + '@modelcontextprotocol/sdk': 1.26.0(zod@4.3.6) + '@schematics/angular': 21.2.10(chokidar@5.0.0) + '@yarnpkg/lockfile': 1.1.0 + algoliasearch: 5.48.1 + ini: 6.0.0 + jsonc-parser: 3.3.1 + listr2: 9.0.5 + npm-package-arg: 13.0.2 + pacote: 21.3.1 + parse5-html-rewriting-stream: 8.0.0 + semver: 7.7.4 + yargs: 18.0.0 + zod: 4.3.6 + transitivePeerDependencies: + - '@cfworker/json-schema' + - '@types/node' + - chokidar + - supports-color + + '@angular/common@21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2)': + dependencies: + '@angular/core': 21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2) + rxjs: 7.8.2 + tslib: 2.8.1 + + '@angular/compiler-cli@21.2.12(@angular/compiler@21.2.12)(typescript@5.9.3)': + dependencies: + '@angular/compiler': 21.2.12 + '@babel/core': 7.29.0 + '@jridgewell/sourcemap-codec': 1.5.5 + chokidar: 5.0.0 + convert-source-map: 1.9.0 + reflect-metadata: 0.2.2 + semver: 7.7.4 + tslib: 2.8.1 + yargs: 18.0.0 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@angular/compiler@21.2.12': + dependencies: + tslib: 2.8.1 + + '@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2)': + dependencies: + rxjs: 7.8.2 + tslib: 2.8.1 + optionalDependencies: + '@angular/compiler': 21.2.12 + zone.js: 0.16.2 + + '@angular/forms@21.2.12(@angular/common@21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2))(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(@angular/platform-browser@21.2.12(@angular/common@21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2))(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2)))(rxjs@7.8.2)': + dependencies: + '@angular/common': 21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2) + '@angular/core': 21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2) + '@angular/platform-browser': 21.2.12(@angular/common@21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2))(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2)) + '@standard-schema/spec': 1.1.0 + rxjs: 7.8.2 + tslib: 2.8.1 + + '@angular/platform-browser@21.2.12(@angular/common@21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2))(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))': + dependencies: + '@angular/common': 21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2) + '@angular/core': 21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2) + tslib: 2.8.1 + + '@angular/router@21.2.12(@angular/common@21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2))(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(@angular/platform-browser@21.2.12(@angular/common@21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2))(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2)))(rxjs@7.8.2)': + dependencies: + '@angular/common': 21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2) + '@angular/core': 21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2) + '@angular/platform-browser': 21.2.12(@angular/common@21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2))(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2)) + rxjs: 7.8.2 + tslib: 2.8.1 + '@asamuzakjp/css-color@5.1.11': dependencies: '@asamuzakjp/generational-cache': 1.0.1 @@ -6164,6 +8175,10 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-split-export-declaration@7.24.7': + dependencies: + '@babel/types': 7.29.0 + '@babel/helper-string-parser@7.27.1': {} '@babel/helper-validator-identifier@7.28.5': {} @@ -6467,156 +8482,312 @@ snapshots: '@esbuild/aix-ppc64@0.25.12': optional: true + '@esbuild/aix-ppc64@0.27.3': + optional: true + + '@esbuild/aix-ppc64@0.27.7': + optional: true + '@esbuild/aix-ppc64@0.28.0': optional: true '@esbuild/android-arm64@0.25.12': optional: true + '@esbuild/android-arm64@0.27.3': + optional: true + + '@esbuild/android-arm64@0.27.7': + optional: true + '@esbuild/android-arm64@0.28.0': optional: true '@esbuild/android-arm@0.25.12': optional: true + '@esbuild/android-arm@0.27.3': + optional: true + + '@esbuild/android-arm@0.27.7': + optional: true + '@esbuild/android-arm@0.28.0': optional: true '@esbuild/android-x64@0.25.12': optional: true + '@esbuild/android-x64@0.27.3': + optional: true + + '@esbuild/android-x64@0.27.7': + optional: true + '@esbuild/android-x64@0.28.0': optional: true '@esbuild/darwin-arm64@0.25.12': optional: true + '@esbuild/darwin-arm64@0.27.3': + optional: true + + '@esbuild/darwin-arm64@0.27.7': + optional: true + '@esbuild/darwin-arm64@0.28.0': optional: true '@esbuild/darwin-x64@0.25.12': optional: true + '@esbuild/darwin-x64@0.27.3': + optional: true + + '@esbuild/darwin-x64@0.27.7': + optional: true + '@esbuild/darwin-x64@0.28.0': optional: true '@esbuild/freebsd-arm64@0.25.12': optional: true + '@esbuild/freebsd-arm64@0.27.3': + optional: true + + '@esbuild/freebsd-arm64@0.27.7': + optional: true + '@esbuild/freebsd-arm64@0.28.0': optional: true '@esbuild/freebsd-x64@0.25.12': optional: true + '@esbuild/freebsd-x64@0.27.3': + optional: true + + '@esbuild/freebsd-x64@0.27.7': + optional: true + '@esbuild/freebsd-x64@0.28.0': optional: true '@esbuild/linux-arm64@0.25.12': optional: true + '@esbuild/linux-arm64@0.27.3': + optional: true + + '@esbuild/linux-arm64@0.27.7': + optional: true + '@esbuild/linux-arm64@0.28.0': optional: true '@esbuild/linux-arm@0.25.12': optional: true + '@esbuild/linux-arm@0.27.3': + optional: true + + '@esbuild/linux-arm@0.27.7': + optional: true + '@esbuild/linux-arm@0.28.0': optional: true '@esbuild/linux-ia32@0.25.12': optional: true + '@esbuild/linux-ia32@0.27.3': + optional: true + + '@esbuild/linux-ia32@0.27.7': + optional: true + '@esbuild/linux-ia32@0.28.0': optional: true '@esbuild/linux-loong64@0.25.12': optional: true + '@esbuild/linux-loong64@0.27.3': + optional: true + + '@esbuild/linux-loong64@0.27.7': + optional: true + '@esbuild/linux-loong64@0.28.0': optional: true '@esbuild/linux-mips64el@0.25.12': optional: true + '@esbuild/linux-mips64el@0.27.3': + optional: true + + '@esbuild/linux-mips64el@0.27.7': + optional: true + '@esbuild/linux-mips64el@0.28.0': optional: true '@esbuild/linux-ppc64@0.25.12': optional: true + '@esbuild/linux-ppc64@0.27.3': + optional: true + + '@esbuild/linux-ppc64@0.27.7': + optional: true + '@esbuild/linux-ppc64@0.28.0': optional: true '@esbuild/linux-riscv64@0.25.12': optional: true + '@esbuild/linux-riscv64@0.27.3': + optional: true + + '@esbuild/linux-riscv64@0.27.7': + optional: true + '@esbuild/linux-riscv64@0.28.0': optional: true '@esbuild/linux-s390x@0.25.12': optional: true + '@esbuild/linux-s390x@0.27.3': + optional: true + + '@esbuild/linux-s390x@0.27.7': + optional: true + '@esbuild/linux-s390x@0.28.0': optional: true '@esbuild/linux-x64@0.25.12': optional: true + '@esbuild/linux-x64@0.27.3': + optional: true + + '@esbuild/linux-x64@0.27.7': + optional: true + '@esbuild/linux-x64@0.28.0': optional: true '@esbuild/netbsd-arm64@0.25.12': optional: true + '@esbuild/netbsd-arm64@0.27.3': + optional: true + + '@esbuild/netbsd-arm64@0.27.7': + optional: true + '@esbuild/netbsd-arm64@0.28.0': optional: true '@esbuild/netbsd-x64@0.25.12': optional: true + '@esbuild/netbsd-x64@0.27.3': + optional: true + + '@esbuild/netbsd-x64@0.27.7': + optional: true + '@esbuild/netbsd-x64@0.28.0': optional: true '@esbuild/openbsd-arm64@0.25.12': optional: true + '@esbuild/openbsd-arm64@0.27.3': + optional: true + + '@esbuild/openbsd-arm64@0.27.7': + optional: true + '@esbuild/openbsd-arm64@0.28.0': optional: true '@esbuild/openbsd-x64@0.25.12': optional: true + '@esbuild/openbsd-x64@0.27.3': + optional: true + + '@esbuild/openbsd-x64@0.27.7': + optional: true + '@esbuild/openbsd-x64@0.28.0': optional: true '@esbuild/openharmony-arm64@0.25.12': optional: true + '@esbuild/openharmony-arm64@0.27.3': + optional: true + + '@esbuild/openharmony-arm64@0.27.7': + optional: true + '@esbuild/openharmony-arm64@0.28.0': optional: true '@esbuild/sunos-x64@0.25.12': optional: true + '@esbuild/sunos-x64@0.27.3': + optional: true + + '@esbuild/sunos-x64@0.27.7': + optional: true + '@esbuild/sunos-x64@0.28.0': optional: true '@esbuild/win32-arm64@0.25.12': optional: true + '@esbuild/win32-arm64@0.27.3': + optional: true + + '@esbuild/win32-arm64@0.27.7': + optional: true + '@esbuild/win32-arm64@0.28.0': optional: true '@esbuild/win32-ia32@0.25.12': optional: true + '@esbuild/win32-ia32@0.27.3': + optional: true + + '@esbuild/win32-ia32@0.27.7': + optional: true + '@esbuild/win32-ia32@0.28.0': optional: true '@esbuild/win32-x64@0.25.12': optional: true + '@esbuild/win32-x64@0.27.3': + optional: true + + '@esbuild/win32-x64@0.27.7': + optional: true + '@esbuild/win32-x64@0.28.0': optional: true @@ -6707,6 +8878,15 @@ snapshots: '@fastify/accept-negotiator@2.0.1': optional: true + '@gar/promise-retry@1.0.3': {} + + '@harperfast/extended-iterable@1.0.3': + optional: true + + '@hono/node-server@1.19.14(hono@4.12.18)': + dependencies: + hono: 4.12.18 + '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.7': @@ -6815,6 +8995,54 @@ snapshots: '@img/sharp-win32-x64@0.34.5': optional: true + '@inquirer/ansi@1.0.2': {} + + '@inquirer/checkbox@4.3.2(@types/node@25.6.2)': + dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2(@types/node@25.6.2) + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@25.6.2) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 25.6.2 + + '@inquirer/confirm@5.1.21(@types/node@25.6.2)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@25.6.2) + '@inquirer/type': 3.0.10(@types/node@25.6.2) + optionalDependencies: + '@types/node': 25.6.2 + + '@inquirer/core@10.3.2(@types/node@25.6.2)': + dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@25.6.2) + cli-width: 4.1.0 + mute-stream: 2.0.0 + signal-exit: 4.1.0 + wrap-ansi: 6.2.0 + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 25.6.2 + + '@inquirer/editor@4.2.23(@types/node@25.6.2)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@25.6.2) + '@inquirer/external-editor': 1.0.3(@types/node@25.6.2) + '@inquirer/type': 3.0.10(@types/node@25.6.2) + optionalDependencies: + '@types/node': 25.6.2 + + '@inquirer/expand@4.0.23(@types/node@25.6.2)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@25.6.2) + '@inquirer/type': 3.0.10(@types/node@25.6.2) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 25.6.2 + '@inquirer/external-editor@1.0.3(@types/node@25.6.2)': dependencies: chardet: 2.1.1 @@ -6822,6 +9050,76 @@ snapshots: optionalDependencies: '@types/node': 25.6.2 + '@inquirer/figures@1.0.15': {} + + '@inquirer/input@4.3.1(@types/node@25.6.2)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@25.6.2) + '@inquirer/type': 3.0.10(@types/node@25.6.2) + optionalDependencies: + '@types/node': 25.6.2 + + '@inquirer/number@3.0.23(@types/node@25.6.2)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@25.6.2) + '@inquirer/type': 3.0.10(@types/node@25.6.2) + optionalDependencies: + '@types/node': 25.6.2 + + '@inquirer/password@4.0.23(@types/node@25.6.2)': + dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2(@types/node@25.6.2) + '@inquirer/type': 3.0.10(@types/node@25.6.2) + optionalDependencies: + '@types/node': 25.6.2 + + '@inquirer/prompts@7.10.1(@types/node@25.6.2)': + dependencies: + '@inquirer/checkbox': 4.3.2(@types/node@25.6.2) + '@inquirer/confirm': 5.1.21(@types/node@25.6.2) + '@inquirer/editor': 4.2.23(@types/node@25.6.2) + '@inquirer/expand': 4.0.23(@types/node@25.6.2) + '@inquirer/input': 4.3.1(@types/node@25.6.2) + '@inquirer/number': 3.0.23(@types/node@25.6.2) + '@inquirer/password': 4.0.23(@types/node@25.6.2) + '@inquirer/rawlist': 4.1.11(@types/node@25.6.2) + '@inquirer/search': 3.2.2(@types/node@25.6.2) + '@inquirer/select': 4.4.2(@types/node@25.6.2) + optionalDependencies: + '@types/node': 25.6.2 + + '@inquirer/rawlist@4.1.11(@types/node@25.6.2)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@25.6.2) + '@inquirer/type': 3.0.10(@types/node@25.6.2) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 25.6.2 + + '@inquirer/search@3.2.2(@types/node@25.6.2)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@25.6.2) + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@25.6.2) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 25.6.2 + + '@inquirer/select@4.4.2(@types/node@25.6.2)': + dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2(@types/node@25.6.2) + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@25.6.2) + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 25.6.2 + + '@inquirer/type@3.0.10(@types/node@25.6.2)': + optionalDependencies: + '@types/node': 25.6.2 + '@ioredis/commands@1.5.1': {} '@isaacs/cliui@9.0.0': {} @@ -6830,6 +9128,8 @@ snapshots: dependencies: minipass: 7.1.3 + '@istanbuljs/schema@0.1.6': {} + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -6862,6 +9162,35 @@ snapshots: '@kwsites/promise-deferred@1.1.1': {} + '@listr2/prompt-adapter-inquirer@3.0.5(@inquirer/prompts@7.10.1(@types/node@25.6.2))(@types/node@25.6.2)(listr2@9.0.5)': + dependencies: + '@inquirer/prompts': 7.10.1(@types/node@25.6.2) + '@inquirer/type': 3.0.10(@types/node@25.6.2) + listr2: 9.0.5 + transitivePeerDependencies: + - '@types/node' + + '@lmdb/lmdb-darwin-arm64@3.5.1': + optional: true + + '@lmdb/lmdb-darwin-x64@3.5.1': + optional: true + + '@lmdb/lmdb-linux-arm64@3.5.1': + optional: true + + '@lmdb/lmdb-linux-arm@3.5.1': + optional: true + + '@lmdb/lmdb-linux-x64@3.5.1': + optional: true + + '@lmdb/lmdb-win32-arm64@3.5.1': + optional: true + + '@lmdb/lmdb-win32-x64@3.5.1': + optional: true + '@manypkg/find-root@1.1.0': dependencies: '@babel/runtime': 7.28.6 @@ -6891,6 +9220,118 @@ snapshots: - encoding - supports-color + '@modelcontextprotocol/sdk@1.26.0(zod@4.3.6)': + dependencies: + '@hono/node-server': 1.19.14(hono@4.12.18) + ajv: 8.20.0 + ajv-formats: 3.0.1(ajv@8.20.0) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.0.8 + express: 5.2.1 + express-rate-limit: 8.5.1(express@5.2.1) + hono: 4.12.18 + jose: 6.2.3 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 4.3.6 + zod-to-json-schema: 3.25.2(zod@4.3.6) + transitivePeerDependencies: + - supports-color + + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': + optional: true + + '@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3': + optional: true + + '@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3': + optional: true + + '@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3': + optional: true + + '@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3': + optional: true + + '@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3': + optional: true + + '@napi-rs/nice-android-arm-eabi@1.1.1': + optional: true + + '@napi-rs/nice-android-arm64@1.1.1': + optional: true + + '@napi-rs/nice-darwin-arm64@1.1.1': + optional: true + + '@napi-rs/nice-darwin-x64@1.1.1': + optional: true + + '@napi-rs/nice-freebsd-x64@1.1.1': + optional: true + + '@napi-rs/nice-linux-arm-gnueabihf@1.1.1': + optional: true + + '@napi-rs/nice-linux-arm64-gnu@1.1.1': + optional: true + + '@napi-rs/nice-linux-arm64-musl@1.1.1': + optional: true + + '@napi-rs/nice-linux-ppc64-gnu@1.1.1': + optional: true + + '@napi-rs/nice-linux-riscv64-gnu@1.1.1': + optional: true + + '@napi-rs/nice-linux-s390x-gnu@1.1.1': + optional: true + + '@napi-rs/nice-linux-x64-gnu@1.1.1': + optional: true + + '@napi-rs/nice-linux-x64-musl@1.1.1': + optional: true + + '@napi-rs/nice-openharmony-arm64@1.1.1': + optional: true + + '@napi-rs/nice-win32-arm64-msvc@1.1.1': + optional: true + + '@napi-rs/nice-win32-ia32-msvc@1.1.1': + optional: true + + '@napi-rs/nice-win32-x64-msvc@1.1.1': + optional: true + + '@napi-rs/nice@1.1.1': + optionalDependencies: + '@napi-rs/nice-android-arm-eabi': 1.1.1 + '@napi-rs/nice-android-arm64': 1.1.1 + '@napi-rs/nice-darwin-arm64': 1.1.1 + '@napi-rs/nice-darwin-x64': 1.1.1 + '@napi-rs/nice-freebsd-x64': 1.1.1 + '@napi-rs/nice-linux-arm-gnueabihf': 1.1.1 + '@napi-rs/nice-linux-arm64-gnu': 1.1.1 + '@napi-rs/nice-linux-arm64-musl': 1.1.1 + '@napi-rs/nice-linux-ppc64-gnu': 1.1.1 + '@napi-rs/nice-linux-riscv64-gnu': 1.1.1 + '@napi-rs/nice-linux-s390x-gnu': 1.1.1 + '@napi-rs/nice-linux-x64-gnu': 1.1.1 + '@napi-rs/nice-linux-x64-musl': 1.1.1 + '@napi-rs/nice-openharmony-arm64': 1.1.1 + '@napi-rs/nice-win32-arm64-msvc': 1.1.1 + '@napi-rs/nice-win32-ia32-msvc': 1.1.1 + '@napi-rs/nice-win32-x64-msvc': 1.1.1 + optional: true + '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: '@emnapi/core': 1.10.0 @@ -6913,6 +9354,62 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.1 + '@npmcli/agent@4.0.0': + dependencies: + agent-base: 7.1.4 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + lru-cache: 11.3.6 + socks-proxy-agent: 8.0.5 + transitivePeerDependencies: + - supports-color + + '@npmcli/fs@5.0.0': + dependencies: + semver: 7.7.4 + + '@npmcli/git@7.0.2': + dependencies: + '@gar/promise-retry': 1.0.3 + '@npmcli/promise-spawn': 9.0.1 + ini: 6.0.0 + lru-cache: 11.3.6 + npm-pick-manifest: 11.0.3 + proc-log: 6.1.0 + semver: 7.7.4 + which: 6.0.1 + + '@npmcli/installed-package-contents@4.0.0': + dependencies: + npm-bundled: 5.0.0 + npm-normalize-package-bin: 5.0.0 + + '@npmcli/node-gyp@5.0.0': {} + + '@npmcli/package-json@7.0.5': + dependencies: + '@npmcli/git': 7.0.2 + glob: 13.0.6 + hosted-git-info: 9.0.3 + json-parse-even-better-errors: 5.0.0 + proc-log: 6.1.0 + semver: 7.7.4 + spdx-expression-parse: 4.0.0 + + '@npmcli/promise-spawn@9.0.1': + dependencies: + which: 6.0.1 + + '@npmcli/redact@4.0.0': {} + + '@npmcli/run-script@10.0.4': + dependencies: + '@npmcli/node-gyp': 5.0.0 + '@npmcli/package-json': 7.0.5 + '@npmcli/promise-spawn': 9.0.1 + node-gyp: 12.3.0 + proc-log: 6.1.0 + '@nuxt/cli@3.35.1(@nuxt/schema@4.4.4)(cac@6.7.14)(magicast@0.5.2)': dependencies: '@bomb.sh/tab': 0.0.14(cac@6.7.14)(citty@0.2.2) @@ -7479,6 +9976,8 @@ snapshots: '@oxc-parser/binding-win32-x64-msvc@0.128.0': optional: true + '@oxc-project/types@0.113.0': {} + '@oxc-project/types@0.128.0': {} '@oxc-transform/binding-android-arm-eabi@0.128.0': @@ -7631,24 +10130,45 @@ snapshots: '@rolldown/binding-android-arm64@1.0.0-rc.18': optional: true + '@rolldown/binding-android-arm64@1.0.0-rc.4': + optional: true + '@rolldown/binding-darwin-arm64@1.0.0-rc.18': optional: true + '@rolldown/binding-darwin-arm64@1.0.0-rc.4': + optional: true + '@rolldown/binding-darwin-x64@1.0.0-rc.18': optional: true + '@rolldown/binding-darwin-x64@1.0.0-rc.4': + optional: true + '@rolldown/binding-freebsd-x64@1.0.0-rc.18': optional: true + '@rolldown/binding-freebsd-x64@1.0.0-rc.4': + optional: true + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.18': optional: true + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.4': + optional: true + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.18': optional: true + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.4': + optional: true + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.18': optional: true + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.4': + optional: true + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.18': optional: true @@ -7658,29 +10178,54 @@ snapshots: '@rolldown/binding-linux-x64-gnu@1.0.0-rc.18': optional: true + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.4': + optional: true + '@rolldown/binding-linux-x64-musl@1.0.0-rc.18': optional: true + '@rolldown/binding-linux-x64-musl@1.0.0-rc.4': + optional: true + '@rolldown/binding-openharmony-arm64@1.0.0-rc.18': optional: true + '@rolldown/binding-openharmony-arm64@1.0.0-rc.4': + optional: true + '@rolldown/binding-wasm32-wasi@1.0.0-rc.18': dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.0-rc.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + dependencies: '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' optional: true '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.18': optional: true + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.4': + optional: true + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.18': optional: true + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.4': + optional: true + '@rolldown/pluginutils@1.0.0-rc.13': {} '@rolldown/pluginutils@1.0.0-rc.18': {} + '@rolldown/pluginutils@1.0.0-rc.4': {} + '@rolldown/pluginutils@1.0.0-rc.7': {} '@rollup/plugin-alias@5.1.1(rollup@4.60.3)': @@ -7837,6 +10382,52 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.60.3': optional: true + '@rollup/wasm-node@4.60.3': + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + + '@schematics/angular@21.2.10(chokidar@5.0.0)': + dependencies: + '@angular-devkit/core': 21.2.10(chokidar@5.0.0) + '@angular-devkit/schematics': 21.2.10(chokidar@5.0.0) + jsonc-parser: 3.3.1 + transitivePeerDependencies: + - chokidar + + '@sigstore/bundle@4.0.0': + dependencies: + '@sigstore/protobuf-specs': 0.5.1 + + '@sigstore/core@3.2.0': {} + + '@sigstore/protobuf-specs@0.5.1': {} + + '@sigstore/sign@4.1.1': + dependencies: + '@gar/promise-retry': 1.0.3 + '@sigstore/bundle': 4.0.0 + '@sigstore/core': 3.2.0 + '@sigstore/protobuf-specs': 0.5.1 + make-fetch-happen: 15.0.5 + proc-log: 6.1.0 + transitivePeerDependencies: + - supports-color + + '@sigstore/tuf@4.0.2': + dependencies: + '@sigstore/protobuf-specs': 0.5.1 + tuf-js: 4.1.0 + transitivePeerDependencies: + - supports-color + + '@sigstore/verify@3.1.0': + dependencies: + '@sigstore/bundle': 4.0.0 + '@sigstore/core': 3.2.0 + '@sigstore/protobuf-specs': 0.5.1 + '@sindresorhus/is@7.2.0': {} '@sindresorhus/merge-streams@4.0.0': {} @@ -7858,6 +10449,15 @@ snapshots: vite: 8.0.11(@types/node@25.6.2)(esbuild@0.28.0)(jiti@2.6.1)(less@4.6.4)(sass@1.99.0)(terser@5.46.0)(yaml@2.8.4) vitefu: 1.1.2(vite@8.0.11(@types/node@25.6.2)(esbuild@0.28.0)(jiti@2.6.1)(less@4.6.4)(sass@1.99.0)(terser@5.46.0)(yaml@2.8.4)) + '@testing-library/angular@19.2.1(@angular/common@21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2))(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(@angular/platform-browser@21.2.12(@angular/common@21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2))(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2)))(@angular/router@21.2.12(@angular/common@21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2))(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(@angular/platform-browser@21.2.12(@angular/common@21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2))(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2)))(rxjs@7.8.2))(@testing-library/dom@10.4.1)': + dependencies: + '@angular/common': 21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2) + '@angular/core': 21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2) + '@angular/platform-browser': 21.2.12(@angular/common@21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2))(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2)) + '@angular/router': 21.2.12(@angular/common@21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2))(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(@angular/platform-browser@21.2.12(@angular/common@21.2.12(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2))(rxjs@7.8.2))(@angular/core@21.2.12(@angular/compiler@21.2.12)(rxjs@7.8.2)(zone.js@0.16.2)))(rxjs@7.8.2) + '@testing-library/dom': 10.4.1 + tslib: 2.8.1 + '@testing-library/dom@10.4.1': dependencies: '@babel/code-frame': 7.29.0 @@ -7912,6 +10512,13 @@ snapshots: optionalDependencies: '@vue/compiler-sfc': 3.5.34 + '@tufjs/canonical-json@2.0.0': {} + + '@tufjs/models@4.1.0': + dependencies: + '@tufjs/canonical-json': 2.0.0 + minimatch: 10.2.5 + '@tybys/wasm-util@0.10.1': dependencies: tslib: 2.8.1 @@ -8066,6 +10673,10 @@ snapshots: - rollup - supports-color + '@vitejs/plugin-basic-ssl@2.1.4(vite@8.0.11(@types/node@25.6.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.6.4)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.4))': + dependencies: + vite: 8.0.11(@types/node@25.6.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.6.4)(sass@1.99.0)(terser@5.46.0)(yaml@2.8.4) + '@vitejs/plugin-react@6.0.1(vite@8.0.11(@types/node@25.6.2)(esbuild@0.28.0)(jiti@2.6.1)(less@4.6.4)(sass@1.99.0)(terser@5.46.0)(yaml@2.8.4))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.7 @@ -8101,7 +10712,7 @@ snapshots: obug: 2.1.1 std-env: 4.1.0 tinyrainbow: 3.1.0 - vitest: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.2)(@vitest/coverage-v8@4.1.5)(jsdom@29.1.1(@noble/hashes@1.8.0))(vite@8.0.11(@types/node@25.6.2)(esbuild@0.28.0)(jiti@2.6.1)(less@4.6.4)(sass@1.99.0)(terser@5.46.0)(yaml@2.8.4)) + vitest: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.2)(@vitest/coverage-v8@4.1.5)(jsdom@29.1.1(@noble/hashes@1.8.0))(vite@8.0.11(@types/node@25.6.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.6.4)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.4)) '@vitest/expect@4.1.5': dependencies: @@ -8112,6 +10723,14 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.0 + '@vitest/mocker@4.1.5(vite@8.0.11(@types/node@25.6.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.6.4)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.4))': + dependencies: + '@vitest/spy': 4.1.5 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 8.0.11(@types/node@25.6.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.6.4)(sass@1.99.0)(terser@5.46.0)(yaml@2.8.4) + '@vitest/mocker@4.1.5(vite@8.0.11(@types/node@25.6.2)(esbuild@0.28.0)(jiti@2.6.1)(less@4.6.4)(sass@1.99.0)(terser@5.46.0)(yaml@2.8.4))': dependencies: '@vitest/spy': 4.1.5 @@ -8283,14 +10902,23 @@ snapshots: js-beautify: 1.15.4 vue-component-type-helpers: 2.2.12 + '@yarnpkg/lockfile@1.1.0': {} + abbrev@2.0.0: {} abbrev@3.0.1: {} + abbrev@4.0.0: {} + abort-controller@3.0.0: dependencies: event-target-shim: 5.0.1 + accepts@2.0.0: + dependencies: + mime-types: 3.0.2 + negotiator: 1.0.0 + acorn-import-attributes@1.9.5(acorn@8.16.0): dependencies: acorn: 8.16.0 @@ -8303,6 +10931,14 @@ snapshots: agent-base@7.1.4: {} + ajv-formats@3.0.1(ajv@8.18.0): + optionalDependencies: + ajv: 8.18.0 + + ajv-formats@3.0.1(ajv@8.20.0): + optionalDependencies: + ajv: 8.20.0 + ajv@6.14.0: dependencies: fast-deep-equal: 3.1.3 @@ -8310,8 +10946,58 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 + ajv@8.18.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.2 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + ajv@8.20.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.2 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + algoliasearch@5.48.1: + dependencies: + '@algolia/abtesting': 1.14.1 + '@algolia/client-abtesting': 5.48.1 + '@algolia/client-analytics': 5.48.1 + '@algolia/client-common': 5.48.1 + '@algolia/client-insights': 5.48.1 + '@algolia/client-personalization': 5.48.1 + '@algolia/client-query-suggestions': 5.48.1 + '@algolia/client-search': 5.48.1 + '@algolia/ingestion': 1.48.1 + '@algolia/monitoring': 1.48.1 + '@algolia/recommend': 5.48.1 + '@algolia/requester-browser-xhr': 5.48.1 + '@algolia/requester-fetch': 5.48.1 + '@algolia/requester-node-http': 5.48.1 + alien-signals@3.1.2: {} + angular-eslint@21.3.1(@angular/cli@21.2.10(@types/node@25.6.2)(chokidar@5.0.0))(chokidar@5.0.0)(eslint@9.39.4(jiti@2.6.1))(typescript-eslint@8.59.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(typescript@5.9.3): + dependencies: + '@angular-devkit/core': 21.2.10(chokidar@5.0.0) + '@angular-devkit/schematics': 21.2.10(chokidar@5.0.0) + '@angular-eslint/builder': 21.3.1(@angular/cli@21.2.10(@types/node@25.6.2)(chokidar@5.0.0))(chokidar@5.0.0)(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@angular-eslint/eslint-plugin': 21.3.1(@typescript-eslint/utils@8.59.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@angular-eslint/eslint-plugin-template': 21.3.1(@angular-eslint/template-parser@21.3.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(@typescript-eslint/types@8.59.2)(@typescript-eslint/utils@8.59.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@angular-eslint/schematics': 21.3.1(@angular-eslint/template-parser@21.3.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(@angular/cli@21.2.10(@types/node@25.6.2)(chokidar@5.0.0))(@typescript-eslint/types@8.59.2)(@typescript-eslint/utils@8.59.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(chokidar@5.0.0)(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@angular-eslint/template-parser': 21.3.1(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@angular/cli': 21.2.10(@types/node@25.6.2)(chokidar@5.0.0) + '@typescript-eslint/types': 8.59.2 + '@typescript-eslint/utils': 8.59.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.4(jiti@2.6.1) + typescript: 5.9.3 + typescript-eslint: 8.59.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + transitivePeerDependencies: + - chokidar + - supports-color + ansi-colors@4.1.3: {} ansi-escapes@7.3.0: @@ -8376,6 +11062,8 @@ snapshots: aria-query@5.3.1: {} + aria-query@5.3.2: {} + array-buffer-byte-length@1.0.2: dependencies: call-bound: 1.0.4 @@ -8488,6 +11176,18 @@ snapshots: baseline-browser-mapping@2.10.27: {} + beasties@0.4.1: + dependencies: + css-select: 6.0.0 + css-what: 7.0.0 + dom-serializer: 2.0.0 + domhandler: 5.0.3 + htmlparser2: 10.1.0 + picocolors: 1.1.1 + postcss: 8.5.14 + postcss-media-query-parser: 0.2.3 + postcss-safe-parser: 7.0.1(postcss@8.5.14) + better-path-resolve@1.0.0: dependencies: is-windows: 1.0.2 @@ -8504,6 +11204,20 @@ snapshots: birpc@4.0.0: {} + body-parser@2.2.2: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.3 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + on-finished: 2.4.1 + qs: 6.15.1 + raw-body: 3.0.2 + type-is: 2.0.1 + transitivePeerDependencies: + - supports-color + boolbase@1.0.0: {} brace-expansion@1.1.12: @@ -8544,6 +11258,8 @@ snapshots: dependencies: run-applescript: 7.1.0 + bytes@3.1.2: {} + c12@3.3.4(magicast@0.5.2): dependencies: chokidar: 5.0.0 @@ -8563,6 +11279,19 @@ snapshots: cac@6.7.14: {} + cacache@20.0.4: + dependencies: + '@npmcli/fs': 5.0.0 + fs-minipass: 3.0.3 + glob: 13.0.6 + lru-cache: 11.3.6 + minipass: 7.1.3 + minipass-collect: 2.0.1 + minipass-flush: 1.0.7 + minipass-pipeline: 1.2.4 + p-map: 7.0.4 + ssri: 13.0.1 + call-bind-apply-helpers@1.0.2: dependencies: es-errors: 1.3.0 @@ -8622,11 +11351,15 @@ snapshots: dependencies: restore-cursor: 5.1.0 + cli-spinners@3.4.0: {} + cli-truncate@5.2.0: dependencies: slice-ansi: 8.0.0 string-width: 8.2.0 + cli-width@4.1.0: {} + cliui@9.0.1: dependencies: string-width: 7.2.0 @@ -8643,12 +11376,18 @@ snapshots: color-name@1.1.4: {} + colorette@2.0.20: {} + commander@10.0.1: {} commander@11.1.0: {} + commander@14.0.3: {} + commander@2.20.3: {} + common-path-prefix@3.0.0: {} + commondir@1.0.1: {} compatx@0.2.0: {} @@ -8674,6 +11413,12 @@ snapshots: consola@3.4.2: {} + content-disposition@1.1.0: {} + + content-type@1.0.5: {} + + convert-source-map@1.9.0: {} + convert-source-map@2.0.0: {} cookie-es@1.2.3: {} @@ -8682,13 +11427,21 @@ snapshots: cookie-es@3.1.1: {} + cookie-signature@1.2.2: {} + + cookie@0.7.2: {} + copy-anything@3.0.5: dependencies: is-what: 4.1.16 - optional: true core-util-is@1.0.3: {} + cors@2.8.6: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + crc-32@1.2.2: {} crc32-stream@6.0.0: @@ -8720,6 +11473,14 @@ snapshots: domutils: 3.2.2 nth-check: 2.1.1 + css-select@6.0.0: + dependencies: + boolbase: 1.0.0 + css-what: 7.0.0 + domhandler: 5.0.3 + domutils: 3.2.2 + nth-check: 2.1.1 + css-tree@2.2.1: dependencies: mdn-data: 2.0.28 @@ -8732,6 +11493,8 @@ snapshots: css-what@6.2.2: {} + css-what@7.0.0: {} + cssesc@3.0.0: {} cssfilter@0.0.10: @@ -8874,6 +11637,8 @@ snapshots: depd@2.0.0: {} + dependency-graph@1.0.0: {} + dequal@2.0.3: {} destr@2.0.5: {} @@ -8943,6 +11708,8 @@ snapshots: emoji-regex@10.6.0: {} + emoji-regex@8.0.0: {} + encodeurl@2.0.0: {} enquirer@2.4.1: @@ -8952,12 +11719,18 @@ snapshots: entities@4.5.0: {} + entities@6.0.1: {} + entities@7.0.1: {} entities@8.0.0: {} + env-paths@2.2.1: {} + environment@1.1.0: {} + err-code@2.0.3: {} + errno@0.1.8: dependencies: prr: 1.0.1 @@ -9112,6 +11885,64 @@ snapshots: '@esbuild/win32-ia32': 0.25.12 '@esbuild/win32-x64': 0.25.12 + esbuild@0.27.3: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.3 + '@esbuild/android-arm': 0.27.3 + '@esbuild/android-arm64': 0.27.3 + '@esbuild/android-x64': 0.27.3 + '@esbuild/darwin-arm64': 0.27.3 + '@esbuild/darwin-x64': 0.27.3 + '@esbuild/freebsd-arm64': 0.27.3 + '@esbuild/freebsd-x64': 0.27.3 + '@esbuild/linux-arm': 0.27.3 + '@esbuild/linux-arm64': 0.27.3 + '@esbuild/linux-ia32': 0.27.3 + '@esbuild/linux-loong64': 0.27.3 + '@esbuild/linux-mips64el': 0.27.3 + '@esbuild/linux-ppc64': 0.27.3 + '@esbuild/linux-riscv64': 0.27.3 + '@esbuild/linux-s390x': 0.27.3 + '@esbuild/linux-x64': 0.27.3 + '@esbuild/netbsd-arm64': 0.27.3 + '@esbuild/netbsd-x64': 0.27.3 + '@esbuild/openbsd-arm64': 0.27.3 + '@esbuild/openbsd-x64': 0.27.3 + '@esbuild/openharmony-arm64': 0.27.3 + '@esbuild/sunos-x64': 0.27.3 + '@esbuild/win32-arm64': 0.27.3 + '@esbuild/win32-ia32': 0.27.3 + '@esbuild/win32-x64': 0.27.3 + + esbuild@0.27.7: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 + esbuild@0.28.0: optionalDependencies: '@esbuild/aix-ppc64': 0.28.0 @@ -9360,6 +12191,12 @@ snapshots: events@3.3.0: {} + eventsource-parser@3.0.8: {} + + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.0.8 + execa@8.0.1: dependencies: cross-spawn: 7.0.6 @@ -9374,6 +12211,46 @@ snapshots: expect-type@1.3.0: {} + exponential-backoff@3.1.3: {} + + express-rate-limit@8.5.1(express@5.2.1): + dependencies: + express: 5.2.1 + ip-address: 10.2.0 + + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.2 + content-disposition: 1.1.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.2 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.15.1 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 + statuses: 2.0.2 + type-is: 2.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + exsolve@1.0.8: {} extendable-error@0.1.7: {} @@ -9404,6 +12281,8 @@ snapshots: dependencies: fast-string-truncated-width: 1.2.1 + fast-uri@3.1.2: {} + fast-wrap-ansi@0.1.6: dependencies: fast-string-width: 1.1.0 @@ -9436,6 +12315,24 @@ snapshots: dependencies: to-regex-range: 5.0.1 + finalhandler@2.1.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + find-cache-directory@6.0.0: + dependencies: + common-path-prefix: 3.0.0 + pkg-dir: 8.0.0 + + find-up-simple@1.0.1: {} + find-up@4.1.0: dependencies: locate-path: 5.0.0 @@ -9463,6 +12360,8 @@ snapshots: dependencies: is-callable: 1.2.7 + forwarded@0.2.0: {} + fraction.js@5.3.4: {} fresh@2.0.0: {} @@ -9479,6 +12378,10 @@ snapshots: jsonfile: 4.0.0 universalify: 0.1.2 + fs-minipass@3.0.3: + dependencies: + minipass: 7.1.3 + fsevents@2.3.2: optional: true @@ -9548,6 +12451,8 @@ snapshots: dependencies: is-glob: 4.0.3 + glob-to-regexp@0.4.1: {} + glob@13.0.6: dependencies: minimatch: 10.2.5 @@ -9636,10 +12541,16 @@ snapshots: dependencies: function-bind: 1.1.2 + hono@4.12.18: {} + hookable@5.5.3: {} hookable@6.1.1: {} + hosted-git-info@9.0.3: + dependencies: + lru-cache: 11.3.6 + html-encoding-sniffer@6.0.0(@noble/hashes@1.8.0): dependencies: '@exodus/bytes': 1.15.0(@noble/hashes@1.8.0) @@ -9648,6 +12559,15 @@ snapshots: html-escaper@2.0.2: {} + htmlparser2@10.1.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + entities: 7.0.1 + + http-cache-semantics@4.2.0: {} + http-errors@2.0.1: dependencies: depd: 2.0.0 @@ -9656,6 +12576,13 @@ snapshots: statuses: 2.0.2 toidentifier: 1.0.1 + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + http-shutdown@1.2.2: {} https-proxy-agent@7.0.6: @@ -9684,6 +12611,10 @@ snapshots: ieee754@1.2.1: {} + ignore-walk@8.0.0: + dependencies: + minimatch: 10.2.5 + ignore@5.3.2: {} ignore@7.0.5: {} @@ -9716,6 +12647,12 @@ snapshots: ini@4.1.1: {} + ini@6.0.0: {} + + injection-js@2.6.1: + dependencies: + tslib: 2.8.1 + internal-slot@1.1.0: dependencies: es-errors: 1.3.0 @@ -9736,6 +12673,10 @@ snapshots: transitivePeerDependencies: - supports-color + ip-address@10.2.0: {} + + ipaddr.js@1.9.1: {} + ipx@3.1.1(db0@0.3.4)(ioredis@5.10.1): dependencies: '@fastify/accept-negotiator': 2.0.1 @@ -9831,6 +12772,8 @@ snapshots: dependencies: call-bound: 1.0.4 + is-fullwidth-code-point@3.0.0: {} + is-fullwidth-code-point@5.1.0: dependencies: get-east-asian-width: 1.5.0 @@ -9858,6 +12801,8 @@ snapshots: global-directory: 4.0.1 is-path-inside: 4.0.0 + is-interactive@2.0.0: {} + is-map@2.0.3: {} is-module@1.0.0: {} @@ -9875,6 +12820,8 @@ snapshots: is-potential-custom-element-name@1.0.1: {} + is-promise@4.0.0: {} + is-reference@1.2.1: dependencies: '@types/estree': 1.0.8 @@ -9919,6 +12866,8 @@ snapshots: dependencies: which-typed-array: 1.1.20 + is-unicode-supported@2.1.0: {} + is-weakmap@2.0.2: {} is-weakref@1.1.1: @@ -9930,8 +12879,7 @@ snapshots: call-bound: 1.0.4 get-intrinsic: 1.3.0 - is-what@4.1.16: - optional: true + is-what@4.1.16: {} is-windows@1.0.2: {} @@ -9949,6 +12897,16 @@ snapshots: istanbul-lib-coverage@3.2.2: {} + istanbul-lib-instrument@6.0.3: + dependencies: + '@babel/core': 7.29.0 + '@babel/parser': 7.29.3 + '@istanbuljs/schema': 0.1.6 + istanbul-lib-coverage: 3.2.2 + semver: 7.7.4 + transitivePeerDependencies: + - supports-color + istanbul-lib-report@3.0.1: dependencies: istanbul-lib-coverage: 3.2.2 @@ -9977,6 +12935,8 @@ snapshots: jiti@2.6.1: {} + jose@6.2.3: {} + js-beautify@1.15.4: dependencies: config-chain: 1.1.13 @@ -10032,16 +12992,26 @@ snapshots: json-buffer@3.0.1: {} + json-parse-even-better-errors@5.0.0: {} + json-schema-traverse@0.4.1: {} + json-schema-traverse@1.0.0: {} + + json-schema-typed@8.0.2: {} + json-stable-stringify-without-jsonify@1.0.1: {} json5@2.2.3: {} + jsonc-parser@3.3.1: {} + jsonfile@4.0.0: optionalDependencies: graceful-fs: 4.2.11 + jsonparse@1.3.1: {} + jsx-ast-utils@3.3.5: dependencies: array-includes: 3.1.9 @@ -10082,7 +13052,6 @@ snapshots: mime: 1.6.0 needle: 3.5.0 source-map: 0.6.1 - optional: true levn@0.4.1: dependencies: @@ -10180,6 +13149,33 @@ snapshots: rfdc: 1.4.1 wrap-ansi: 10.0.0 + listr2@9.0.5: + dependencies: + cli-truncate: 5.2.0 + colorette: 2.0.20 + eventemitter3: 5.0.4 + log-update: 6.1.0 + rfdc: 1.4.1 + wrap-ansi: 9.0.2 + + lmdb@3.5.1: + dependencies: + '@harperfast/extended-iterable': 1.0.3 + msgpackr: 1.11.12 + node-addon-api: 6.1.0 + node-gyp-build-optional-packages: 5.2.2 + ordered-binary: 1.6.1 + weak-lru-cache: 1.2.2 + optionalDependencies: + '@lmdb/lmdb-darwin-arm64': 3.5.1 + '@lmdb/lmdb-darwin-x64': 3.5.1 + '@lmdb/lmdb-linux-arm': 3.5.1 + '@lmdb/lmdb-linux-arm64': 3.5.1 + '@lmdb/lmdb-linux-x64': 3.5.1 + '@lmdb/lmdb-win32-arm64': 3.5.1 + '@lmdb/lmdb-win32-x64': 3.5.1 + optional: true + local-pkg@1.1.2: dependencies: mlly: 1.8.2 @@ -10210,6 +13206,11 @@ snapshots: lodash@4.17.23: {} + log-symbols@7.0.1: + dependencies: + is-unicode-supported: 2.1.0 + yoctocolors: 2.1.2 + log-update@6.1.0: dependencies: ansi-escapes: 7.3.0 @@ -10264,15 +13265,36 @@ snapshots: dependencies: semver: 7.7.4 + make-fetch-happen@15.0.5: + dependencies: + '@gar/promise-retry': 1.0.3 + '@npmcli/agent': 4.0.0 + '@npmcli/redact': 4.0.0 + cacache: 20.0.4 + http-cache-semantics: 4.2.0 + minipass: 7.1.3 + minipass-fetch: 5.0.2 + minipass-flush: 1.0.7 + minipass-pipeline: 1.2.4 + negotiator: 1.0.0 + proc-log: 6.1.0 + ssri: 13.0.1 + transitivePeerDependencies: + - supports-color + math-intrinsics@1.1.0: {} mdn-data@2.0.28: {} mdn-data@2.27.1: {} + media-typer@1.1.0: {} + meow@13.2.0: optional: true + merge-descriptors@2.0.0: {} + merge-stream@2.0.0: {} merge2@1.4.1: {} @@ -10297,21 +13319,49 @@ snapshots: mimic-function@5.0.1: {} - minimatch@10.2.5: + minimatch@10.2.5: + dependencies: + brace-expansion: 5.0.5 + + minimatch@3.1.5: + dependencies: + brace-expansion: 1.1.12 + + minimatch@5.1.6: + dependencies: + brace-expansion: 2.0.2 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 + + minipass-collect@2.0.1: + dependencies: + minipass: 7.1.3 + + minipass-fetch@5.0.2: + dependencies: + minipass: 7.1.3 + minipass-sized: 2.0.0 + minizlib: 3.1.0 + optionalDependencies: + iconv-lite: 0.7.2 + + minipass-flush@1.0.7: dependencies: - brace-expansion: 5.0.5 + minipass: 3.3.6 - minimatch@3.1.5: + minipass-pipeline@1.2.4: dependencies: - brace-expansion: 1.1.12 + minipass: 3.3.6 - minimatch@5.1.6: + minipass-sized@2.0.0: dependencies: - brace-expansion: 2.0.2 + minipass: 7.1.3 - minimatch@9.0.5: + minipass@3.3.6: dependencies: - brace-expansion: 2.0.2 + yallist: 4.0.0 minipass@7.1.3: {} @@ -10356,8 +13406,27 @@ snapshots: ms@2.1.3: {} + msgpackr-extract@3.0.3: + dependencies: + node-gyp-build-optional-packages: 5.2.2 + optionalDependencies: + '@msgpackr-extract/msgpackr-extract-darwin-arm64': 3.0.3 + '@msgpackr-extract/msgpackr-extract-darwin-x64': 3.0.3 + '@msgpackr-extract/msgpackr-extract-linux-arm': 3.0.3 + '@msgpackr-extract/msgpackr-extract-linux-arm64': 3.0.3 + '@msgpackr-extract/msgpackr-extract-linux-x64': 3.0.3 + '@msgpackr-extract/msgpackr-extract-win32-x64': 3.0.3 + optional: true + + msgpackr@1.11.12: + optionalDependencies: + msgpackr-extract: 3.0.3 + optional: true + muggle-string@0.4.1: {} + mute-stream@2.0.0: {} + nanoid@3.3.11: {} nanotar@0.3.0: {} @@ -10370,6 +13439,37 @@ snapshots: sax: 1.5.0 optional: true + negotiator@1.0.0: {} + + ng-packagr@21.2.3(@angular/compiler-cli@21.2.12(@angular/compiler@21.2.12)(typescript@5.9.3))(tslib@2.8.1)(typescript@5.9.3): + dependencies: + '@ampproject/remapping': 2.3.0 + '@angular/compiler-cli': 21.2.12(@angular/compiler@21.2.12)(typescript@5.9.3) + '@rollup/plugin-json': 6.1.0(rollup@4.60.3) + '@rollup/wasm-node': 4.60.3 + ajv: 8.20.0 + ansi-colors: 4.1.3 + browserslist: 4.28.2 + chokidar: 5.0.0 + commander: 14.0.3 + dependency-graph: 1.0.0 + esbuild: 0.27.7 + find-cache-directory: 6.0.0 + injection-js: 2.6.1 + jsonc-parser: 3.3.1 + less: 4.6.4 + ora: 9.4.0 + piscina: 5.1.4 + postcss: 8.5.14 + rollup-plugin-dts: 6.4.1(rollup@4.60.3)(typescript@5.9.3) + rxjs: 7.8.2 + sass: 1.99.0 + tinyglobby: 0.2.16 + tslib: 2.8.1 + typescript: 5.9.3 + optionalDependencies: + rollup: 4.60.3 + nitropack@2.13.4(oxc-parser@0.128.0)(rolldown@1.0.0-rc.18): dependencies: '@cloudflare/kv-asset-handler': 0.4.2 @@ -10473,6 +13573,9 @@ snapshots: - supports-color - uploadthing + node-addon-api@6.1.0: + optional: true + node-addon-api@7.1.1: {} node-exports-info@1.6.0: @@ -10490,8 +13593,26 @@ snapshots: node-forge@1.4.0: {} + node-gyp-build-optional-packages@5.2.2: + dependencies: + detect-libc: 2.1.2 + optional: true + node-gyp-build@4.8.4: {} + node-gyp@12.3.0: + dependencies: + env-paths: 2.2.1 + exponential-backoff: 3.1.3 + graceful-fs: 4.2.11 + nopt: 9.0.0 + proc-log: 6.1.0 + semver: 7.7.4 + tar: 7.5.9 + tinyglobby: 0.2.16 + undici: 6.25.0 + which: 6.0.1 + node-mock-http@1.0.4: {} node-releases@2.0.38: {} @@ -10504,8 +13625,54 @@ snapshots: dependencies: abbrev: 3.0.1 + nopt@9.0.0: + dependencies: + abbrev: 4.0.0 + normalize-path@3.0.0: {} + npm-bundled@5.0.0: + dependencies: + npm-normalize-package-bin: 5.0.0 + + npm-install-checks@8.0.0: + dependencies: + semver: 7.7.4 + + npm-normalize-package-bin@5.0.0: {} + + npm-package-arg@13.0.2: + dependencies: + hosted-git-info: 9.0.3 + proc-log: 6.1.0 + semver: 7.7.4 + validate-npm-package-name: 7.0.2 + + npm-packlist@10.0.4: + dependencies: + ignore-walk: 8.0.0 + proc-log: 6.1.0 + + npm-pick-manifest@11.0.3: + dependencies: + npm-install-checks: 8.0.0 + npm-normalize-package-bin: 5.0.0 + npm-package-arg: 13.0.2 + semver: 7.7.4 + + npm-registry-fetch@19.1.1: + dependencies: + '@npmcli/redact': 4.0.0 + jsonparse: 1.3.1 + make-fetch-happen: 15.0.5 + minipass: 7.1.3 + minipass-fetch: 5.0.2 + minizlib: 3.1.0 + npm-package-arg: 13.0.2 + proc-log: 6.1.0 + transitivePeerDependencies: + - supports-color + npm-run-path@5.3.0: dependencies: path-key: 4.0.0 @@ -10741,6 +13908,10 @@ snapshots: dependencies: ee-first: 1.1.1 + once@1.4.0: + dependencies: + wrappy: 1.0.2 + onetime@6.0.0: dependencies: mimic-fn: 4.0.0 @@ -10774,6 +13945,31 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 + ora@9.3.0: + dependencies: + chalk: 5.6.2 + cli-cursor: 5.0.0 + cli-spinners: 3.4.0 + is-interactive: 2.0.0 + is-unicode-supported: 2.1.0 + log-symbols: 7.0.1 + stdin-discarder: 0.3.2 + string-width: 8.2.0 + + ora@9.4.0: + dependencies: + chalk: 5.6.2 + cli-cursor: 5.0.0 + cli-spinners: 3.4.0 + is-interactive: 2.0.0 + is-unicode-supported: 2.1.0 + log-symbols: 7.0.1 + stdin-discarder: 0.3.2 + string-width: 8.2.0 + + ordered-binary@1.6.1: + optional: true + outdent@0.5.0: {} own-keys@1.0.1: @@ -10880,6 +14076,8 @@ snapshots: p-map@2.1.0: {} + p-map@7.0.4: {} + p-try@2.2.0: {} package-json-from-dist@1.0.1: {} @@ -10888,12 +14086,43 @@ snapshots: dependencies: quansync: 0.2.11 + pacote@21.3.1: + dependencies: + '@npmcli/git': 7.0.2 + '@npmcli/installed-package-contents': 4.0.0 + '@npmcli/package-json': 7.0.5 + '@npmcli/promise-spawn': 9.0.1 + '@npmcli/run-script': 10.0.4 + cacache: 20.0.4 + fs-minipass: 3.0.3 + minipass: 7.1.3 + npm-package-arg: 13.0.2 + npm-packlist: 10.0.4 + npm-pick-manifest: 11.0.3 + npm-registry-fetch: 19.1.1 + proc-log: 6.1.0 + promise-retry: 2.0.1 + sigstore: 4.1.0 + ssri: 13.0.1 + tar: 7.5.9 + transitivePeerDependencies: + - supports-color + parent-module@1.0.1: dependencies: callsites: 3.1.0 - parse-node-version@1.0.1: - optional: true + parse-node-version@1.0.1: {} + + parse5-html-rewriting-stream@8.0.0: + dependencies: + entities: 6.0.1 + parse5: 8.0.1 + parse5-sax-parser: 8.0.0 + + parse5-sax-parser@8.0.0: + dependencies: + parse5: 8.0.1 parse5@8.0.1: dependencies: @@ -10918,6 +14147,8 @@ snapshots: lru-cache: 11.3.6 minipass: 7.1.3 + path-to-regexp@8.4.2: {} + path-type@4.0.0: {} pathe@1.1.2: {} @@ -10934,6 +14165,16 @@ snapshots: pify@4.0.1: {} + piscina@5.1.4: + optionalDependencies: + '@napi-rs/nice': 1.1.1 + + pkce-challenge@5.0.1: {} + + pkg-dir@8.0.0: + dependencies: + find-up-simple: 1.0.1 + pkg-types@1.3.1: dependencies: confbox: 0.1.8 @@ -11000,6 +14241,8 @@ snapshots: optionalDependencies: postcss: 8.5.14 + postcss-media-query-parser@0.2.3: {} + postcss-merge-longhand@7.0.7(postcss@8.5.14): dependencies: postcss: 8.5.14 @@ -11161,10 +14404,17 @@ snapshots: ansi-styles: 5.2.0 react-is: 17.0.2 + proc-log@6.1.0: {} + process-nextick-args@2.0.1: {} process@0.11.10: {} + promise-retry@2.0.1: + dependencies: + err-code: 2.0.3 + retry: 0.12.0 + prop-types@15.8.1: dependencies: loose-envify: 1.4.0 @@ -11179,11 +14429,20 @@ snapshots: proto-list@1.2.4: {} + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + prr@1.0.1: optional: true punycode@2.3.1: {} + qs@6.15.1: + dependencies: + side-channel: 1.1.0 + quansync@0.2.11: {} queue-microtask@1.2.3: {} @@ -11192,6 +14451,13 @@ snapshots: range-parser@1.2.1: {} + raw-body@3.0.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + unpipe: 1.0.0 + rc9@3.0.1: dependencies: defu: 6.1.7 @@ -11247,6 +14513,8 @@ snapshots: dependencies: redis-errors: 1.2.0 + reflect-metadata@0.2.2: {} + reflect.getprototypeof@1.0.10: dependencies: call-bind: 1.0.8 @@ -11327,8 +14595,33 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.18 '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.18 - rollup-plugin-dts@6.3.0(rollup@4.60.3)(typescript@5.9.3): + rolldown@1.0.0-rc.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0): dependencies: + '@oxc-project/types': 0.113.0 + '@rolldown/pluginutils': 1.0.0-rc.4 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.0-rc.4 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.4 + '@rolldown/binding-darwin-x64': 1.0.0-rc.4 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.4 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.4 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.4 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.4 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.4 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.4 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.4 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.4 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.4 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + + rollup-plugin-dts@6.4.1(rollup@4.60.3)(typescript@5.9.3): + dependencies: + '@jridgewell/remapping': 2.3.5 + '@jridgewell/sourcemap-codec': 1.5.5 + convert-source-map: 2.0.0 magic-string: 0.30.21 rollup: 4.60.3 typescript: 5.9.3 @@ -11378,12 +14671,26 @@ snapshots: rou3@0.8.1: {} + router@2.2.0: + dependencies: + debug: 4.4.3 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.4.2 + transitivePeerDependencies: + - supports-color + run-applescript@7.1.0: {} run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 + rxjs@7.8.2: + dependencies: + tslib: 2.8.1 + sade@1.8.1: dependencies: mri: 1.2.0 @@ -11413,6 +14720,14 @@ snapshots: safer-buffer@2.1.2: {} + sass@1.97.3: + dependencies: + chokidar: 4.0.3 + immutable: 5.1.5 + source-map-js: 1.2.1 + optionalDependencies: + '@parcel/watcher': 2.5.6 + sass@1.99.0: dependencies: chokidar: 4.0.3 @@ -11569,6 +14884,17 @@ snapshots: signal-exit@4.1.0: {} + sigstore@4.1.0: + dependencies: + '@sigstore/bundle': 4.0.0 + '@sigstore/core': 3.2.0 + '@sigstore/protobuf-specs': 0.5.1 + '@sigstore/sign': 4.1.1 + '@sigstore/tuf': 4.0.2 + '@sigstore/verify': 3.1.0 + transitivePeerDependencies: + - supports-color + simple-git@3.33.0: dependencies: '@kwsites/file-exists': 1.1.1 @@ -11604,8 +14930,23 @@ snapshots: ansi-styles: 6.2.3 is-fullwidth-code-point: 5.1.0 + smart-buffer@4.2.0: {} + smob@1.6.1: {} + socks-proxy-agent@8.0.5: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + socks: 2.8.9 + transitivePeerDependencies: + - supports-color + + socks@2.8.9: + dependencies: + ip-address: 10.2.0 + smart-buffer: 4.2.0 + source-map-js@1.2.1: {} source-map-support@0.5.21: @@ -11622,10 +14963,23 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 + spdx-exceptions@2.5.0: {} + + spdx-expression-parse@4.0.0: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.23 + + spdx-license-ids@3.0.23: {} + sprintf-js@1.0.3: {} srvx@0.11.15: {} + ssri@13.0.1: + dependencies: + minipass: 7.1.3 + stackback@0.0.2: {} standard-as-callback@2.1.0: {} @@ -11636,6 +14990,8 @@ snapshots: std-env@4.1.0: {} + stdin-discarder@0.3.2: {} + stop-iteration-iterator@1.1.0: dependencies: es-errors: 1.3.0 @@ -11652,6 +15008,12 @@ snapshots: string-argv@0.3.2: {} + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + string-width@7.2.0: dependencies: emoji-regex: 10.6.0 @@ -11848,6 +15210,11 @@ snapshots: tinyexec@1.1.2: {} + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + tinyglobby@0.2.16: dependencies: fdir: 6.5.0(picomatch@4.0.4) @@ -11887,8 +15254,15 @@ snapshots: optionalDependencies: typescript: 5.9.3 - tslib@2.8.1: - optional: true + tslib@2.8.1: {} + + tuf-js@4.1.0: + dependencies: + '@tufjs/models': 4.1.0 + debug: 4.4.3 + make-fetch-happen: 15.0.5 + transitivePeerDependencies: + - supports-color type-check@0.4.0: dependencies: @@ -11898,6 +15272,12 @@ snapshots: dependencies: tagged-tag: 1.0.0 + type-is@2.0.1: + dependencies: + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.2 + type-level-regexp@0.1.17: {} typed-array-buffer@1.0.3: @@ -11933,6 +15313,17 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 + typescript-eslint@8.59.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.59.2(@typescript-eslint/parser@8.59.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.59.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.59.2(typescript@5.9.3) + '@typescript-eslint/utils': 8.59.2(eslint@9.39.4(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.4(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + typescript@5.9.3: {} ufo@1.6.4: {} @@ -11968,7 +15359,7 @@ snapshots: pkg-types: 2.3.1 pretty-bytes: 7.1.0 rollup: 4.60.3 - rollup-plugin-dts: 6.3.0(rollup@4.60.3)(typescript@5.9.3) + rollup-plugin-dts: 6.4.1(rollup@4.60.3)(typescript@5.9.3) scule: 1.3.0 tinyglobby: 0.2.16 untyped: 2.0.0 @@ -11991,6 +15382,10 @@ snapshots: undici-types@7.19.2: {} + undici@6.25.0: {} + + undici@7.24.4: {} + undici@7.25.0: {} unenv@2.0.0-rc.24: @@ -12026,6 +15421,8 @@ snapshots: universalify@0.1.2: {} + unpipe@1.0.0: {} + unplugin-utils@0.3.1: dependencies: pathe: 2.0.3 @@ -12100,6 +15497,10 @@ snapshots: util-deprecate@1.0.2: {} + validate-npm-package-name@7.0.2: {} + + vary@1.1.2: {} + vite-dev-rpc@1.1.0(vite@8.0.11(@types/node@25.6.2)(esbuild@0.28.0)(jiti@2.6.1)(less@4.6.4)(sass@1.99.0)(terser@5.46.0)(yaml@2.8.4)): dependencies: birpc: 2.9.0 @@ -12177,6 +15578,23 @@ snapshots: vite: 8.0.11(@types/node@25.6.2)(esbuild@0.28.0)(jiti@2.6.1)(less@4.6.4)(sass@1.99.0)(terser@5.46.0)(yaml@2.8.4) vue: 3.5.34(typescript@5.9.3) + vite@8.0.11(@types/node@25.6.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.6.4)(sass@1.99.0)(terser@5.46.0)(yaml@2.8.4): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.14 + rolldown: 1.0.0-rc.18 + tinyglobby: 0.2.16 + optionalDependencies: + '@types/node': 25.6.2 + esbuild: 0.27.3 + fsevents: 2.3.3 + jiti: 2.6.1 + less: 4.6.4 + sass: 1.99.0 + terser: 5.46.0 + yaml: 2.8.4 + vite@8.0.11(@types/node@25.6.2)(esbuild@0.28.0)(jiti@2.6.1)(less@4.6.4)(sass@1.99.0)(terser@5.46.0)(yaml@2.8.4): dependencies: lightningcss: 1.32.0 @@ -12217,6 +15635,36 @@ snapshots: - vite - vitest + vitest@4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.2)(@vitest/coverage-v8@4.1.5)(jsdom@29.1.1(@noble/hashes@1.8.0))(vite@8.0.11(@types/node@25.6.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.6.4)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.4)): + dependencies: + '@vitest/expect': 4.1.5 + '@vitest/mocker': 4.1.5(vite@8.0.11(@types/node@25.6.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.6.4)(sass@1.97.3)(terser@5.46.0)(yaml@2.8.4)) + '@vitest/pretty-format': 4.1.5 + '@vitest/runner': 4.1.5 + '@vitest/snapshot': 4.1.5 + '@vitest/spy': 4.1.5 + '@vitest/utils': 4.1.5 + es-module-lexer: 2.0.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.4 + std-env: 4.1.0 + tinybench: 2.9.0 + tinyexec: 1.1.2 + tinyglobby: 0.2.16 + tinyrainbow: 3.1.0 + vite: 8.0.11(@types/node@25.6.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.6.4)(sass@1.99.0)(terser@5.46.0)(yaml@2.8.4) + why-is-node-running: 2.3.0 + optionalDependencies: + '@opentelemetry/api': 1.9.1 + '@types/node': 25.6.2 + '@vitest/coverage-v8': 4.1.5(vitest@4.1.5) + jsdom: 29.1.1(@noble/hashes@1.8.0) + transitivePeerDependencies: + - msw + vitest@4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.6.2)(@vitest/coverage-v8@4.1.5)(jsdom@29.1.1(@noble/hashes@1.8.0))(vite@8.0.11(@types/node@25.6.2)(esbuild@0.28.0)(jiti@2.6.1)(less@4.6.4)(sass@1.99.0)(terser@5.46.0)(yaml@2.8.4)): dependencies: '@vitest/expect': 4.1.5 @@ -12319,6 +15767,14 @@ snapshots: dependencies: xml-name-validator: 5.0.0 + watchpack@2.5.1: + dependencies: + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + + weak-lru-cache@1.2.2: + optional: true + webidl-conversions@3.0.1: {} webidl-conversions@8.0.1: {} @@ -12402,12 +15858,20 @@ snapshots: string-width: 8.2.0 strip-ansi: 7.2.0 + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi@9.0.2: dependencies: ansi-styles: 6.2.3 string-width: 7.2.0 strip-ansi: 7.2.0 + wrappy@1.0.2: {} + ws@8.19.0: {} wsl-utils@0.1.0: @@ -12435,6 +15899,8 @@ snapshots: yallist@3.1.1: {} + yallist@4.0.0: {} + yallist@5.0.0: {} yaml@1.10.2: {} @@ -12454,6 +15920,10 @@ snapshots: yocto-queue@0.1.0: {} + yoctocolors-cjs@2.1.3: {} + + yoctocolors@2.1.2: {} + youch-core@0.3.3: dependencies: '@poppinss/exception': 1.2.3 @@ -12475,5 +15945,11 @@ snapshots: compress-commons: 6.0.2 readable-stream: 4.7.0 - zod@4.3.6: + zod-to-json-schema@3.25.2(zod@4.3.6): + dependencies: + zod: 4.3.6 + + zod@4.3.6: {} + + zone.js@0.16.2: optional: true diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index d5914883..b9cebbc1 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -5,4 +5,6 @@ packages: onlyBuiltDependencies: - '@parcel/watcher' - esbuild + - lmdb + - msgpackr-extract - sharp diff --git a/tsconfig.json b/tsconfig.json index 7a8a152a..181955cf 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,7 +19,8 @@ { "path": "./packages/phone-mask-vue" }, { "path": "./packages/phone-mask-nuxt" }, { "path": "./packages/phone-mask-react" }, - { "path": "./packages/phone-mask-svelte" } + { "path": "./packages/phone-mask-svelte" }, + { "path": "./packages/phone-mask-angular" } ], "include": [], "exclude": ["node_modules", "dist"]