diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index db4e3bb..87245ca 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,4 +1,4 @@ # This is a managed file. Manual changes will be overwritten. # https://github.com/FusionAuth/fusionauth-public-repos/ -.github/ @fusionauth/owners @fusionauth/platform +.github/ @fusionauth/owners @fusionauth/platform @fusionauth/sdk-owners diff --git a/.github/workflows/lint-and-format.yml b/.github/workflows/lint-and-format.yml index d2aa06c..8ac84f6 100644 --- a/.github/workflows/lint-and-format.yml +++ b/.github/workflows/lint-and-format.yml @@ -2,7 +2,6 @@ name: Lint and Format on: pull_request: - branches: [main] jobs: check: diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 7007a9a..0adac1c 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -2,7 +2,6 @@ name: Run Tests on: pull_request: - branches: [main] jobs: test: diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..7eeeba1 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,64 @@ +# AGENTS.md — fusionauth-javascript-sdk + +## Repo Layout + +Yarn workspace monorepo: + +- `packages/core` — `@fusionauth-sdk/core`, shared logic for React/Angular/Vue SDKs +- `packages/lexicon` — `@fusionauth-sdk/lexicon`, shared utility types (Path, GUID, etc.) +- `packages/sdk-react` — `@fusionauth/react-sdk` +- `packages/sdk-angular` — Angular SDK (`sdk-angular-workspace`) +- `packages/sdk-vue` — `@fusionauth/vue-sdk` + +## Package Manager + +- **Yarn 1.22.x** via Corepack, not npm. `yarn` may not be on `PATH` directly — + use `corepack yarn ` if plain `yarn` isn't found. +- Root scripts: `yarn build:core`, `yarn build:sdk-react`, etc. Per-workspace: + `yarn workspace @fusionauth-sdk/core test`. + +## Node Version Constraint + +- **Angular SDK requires Node ^22.22.3 / ^24.15.0 / >=26.0.0.** If the active + Node is v20.x, `yarn workspace sdk-angular-workspace test` (and the root + `yarn test` which runs it) will fail with an engine/CLI version error. + This is an environment limitation, not a code issue — don't try to "fix" it + by changing the Angular config. +- If `yarn install` complains about the Angular engine mismatch, use + `yarn install --ignore-engines`. + +## Testing + +- Vitest, `environment: 'jsdom'` (see each package's `vite.config.ts`). +- `packages/core` tests needing `indexedDB` must polyfill it with + `fake-indexeddb`'s `IDBFactory` (jsdom has no native IndexedDB). +- Husky's `.husky/pre-commit` hook runs `yarn test` across **all** workspaces + plus `lint-staged`. In environments without Node 22+, this hook will fail + on the Angular workspace even when your actual changes are fine — verify + the specific package's tests pass, note that the Angular failure is + environmental, and use `git commit --no-verify` if needed (call this out + explicitly to the user rather than silently bypassing). + +## Lint / Format + +- ESLint config: root `.eslintrc.json` (`@typescript-eslint`, warns on unused + vars, `prefer-const`). +- Prettier: root `.prettierrc` (single quotes, semi, trailing commas, 80 print + width). Run `npx prettier --check ` / `--write` before committing. + +## Code Conventions + +- Each module lives in its own folder with `X.ts`, `X.test.ts`, and an + `index.ts` barrel export (see `UrlHelper/`, `CookieHelpers/`, `DPoP/`). +- Constructors that take more than one argument use a config object (e.g. + `DPoPStorageConfig`, `UrlHelperConfig`) rather than positional parameters. +- Browser-only APIs (`localStorage`, `indexedDB`, etc.) should degrade + gracefully for non-browser/SSR consumers — see `RedirectHelper.ts`'s + try/catch fallback pattern. +- Doc comments (`/** ... */`) on all public `SDKConfig` fields and public + class methods, matching existing style. +- **IndexedDB `dbVersion`**: IndexedDB versions can only increase. Never pass + a `dbVersion` lower than one already persisted in a browser — doing so + produces a `VersionError` and the database will not open. Only increment + `dbVersion` when a structural schema change (e.g. new object store) is also + being made inside `onupgradeneeded`. diff --git a/README.md b/README.md index 7e7e635..0e1acb1 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,14 @@ The e2e tests are structured to use the Page Object Model (POM) design pattern. Example: In common.page.ts, methods for navigation and authentication are defined. Tests import these page objects to perform actions, ensuring that if the UI changes, only the page object needs updating, not all the tests. +### DPoP E2E tests + +`e2e/tests/dpop-endpoints.test.ts` — mirrors `endpoints.test.ts`, but drives a consuming quickstart application configured with `useDpop: true` through its UI. Since DPoP mode has no hosted backend mode (`SDKCore` talks directly to FusionAuth), this validates the *direct* calls to `/oauth2/authorize`, `/oauth2/token` (both the authorization code exchange and the refresh token grant), `/oauth2/userinfo`, and `/oauth2/logout`: + ``` + SERVER_COMMAND="your-dpop-quickstart-start-command" PORT=your-port-number npx playwright test e2e/tests/dpop-endpoints.test.ts --config playwright.dpop-endpoints.config.ts + ``` + This must be run on its own — it cannot be combined with `endpoints.test.ts` / `cookies.test.ts` in the same invocation, since those require a hosted backend mode quickstart instance instead. + ## Architecture We use a monorepo because our SDKs share core functionality, which is contained in the @fusionauth-sdk/core package. This private module is bundled into the distributed SDK packages, allowing us to maintain core logic in a single place. diff --git a/e2e/pages/common.page.ts b/e2e/pages/common.page.ts index 3afec66..6b14dbb 100644 --- a/e2e/pages/common.page.ts +++ b/e2e/pages/common.page.ts @@ -40,10 +40,8 @@ export class quickstartPage { await this.locators.passwordInput.clear(); await this.locators.passwordInput.fill('password'); await this.locators.submitBtn.click(); - // Wait for the full OAuth callback chain to complete (form POST → /app/callback - // code exchange → redirect back to the app). Without this, webkit doesn't finish - // committing the session cookies before the test body reads them. await expect(this.locators.logOutBtn).toBeVisible(); + await this.page.waitForLoadState('load'); } async navToRegister() { @@ -52,7 +50,16 @@ export class quickstartPage { } async logOut() { + const logoutNavigationPromise = this.page.waitForURL( + url => /\/(oauth2|app)\/logout/.test(url.pathname), + { timeout: 10_000 }, + ); + await this.locators.logOutBtn.click(); + await logoutNavigationPromise; + await expect(this.locators.logInBtn.nth(0)).toBeVisible(); + // See the comment in authenticate() above. + await this.page.waitForLoadState('load'); } } diff --git a/e2e/tests/dpop-endpoints.test.ts b/e2e/tests/dpop-endpoints.test.ts new file mode 100644 index 0000000..88f28c1 --- /dev/null +++ b/e2e/tests/dpop-endpoints.test.ts @@ -0,0 +1,197 @@ +/** + * DPoP Endpoint Tests + * + * Mirrors `endpoints.test.ts`, but for a consuming quickstart application + * configured with `useDpop: true`. Since DPoP mode has no hosted backend to + * proxy through (`SDKCore` talks directly to FusionAuth), these tests + * validate the *direct* calls to FusionAuth's `/oauth2/authorize`, + * `/oauth2/token`, `/oauth2/userinfo`, and `/oauth2/logout` endpoints, and + * check for tokens in `localStorage` instead of `app.*` HttpOnly cookies. + * + * Run with: + * SERVER_COMMAND="your-dpop-quickstart-start-command" PORT=your-port-number \ + * npx playwright test e2e/tests/dpop-endpoints.test.ts \ + * --config playwright.dpop-endpoints.config.ts + * + * Prerequisites: + * - A consuming quickstart application (e.g. fusionauth-quickstart-javascript-react-web) + * configured with `useDpop: true`, `shouldAutoRefresh: true`, and + * `shouldAutoFetchUserInfo: true` + * - short access token (JWT) lifetime configured — e.g. 30-60 seconds — + * so the auto-refresh test below doesn't need a long wall-clock wait. + * Set `autoRefreshSecondsBeforeExpiry` so the refresh fires comfortably + * before expiry (e.g. 20s before a 30s token lifetime). + * - CORS must be configured in FusionAuth (Settings -> System -> CORS) + * to allow the quickstart's origin (e.g. http://localhost:3000) to call + * `/oauth2/userinfo` directly: enable the filter, add the origin to + * Allowed origins, and add `DPoP` and `Authorization` to Allowed + * headers. Without this, the userinfo request's CORS preflight fails + * with "No 'Access-Control-Allow-Origin' header is present" + */ + +import { Page, test, BrowserContext, expect } from '@playwright/test'; +import { quickstartPage } from '../pages/common.page'; + +interface DPoPTokens { + accessToken: string; + refreshToken?: string; + expiresAt: number; + tokenType: string; +} + +async function readDpopTokens(page: Page): Promise { + const evaluateTokens = () => + page.evaluate(() => { + const key = Object.keys(localStorage).find(k => + k.startsWith('fusionauth-sdk:tokens:'), + ); + return key ? localStorage.getItem(key) : null; + }); + + let raw: string | null; + try { + raw = await evaluateTokens(); + } catch (error) { + if ( + error instanceof Error && + error.message.includes('Execution context was destroyed') + ) { + await page.waitForLoadState('load'); + raw = await evaluateTokens(); + } else { + throw error; + } + } + return raw ? JSON.parse(raw) : null; +} + +test.describe('DPoP Endpoint Tests', () => { + test.describe.configure({ mode: 'serial' }); + + let page: Page; + let quickstart: quickstartPage; + let browserContext: BrowserContext; + + test.beforeAll(async ({ browser }) => { + browserContext = await browser.newContext(); + page = await browserContext.newPage(); + quickstart = new quickstartPage(page); + }); + + test.afterAll(async () => { + await page?.close(); + await browserContext?.close(); + }); + + test.beforeEach(async () => { + await page.goto('/'); + }); + + test('Login redirects directly to /oauth2/authorize with dpop_jkt and code_challenge, then exchanges the code at /oauth2/token', async () => { + await quickstart.navToLogIn(); + + const authorizeUrl = new URL(page.url()); + expect(authorizeUrl.pathname).toBe('/oauth2/authorize'); + expect(authorizeUrl.searchParams.get('response_type')).toBe('code'); + expect(authorizeUrl.searchParams.get('code_challenge_method')).toBe('S256'); + + const dpopJkt = authorizeUrl.searchParams.get('dpop_jkt'); + const codeChallenge = authorizeUrl.searchParams.get('code_challenge'); + expect(dpopJkt).toBeTruthy(); + expect(codeChallenge).toBeTruthy(); + + const tokenExchangeResponsePromise = page.waitForResponse( + response => + response.url().includes('/oauth2/token') && + response.request().method() === 'POST', + ); + + await quickstart.authenticate(); + + const tokenExchangeResponse = await tokenExchangeResponsePromise; + const tokenExchangeRequest = tokenExchangeResponse.request(); + expect(new URL(tokenExchangeRequest.url()).pathname).toBe('/oauth2/token'); + expect(tokenExchangeRequest.headers()['dpop']).toBeTruthy(); + + const body = new URLSearchParams(tokenExchangeRequest.postData() ?? ''); + expect(body.get('grant_type')).toBe('authorization_code'); + expect(body.get('code_verifier')).toBeTruthy(); + + const tokens = await readDpopTokens(page); + expect(tokens).not.toBeNull(); + expect(tokens!.tokenType).toBe('DPoP'); + expect(tokens!.accessToken).toBeTruthy(); + + const cookies = await browserContext.cookies(); + ['app.at', 'app.idt', 'app.rt', 'app.at_exp'].forEach(name => { + expect(cookies.find(cookie => cookie.name === name)).toBeUndefined(); + }); + + await quickstart.logOut(); + }); + + test('User info is fetched after login, and the access token auto-refreshes via a direct /oauth2/token refresh_token grant', async () => { + // The refresh window depends on the FusionAuth Application's configured + // access token lifetime and the quickstart's autoRefreshSecondsBeforeExpiry. + test.setTimeout(90_000); + + await quickstart.navToLogIn(); + + const userInfoResponsePromise = page.waitForResponse(response => + response.url().includes('/oauth2/userinfo'), + ); + + await quickstart.authenticate(); + + const userInfoResponse = await userInfoResponsePromise; + const userInfoRequest = userInfoResponse.request(); + expect(new URL(userInfoRequest.url()).pathname).toBe('/oauth2/userinfo'); + expect(userInfoRequest.headers()['dpop']).toBeTruthy(); + expect(userInfoResponse.ok()).toBe(true); + + await expect(page.getByText('richard@example.com')).toBeVisible(); + + const initialTokens = await readDpopTokens(page); + expect(initialTokens).not.toBeNull(); + + const refreshResponse = await page.waitForResponse( + response => + response.url().includes('/oauth2/token') && + (response.request().postData() ?? '').includes( + 'grant_type=refresh_token', + ), + { timeout: 60_000 }, + ); + + const refreshRequest = refreshResponse.request(); + expect(refreshRequest.headers()['dpop']).toBeTruthy(); + const body = new URLSearchParams(refreshRequest.postData() ?? ''); + expect(body.get('refresh_token')).toBeTruthy(); + + const refreshedTokens = await readDpopTokens(page); + expect(refreshedTokens).not.toBeNull(); + expect(refreshedTokens!.accessToken).not.toBe(initialTokens!.accessToken); + + await quickstart.logOut(); + }); + + test('Logout redirects directly to /oauth2/logout and clears local DPoP state', async () => { + await quickstart.navToLogIn(); + await quickstart.authenticate(); + + expect(await readDpopTokens(page)).not.toBeNull(); + + const logoutRequestPromise = page.waitForRequest(request => + request.url().includes('/oauth2/logout'), + ); + + await quickstart.logOut(); + + const logoutRequest = await logoutRequestPromise; + const logoutUrl = new URL(logoutRequest.url()); + expect(logoutUrl.pathname).toBe('/oauth2/logout'); + expect(logoutUrl.searchParams.get('client_id')).toBeTruthy(); + + expect(await readDpopTokens(page)).toBeNull(); + }); +}); diff --git a/package.json b/package.json index 6a9687b..5e9efa5 100644 --- a/package.json +++ b/package.json @@ -46,9 +46,10 @@ "test:core": "yarn workspace @fusionauth-sdk/core test", "test:lexicon": "yarn workspace @fusionauth-sdk/lexicon test", "test:sdk-angular": "yarn workspace sdk-angular-workspace test", - "test:sdk-react": "yarn workspace @fusionauth/react-sdk test", - "test:sdk-vue": "yarn workspace @fusionauth/vue-sdk test", + "test:sdk-react": "yarn build:core && yarn workspace @fusionauth/react-sdk test", + "test:sdk-vue": "yarn build:core && yarn workspace @fusionauth/vue-sdk test", "test:e2e": "yarn playwright test", + "test:e2e:dpop-endpoints": "yarn playwright test --config playwright.dpop-endpoints.config.ts", "lint:fix": "eslint . --ext .ts,.tsx --fix", "lint:check": "eslint . --ext .ts,.tsx --max-warnings 0", "format:fix": "prettier --write .", diff --git a/packages/core/package.json b/packages/core/package.json index cdfe120..0e91c74 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -16,10 +16,14 @@ "test:watch": "vitest", "test": "vitest --watch=false" }, + "dependencies": { + "dpop": "^2.1.1" + }, "devDependencies": { + "fake-indexeddb": "^6.0.0", "typescript": "^5.2.2", "vite": "^5.2.0", "vite-plugin-dts": "^3.8.0", - "vitest": "^1.4.0" + "vitest": "^3.2.6" } } diff --git a/packages/core/src/DPoP/DPoPManager.test.ts b/packages/core/src/DPoP/DPoPManager.test.ts new file mode 100644 index 0000000..a78f521 --- /dev/null +++ b/packages/core/src/DPoP/DPoPManager.test.ts @@ -0,0 +1,1004 @@ +// @vitest-environment node +// dpop's generateProof uses TextEncoder internally. The jsdom environment +// polyfills TextEncoder in a way that its output lacks Uint8Array.prototype +// methods (e.g. subarray), causing dpop's base64url encoder to throw. The +// node environment has a spec-compliant TextEncoder, so we use it here. +// DPoPStorage uses fake-indexeddb to stand in for the missing IndexedDB global. + +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { IDBFactory } from 'fake-indexeddb'; + +import { DPoPManager } from './DPoPManager'; +import { DPoPTokens } from './DPoPTokenStore'; +import { UrlHelper } from '../UrlHelper'; +import { RedirectHelper } from '../RedirectHelper'; + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +const CLIENT_ID = 'test-client'; +const SERVER_URL = 'https://auth.example.com'; +const REDIRECT_URI = 'https://app.example.com/callback'; +const RESOURCE_URL = 'https://api.example.com/data'; + +/** Decode the payload of a JWT without verifying the signature. */ +function decodeJwtPayload(jwt: string): Record { + const [, payloadB64] = jwt.split('.'); + // base64url → base64 → JSON + const json = atob(payloadB64.replace(/-/g, '+').replace(/_/g, '/')); + return JSON.parse(json) as Record; +} + +function makeTokens(overrides?: Partial): DPoPTokens { + return { + accessToken: 'test-access-token', + refreshToken: 'test-refresh-token', + expiresAt: Date.now() + 60_000, + tokenType: 'DPoP', + ...overrides, + }; +} + +function makeUrlHelper(): UrlHelper { + return new UrlHelper({ + serverUrl: SERVER_URL, + clientId: CLIENT_ID, + redirectUri: REDIRECT_URI, + }); +} + +function makeManager( + tokenStorage: 'localStorage' | 'memory' = 'memory', + urlHelper: UrlHelper = makeUrlHelper(), + redirectHelper: RedirectHelper = new RedirectHelper(), +): DPoPManager { + return new DPoPManager(CLIENT_ID, urlHelper, redirectHelper, tokenStorage); +} + +/** + * Stubs `window` with a minimal `location`/`history` so `startLogin()`, + * `startLogout()`, `startRegister()`, and `handlePostRedirect()` — which + * this file exercises in the `node` test environment where `window` is + * otherwise undefined — can run. Returns the `assign`/`replaceState` spies. + */ +function stubWindow(search = '') { + const assign = vi.fn(); + const replaceState = vi.fn(); + vi.stubGlobal('window', { + location: { + origin: 'https://app.example.com', + pathname: '/callback', + search, + hash: '', + assign, + }, + history: { replaceState }, + // RedirectHelper.handlePreDpopRedirect()/handlePreRedirect() generate a + // random string via window.crypto.getRandomValues(). + crypto: globalThis.crypto, + }); + return { assign, replaceState }; +} + +/** Minimal `Response`-like stub that satisfies the fetch return contract. */ +function makeResponse( + status: number, + headers: Record = {}, + body?: string, +): Response { + return new Response(body ?? null, { status, headers }); +} + +beforeEach(() => { + // Provide a fresh in-process IndexedDB for each test so tests are isolated. + // @ts-ignore — the node environment does not implement indexedDB; fake-indexeddb fills the gap. + globalThis.indexedDB = new IDBFactory(); + // DPoPTokenStore accesses localStorage gracefully (returns null on error), but + // setting up a minimal stub keeps the tests clean and explicit. + if (typeof globalThis.localStorage === 'undefined') { + const store: Record = {}; + // @ts-ignore + globalThis.localStorage = { + getItem: (k: string) => store[k] ?? null, + setItem: (k: string, v: string) => { + store[k] = v; + }, + removeItem: (k: string) => { + delete store[k]; + }, + clear: () => { + for (const k in store) delete store[k]; + }, + }; + } else { + localStorage.clear(); + } +}); + +afterEach(() => { + vi.restoreAllMocks(); + vi.unstubAllGlobals(); +}); + +describe('getOrCreateKeyPair()', () => { + it('generates and persists a key pair on the first call', async () => { + const manager = makeManager(); + const keyPair = await manager.getOrCreateKeyPair(); + + expect(keyPair).toBeDefined(); + expect(keyPair.privateKey.type).toBe('private'); + expect(keyPair.publicKey.type).toBe('public'); + expect(keyPair.privateKey.extractable).toBe(false); + }); + + it('returns the same key pair on a second call (memoised — no re-generation)', async () => { + const manager = makeManager(); + const first = await manager.getOrCreateKeyPair(); + const second = await manager.getOrCreateKeyPair(); + + // Reference equality: the memoised promise resolves to the same object. + expect(second).toBe(first); + }); + + it('loads an existing key pair from DPoPStorage instead of generating a new one', async () => { + // Pre-populate storage by running a full first manager to generate+persist. + const seed = makeManager(); + const original = await seed.getOrCreateKeyPair(); + + // A second manager sharing the same IndexedDB and clientId should load the + // existing key pair rather than overwrite it. + const manager = makeManager(); + const loaded = await manager.getOrCreateKeyPair(); + + // The loaded key pair should have the same algorithm as the seeded one. + expect(loaded.privateKey.algorithm).toStrictEqual( + original.privateKey.algorithm, + ); + expect(loaded.publicKey.algorithm).toStrictEqual( + original.publicKey.algorithm, + ); + }); + + it('generates a fresh key pair after clear()', async () => { + const manager = makeManager(); + const first = await manager.getOrCreateKeyPair(); + + await manager.clear(); + + const second = await manager.getOrCreateKeyPair(); + // After clear the promise is reset, so a new object is produced. + expect(second).not.toBe(first); + }); +}); + +describe('generateProof()', () => { + it('produces a well-formed DPoP proof JWT with correct htu and htm', async () => { + const manager = makeManager(); + const proof = await manager.generateProof(RESOURCE_URL, 'GET'); + + const payload = decodeJwtPayload(proof); + expect(payload.htu).toBe(RESOURCE_URL); + expect(payload.htm).toBe('GET'); + }); + + it('strips the query string and fragment from htu per RFC 9449', async () => { + const manager = makeManager(); + const urlWithQueryAndFragment = `${RESOURCE_URL}?foo=bar&baz=qux#section`; + const proof = await manager.generateProof(urlWithQueryAndFragment, 'GET'); + + const payload = decodeJwtPayload(proof); + // htu must be normalised to the URL without query/fragment. + expect(payload.htu).toBe(RESOURCE_URL); + }); + + it('normalises htm to uppercase regardless of caller casing', async () => { + const manager = makeManager(); + const proof = await manager.generateProof(RESOURCE_URL, 'post'); + + const payload = decodeJwtPayload(proof); + expect(payload.htm).toBe('POST'); + }); + + it('resolves a relative htu against window.location.origin instead of throwing', async () => { + vi.stubGlobal('window', { + location: { origin: 'https://app.example.com' }, + }); + const manager = makeManager(); + const proof = await manager.generateProof('/api/data', 'GET'); + + const payload = decodeJwtPayload(proof); + expect(payload.htu).toBe('https://app.example.com/api/data'); + vi.unstubAllGlobals(); + }); + + it('includes ath claim when an accessToken is provided', async () => { + const manager = makeManager(); + const proof = await manager.generateProof( + RESOURCE_URL, + 'POST', + 'my-access-token', + ); + + const payload = decodeJwtPayload(proof); + expect(payload.ath).toBeDefined(); + // ath must be a non-empty string (base64url-encoded SHA-256 hash) + expect(typeof payload.ath).toBe('string'); + expect((payload.ath as string).length).toBeGreaterThan(0); + }); + + it('omits ath when no accessToken is provided', async () => { + const manager = makeManager(); + const proof = await manager.generateProof(RESOURCE_URL, 'GET'); + + const payload = decodeJwtPayload(proof); + expect(payload.ath).toBeUndefined(); + }); + + it('includes nonce from the in-memory cache for the matching origin', async () => { + const manager = makeManager(); + + // Trigger a 401/use_dpop_nonce cycle via fetch() to populate the cache. + vi.spyOn(globalThis, 'fetch') + .mockResolvedValueOnce( + makeResponse(401, { + 'WWW-Authenticate': 'DPoP error="use_dpop_nonce"', + 'DPoP-Nonce': 'server-nonce-abc', + }), + ) + .mockResolvedValueOnce(makeResponse(200)); + + await manager.fetch(RESOURCE_URL); + + // Now call generateProof directly — the nonce should come from the cache. + const proof = await manager.generateProof(RESOURCE_URL, 'GET'); + const payload = decodeJwtPayload(proof); + expect(payload.nonce).toBe('server-nonce-abc'); + }); + + it('explicit nonce argument overrides the per-origin cache', async () => { + const manager = makeManager(); + + // Seed a cached nonce via a 401 retry. + vi.spyOn(globalThis, 'fetch') + .mockResolvedValueOnce( + makeResponse(401, { + 'WWW-Authenticate': 'DPoP error="use_dpop_nonce"', + 'DPoP-Nonce': 'cached-nonce', + }), + ) + .mockResolvedValueOnce(makeResponse(200)); + + await manager.fetch(RESOURCE_URL); + + const proof = await manager.generateProof( + RESOURCE_URL, + 'GET', + undefined, + 'explicit-nonce', + ); + const payload = decodeJwtPayload(proof); + expect(payload.nonce).toBe('explicit-nonce'); + }); + + it('omits nonce when none is cached and no explicit nonce is provided', async () => { + const manager = makeManager(); + const proof = await manager.generateProof(RESOURCE_URL, 'GET'); + + const payload = decodeJwtPayload(proof); + expect(payload.nonce).toBeUndefined(); + }); +}); + +describe('fetch()', () => { + it('sets DPoP header on outgoing requests', async () => { + const manager = makeManager(); + let capturedHeaders: Headers | undefined; + + vi.spyOn(globalThis, 'fetch').mockImplementation(async input => { + capturedHeaders = (input as Request).headers; + return makeResponse(200); + }); + + await manager.fetch(RESOURCE_URL); + + expect(capturedHeaders?.has('DPoP')).toBe(true); + // The DPoP header value should be a three-part JWT. + const dpopHeader = capturedHeaders!.get('DPoP')!; + expect(dpopHeader.split('.').length).toBe(3); + }); + + it('sets Authorization: DPoP when a stored access token exists', async () => { + const manager = makeManager(); + manager.setTokens(makeTokens({ accessToken: 'stored-access-token' })); + + let capturedHeaders: Headers | undefined; + vi.spyOn(globalThis, 'fetch').mockImplementation(async input => { + capturedHeaders = (input as Request).headers; + return makeResponse(200); + }); + + await manager.fetch(RESOURCE_URL); + + expect(capturedHeaders?.get('Authorization')).toBe( + 'DPoP stored-access-token', + ); + }); + + it('does not set Authorization header when no token is stored', async () => { + const manager = makeManager(); + let capturedHeaders: Headers | undefined; + + vi.spyOn(globalThis, 'fetch').mockImplementation(async input => { + capturedHeaders = (input as Request).headers; + return makeResponse(200); + }); + + await manager.fetch(RESOURCE_URL); + + expect(capturedHeaders?.has('Authorization')).toBe(false); + }); + + it('preserves caller-provided headers alongside DPoP headers', async () => { + const manager = makeManager(); + let capturedHeaders: Headers | undefined; + + vi.spyOn(globalThis, 'fetch').mockImplementation(async input => { + capturedHeaders = (input as Request).headers; + return makeResponse(200); + }); + + await manager.fetch(RESOURCE_URL, { + headers: { 'X-Custom-Header': 'custom-value' }, + }); + + expect(capturedHeaders?.get('X-Custom-Header')).toBe('custom-value'); + expect(capturedHeaders?.has('DPoP')).toBe(true); + }); + + it('merges headers from both a Request object and init when both are provided', async () => { + const manager = makeManager(); + let capturedHeaders: Headers | undefined; + + vi.spyOn(globalThis, 'fetch').mockImplementation(async input => { + capturedHeaders = (input as Request).headers; + return makeResponse(200); + }); + + const request = new Request(RESOURCE_URL, { + headers: { 'X-From-Request': 'request-value' }, + }); + + await manager.fetch(request, { + headers: { 'X-From-Init': 'init-value' }, + }); + + // Both header sources must survive — neither is silently dropped. + expect(capturedHeaders?.get('X-From-Request')).toBe('request-value'); + expect(capturedHeaders?.get('X-From-Init')).toBe('init-value'); + expect(capturedHeaders?.has('DPoP')).toBe(true); + }); + + it('Request headers win over init headers on a conflicting header name', async () => { + const manager = makeManager(); + let capturedHeaders: Headers | undefined; + + vi.spyOn(globalThis, 'fetch').mockImplementation(async input => { + capturedHeaders = (input as Request).headers; + return makeResponse(200); + }); + + const request = new Request(RESOURCE_URL, { + headers: { 'X-Conflict': 'from-request' }, + }); + + await manager.fetch(request, { + headers: { 'X-Conflict': 'from-init' }, + }); + + // The Request's value must win over the conflicting init.headers value. + expect(capturedHeaders?.get('X-Conflict')).toBe('from-request'); + }); + + describe('nonce retry', () => { + it('retries exactly once on 401 + use_dpop_nonce + DPoP-Nonce header', async () => { + const manager = makeManager(); + const fetchSpy = vi + .spyOn(globalThis, 'fetch') + .mockResolvedValueOnce( + makeResponse(401, { + 'WWW-Authenticate': 'DPoP error="use_dpop_nonce"', + 'DPoP-Nonce': 'server-nonce-xyz', + }), + ) + .mockResolvedValueOnce(makeResponse(200)); + + const response = await manager.fetch(RESOURCE_URL); + + expect(fetchSpy).toHaveBeenCalledTimes(2); + expect(response.status).toBe(200); + }); + + it('includes the cached nonce in the retry proof', async () => { + const manager = makeManager(); + const capturedProofs: string[] = []; + + vi.spyOn(globalThis, 'fetch').mockImplementation(async input => { + const headers = (input as Request).headers; + const proof = headers.get('DPoP'); + if (proof) capturedProofs.push(proof); + + if (capturedProofs.length === 1) { + return makeResponse(401, { + 'WWW-Authenticate': 'DPoP error="use_dpop_nonce"', + 'DPoP-Nonce': 'retry-nonce-42', + }); + } + return makeResponse(200); + }); + + await manager.fetch(RESOURCE_URL); + + expect(capturedProofs.length).toBe(2); + // The second (retry) proof must carry the server-supplied nonce. + const retryPayload = decodeJwtPayload(capturedProofs[1]); + expect(retryPayload.nonce).toBe('retry-nonce-42'); + // The first proof must NOT have had a nonce (cache was empty). + const firstPayload = decodeJwtPayload(capturedProofs[0]); + expect(firstPayload.nonce).toBeUndefined(); + }); + + it('does not retry a second time when the retry also returns 401/use_dpop_nonce', async () => { + const manager = makeManager(); + const fetchSpy = vi.spyOn(globalThis, 'fetch').mockResolvedValue( + makeResponse(401, { + 'WWW-Authenticate': 'DPoP error="use_dpop_nonce"', + 'DPoP-Nonce': 'nonce-value', + }), + ); + + const response = await manager.fetch(RESOURCE_URL); + + // Exactly two calls: original + one retry. + expect(fetchSpy).toHaveBeenCalledTimes(2); + // The second 401 is returned as-is. + expect(response.status).toBe(401); + }); + + it('does not retry when 401 lacks WWW-Authenticate: use_dpop_nonce', async () => { + const manager = makeManager(); + const fetchSpy = vi + .spyOn(globalThis, 'fetch') + .mockResolvedValueOnce(makeResponse(401)); + + const response = await manager.fetch(RESOURCE_URL); + + expect(fetchSpy).toHaveBeenCalledTimes(1); + expect(response.status).toBe(401); + }); + + it('does not retry when 401 + use_dpop_nonce but DPoP-Nonce header is absent', async () => { + const manager = makeManager(); + const fetchSpy = vi.spyOn(globalThis, 'fetch').mockResolvedValueOnce( + makeResponse(401, { + 'WWW-Authenticate': 'DPoP error="use_dpop_nonce"', + // No DPoP-Nonce header — malformed server response. + }), + ); + + const response = await manager.fetch(RESOURCE_URL); + + expect(fetchSpy).toHaveBeenCalledTimes(1); + expect(response.status).toBe(401); + }); + + it('retries successfully when input is a Request with a body (body is not double-consumed)', async () => { + const manager = makeManager(); + let callCount = 0; + + vi.spyOn(globalThis, 'fetch').mockImplementation(async input => { + callCount++; + // Simulate what native fetch does internally when sending a request + // body — reading it. If DPoPManager.fetch() reused the same Request + // instance across both attempts, this second read would throw + // "body already used" instead of resolving with the text. + const bodyText = await (input as Request).text(); + expect(bodyText).toBe('{"foo":1}'); + + if (callCount === 1) { + return makeResponse(401, { + 'WWW-Authenticate': 'DPoP error="use_dpop_nonce"', + 'DPoP-Nonce': 'nonce-for-request-body-retry', + }); + } + return makeResponse(200); + }); + + const request = new Request(RESOURCE_URL, { + method: 'POST', + body: '{"foo":1}', + }); + + const response = await manager.fetch(request); + + expect(callCount).toBe(2); + expect(response.status).toBe(200); + }); + + it('retries successfully when init.body is a raw ReadableStream (body is not double-consumed)', async () => { + const manager = makeManager(); + let callCount = 0; + + vi.spyOn(globalThis, 'fetch').mockImplementation(async input => { + callCount++; + // Same rationale as the Request-with-body retry test above: if the + // stream were reused/double-read instead of teed via Request.clone(), + // this second read would throw instead of resolving with the text. + const bodyText = await (input as Request).text(); + expect(bodyText).toBe('stream-body'); + + if (callCount === 1) { + return makeResponse(401, { + 'WWW-Authenticate': 'DPoP error="use_dpop_nonce"', + 'DPoP-Nonce': 'nonce-for-stream-retry', + }); + } + return makeResponse(200); + }); + + const stream = new ReadableStream({ + start(controller) { + controller.enqueue(new TextEncoder().encode('stream-body')); + controller.close(); + }, + }); + + const response = await manager.fetch(RESOURCE_URL, { + method: 'POST', + body: stream, + duplex: 'half', + } as RequestInit); + + expect(callCount).toBe(2); + expect(response.status).toBe(200); + }); + + it('does not throw for a raw ReadableStream body when no retry is needed', async () => { + const manager = makeManager(); + + vi.spyOn(globalThis, 'fetch').mockResolvedValueOnce(makeResponse(200)); + + const stream = new ReadableStream({ + start(controller) { + controller.enqueue(new TextEncoder().encode('stream-body')); + controller.close(); + }, + }); + + const response = await manager.fetch(RESOURCE_URL, { + method: 'POST', + body: stream, + duplex: 'half', + } as RequestInit); + + expect(response.status).toBe(200); + }); + }); +}); + +describe('getExpiresAt()', () => { + it('returns -1 when no tokens are stored', () => { + const manager = makeManager(); + expect(manager.getExpiresAt()).toBe(-1); + }); + + it('returns the expiresAt of the stored tokens', () => { + const manager = makeManager(); + const expiresAt = Date.now() + 60_000; + manager.setTokens(makeTokens({ expiresAt })); + expect(manager.getExpiresAt()).toBe(expiresAt); + }); + + it('returns -1 after clear()', async () => { + const manager = makeManager(); + manager.setTokens(makeTokens()); + + await manager.clear(); + + expect(manager.getExpiresAt()).toBe(-1); + }); +}); + +describe('getAccessToken()', () => { + it('returns null when no tokens are stored', () => { + const manager = makeManager(); + expect(manager.getAccessToken()).toBeNull(); + }); + + it('returns the accessToken of the stored tokens', () => { + const manager = makeManager(); + manager.setTokens(makeTokens({ accessToken: 'stored-access-token' })); + expect(manager.getAccessToken()).toBe('stored-access-token'); + }); + + it('returns null after clear()', async () => { + const manager = makeManager(); + manager.setTokens(makeTokens()); + + await manager.clear(); + + expect(manager.getAccessToken()).toBeNull(); + }); +}); + +describe('clear()', () => { + it('removes the key pair from DPoPStorage', async () => { + const manager = makeManager(); + await manager.getOrCreateKeyPair(); // generate + persist + + await manager.clear(); + + // A fresh manager sharing the same IndexedDB should find nothing. + const fresh = makeManager(); + // Before calling getOrCreateKeyPair() we need to peek at storage directly. + // Import DPoPStorage so we can query independently. + const { DPoPStorage } = await import('./DPoPStorage'); + const storage = new DPoPStorage({ clientId: CLIENT_ID }); + const stored = await storage.getKeyPair(); + expect(stored).toBeUndefined(); + // Silence unused-variable warning — fresh is used to confirm the type. + expect(fresh).toBeDefined(); + }); + + it('clears tokens from DPoPTokenStore', async () => { + const manager = makeManager(); + manager.setTokens(makeTokens()); + expect(manager.isLoggedIn).toBe(true); + + await manager.clear(); + + expect(manager.isLoggedIn).toBe(false); + }); + + it('clears the in-memory nonce cache', async () => { + const manager = makeManager(); + + // Seed the nonce cache via a 401 retry. + vi.spyOn(globalThis, 'fetch') + .mockResolvedValueOnce( + makeResponse(401, { + 'WWW-Authenticate': 'DPoP error="use_dpop_nonce"', + 'DPoP-Nonce': 'cached-nonce', + }), + ) + .mockResolvedValueOnce(makeResponse(200)); + + await manager.fetch(RESOURCE_URL); + + // Confirm the nonce was cached (proof should include it). + const beforeClear = decodeJwtPayload( + await manager.generateProof(RESOURCE_URL, 'GET'), + ); + expect(beforeClear.nonce).toBe('cached-nonce'); + + await manager.clear(); + + // After clear the nonce should be gone from the proof. + vi.restoreAllMocks(); // stop the fetch spy so generateProof can run freely + const afterClear = decodeJwtPayload( + await manager.generateProof(RESOURCE_URL, 'GET'), + ); + expect(afterClear.nonce).toBeUndefined(); + }); + + it('resets the memoised key-pair promise so next call regenerates', async () => { + const manager = makeManager(); + const first = await manager.getOrCreateKeyPair(); + + await manager.clear(); + + const second = await manager.getOrCreateKeyPair(); + // clear() resets the promise — a new object is created. + expect(second).not.toBe(first); + }); +}); + +describe('startLogin()', () => { + it('persists code_verifier via RedirectHelper and redirects to /oauth2/authorize with dpop_jkt/code_challenge/state', async () => { + const { assign } = stubWindow(); + const redirectHelper = new RedirectHelper(); + const manager = makeManager('memory', makeUrlHelper(), redirectHelper); + + await manager.startLogin('my-state'); + + expect(assign).toHaveBeenCalledOnce(); + const url = new URL(assign.mock.calls[0][0].toString()); + expect(url.pathname).toBe('/oauth2/authorize'); + // The OAuth `state` param sent to the server is the SDK-generated + // transactionState — not the caller's own state — since it's the actual + // CSRF defense (see RedirectHelper.handlePreDpopRedirect()). + expect(url.searchParams.get('state')).toBe( + redirectHelper.getTransactionState(), + ); + expect(url.searchParams.get('state')).not.toBe('my-state'); + expect(url.searchParams.has('dpop_jkt')).toBe(true); + expect(url.searchParams.has('code_challenge')).toBe(true); + + expect(redirectHelper.getCodeVerifier()).toBeDefined(); + expect(redirectHelper.getState()).toBe('my-state'); + }); +}); + +describe('startLogout()', () => { + it('clears DPoP state and redirects to /oauth2/logout', async () => { + const { assign } = stubWindow(); + const manager = makeManager(); + manager.setTokens(makeTokens()); + expect(manager.isLoggedIn).toBe(true); + + await manager.startLogout(); + + expect(manager.isLoggedIn).toBe(false); + expect(assign).toHaveBeenCalledOnce(); + const url = new URL(assign.mock.calls[0][0].toString()); + expect(url.pathname).toBe('/oauth2/logout'); + }); + + it('still redirects even if clear() throws', async () => { + const { assign } = stubWindow(); + const manager = makeManager(); + vi.spyOn(manager, 'clear').mockRejectedValueOnce(new Error('boom')); + + await expect(manager.startLogout()).rejects.toThrow('boom'); + expect(assign).toHaveBeenCalledOnce(); + }); +}); + +describe('startRegister()', () => { + it('persists code_verifier via RedirectHelper and redirects to /oauth2/register with dpop_jkt/code_challenge/state', async () => { + const { assign } = stubWindow(); + const redirectHelper = new RedirectHelper(); + const manager = makeManager('memory', makeUrlHelper(), redirectHelper); + + await manager.startRegister('my-state'); + + expect(assign).toHaveBeenCalledOnce(); + const url = new URL(assign.mock.calls[0][0].toString()); + expect(url.pathname).toBe('/oauth2/register'); + // See the equivalent startLogin() assertion above for why this is the + // generated transactionState, not the caller's own state. + expect(url.searchParams.get('state')).toBe( + redirectHelper.getTransactionState(), + ); + expect(url.searchParams.get('state')).not.toBe('my-state'); + expect(url.searchParams.has('dpop_jkt')).toBe(true); + expect(url.searchParams.has('code_challenge')).toBe(true); + + expect(redirectHelper.getCodeVerifier()).toBeDefined(); + expect(redirectHelper.getState()).toBe('my-state'); + }); +}); + +describe('refreshToken()', () => { + it('throws when no refresh token is stored', async () => { + const manager = makeManager(); + await expect(manager.refreshToken()).rejects.toThrow( + 'No refresh token available. Have you called startLogin()?', + ); + }); + + it('sends a DPoP header and refresh_token grant body to /oauth2/token', async () => { + const manager = makeManager(); + manager.setTokens(makeTokens({ refreshToken: 'old-refresh-token' })); + + const fetchSpy = vi.spyOn(globalThis, 'fetch').mockResolvedValue( + makeResponse( + 200, + {}, + JSON.stringify({ + access_token: 'new-access-token', + refresh_token: 'new-refresh-token', + expires_in: 3600, + token_type: 'DPoP', + }), + ), + ); + + const response = await manager.refreshToken(); + + expect(response.status).toBe(200); + expect(fetchSpy).toHaveBeenCalledOnce(); + const [url, init] = fetchSpy.mock.calls[0]; + expect(new URL(url.toString()).pathname).toBe('/oauth2/token'); + const headers = init?.headers as Record; + expect(headers['DPoP']).toBeDefined(); + const body = new URLSearchParams(init?.body as string); + expect(body.get('grant_type')).toBe('refresh_token'); + expect(body.get('refresh_token')).toBe('old-refresh-token'); + expect(body.get('client_id')).toBe(CLIENT_ID); + + expect(manager.getAccessToken()).toBe('new-access-token'); + }); + + it('throws when the response is not ok', async () => { + const manager = makeManager(); + manager.setTokens(makeTokens()); + vi.spyOn(globalThis, 'fetch').mockResolvedValue( + makeResponse(400, {}, 'invalid_grant'), + ); + + await expect(manager.refreshToken()).rejects.toThrow(); + }); + + it('throws when token_type is not DPoP', async () => { + const manager = makeManager(); + manager.setTokens(makeTokens()); + vi.spyOn(globalThis, 'fetch').mockResolvedValue( + makeResponse( + 200, + {}, + JSON.stringify({ + access_token: 'a', + expires_in: 3600, + token_type: 'Bearer', + }), + ), + ); + + await expect(manager.refreshToken()).rejects.toThrow('token_type'); + }); + + it('throws when expires_in is not a positive number', async () => { + const manager = makeManager(); + manager.setTokens(makeTokens()); + vi.spyOn(globalThis, 'fetch').mockResolvedValue( + makeResponse( + 200, + {}, + JSON.stringify({ + access_token: 'a', + expires_in: 0, + token_type: 'DPoP', + }), + ), + ); + + await expect(manager.refreshToken()).rejects.toThrow('expires_in'); + }); +}); + +describe('handlePostRedirect()', () => { + it('returns undefined when there is no code query param', async () => { + stubWindow(); + const manager = makeManager(); + + expect(await manager.handlePostRedirect()).toBeUndefined(); + }); + + it('returns undefined when code is present but no code_verifier was persisted', async () => { + stubWindow('?code=abc123'); + const manager = makeManager(); + + expect(await manager.handlePostRedirect()).toBeUndefined(); + }); + + it('returns a state-mismatch Error and does not exchange the code (CSRF protection)', async () => { + stubWindow(); // establishes window.crypto for handlePreDpopRedirect() + const redirectHelper = new RedirectHelper(); + redirectHelper.handlePreDpopRedirect('my-code-verifier', 'expected-state'); + // The URL's `state` never matches a real transactionState regardless of + // its value — this proves the mismatch check independent of what the + // caller's own `state` was. + stubWindow('?code=abc123&state=attacker-state'); + const manager = makeManager('memory', makeUrlHelper(), redirectHelper); + const fetchSpy = vi.spyOn(globalThis, 'fetch'); + + const error = await manager.handlePostRedirect(); + + expect(error?.message).toContain('state'); + expect(fetchSpy).not.toHaveBeenCalled(); + }); + + it('exchanges the code, stores tokens, clears the URL, and invokes the callback', async () => { + stubWindow(); // establishes window.crypto for handlePreDpopRedirect() + const redirectHelper = new RedirectHelper(); + const transactionState = redirectHelper.handlePreDpopRedirect( + 'my-code-verifier', + 'my-state', + ); + const { replaceState } = stubWindow( + `?code=abc123&state=${transactionState}`, + ); + const manager = makeManager('memory', makeUrlHelper(), redirectHelper); + + vi.spyOn(globalThis, 'fetch').mockResolvedValue( + makeResponse( + 200, + {}, + JSON.stringify({ + access_token: 'access-token', + refresh_token: 'refresh-token', + expires_in: 3600, + token_type: 'DPoP', + }), + ), + ); + + const callback = vi.fn(); + const result = await manager.handlePostRedirect(callback); + + expect(result).toBeUndefined(); + expect(manager.getAccessToken()).toBe('access-token'); + expect(callback).toHaveBeenCalledWith('my-state'); + expect(replaceState).toHaveBeenCalledOnce(); + }); + + it('returns an Error instead of throwing when the token exchange fails', async () => { + stubWindow(); // establishes window.crypto for handlePreDpopRedirect() + const redirectHelper = new RedirectHelper(); + const transactionState = + redirectHelper.handlePreDpopRedirect('my-code-verifier'); + stubWindow(`?code=abc123&state=${transactionState}`); + const manager = makeManager('memory', makeUrlHelper(), redirectHelper); + + vi.spyOn(globalThis, 'fetch').mockResolvedValue( + makeResponse(400, {}, 'invalid_grant'), + ); + + const error = await manager.handlePostRedirect(); + expect(error).toBeInstanceOf(Error); + }); + + it('returns an Error when token_type is not DPoP', async () => { + stubWindow(); // establishes window.crypto for handlePreDpopRedirect() + const redirectHelper = new RedirectHelper(); + const transactionState = + redirectHelper.handlePreDpopRedirect('my-code-verifier'); + stubWindow(`?code=abc123&state=${transactionState}`); + const manager = makeManager('memory', makeUrlHelper(), redirectHelper); + + vi.spyOn(globalThis, 'fetch').mockResolvedValue( + makeResponse( + 200, + {}, + JSON.stringify({ + access_token: 'a', + expires_in: 3600, + token_type: 'Bearer', + }), + ), + ); + + const error = await manager.handlePostRedirect(); + expect(error?.message).toContain('token_type'); + }); +}); + +describe('fetchUserInfo()', () => { + it('throws when no access token is stored', async () => { + const manager = makeManager(); + await expect(manager.fetchUserInfo()).rejects.toThrow( + 'No access token available. Have you called startLogin()?', + ); + }); + + it('fetches /oauth2/userinfo and returns the parsed claims', async () => { + const manager = makeManager(); + manager.setTokens(makeTokens({ accessToken: 'my-access-token' })); + + vi.spyOn(globalThis, 'fetch').mockResolvedValue( + makeResponse(200, {}, JSON.stringify({ email: 'user@example.com' })), + ); + + const userInfo = await manager.fetchUserInfo<{ email: string }>(); + expect(userInfo).toEqual({ email: 'user@example.com' }); + }); + + it('throws when the response is not ok', async () => { + const manager = makeManager(); + manager.setTokens(makeTokens()); + vi.spyOn(globalThis, 'fetch').mockResolvedValue(makeResponse(401)); + + await expect(manager.fetchUserInfo()).rejects.toThrow(/status code 401/); + }); +}); diff --git a/packages/core/src/DPoP/DPoPManager.ts b/packages/core/src/DPoP/DPoPManager.ts new file mode 100644 index 0000000..b5f567e --- /dev/null +++ b/packages/core/src/DPoP/DPoPManager.ts @@ -0,0 +1,485 @@ +import * as dpop from 'dpop'; +import type { KeyPair } from 'dpop'; + +import { DPoPStorage } from './DPoPStorage'; +import { DPoPTokenStore, DPoPTokens } from './DPoPTokenStore'; +import { UrlHelper } from '../UrlHelper'; +import { RedirectHelper } from '../RedirectHelper'; +import * as Pkce from '../Pkce'; + +/** + * Central coordinator for all DPoP operations. + * + * `SDKCore` constructs a `DPoPManager` instance when `useDpop: true`. Framework + * layers hold a reference to expose `dpopFetch` and `generateProof`. + */ +export class DPoPManager { + private readonly tokenStore: DPoPTokenStore; + private readonly storage: DPoPStorage; + private readonly urlHelper: UrlHelper; + private readonly redirectHelper: RedirectHelper; + + /** In-memory nonce cache keyed by origin (e.g. `https://api.example.com`). */ + private readonly nonces = new Map(); + + /** + * Memoised promise for the active key pair. A single `Promise` is shared so + * concurrent callers all await the same generation/load and the key pair is + * never regenerated within the lifetime of a `DPoPManager` instance (unless + * `clear()` is called). + */ + private keyPairPromise: Promise | undefined; + + constructor( + clientId: string, + urlHelper: UrlHelper, + redirectHelper: RedirectHelper, + tokenStorage: 'localStorage' | 'memory' = 'localStorage', + ) { + this.storage = new DPoPStorage({ clientId }); + this.tokenStore = new DPoPTokenStore(clientId, tokenStorage); + this.urlHelper = urlHelper; + this.redirectHelper = redirectHelper; + } + + /** + * Loads the persisted `CryptoKeyPair` from `DPoPStorage`, or generates a new + * non-extractable ES256 key pair and persists it. Lazy — called on first DPoP + * operation. Subsequent calls return the memoised result immediately. + */ + async getOrCreateKeyPair(): Promise { + if (!this.keyPairPromise) { + this.keyPairPromise = (async () => { + const existing = await this.storage.getKeyPair(); + if (existing) return existing; + + const keyPair = await dpop.generateKeyPair('ES256', { + extractable: false, + }); + await this.storage.setKeyPair(keyPair); + return keyPair; + })(); + } + return this.keyPairPromise; + } + + /** + * Computes the JWK SHA-256 thumbprint of the public key via + * `dpop.calculateThumbprint()`. Used for the `dpop_jkt` parameter on + * `/oauth2/authorize`. + */ + async getThumbprint(): Promise { + const { publicKey } = await this.getOrCreateKeyPair(); + return dpop.calculateThumbprint(publicKey); + } + + /** + * `true` when stored tokens exist and have not yet expired. Used by + * `SDKCore.isLoggedIn` in DPoP mode instead of the `app.at_exp` cookie. + */ + get isLoggedIn(): boolean { + return !this.tokenStore.isExpired; + } + + /** + * Stores a new set of DPoP-bound tokens. Called by `SDKCore` after a + * successful authorization code exchange or token refresh. + */ + setTokens(tokens: DPoPTokens): void { + this.tokenStore.set(tokens); + } + + /** + * Returns the stored refresh token string, or `null` if none is stored. + * Used by `SDKCore.refreshToken()` in DPoP mode. + */ + getRefreshToken(): string | null { + return this.tokenStore.get()?.refreshToken ?? null; + } + + /** + * Returns the stored access token string, or `null` if none is stored. + */ + getAccessToken(): string | null { + return this.tokenStore.getAccessToken(); + } + + /** + * Returns the expiration moment (ms since epoch) of the stored access + * token, or `-1` if no tokens are stored. Mirrors the `-1` convention used + * by `CookieHelpers.getAccessTokenExpirationMoment()` so `SDKCore` can + * schedule token expiration / auto-refresh identically in both modes. + */ + getExpiresAt(): number | -1 { + return this.tokenStore.get()?.expiresAt ?? -1; + } + + /** + * Generates a signed DPoP proof JWT. + * + * - `ath` (access token hash) is included only when `accessToken` is provided. + * - Nonce precedence: explicit `nonce` argument → cached nonce for the target + * origin → `undefined` (no nonce claim). + * - Per RFC 9449, `htu` is normalised by stripping any query string and + * fragment (e.g. `Request.url` may include a query string), and `htm` is + * normalised to uppercase (DPoP verifiers commonly require this). + * + * @param htu HTTP URI of the request. Any query/fragment is stripped. + * @param htm HTTP method of the request (e.g. `'POST'`). Case-insensitive. + * @param accessToken Optional access token; when provided, `ath` is included. + * @param nonce Optional explicit nonce; overrides the per-origin cache. + */ + async generateProof( + htu: string, + htm: string, + accessToken?: string, + nonce?: string, + ): Promise { + const keyPair = await this.getOrCreateKeyPair(); + + // Per RFC 9449, htu MUST NOT include the query or fragment components. + // Relative URLs (e.g. `/api/data`) are resolved against the current + // origin, since `dpopFetch()` accepts them. + const base = + typeof window !== 'undefined' ? window.location.origin : undefined; + const url = new URL(htu, base); + const normalizedHtu = `${url.origin}${url.pathname}`; + const normalizedHtm = htm.toUpperCase(); + + // Resolve the nonce: explicit arg wins, then fall back to per-origin cache. + const effectiveNonce = nonce ?? this.nonces.get(url.origin) ?? undefined; + + return dpop.generateProof( + keyPair, + normalizedHtu, + normalizedHtm, + effectiveNonce, + accessToken, + ); + } + + /** + * The `dpopFetch` implementation. + * + * 1. Retrieves the stored access token from `DPoPTokenStore`. + * 2. Generates a DPoP proof (with `ath` when an access token is available). + * 3. Sets `Authorization: DPoP ` and `DPoP: ` on the request. + * 4. Calls the native `fetch`. + * 5. On a `401` whose `WWW-Authenticate` header contains `use_dpop_nonce` + * **and** whose `DPoP-Nonce` response header is present, caches the nonce + * and retries the request exactly once. A second `401` is returned as-is. + */ + async fetch(input: RequestInfo | URL, init?: RequestInit): Promise { + // Normalise into a single Request object up front, then clone it twice — + // before either clone is read from — so the initial attempt and a + // potential retry each get an independent, unconsumed body. + // Request.clone() safely tees any internal streaming body per spec, so + // this covers Request objects, raw ReadableStream bodies passed via + // init.body, and every other allowed `fetch` input shape uniformly. + const request = this._buildWorkingRequest(input, init); + const primaryRequest = request.clone(); + const retryRequest = request.clone(); + + const response = await this._doFetch(primaryRequest); + + if (response.status === 401 && this._isUseNonceError(response)) { + // Cache the server-provided nonce for this origin. + const origin = new URL(request.url).origin; + const serverNonce = response.headers.get('DPoP-Nonce')!; + this.nonces.set(origin, serverNonce); + + // Single retry — return the result regardless of status. + return this._doFetch(retryRequest); + } + + return response; + } + + /** + * Clears all DPoP state: + * - Key pair from `DPoPStorage` + * - Tokens from `DPoPTokenStore` + * - In-memory nonce cache + * + * The memoised key-pair promise is also reset so the next call to + * `getOrCreateKeyPair()` generates a fresh key pair. Called on logout. + */ + async clear(): Promise { + this.keyPairPromise = undefined; + this.nonces.clear(); + await Promise.all([this.storage.clearKeyPair(), this.tokenStore.clear()]); + } + + /** + * Starts the authorization code grant flow. + */ + async startLogin(state?: string): Promise { + await this.getOrCreateKeyPair(); + const dpopJkt = await this.getThumbprint(); + const codeVerifier = Pkce.generateCodeVerifier(); + const codeChallenge = await Pkce.generateCodeChallenge(codeVerifier); + const transactionState = this.redirectHelper.handlePreDpopRedirect( + codeVerifier, + state, + ); + window.location.assign( + this.urlHelper.getAuthorizeUrl(dpopJkt, codeChallenge, transactionState), + ); + } + + /** + * Performs the OAut2logout flow: clears the key pair, stored tokens, and + * in-memory nonces, then redirects to `/oauth2/logout`. + */ + async startLogout(): Promise { + try { + await this.clear(); + } finally { + window.location.assign(this.urlHelper.getOAuth2LogoutUrl()); + } + } + + /** + * Performs the register flow. + */ + async startRegister(state?: string): Promise { + await this.getOrCreateKeyPair(); + const dpopJkt = await this.getThumbprint(); + const codeVerifier = Pkce.generateCodeVerifier(); + const codeChallenge = await Pkce.generateCodeChallenge(codeVerifier); + const transactionState = this.redirectHelper.handlePreDpopRedirect( + codeVerifier, + state, + ); + window.location.assign( + this.urlHelper.getOAuth2RegisterUrl( + dpopJkt, + codeChallenge, + transactionState, + ), + ); + } + + /** + * Performs the refresh token grant. + * @throws {Error} if no refresh token is stored, or the request fails. + */ + async refreshToken(): Promise { + const refreshToken = this.getRefreshToken(); + if (!refreshToken) { + throw new Error( + 'No refresh token available. Have you called startLogin()?', + ); + } + + const tokenUrl = this.urlHelper.getTokenUrl(); + const proof = await this.generateProof(tokenUrl.toString(), 'POST'); + + const body = new URLSearchParams({ + grant_type: 'refresh_token', + refresh_token: refreshToken, + client_id: this.urlHelper.clientId, + }); + + const response = await fetch(tokenUrl, { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + DPoP: proof, + }, + body: body.toString(), + }); + + if (!response.ok) { + const errorDetails = { + status: response.status, + details: + (await response.text()) || + 'Failed to refresh fusionauth access token', + }; + throw new Error(JSON.stringify(errorDetails)); + } + + const tokenResponse = await response.clone().json(); + this.setTokens(this.parseTokenResponse(tokenResponse, refreshToken)); + + return response; + } + + /** + * Performs the authorization code exchange for tokens. + */ + async handlePostRedirect( + callback?: (state?: string) => void, + ): Promise { + const code = new URLSearchParams(window.location.search).get('code'); + const codeVerifier = this.redirectHelper.getCodeVerifier(); + + // No pending exchange + if (!code || !codeVerifier) { + return undefined; + } + + // CSRF protection: the `state` echoed back on the redirect must match + // the SDK-generated `transactionState` persisted before redirecting — + // not the caller's own `state`, which may be predictable or absent and + // so cannot serve as a CSRF defense. + const returnedState = + new URLSearchParams(window.location.search).get('state') ?? undefined; + if (returnedState !== this.redirectHelper.getTransactionState()) { + return new Error( + 'FusionAuth SDK: state parameter mismatch. Aborting to prevent a possible CSRF attack.', + ); + } + + try { + const tokenUrl = this.urlHelper.getTokenUrl(); + const proof = await this.generateProof(tokenUrl.toString(), 'POST'); + + const body = new URLSearchParams({ + grant_type: 'authorization_code', + code, + code_verifier: codeVerifier, + client_id: this.urlHelper.clientId, + redirect_uri: this.urlHelper.redirectUri, + }); + + const response = await fetch(tokenUrl, { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + DPoP: proof, + }, + body: body.toString(), + }); + + if (!response.ok) { + const errorDetails = { + status: response.status, + details: + (await response.text()) || + 'Failed to exchange authorization code for tokens', + }; + return new Error(JSON.stringify(errorDetails)); + } + + const tokenResponse = await response.json(); + const tokens = this.parseTokenResponse(tokenResponse); + this.setTokens(tokens); + + this.redirectHelper.clearCodeFromUrl(); + this.redirectHelper.handlePostRedirect(callback); + return undefined; + } catch (error) { + return error as Error; + } + } + + /** + * Fetches userInfo from `/oauth2/userinfo`. + * @throws {Error} if no access token is stored, or the request fails. + */ + async fetchUserInfo(): Promise { + const accessToken = this.getAccessToken(); + if (!accessToken) { + throw new Error( + 'No access token available. Have you called startLogin()?', + ); + } + + const userInfoResponse = await this.fetch(this.urlHelper.getUserInfoUrl()); + + if (!userInfoResponse.ok) { + throw new Error( + `Unable to fetch userInfo. Request failed with status code ${userInfoResponse?.status}`, + ); + } + + return (await userInfoResponse.json()) as T; + } + + // --------------------------------------------------------------------------- + // Private helpers + // --------------------------------------------------------------------------- + + /** Builds the request with DPoP headers and delegates to native `fetch`. */ + private async _doFetch(request: Request): Promise { + const accessToken = this.tokenStore.getAccessToken(); + const proof = await this.generateProof( + request.url, + request.method, + accessToken ?? undefined, + ); + + // Request.headers is a live, mutable Headers instance — set the + // DPoP-specific headers directly on it rather than reconstructing. + if (accessToken) { + request.headers.set('Authorization', `DPoP ${accessToken}`); + } + request.headers.set('DPoP', proof); + + return globalThis.fetch(request); + } + + /** Returns `true` when the response signals a DPoP nonce retry is warranted */ + private _isUseNonceError(response: Response): boolean { + const wwwAuth = response.headers.get('WWW-Authenticate') ?? ''; + return ( + wwwAuth.includes('use_dpop_nonce') && response.headers.has('DPoP-Nonce') + ); + } + + /** + * Normalises any allowed `fetch()` input shape into a single `Request` + * object, merging headers from both `input` (when it's a `Request`) and + * `init` so neither source is silently dropped. + + */ + private _buildWorkingRequest( + input: RequestInfo | URL, + init?: RequestInit, + ): Request { + if (!(input instanceof Request)) { + return new Request(input, init); + } + + const headers = new Headers(init?.headers); + input.headers.forEach((value, key) => headers.set(key, value)); + return new Request(input.clone(), { ...init, headers }); + } + + /** + * Validates a `/oauth2/token` response. + */ + private parseTokenResponse( + tokenResponse: { + access_token?: string; + refresh_token?: string; + expires_in?: number; + token_type?: string; + }, + fallbackRefreshToken?: string, + ): DPoPTokens { + if (tokenResponse.token_type !== 'DPoP') { + throw new Error( + `FusionAuth SDK: expected token_type "DPoP" but received "${tokenResponse.token_type}".`, + ); + } + if ( + typeof tokenResponse.expires_in !== 'number' || + !Number.isFinite(tokenResponse.expires_in) || + tokenResponse.expires_in <= 0 + ) { + throw new Error( + `FusionAuth SDK: invalid expires_in "${tokenResponse.expires_in}" in token response.`, + ); + } + + return { + accessToken: tokenResponse.access_token!, + refreshToken: tokenResponse.refresh_token ?? fallbackRefreshToken, + expiresAt: Date.now() + tokenResponse.expires_in * 1000, + tokenType: 'DPoP', + }; + } +} diff --git a/packages/core/src/DPoP/DPoPStorage.test.ts b/packages/core/src/DPoP/DPoPStorage.test.ts new file mode 100644 index 0000000..4b4a03d --- /dev/null +++ b/packages/core/src/DPoP/DPoPStorage.test.ts @@ -0,0 +1,258 @@ +import { describe, it, expect, beforeEach } from 'vitest'; +import { IDBFactory } from 'fake-indexeddb'; +import { generateKeyPair } from 'dpop'; + +import { + DPoPStorage, + DEFAULT_DPOP_DB_NAME, + DEFAULT_DPOP_DB_VERSION, + DEFAULT_DPOP_STORE_NAME, +} from './DPoPStorage'; + +// Provide a fresh in-process IndexedDB for each test so tests are isolated. +beforeEach(() => { + // @ts-ignore — jsdom does not implement indexedDB; fake-indexeddb fills the gap. + globalThis.indexedDB = new IDBFactory(); +}); + +describe('DPoPStorage', () => { + it('returns undefined when no key pair has been stored', async () => { + const storage = new DPoPStorage({ clientId: 'client-a' }); + const result = await storage.getKeyPair(); + expect(result).toBeUndefined(); + }); + + it('persists a key pair and retrieves it', async () => { + const storage = new DPoPStorage({ clientId: 'client-a' }); + const keyPair = await generateKeyPair('ES256', { extractable: false }); + + await storage.setKeyPair(keyPair); + const retrieved = await storage.getKeyPair(); + + expect(retrieved).toBeDefined(); + // CryptoKey objects are deserialized from IndexedDB — reference equality + // will not hold. Assert structural identity instead. + expect(retrieved!.privateKey.type).toBe('private'); + expect(retrieved!.privateKey.algorithm).toStrictEqual( + keyPair.privateKey.algorithm, + ); + expect(retrieved!.publicKey.type).toBe('public'); + expect(retrieved!.publicKey.algorithm).toStrictEqual( + keyPair.publicKey.algorithm, + ); + }); + + it('returns the same key pair on a subsequent call (same IDBFactory instance)', async () => { + const storage = new DPoPStorage({ clientId: 'client-a' }); + const keyPair = await generateKeyPair('ES256', { extractable: false }); + await storage.setKeyPair(keyPair); + + const first = await storage.getKeyPair(); + const second = await storage.getKeyPair(); + + expect(second!.privateKey.algorithm).toStrictEqual( + first!.privateKey.algorithm, + ); + expect(second!.publicKey.algorithm).toStrictEqual( + first!.publicKey.algorithm, + ); + }); + + it('clearKeyPair removes the stored value', async () => { + const storage = new DPoPStorage({ clientId: 'client-a' }); + const keyPair = await generateKeyPair('ES256', { extractable: false }); + await storage.setKeyPair(keyPair); + + await storage.clearKeyPair(); + + const result = await storage.getKeyPair(); + expect(result).toBeUndefined(); + }); + + it('isolates key pairs by clientId — different clients do not share keys', async () => { + const storageA = new DPoPStorage({ clientId: 'client-a' }); + const storageB = new DPoPStorage({ clientId: 'client-b' }); + + const keyPairA = await generateKeyPair('ES256', { extractable: false }); + await storageA.setKeyPair(keyPairA); + + // client-b should see nothing + const resultB = await storageB.getKeyPair(); + expect(resultB).toBeUndefined(); + + // client-a's data is still intact + const resultA = await storageA.getKeyPair(); + expect(resultA).toBeDefined(); + expect(resultA!.privateKey.algorithm).toStrictEqual( + keyPairA.privateKey.algorithm, + ); + }); + + it('clearKeyPair for one clientId does not affect another', async () => { + const storageA = new DPoPStorage({ clientId: 'client-a' }); + const storageB = new DPoPStorage({ clientId: 'client-b' }); + + const keyPairA = await generateKeyPair('ES256', { extractable: false }); + const keyPairB = await generateKeyPair('ES256', { extractable: false }); + await storageA.setKeyPair(keyPairA); + await storageB.setKeyPair(keyPairB); + + await storageA.clearKeyPair(); + + expect(await storageA.getKeyPair()).toBeUndefined(); + const resultB = await storageB.getKeyPair(); + expect(resultB).toBeDefined(); + expect(resultB!.privateKey.algorithm).toStrictEqual( + keyPairB.privateKey.algorithm, + ); + }); + + describe('config defaults', () => { + it('uses DEFAULT_DPOP_DB_NAME when dbName is not provided', async () => { + const storage = new DPoPStorage({ clientId: 'client-a' }); + const keyPair = await generateKeyPair('ES256', { extractable: false }); + await storage.setKeyPair(keyPair); + + // Verify the key landed in the default database by opening it directly. + const db = await new Promise((resolve, reject) => { + const req = indexedDB.open( + DEFAULT_DPOP_DB_NAME, + DEFAULT_DPOP_DB_VERSION, + ); + req.onsuccess = () => resolve(req.result); + req.onerror = () => reject(req.error); + }); + const result = await new Promise((resolve, reject) => { + const tx = db.transaction(DEFAULT_DPOP_STORE_NAME, 'readonly'); + const req = tx.objectStore(DEFAULT_DPOP_STORE_NAME).get('client-a'); + tx.oncomplete = () => { + db.close(); + resolve(req.result); + }; + tx.onerror = () => { + db.close(); + reject(tx.error); + }; + }); + expect(result).toBeDefined(); + }); + + it('uses custom dbName and storeName when provided', async () => { + const storage = new DPoPStorage({ + clientId: 'client-a', + dbName: 'my-custom-db', + storeName: 'my-custom-store', + }); + const keyPair = await generateKeyPair('ES256', { extractable: false }); + await storage.setKeyPair(keyPair); + + // Verify the key landed in the custom database, not the default one. + const customDb = await new Promise((resolve, reject) => { + const req = indexedDB.open('my-custom-db', DEFAULT_DPOP_DB_VERSION); + req.onupgradeneeded = e => { + (e.target as IDBOpenDBRequest).result.createObjectStore( + 'my-custom-store', + ); + }; + req.onsuccess = () => resolve(req.result); + req.onerror = () => reject(req.error); + }); + const result = await new Promise((resolve, reject) => { + const tx = customDb.transaction('my-custom-store', 'readonly'); + const req = tx.objectStore('my-custom-store').get('client-a'); + tx.oncomplete = () => { + customDb.close(); + resolve(req.result); + }; + tx.onerror = () => { + customDb.close(); + reject(tx.error); + }; + }); + expect(result).toBeDefined(); + + // And nothing landed in the default database. + const defaultStorage = new DPoPStorage({ clientId: 'client-a' }); + expect(await defaultStorage.getKeyPair()).toBeUndefined(); + }); + + it('two instances with different dbNames but the same clientId do not share keys', async () => { + const storageA = new DPoPStorage({ + clientId: 'client-a', + dbName: 'db-one', + }); + const storageB = new DPoPStorage({ + clientId: 'client-a', + dbName: 'db-two', + }); + + const keyPair = await generateKeyPair('ES256', { extractable: false }); + await storageA.setKeyPair(keyPair); + + expect(await storageB.getKeyPair()).toBeUndefined(); + }); + + it('rejects with a VersionError when dbVersion is lower than an already-open database', async () => { + // Open the database at version 2 first. + await new Promise((resolve, reject) => { + const req = indexedDB.open(DEFAULT_DPOP_DB_NAME, 2); + req.onupgradeneeded = e => { + const db = (e.target as IDBOpenDBRequest).result; + if (!db.objectStoreNames.contains(DEFAULT_DPOP_STORE_NAME)) { + db.createObjectStore(DEFAULT_DPOP_STORE_NAME); + } + }; + req.onsuccess = () => { + req.result.close(); + resolve(); + }; + req.onerror = () => reject(req.error); + }); + + // Now attempt to open the same database at version 1 — must reject. + const storage = new DPoPStorage({ + clientId: 'client-a', + dbVersion: 1, // lower than the persisted version 2 + }); + await expect(storage.getKeyPair()).rejects.toBeDefined(); + }); + }); + + describe('openDb() error handling', () => { + it('rejects with a descriptive error when indexedDB is unavailable (SSR / non-browser)', async () => { + // @ts-ignore + delete globalThis.indexedDB; + + const storage = new DPoPStorage({ clientId: 'client-a' }); + await expect(storage.getKeyPair()).rejects.toThrow( + 'indexedDB is not available in this environment', + ); + await expect( + storage.setKeyPair( + await generateKeyPair('ES256', { extractable: false }), + ), + ).rejects.toThrow('indexedDB is not available in this environment'); + await expect(storage.clearKeyPair()).rejects.toThrow( + 'indexedDB is not available in this environment', + ); + // globalThis.indexedDB is restored by the next beforeEach + }); + + it('rejects when indexedDB.open() throws synchronously', async () => { + const originalOpen = globalThis.indexedDB.open.bind(globalThis.indexedDB); + + try { + globalThis.indexedDB.open = () => { + throw new Error('blocked by security policy'); + }; + + const storage = new DPoPStorage({ clientId: 'client-a' }); + await expect(storage.getKeyPair()).rejects.toThrow( + 'blocked by security policy', + ); + } finally { + globalThis.indexedDB.open = originalOpen; + } + }); + }); +}); diff --git a/packages/core/src/DPoP/DPoPStorage.ts b/packages/core/src/DPoP/DPoPStorage.ts new file mode 100644 index 0000000..c776a96 --- /dev/null +++ b/packages/core/src/DPoP/DPoPStorage.ts @@ -0,0 +1,163 @@ +import type { KeyPair } from 'dpop'; + +export const DEFAULT_DPOP_DB_NAME = 'fusionauth-sdk:dpop'; +export const DEFAULT_DPOP_DB_VERSION = 1; +export const DEFAULT_DPOP_STORE_NAME = 'keypair'; + +/** + * Configuration for `DPoPStorage`. + * + * All fields except `clientId` are optional and fall back to well-known + * defaults. Override them only when you have a specific reason to do so — + * for example, to isolate parallel test runs or to avoid collisions with + * another SDK instance on the same origin. + * + * **`dbVersion` warning:** IndexedDB versions can only increase. If a browser + * already has the database open at version N, opening the same database name + * at version M < N will fail with a `VersionError`. Only increase + * `dbVersion` (relative to whatever is already persisted in browsers), and + * only do so when you also need to make a structural change to the object + * store inside `onupgradeneeded`. Never decrement it. + */ +export interface DPoPStorageConfig { + /** + * The OAuth2 `client_id` of the application. Used to namespace key pairs + * so that multiple FusionAuth applications on the same origin do not share + * IndexedDB records. + */ + clientId: string; + + /** + * IndexedDB database name. + * @default 'fusionauth-sdk:dpop' + */ + dbName?: string; + + /** + * IndexedDB schema version. Must only increase — see warning above. + * @default 1 + */ + dbVersion?: number; + + /** + * Name of the IndexedDB object store used to persist key pairs. + * @default 'keypair' + */ + storeName?: string; +} + +/** + * IndexedDB abstraction for persisting the ES256 `CryptoKeyPair` across + * browser sessions. Keys are namespaced by `clientId` to isolate multiple + * FusionAuth applications hosted on the same origin. + */ +export class DPoPStorage { + private readonly clientId: string; + private readonly dbName: string; + private readonly dbVersion: number; + private readonly storeName: string; + + constructor(config: DPoPStorageConfig) { + this.clientId = config.clientId; + this.dbName = config.dbName ?? DEFAULT_DPOP_DB_NAME; + this.dbVersion = config.dbVersion ?? DEFAULT_DPOP_DB_VERSION; + this.storeName = config.storeName ?? DEFAULT_DPOP_STORE_NAME; + } + + /** + * Retrieves the persisted `CryptoKeyPair` for this `clientId`, or + * `undefined` if none exists. + */ + async getKeyPair(): Promise { + const db = await this.openDb(); + return new Promise((resolve, reject) => { + const tx = db.transaction(this.storeName, 'readonly'); + const req = tx.objectStore(this.storeName).get(this.clientId); + tx.oncomplete = () => { + db.close(); + resolve(req.result as KeyPair | undefined); + }; + tx.onerror = () => { + db.close(); + reject(tx.error); + }; + tx.onabort = () => { + db.close(); + reject(tx.error ?? new Error('IndexedDB transaction aborted')); + }; + }); + } + + /** + * Persists a `CryptoKeyPair` to IndexedDB under this `clientId`. + */ + async setKeyPair(keyPair: KeyPair): Promise { + const db = await this.openDb(); + return new Promise((resolve, reject) => { + const tx = db.transaction(this.storeName, 'readwrite'); + tx.objectStore(this.storeName).put(keyPair, this.clientId); + tx.oncomplete = () => { + db.close(); + resolve(); + }; + tx.onerror = () => { + db.close(); + reject(tx.error); + }; + tx.onabort = () => { + db.close(); + reject(tx.error ?? new Error('IndexedDB transaction aborted')); + }; + }); + } + + /** + * Removes the stored key pair for this `clientId`. Called on logout. + */ + async clearKeyPair(): Promise { + const db = await this.openDb(); + return new Promise((resolve, reject) => { + const tx = db.transaction(this.storeName, 'readwrite'); + tx.objectStore(this.storeName).delete(this.clientId); + tx.oncomplete = () => { + db.close(); + resolve(); + }; + tx.onerror = () => { + db.close(); + reject(tx.error); + }; + tx.onabort = () => { + db.close(); + reject(tx.error ?? new Error('IndexedDB transaction aborted')); + }; + }); + } + + private openDb(): Promise { + return new Promise((resolve, reject) => { + // Graceful fallback for non-browser/SSR environments. + if (typeof indexedDB === 'undefined') { + reject(new Error('indexedDB is not available in this environment')); + return; + } + let req: IDBOpenDBRequest; + try { + req = indexedDB.open(this.dbName, this.dbVersion); + } catch (err) { + reject(err); + return; + } + + req.onupgradeneeded = event => { + const db = (event.target as IDBOpenDBRequest).result; + if (!db.objectStoreNames.contains(this.storeName)) { + db.createObjectStore(this.storeName); + } + }; + + req.onsuccess = () => resolve(req.result); + req.onerror = () => reject(req.error); + }); + } +} diff --git a/packages/core/src/DPoP/DPoPTokenStore.test.ts b/packages/core/src/DPoP/DPoPTokenStore.test.ts new file mode 100644 index 0000000..ea866f4 --- /dev/null +++ b/packages/core/src/DPoP/DPoPTokenStore.test.ts @@ -0,0 +1,176 @@ +import { describe, it, expect, beforeEach } from 'vitest'; + +import { DPoPTokenStore, DPoPTokens } from './DPoPTokenStore'; + +const CLIENT_ID = 'test-client'; +const STORAGE_KEY = `fusionauth-sdk:tokens:${CLIENT_ID}`; + +function makeTokens(overrides?: Partial): DPoPTokens { + return { + accessToken: 'access-token-value', + refreshToken: 'refresh-token-value', + expiresAt: Date.now() + 60_000, // expires in 60 s by default + tokenType: 'DPoP', + ...overrides, + }; +} + +beforeEach(() => { + localStorage.clear(); +}); + +describe('DPoPTokenStore — localStorage mode', () => { + it('returns null when nothing is stored', () => { + const store = new DPoPTokenStore(CLIENT_ID, 'localStorage'); + expect(store.get()).toBeNull(); + }); + + it('tokens survive get() after set()', () => { + const store = new DPoPTokenStore(CLIENT_ID, 'localStorage'); + const tokens = makeTokens(); + + store.set(tokens); + const retrieved = store.get(); + + expect(retrieved).toEqual(tokens); + }); + + it('writes tokens to localStorage', () => { + const store = new DPoPTokenStore(CLIENT_ID, 'localStorage'); + const tokens = makeTokens(); + + store.set(tokens); + + const raw = localStorage.getItem(STORAGE_KEY); + expect(raw).not.toBeNull(); + expect(JSON.parse(raw!)).toEqual(tokens); + }); + + it('clear() removes tokens', () => { + const store = new DPoPTokenStore(CLIENT_ID, 'localStorage'); + store.set(makeTokens()); + + store.clear(); + + expect(store.get()).toBeNull(); + expect(localStorage.getItem(STORAGE_KEY)).toBeNull(); + }); + + it('getAccessToken() returns the access token string after set()', () => { + const store = new DPoPTokenStore(CLIENT_ID, 'localStorage'); + store.set(makeTokens()); + + expect(store.getAccessToken()).toBe('access-token-value'); + }); + + it('getAccessToken() returns null when no tokens are stored', () => { + const store = new DPoPTokenStore(CLIENT_ID, 'localStorage'); + expect(store.getAccessToken()).toBeNull(); + }); + + it('getAccessToken() returns null after clear()', () => { + const store = new DPoPTokenStore(CLIENT_ID, 'localStorage'); + store.set(makeTokens()); + store.clear(); + + expect(store.getAccessToken()).toBeNull(); + }); + + it('isExpired returns false when tokens are fresh', () => { + const store = new DPoPTokenStore(CLIENT_ID, 'localStorage'); + store.set(makeTokens({ expiresAt: Date.now() + 60_000 })); + + expect(store.isExpired).toBe(false); + }); + + it('isExpired returns true when expiresAt is in the past', () => { + const store = new DPoPTokenStore(CLIENT_ID, 'localStorage'); + store.set(makeTokens({ expiresAt: Date.now() - 1 })); + + expect(store.isExpired).toBe(true); + }); + + it('isExpired returns true when no tokens are stored', () => { + const store = new DPoPTokenStore(CLIENT_ID, 'localStorage'); + expect(store.isExpired).toBe(true); + }); + + it('defaults to localStorage when no storageType is provided', () => { + const store = new DPoPTokenStore(CLIENT_ID); + const tokens = makeTokens(); + store.set(tokens); + + expect(localStorage.getItem(STORAGE_KEY)).not.toBeNull(); + }); +}); + +describe('DPoPTokenStore — memory mode', () => { + it('returns null when nothing is stored', () => { + const store = new DPoPTokenStore(CLIENT_ID, 'memory'); + expect(store.get()).toBeNull(); + }); + + it('tokens survive get() after set()', () => { + const store = new DPoPTokenStore(CLIENT_ID, 'memory'); + const tokens = makeTokens(); + + store.set(tokens); + + expect(store.get()).toEqual(tokens); + }); + + it('does NOT write tokens to localStorage', () => { + const store = new DPoPTokenStore(CLIENT_ID, 'memory'); + store.set(makeTokens()); + + expect(localStorage.getItem(STORAGE_KEY)).toBeNull(); + }); + + it('clear() removes tokens from memory', () => { + const store = new DPoPTokenStore(CLIENT_ID, 'memory'); + store.set(makeTokens()); + + store.clear(); + + expect(store.get()).toBeNull(); + }); + + it('getAccessToken() returns the access token string after set()', () => { + const store = new DPoPTokenStore(CLIENT_ID, 'memory'); + store.set(makeTokens()); + + expect(store.getAccessToken()).toBe('access-token-value'); + }); + + it('getAccessToken() returns null when no tokens are stored', () => { + const store = new DPoPTokenStore(CLIENT_ID, 'memory'); + expect(store.getAccessToken()).toBeNull(); + }); + + it('getAccessToken() returns null after clear()', () => { + const store = new DPoPTokenStore(CLIENT_ID, 'memory'); + store.set(makeTokens()); + store.clear(); + + expect(store.getAccessToken()).toBeNull(); + }); + + it('isExpired returns false when tokens are fresh', () => { + const store = new DPoPTokenStore(CLIENT_ID, 'memory'); + store.set(makeTokens({ expiresAt: Date.now() + 60_000 })); + + expect(store.isExpired).toBe(false); + }); + + it('isExpired returns true when expiresAt is in the past', () => { + const store = new DPoPTokenStore(CLIENT_ID, 'memory'); + store.set(makeTokens({ expiresAt: Date.now() - 1 })); + + expect(store.isExpired).toBe(true); + }); + + it('isExpired returns true when no tokens are stored', () => { + const store = new DPoPTokenStore(CLIENT_ID, 'memory'); + expect(store.isExpired).toBe(true); + }); +}); diff --git a/packages/core/src/DPoP/DPoPTokenStore.ts b/packages/core/src/DPoP/DPoPTokenStore.ts new file mode 100644 index 0000000..62ba783 --- /dev/null +++ b/packages/core/src/DPoP/DPoPTokenStore.ts @@ -0,0 +1,101 @@ +/** + * Shape of a DPoP-bound token set stored by `DPoPTokenStore`. + */ +export interface DPoPTokens { + accessToken: string; + refreshToken: string | undefined; + /** Unix timestamp in milliseconds when the access token expires. */ + expiresAt: number; + tokenType: 'DPoP'; +} + +/** + * Storage backend for DPoP-bound access and refresh tokens. + * + * - `'localStorage'`: tokens are persisted in `localStorage` under the key + * `fusionauth-sdk:tokens:` and survive page reloads. + * - `'memory'`: tokens are kept in memory only and are lost on page reload. + * + * The backend is selected at construction time via the `storageType` option, + * which corresponds to `SDKConfig.dpopTokenStorage`. + */ +export class DPoPTokenStore { + private readonly storageKey: string; + private readonly storageType: 'localStorage' | 'memory'; + private memoryStore: DPoPTokens | null = null; + + constructor( + clientId: string, + storageType: 'localStorage' | 'memory' = 'localStorage', + ) { + this.storageKey = `fusionauth-sdk:tokens:${clientId}`; + this.storageType = storageType; + } + + /** Returns the stored `DPoPTokens`, or `null` if none are stored. */ + get(): DPoPTokens | null { + if (this.storageType === 'memory') { + return this.memoryStore; + } + + const raw = this.getLocalStorage()?.getItem(this.storageKey); + if (!raw) return null; + + try { + const parsed = JSON.parse(raw) as Partial; + if ( + typeof parsed.accessToken !== 'string' || + (parsed.refreshToken !== undefined && + typeof parsed.refreshToken !== 'string') || + typeof parsed.expiresAt !== 'number' || + parsed.tokenType !== 'DPoP' + ) { + return null; + } + return parsed as DPoPTokens; + } catch { + return null; + } + } + + /** Stores a new set of DPoP tokens. */ + set(tokens: DPoPTokens): void { + if (this.storageType === 'memory') { + this.memoryStore = tokens; + return; + } + + this.getLocalStorage()?.setItem(this.storageKey, JSON.stringify(tokens)); + } + + /** Removes stored tokens. Called on logout. */ + clear(): void { + this.memoryStore = null; + this.getLocalStorage()?.removeItem(this.storageKey); + } + + /** + * Returns the stored access token string, or `null` if no tokens are stored. + */ + getAccessToken(): string | null { + return this.get()?.accessToken ?? null; + } + + /** + * Returns `true` if the stored tokens have expired (i.e. `expiresAt` is in + * the past), or if no tokens are stored. + */ + get isExpired(): boolean { + const tokens = this.get(); + if (!tokens) return true; + return tokens.expiresAt <= Date.now(); + } + + private getLocalStorage(): Storage | null { + try { + return localStorage; + } catch { + return null; + } + } +} diff --git a/packages/core/src/DPoP/index.ts b/packages/core/src/DPoP/index.ts new file mode 100644 index 0000000..7e19bd5 --- /dev/null +++ b/packages/core/src/DPoP/index.ts @@ -0,0 +1,3 @@ +export * from './DPoPStorage'; +export * from './DPoPTokenStore'; +export * from './DPoPManager'; diff --git a/packages/core/src/Pkce/Pkce.test.ts b/packages/core/src/Pkce/Pkce.test.ts new file mode 100644 index 0000000..2ac09b6 --- /dev/null +++ b/packages/core/src/Pkce/Pkce.test.ts @@ -0,0 +1,75 @@ +// @vitest-environment node +// crypto.subtle.digest requires a spec-compliant SubtleCrypto implementation. +// The jsdom environment's crypto only provides getRandomValues/randomUUID. +// The node environment has a full WebCrypto implementation, matching the +// browser target for which this code is written. + +import { describe, it, expect } from 'vitest'; +import { generateCodeVerifier, generateCodeChallenge } from './Pkce'; + +// --------------------------------------------------------------------------- +// RFC 7636 Appendix B test vector +// verifier: dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk +// challenge: E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM +// (Same vector referenced in UrlHelper.test.ts) +// --------------------------------------------------------------------------- +const RFC_VERIFIER = 'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk'; +const RFC_CHALLENGE = 'E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM'; + +describe('Pkce', () => { + describe('generateCodeVerifier', () => { + it('returns a base64url string of 43 characters (32 bytes encoded)', () => { + const verifier = generateCodeVerifier(); + expect(verifier).toHaveLength(43); + }); + + it('uses only base64url characters [A-Za-z0-9\\-_]', () => { + const verifier = generateCodeVerifier(); + expect(verifier).toMatch(/^[A-Za-z0-9\-_]+$/); + }); + + it('contains no base64 padding characters', () => { + const verifier = generateCodeVerifier(); + expect(verifier).not.toContain('='); + }); + + it('produces a different value on each call (collision-resistant)', () => { + const a = generateCodeVerifier(); + const b = generateCodeVerifier(); + expect(a).not.toBe(b); + }); + }); + + describe('generateCodeChallenge', () => { + it('matches the RFC 7636 Appendix B test vector', async () => { + const challenge = await generateCodeChallenge(RFC_VERIFIER); + expect(challenge).toBe(RFC_CHALLENGE); + }); + + it('returns a base64url string with no padding', async () => { + const verifier = generateCodeVerifier(); + const challenge = await generateCodeChallenge(verifier); + expect(challenge).toMatch(/^[A-Za-z0-9\-_]+$/); + expect(challenge).not.toContain('='); + }); + + it('returns a 43-character string (SHA-256 → 32 bytes → base64url)', async () => { + const verifier = generateCodeVerifier(); + const challenge = await generateCodeChallenge(verifier); + expect(challenge).toHaveLength(43); + }); + + it('produces the same challenge for the same verifier (deterministic)', async () => { + const verifier = generateCodeVerifier(); + const a = await generateCodeChallenge(verifier); + const b = await generateCodeChallenge(verifier); + expect(a).toBe(b); + }); + + it('produces different challenges for different verifiers', async () => { + const a = await generateCodeChallenge(generateCodeVerifier()); + const b = await generateCodeChallenge(generateCodeVerifier()); + expect(a).not.toBe(b); + }); + }); +}); diff --git a/packages/core/src/Pkce/Pkce.ts b/packages/core/src/Pkce/Pkce.ts new file mode 100644 index 0000000..fc05cbb --- /dev/null +++ b/packages/core/src/Pkce/Pkce.ts @@ -0,0 +1,51 @@ +/** + * PKCE (Proof Key for Code Exchange) utilities — RFC 7636. + * + * Uses the bare global `crypto` object (available as `globalThis.crypto` in + * browsers, Node 19+, and the vitest node environment) rather than + * `window.crypto` so that both browser and non-browser environments can call + * these functions without mocking. + */ + +/** + * Generates a cryptographically random PKCE `code_verifier`. + * + * The verifier is 32 random bytes encoded as base64url (43 characters), + * satisfying RFC 7636 §4.1 (43–128 characters from the unreserved character + * set `[A-Z a-z 0-9 - . _ ~]`). + */ +export function generateCodeVerifier(): string { + const array = new Uint8Array(32); + crypto.getRandomValues(array); + return base64urlEncode(array); +} + +/** + * Computes the PKCE `code_challenge` from a `code_verifier`. + * + * `code_challenge = BASE64URL(SHA-256(ASCII(code_verifier)))` — RFC 7636 §4.2. + * + * @param verifier A `code_verifier` generated by {@link generateCodeVerifier}. + */ +export async function generateCodeChallenge(verifier: string): Promise { + const data = new TextEncoder().encode(verifier); + const hash = await crypto.subtle.digest('SHA-256', data); + return base64urlEncode(new Uint8Array(hash)); +} + +// --------------------------------------------------------------------------- +// Private helpers +// --------------------------------------------------------------------------- + +/** Encodes a `Uint8Array` as a base64url string (no padding). */ +function base64urlEncode(bytes: Uint8Array): string { + // Convert bytes to a binary string, then btoa, then convert to base64url. + let binary = ''; + for (let i = 0; i < bytes.length; i++) { + binary += String.fromCharCode(bytes[i]!); + } + return btoa(binary) + .replace(/\+/g, '-') + .replace(/\//g, '_') + .replace(/=+$/, ''); +} diff --git a/packages/core/src/Pkce/index.ts b/packages/core/src/Pkce/index.ts new file mode 100644 index 0000000..5b82d5c --- /dev/null +++ b/packages/core/src/Pkce/index.ts @@ -0,0 +1 @@ +export * from './Pkce'; diff --git a/packages/core/src/RedirectHelper/RedirectHelper.test.ts b/packages/core/src/RedirectHelper/RedirectHelper.test.ts new file mode 100644 index 0000000..598ec45 --- /dev/null +++ b/packages/core/src/RedirectHelper/RedirectHelper.test.ts @@ -0,0 +1,262 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { RedirectHelper } from './RedirectHelper'; +import { mockWindowLocation } from '../testUtils'; + +describe('RedirectHelper', () => { + afterEach(() => { + localStorage.clear(); + vi.restoreAllMocks(); + }); + + describe('handlePreRedirect / handlePostRedirect (hosted backend mode)', () => { + it('stores a redirect marker in localStorage', () => { + const helper = new RedirectHelper(); + expect(localStorage.getItem('fa-sdk-redirect-value')).toBeNull(); + + helper.handlePreRedirect(); + expect(localStorage.getItem('fa-sdk-redirect-value')).not.toBeNull(); + }); + + it('invokes the callback with undefined when no state was provided', () => { + const helper = new RedirectHelper(); + const callback = vi.fn(); + + helper.handlePreRedirect(); + helper.handlePostRedirect(callback); + + expect(callback).toHaveBeenCalledOnce(); + expect(callback).toHaveBeenCalledWith(undefined); + }); + + it('invokes the callback with the stored state', () => { + const helper = new RedirectHelper(); + const callback = vi.fn(); + + helper.handlePreRedirect('my-state'); + helper.handlePostRedirect(callback); + + expect(callback).toHaveBeenCalledWith('my-state'); + }); + + it('preserves state values that contain colons', () => { + const helper = new RedirectHelper(); + const callback = vi.fn(); + const stateWithColons = 'return:/dashboard?tab=2'; + + helper.handlePreRedirect(stateWithColons); + helper.handlePostRedirect(callback); + + expect(callback).toHaveBeenCalledWith(stateWithColons); + }); + + it('removes the redirect marker from localStorage after post-redirect', () => { + const helper = new RedirectHelper(); + + helper.handlePreRedirect('some-state'); + expect(localStorage.getItem('fa-sdk-redirect-value')).not.toBeNull(); + + helper.handlePostRedirect(); + expect(localStorage.getItem('fa-sdk-redirect-value')).toBeNull(); + }); + + it('does not invoke callback when no redirect was initiated', () => { + const helper = new RedirectHelper(); + const callback = vi.fn(); + + helper.handlePostRedirect(callback); + + expect(callback).not.toHaveBeenCalled(); + }); + + it('does not throw when no callback is provided to handlePostRedirect', () => { + const helper = new RedirectHelper(); + helper.handlePreRedirect('state'); + expect(() => helper.handlePostRedirect()).not.toThrow(); + }); + }); + + describe('handlePreDpopRedirect (DPoP mode)', () => { + it('persists the code_verifier and returns it via getCodeVerifier()', () => { + const helper = new RedirectHelper(); + const verifier = 'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk'; + + helper.handlePreDpopRedirect(verifier); + + expect(helper.getCodeVerifier()).toBe(verifier); + }); + + it('persists code_verifier, state, and transactionState; all are retrievable', () => { + const helper = new RedirectHelper(); + const verifier = 'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk'; + const state = 'my-state'; + const callback = vi.fn(); + + const transactionState = helper.handlePreDpopRedirect(verifier, state); + + expect(helper.getCodeVerifier()).toBe(verifier); + expect(helper.getTransactionState()).toBe(transactionState); + helper.handlePostRedirect(callback); + expect(callback).toHaveBeenCalledWith(state); + }); + + it('returns a transactionState distinct from both the code_verifier and the caller state', () => { + const helper = new RedirectHelper(); + const verifier = 'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk'; + const state = 'my-state'; + + const transactionState = helper.handlePreDpopRedirect(verifier, state); + + expect(transactionState).not.toBe(verifier); + expect(transactionState).not.toBe(state); + expect(transactionState.length).toBeGreaterThan(0); + }); + + it('generates a different transactionState on each call', () => { + const helper = new RedirectHelper(); + + const first = helper.handlePreDpopRedirect('verifier-1'); + const second = helper.handlePreDpopRedirect('verifier-2'); + + expect(first).not.toBe(second); + }); + + it('preserves state with colons alongside a code_verifier', () => { + const helper = new RedirectHelper(); + const verifier = 'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk'; + const stateWithColons = 'return:/dashboard?tab=2'; + const callback = vi.fn(); + + helper.handlePreDpopRedirect(verifier, stateWithColons); + + expect(helper.getCodeVerifier()).toBe(verifier); + helper.handlePostRedirect(callback); + expect(callback).toHaveBeenCalledWith(stateWithColons); + }); + + it('returns undefined from getCodeVerifier() when no redirect was initiated', () => { + const helper = new RedirectHelper(); + expect(helper.getCodeVerifier()).toBeUndefined(); + }); + + it('returns undefined from getCodeVerifier() when no verifier was stored (hosted backend mode)', () => { + const helper = new RedirectHelper(); + helper.handlePreRedirect('some-state'); + expect(helper.getCodeVerifier()).toBeUndefined(); + }); + + it('getCodeVerifier() still works after a handlePostRedirect call clears storage', () => { + const helper = new RedirectHelper(); + helper.handlePreDpopRedirect('verifier-value', 'state'); + + // Post-redirect removes the marker. + helper.handlePostRedirect(); + + // After cleanup, getCodeVerifier() should return undefined. + expect(helper.getCodeVerifier()).toBeUndefined(); + }); + + it('getState() returns the persisted state', () => { + const helper = new RedirectHelper(); + helper.handlePreDpopRedirect('verifier-value', 'my-state'); + expect(helper.getState()).toBe('my-state'); + }); + + it('getState() returns undefined when no redirect was initiated', () => { + const helper = new RedirectHelper(); + expect(helper.getState()).toBeUndefined(); + }); + + it('getTransactionState() returns undefined when no redirect was initiated', () => { + const helper = new RedirectHelper(); + expect(helper.getTransactionState()).toBeUndefined(); + }); + + it('getTransactionState() returns undefined in hosted backend mode', () => { + const helper = new RedirectHelper(); + helper.handlePreRedirect('some-state'); + expect(helper.getTransactionState()).toBeUndefined(); + }); + + it('getTransactionState() still works after a handlePostRedirect call clears storage', () => { + const helper = new RedirectHelper(); + helper.handlePreDpopRedirect('verifier-value', 'state'); + + helper.handlePostRedirect(); + + expect(helper.getTransactionState()).toBeUndefined(); + }); + }); + + describe('clearCodeFromUrl()', () => { + it('removes code from the URL via history.replaceState(), preserving other params', () => { + mockWindowLocation(vi, '?code=abc123&state=my-state'); + const replaceState = vi.spyOn(window.history, 'replaceState'); + + const helper = new RedirectHelper(); + helper.clearCodeFromUrl(); + + expect(replaceState).toHaveBeenCalledOnce(); + const [, , url] = replaceState.mock.calls[0]; + const cleanedUrl = new URL(url as string); + expect(cleanedUrl.searchParams.get('code')).toBeNull(); + expect(cleanedUrl.searchParams.get('state')).toBe('my-state'); + }); + + it('does not throw when there is no code in the URL', () => { + mockWindowLocation(vi, ''); + const helper = new RedirectHelper(); + expect(() => helper.clearCodeFromUrl()).not.toThrow(); + }); + }); + + describe('storage format', () => { + it('hosted backend mode stores a plain, non-JSON string', () => { + const helper = new RedirectHelper(); + helper.handlePreRedirect('some-state'); + + const raw = localStorage.getItem('fa-sdk-redirect-value')!; + expect(() => JSON.parse(raw)).toThrow(); + expect(raw).toMatch(/^[0-9a-f]+:some-state$/); + }); + + it('DPoP mode stores a JSON object with codeVerifier, transactionState, and state', () => { + const helper = new RedirectHelper(); + const transactionState = helper.handlePreDpopRedirect( + 'some-verifier', + 'some-state', + ); + + const raw = localStorage.getItem('fa-sdk-redirect-value')!; + const parsed = JSON.parse(raw); + expect(parsed).toEqual({ + codeVerifier: 'some-verifier', + transactionState, + state: 'some-state', + }); + }); + + it('a hosted backend mode call after a DPoP mode call is not confused with the old JSON value', () => { + const helper = new RedirectHelper(); + const callback = vi.fn(); + + helper.handlePreDpopRedirect('dpop-verifier', 'dpop-state'); + helper.handlePreRedirect('hosted-backend-state'); // overwrites with the plain format + + expect(helper.getCodeVerifier()).toBeUndefined(); + helper.handlePostRedirect(callback); + expect(callback).toHaveBeenCalledWith('hosted-backend-state'); + }); + + it('a DPoP mode call after a hosted backend mode call is not confused with the old plain value', () => { + const helper = new RedirectHelper(); + const callback = vi.fn(); + + helper.handlePreRedirect('hosted-backend-state'); + helper.handlePreDpopRedirect('dpop-verifier', 'dpop-state'); // overwrites with the JSON format + + expect(helper.getCodeVerifier()).toBe('dpop-verifier'); + helper.handlePostRedirect(callback); + expect(callback).toHaveBeenCalledWith('dpop-state'); + }); + }); +}); diff --git a/packages/core/src/RedirectHelper/RedirectHelper.ts b/packages/core/src/RedirectHelper/RedirectHelper.ts index b2e9323..8bd3312 100644 --- a/packages/core/src/RedirectHelper/RedirectHelper.ts +++ b/packages/core/src/RedirectHelper/RedirectHelper.ts @@ -1,6 +1,10 @@ -/** A class responsible for storing a redirect value in localStorage and cleanup afterward. */ +/** + * A class responsible for storing pre-redirect values in localStorage and + * cleaning them up afterward. + */ export class RedirectHelper { private readonly REDIRECT_VALUE = 'fa-sdk-redirect-value'; + private get storage(): Storage { try { return localStorage; @@ -9,38 +13,135 @@ export class RedirectHelper { return { /* eslint-disable */ setItem(_key: string, _value: string) {}, - getItem(_key: string) {}, + getItem(_key: string) { + return null; + }, removeItem(_key: string) {}, /* eslint-enable */ } as Storage; } } + /** + * Persists a redirect marker and an optional `state` value to localStorage + * before a redirect is initiated, for hosted backend mode. + * + * Format: a plain string `${randomNonce}:${state ?? ''}`. + * + * @param state Optional OAuth2 state string echoed back post-login. + */ handlePreRedirect(state?: string) { const valueForStorage = `${this.generateRandomString()}:${state ?? ''}`; this.storage.setItem(this.REDIRECT_VALUE, valueForStorage); } + /** + * Persists a redirect marker for DPoP mode: the PKCE `code_verifier`, an + * optional caller-supplied `state`, and a freshly generated + * `transactionState`, all as a JSON object. + * + * `transactionState` — not the caller's `state` — must be sent as the + * OAuth2 `state` parameter on the `/oauth2/authorize` (or `/oauth2/register`) + * request, and is what {@link getTransactionState} returns for verifying + * the value FusionAuth echoes back on redirect. + * + * @param codeVerifier PKCE `code_verifier` for the pending exchange. + * @param state Optional caller-supplied state, returned as-is to + * the {@link handlePostRedirect} callback. + * @returns The generated `transactionState` to send as the OAuth2 `state` + * parameter. + */ + handlePreDpopRedirect(codeVerifier: string, state?: string): string { + const transactionState = this.generateRandomString(); + this.storage.setItem( + this.REDIRECT_VALUE, + JSON.stringify({ codeVerifier, transactionState, state }), + ); + return transactionState; + } + handlePostRedirect(callback?: (state?: string) => void) { - const didRedirect = Boolean(this.storage.getItem(this.REDIRECT_VALUE)); - if (!didRedirect) { + const raw = this.storage.getItem(this.REDIRECT_VALUE); + if (!raw) { return; } - const state = this.state; - callback?.(state); + callback?.(this.parseStoredValue(raw).state); this.storage.removeItem(this.REDIRECT_VALUE); } - private get state() { - const redirectValue = this.storage.getItem(this.REDIRECT_VALUE); + /** + * Removes `code` from the current URL, leaving other query params intact. + */ + clearCodeFromUrl(): void { + const { origin, pathname, search, hash } = window.location; + const url = new URL(`${origin}${pathname}${search}${hash}`); + url.searchParams.delete('code'); + window.history.replaceState(null, '', url.toString()); + } + + /** + * Returns the PKCE `code_verifier` that was persisted by + * {@link handlePreDpopRedirect}, or `undefined` if none was stored (hosted + * backend mode) or if no redirect has been initiated. + */ + getCodeVerifier(): string | undefined { + const raw = this.storage.getItem(this.REDIRECT_VALUE); + if (!raw) return undefined; - if (!redirectValue) { - return; + return this.parseStoredValue(raw).codeVerifier; + } + + /** + * Returns the `state` value persisted by {@link handlePreRedirect} or + * {@link handlePreDpopRedirect}, or `undefined` if none was stored or no + * redirect has been initiated. + */ + getState(): string | undefined { + const raw = this.storage.getItem(this.REDIRECT_VALUE); + if (!raw) return undefined; + + return this.parseStoredValue(raw).state; + } + + /** + * Returns the `transactionState` persisted by {@link handlePreDpopRedirect}, + * or `undefined` if none was stored (hosted backend mode) or if no redirect + * has been initiated. + */ + getTransactionState(): string | undefined { + const raw = this.storage.getItem(this.REDIRECT_VALUE); + if (!raw) return undefined; + + return this.parseStoredValue(raw).transactionState; + } + + /** + * Parses a raw stored value for either mode. + */ + private parseStoredValue(raw: string): { + codeVerifier?: string; + transactionState?: string; + state?: string; + } { + if (raw.startsWith('{')) { + // DPoP mode + const parsed = JSON.parse(raw) as { + codeVerifier?: string; + transactionState?: string; + state?: string; + }; + return { + codeVerifier: parsed.codeVerifier || undefined, + transactionState: parsed.transactionState || undefined, + state: parsed.state ?? undefined, + }; } - const [, ...stateValue] = redirectValue.split(':'); - return stateValue.join(':') || undefined; + // Hosted backend mode format: randomNonce:state (state may itself + // contain colons; rejoin the remainder to preserve them). + const [, ...stateValue] = raw.split(':'); + return { state: stateValue.join(':') || undefined }; } private generateRandomString() { diff --git a/packages/core/src/SDKConfig/SDKConfig.ts b/packages/core/src/SDKConfig/SDKConfig.ts index 32ef2fb..f4797a7 100644 --- a/packages/core/src/SDKConfig/SDKConfig.ts +++ b/packages/core/src/SDKConfig/SDKConfig.ts @@ -99,4 +99,27 @@ export interface SDKConfig { * Callback to be invoked at the moment of access token expiration */ onTokenExpiration: () => void; + + /** + * Opt-in to DPoP mode. When `true`, the SDK calls FusionAuth endpoints + * directly and stores tokens in JavaScript-accessible storage. + * Defaults to `false`. + */ + useDpop?: boolean; + + /** + * Token storage location in DPoP mode. Only meaningful when `useDpop: true`. + * Defaults to `'localStorage'`. + */ + dpopTokenStorage?: 'localStorage' | 'memory'; + + /** + * Callback invoked if `startLogin()` fails in DPoP mode (e.g. the DPoP key + * pair could not be generated/loaded, or PKCE parameter generation + * failed). `startLogin()` is synchronous (`void`), so this is the only way + * to observe an async failure in the DPoP login flow. Defaults to logging + * the error via `console.error` if not provided. Only relevant when + * `useDpop: true`. + */ + onLoginFailure?: (error: Error) => void; } diff --git a/packages/core/src/SDKContext/SDKContext.ts b/packages/core/src/SDKContext/SDKContext.ts index 216b043..ea0169f 100644 --- a/packages/core/src/SDKContext/SDKContext.ts +++ b/packages/core/src/SDKContext/SDKContext.ts @@ -55,6 +55,33 @@ export interface SDKContext { * This is handled automatically if the SDK is configured with `shouldAutoRefresh`. */ initAutoRefresh: () => void; + + /** + * Fetch wrapper that automatically attaches DPoP proof headers. + * Present only when `useDpop: true`. + */ + dpopFetch?: ( + input: RequestInfo | URL, + init?: RequestInit, + ) => Promise; + + /** + * Returns a signed DPoP proof JWT for use with axios or other + * HTTP libraries. Present only when `useDpop: true`. + */ + generateProof?: ( + htu: string, + htm: string, + accessToken?: string, + nonce?: string, + ) => Promise; + + /** + * Returns the stored DPoP access token, or `null` if not logged in. + * Throws a descriptive error when `useDpop: false`. + * Present only when `useDpop: true`. + */ + getAccessToken?: () => string | null; } /** diff --git a/packages/core/src/SDKCore/SDKCore.test.ts b/packages/core/src/SDKCore/SDKCore.test.ts index a427fd3..4a2ca1e 100644 --- a/packages/core/src/SDKCore/SDKCore.test.ts +++ b/packages/core/src/SDKCore/SDKCore.test.ts @@ -1,8 +1,16 @@ +// @vitest-environment jsdom +// SDKCore uses document.cookie (via CookieHelpers), window.location.assign, +// and localStorage — all browser-only globals that jsdom provides. +// This annotation is explicit so that importing DPoPManager (which has its own +// @vitest-environment node override) does not cause vitest to run this file in +// the node environment when the full test suite is executed together. import { afterEach, describe, it, expect, vi } from 'vitest'; import { SDKConfig } from '../SDKConfig'; import { SDKCore } from '.'; import { RedirectHelper } from '../RedirectHelper'; +import { DPoPManager } from '../DPoP'; +import * as Pkce from '../Pkce'; import { mockIsLoggedIn, mockWindowLocation, removeAt_expCookie } from '..'; @@ -165,4 +173,957 @@ describe('SDKCore', () => { expect(onRedirect).not.toHaveBeenCalled(); }); + + describe('DPoP mode', () => { + const MOCK_JKT = 'mock-dpop-jkt-thumbprint'; + const MOCK_VERIFIER = 'mock-code-verifier-43-chars-xxxxxxxxxxxxxxxx'; + const MOCK_CHALLENGE = 'mock-code-challenge-43-chars-xxxxxxxxxxxx'; + + const dpopConfig: SDKConfig = { + ...config, + useDpop: true, + serverUrl: 'http://my-fusionauth-server', + }; + + it('startLogin() in DPoP mode redirects to /oauth2/authorize with dpop_jkt and code_challenge', async () => { + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + vi.spyOn(DPoPManager.prototype, 'getThumbprint').mockResolvedValue( + MOCK_JKT, + ); + vi.spyOn(Pkce, 'generateCodeVerifier').mockReturnValue(MOCK_VERIFIER); + vi.spyOn(Pkce, 'generateCodeChallenge').mockResolvedValue(MOCK_CHALLENGE); + const location = mockWindowLocation(vi); + + const core = new SDKCore(dpopConfig); + core.startLogin(); + await vi.waitFor(() => expect(location.assign).toHaveBeenCalledOnce()); + + const assignedUrl = new URL( + (location.assign as ReturnType).mock.calls[0][0], + ); + expect(assignedUrl.pathname).toBe('/oauth2/authorize'); + expect(assignedUrl.searchParams.get('dpop_jkt')).toBe(MOCK_JKT); + expect(assignedUrl.searchParams.get('code_challenge')).toBe( + MOCK_CHALLENGE, + ); + expect(assignedUrl.searchParams.get('code_challenge_method')).toBe( + 'S256', + ); + expect(assignedUrl.searchParams.get('response_type')).toBe('code'); + }); + + it('startLogin() in DPoP mode persists code_verifier via RedirectHelper', async () => { + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + vi.spyOn(DPoPManager.prototype, 'getThumbprint').mockResolvedValue( + MOCK_JKT, + ); + vi.spyOn(Pkce, 'generateCodeVerifier').mockReturnValue(MOCK_VERIFIER); + vi.spyOn(Pkce, 'generateCodeChallenge').mockResolvedValue(MOCK_CHALLENGE); + const location = mockWindowLocation(vi); + + const core = new SDKCore(dpopConfig); + core.startLogin(); + await vi.waitFor(() => expect(location.assign).toHaveBeenCalledOnce()); + + const redirectHelper = new RedirectHelper(); + expect(redirectHelper.getCodeVerifier()).toBe(MOCK_VERIFIER); + }); + + it('startLogin() in DPoP mode includes state in the authorize URL', async () => { + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + vi.spyOn(DPoPManager.prototype, 'getThumbprint').mockResolvedValue( + MOCK_JKT, + ); + vi.spyOn(Pkce, 'generateCodeVerifier').mockReturnValue(MOCK_VERIFIER); + vi.spyOn(Pkce, 'generateCodeChallenge').mockResolvedValue(MOCK_CHALLENGE); + const location = mockWindowLocation(vi); + + const core = new SDKCore(dpopConfig); + core.startLogin('my-state'); + await vi.waitFor(() => expect(location.assign).toHaveBeenCalledOnce()); + + const assignedUrl = new URL( + (location.assign as ReturnType).mock.calls[0][0], + ); + // The OAuth `state` param sent to the server is the SDK-generated + // transactionState, not the caller's own state — see + // RedirectHelper.handlePreDpopRedirect() for why this is the actual + // CSRF defense. + const redirectHelper = new RedirectHelper(); + expect(assignedUrl.searchParams.get('state')).toBe( + redirectHelper.getTransactionState(), + ); + expect(assignedUrl.searchParams.get('state')).not.toBe('my-state'); + expect(redirectHelper.getState()).toBe('my-state'); + }); + + it('startRegister() in DPoP mode redirects to /oauth2/register with dpop_jkt and code_challenge', async () => { + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + vi.spyOn(DPoPManager.prototype, 'getThumbprint').mockResolvedValue( + MOCK_JKT, + ); + vi.spyOn(Pkce, 'generateCodeVerifier').mockReturnValue(MOCK_VERIFIER); + vi.spyOn(Pkce, 'generateCodeChallenge').mockResolvedValue(MOCK_CHALLENGE); + const location = mockWindowLocation(vi); + + const core = new SDKCore(dpopConfig); + core.startRegister(); + await vi.waitFor(() => expect(location.assign).toHaveBeenCalledOnce()); + + const assignedUrl = new URL( + (location.assign as ReturnType).mock.calls[0][0], + ); + expect(assignedUrl.pathname).toBe('/oauth2/register'); + expect(assignedUrl.searchParams.get('dpop_jkt')).toBe(MOCK_JKT); + expect(assignedUrl.searchParams.get('code_challenge')).toBe( + MOCK_CHALLENGE, + ); + expect(assignedUrl.searchParams.get('code_challenge_method')).toBe( + 'S256', + ); + expect(assignedUrl.searchParams.get('response_type')).toBe('code'); + }); + + it('startRegister() in DPoP mode persists code_verifier via RedirectHelper', async () => { + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + vi.spyOn(DPoPManager.prototype, 'getThumbprint').mockResolvedValue( + MOCK_JKT, + ); + vi.spyOn(Pkce, 'generateCodeVerifier').mockReturnValue(MOCK_VERIFIER); + vi.spyOn(Pkce, 'generateCodeChallenge').mockResolvedValue(MOCK_CHALLENGE); + const location = mockWindowLocation(vi); + + const core = new SDKCore(dpopConfig); + core.startRegister(); + await vi.waitFor(() => expect(location.assign).toHaveBeenCalledOnce()); + + const redirectHelper = new RedirectHelper(); + expect(redirectHelper.getCodeVerifier()).toBe(MOCK_VERIFIER); + }); + + it('reports a DPoP startRegister() failure via onLoginFailure instead of an unhandled rejection', async () => { + const failure = new Error('crypto.subtle unavailable'); + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockRejectedValue( + failure, + ); + mockWindowLocation(vi); + + const onLoginFailure = vi.fn(); + const core = new SDKCore({ ...dpopConfig, onLoginFailure }); + + core.startRegister(); + await vi.waitFor(() => expect(onLoginFailure).toHaveBeenCalledOnce()); + + expect(onLoginFailure).toHaveBeenCalledWith(failure); + }); + + it('reports a DPoP startLogin() failure via onLoginFailure instead of an unhandled rejection', async () => { + const failure = new Error('crypto.subtle unavailable'); + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockRejectedValue( + failure, + ); + mockWindowLocation(vi); + + const onLoginFailure = vi.fn(); + const core = new SDKCore({ ...dpopConfig, onLoginFailure }); + + core.startLogin(); + await vi.waitFor(() => expect(onLoginFailure).toHaveBeenCalledOnce()); + + expect(onLoginFailure).toHaveBeenCalledWith(failure); + }); + + it('falls back to console.error when a DPoP startLogin() failure occurs and onLoginFailure is not configured', async () => { + const failure = new Error('IndexedDB blocked'); + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockRejectedValue( + failure, + ); + mockWindowLocation(vi); + const consoleError = vi + .spyOn(console, 'error') + .mockImplementation(() => {}); + + const core = new SDKCore(dpopConfig); // no onLoginFailure configured + core.startLogin(); + await vi.waitFor(() => + expect(consoleError).toHaveBeenCalledWith( + 'FusionAuth SDK: startLogin failed', + failure, + ), + ); + }); + + it('startLogout() in DPoP mode clears DPoPManager state and redirects to /oauth2/logout directly', async () => { + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + const clearSpy = vi + .spyOn(DPoPManager.prototype, 'clear') + .mockResolvedValue(undefined); + const location = mockWindowLocation(vi); + + const core = new SDKCore(dpopConfig); + core.startLogout(); + await vi.waitFor(() => expect(location.assign).toHaveBeenCalledOnce()); + + expect(clearSpy).toHaveBeenCalledOnce(); + + const assignedUrl = new URL( + String((location.assign as ReturnType).mock.calls[0][0]), + ); + + expect(assignedUrl.pathname).toBe('/oauth2/logout'); + expect(assignedUrl.searchParams.get('client_id')).toBe( + dpopConfig.clientId, + ); + }); + + it('getAccessToken() returns the stored access token when useDpop: true', () => { + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + const core = new SDKCore(dpopConfig); + + const dpopManager = (core as any).dpopManager as DPoPManager; + dpopManager.setTokens({ + accessToken: 'mock-access-token', + refreshToken: undefined, + expiresAt: Date.now() + 60_000, + tokenType: 'DPoP', + }); + + expect(core.getAccessToken()).toBe('mock-access-token'); + }); + + it('getAccessToken() returns null when logged out in DPoP mode', () => { + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + const core = new SDKCore(dpopConfig); + + expect(core.getAccessToken()).toBeNull(); + }); + + it('getAccessToken() throws when useDpop: false', () => { + const core = new SDKCore(config); // no useDpop + + expect(() => core.getAccessToken()).toThrow( + 'getAccessToken() is only available in DPoP mode. In hosted backend mode, tokens are stored in HttpOnly cookies and are not accessible to JavaScript.', + ); + }); + + it('dpopFetch() delegates to DPoPManager.fetch() when useDpop: true', async () => { + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + const mockResponse = new Response(null, { status: 200 }); + const fetchSpy = vi + .spyOn(DPoPManager.prototype, 'fetch') + .mockResolvedValue(mockResponse); + + const core = new SDKCore(dpopConfig); + const init = { method: 'GET' }; + const response = await core.dpopFetch( + 'https://api.example.com/data', + init, + ); + + expect(fetchSpy).toHaveBeenCalledWith( + 'https://api.example.com/data', + init, + ); + expect(response).toBe(mockResponse); + }); + + it('dpopFetch() throws when useDpop: false', async () => { + const core = new SDKCore(config); // no useDpop + + await expect( + core.dpopFetch('https://api.example.com/data'), + ).rejects.toThrow( + 'dpopFetch() is only available in DPoP mode. In hosted backend mode, use fetch() with credentials: "include" instead.', + ); + }); + + it('generateProof() delegates to DPoPManager.generateProof() when useDpop: true', async () => { + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + const generateProofSpy = vi + .spyOn(DPoPManager.prototype, 'generateProof') + .mockResolvedValue('mock-dpop-proof-jwt'); + + const core = new SDKCore(dpopConfig); + const proof = await core.generateProof( + 'https://api.example.com/data', + 'POST', + 'mock-access-token', + 'mock-nonce', + ); + + expect(generateProofSpy).toHaveBeenCalledWith( + 'https://api.example.com/data', + 'POST', + 'mock-access-token', + 'mock-nonce', + ); + expect(proof).toBe('mock-dpop-proof-jwt'); + }); + + it('generateProof() throws when useDpop: false', async () => { + const core = new SDKCore(config); // no useDpop + + await expect( + core.generateProof('https://api.example.com/data', 'POST'), + ).rejects.toThrow( + 'generateProof() is only available in DPoP mode. In hosted backend mode, tokens are stored in HttpOnly cookies and DPoP proofs are not applicable.', + ); + }); + + describe('fetchUserInfo() in DPoP mode', () => { + function seedAccessToken( + core: SDKCore, + accessToken = 'mock-access-token', + ) { + const dpopManager = (core as any).dpopManager as DPoPManager; + dpopManager.setTokens({ + accessToken, + refreshToken: undefined, + expiresAt: Date.now() + 60_000, + tokenType: 'DPoP', + }); + } + + it('calls DPoPManager.fetch() targeting /oauth2/userinfo and returns the claims', async () => { + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + const core = new SDKCore(dpopConfig); + seedAccessToken(core); + + const userInfoClaims = { sub: 'mock-sub', email: 'user@example.com' }; + const fetchSpy = vi + .spyOn(DPoPManager.prototype, 'fetch') + .mockResolvedValue( + new Response(JSON.stringify(userInfoClaims), { status: 200 }), + ); + + const userInfo = await core.fetchUserInfo(); + + expect(fetchSpy).toHaveBeenCalledOnce(); + const requestedUrl = fetchSpy.mock.calls[0]?.[0]; + expect(new URL(String(requestedUrl)).pathname).toBe('/oauth2/userinfo'); + expect(userInfo).toEqual(userInfoClaims); + }); + + it('hosted backend mode fetchUserInfo() is unaffected', async () => { + vi.spyOn(window, 'fetch').mockResolvedValue( + new Response(JSON.stringify({ sub: 'mock-sub' }), { status: 200 }), + ); + + const core = new SDKCore(config); // no useDpop + const userInfo = await core.fetchUserInfo(); + + expect(userInfo).toEqual({ sub: 'mock-sub' }); + expect(window.fetch).toHaveBeenCalledWith( + expect.objectContaining({ pathname: '/app/me/' }), + { credentials: 'include' }, + ); + }); + }); + + describe('handlePostRedirect() in DPoP mode', () => { + const MOCK_PROOF = 'mock-dpop-proof-jwt'; + const MOCK_CODE = 'mock-authorization-code'; + const MOCK_ACCESS_TOKEN = 'mock-access-token'; + const MOCK_REFRESH_TOKEN = 'mock-refresh-token'; + const EXPIRES_IN_SECONDS = 3600; + + /** Mocks the DPoP key-pair/PKCE steps so `startLogin()` runs without WebCrypto. */ + function mockDpopLoginDependencies() { + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + vi.spyOn(DPoPManager.prototype, 'getThumbprint').mockResolvedValue( + MOCK_JKT, + ); + vi.spyOn(Pkce, 'generateCodeVerifier').mockReturnValue(MOCK_VERIFIER); + vi.spyOn(Pkce, 'generateCodeChallenge').mockResolvedValue( + MOCK_CHALLENGE, + ); + } + + function mockTokenResponse( + overrides: Partial<{ + access_token: string; + refresh_token?: string; + expires_in: number; + token_type: string; + }> = {}, + ) { + return vi.spyOn(window, 'fetch').mockResolvedValue( + new Response( + JSON.stringify({ + access_token: MOCK_ACCESS_TOKEN, + refresh_token: MOCK_REFRESH_TOKEN, + expires_in: EXPIRES_IN_SECONDS, + token_type: 'DPoP', + ...overrides, + }), + { status: 200 }, + ), + ); + } + + /** + * Runs `startLogin()` (with DPoP dependencies mocked) to legitimately + * persist a `code_verifier` via `RedirectHelper`, then simulates landing + * back on the redirect URI with `?code=...&state=...` in the query + * string, using the real SDK-generated transactionState so the CSRF + * check in `handlePostRedirect()` passes. + */ + async function primePendingRedirect(core: SDKCore) { + const location = mockWindowLocation(vi); + core.startLogin(); + await vi.waitFor(() => expect(location.assign).toHaveBeenCalledOnce()); + const transactionState = new RedirectHelper().getTransactionState(); + location.search = `?code=${MOCK_CODE}&state=${transactionState}`; + return location; + } + + it('does nothing when there is no code query param', async () => { + mockWindowLocation(vi); // default search — no code + const fetchMock = vi.spyOn(window, 'fetch'); + const core = new SDKCore(dpopConfig); + const onRedirect = vi.fn(); + + core.handlePostRedirect(onRedirect); + await Promise.resolve(); + + expect(fetchMock).not.toHaveBeenCalled(); + expect(onRedirect).not.toHaveBeenCalled(); + }); + + it('does nothing when code is present but no code_verifier was persisted', async () => { + mockWindowLocation(vi, `?code=${MOCK_CODE}`); + const fetchMock = vi.spyOn(window, 'fetch'); + const core = new SDKCore(dpopConfig); + const onRedirect = vi.fn(); + + core.handlePostRedirect(onRedirect); + await Promise.resolve(); + + expect(fetchMock).not.toHaveBeenCalled(); + expect(onRedirect).not.toHaveBeenCalled(); + }); + + it('exchanges the code with a DPoP header and stores tokens', async () => { + mockDpopLoginDependencies(); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + MOCK_PROOF, + ); + + const core = new SDKCore(dpopConfig); + await primePendingRedirect(core); + const fetchMock = mockTokenResponse(); + + const onRedirect = vi.fn(); + core.handlePostRedirect(onRedirect); + await vi.waitFor(() => expect(onRedirect).toHaveBeenCalledOnce()); + + expect(fetchMock).toHaveBeenCalledOnce(); + const call = fetchMock.mock.calls[0]; + if (!call) throw new Error('fetch was not called'); + const [url, init] = call; + expect(new URL(url.toString()).pathname).toBe('/oauth2/token'); + expect(init?.method).toBe('POST'); + + const headers = init?.headers as Record; + expect(headers['DPoP']).toBe(MOCK_PROOF); + expect(headers['Content-Type']).toBe( + 'application/x-www-form-urlencoded', + ); + + const body = new URLSearchParams(init?.body as string); + expect(body.get('grant_type')).toBe('authorization_code'); + expect(body.get('code')).toBe(MOCK_CODE); + expect(body.get('code_verifier')).toBe(MOCK_VERIFIER); + expect(body.get('client_id')).toBe(dpopConfig.clientId); + expect(body.get('redirect_uri')).toBe(dpopConfig.redirectUri); + + expect(DPoPManager.prototype.generateProof).toHaveBeenCalledWith( + expect.stringContaining('/oauth2/token'), + 'POST', + ); + + expect(core.isLoggedIn).toBe(true); + }); + + it('performs an independent exchange attempt per call when called concurrently (no dedup)', async () => { + mockDpopLoginDependencies(); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + MOCK_PROOF, + ); + + const core = new SDKCore(dpopConfig); + await primePendingRedirect(core); + const fetchMock = mockTokenResponse(); + + const first = core.handlePostRedirect(); + const second = core.handlePostRedirect(); + + await Promise.all([first, second]); + + expect(fetchMock).toHaveBeenCalledTimes(2); + }); + + it('invokes the callback with the state persisted by startLogin() and cleans up the redirect marker', async () => { + mockDpopLoginDependencies(); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + MOCK_PROOF, + ); + + const core = new SDKCore(dpopConfig); + const location = mockWindowLocation(vi); + core.startLogin('my-post-redirect-state'); + await vi.waitFor(() => expect(location.assign).toHaveBeenCalledOnce()); + // The server echoes back the SDK-generated transactionState, not the + // caller's own state — see RedirectHelper.handlePreDpopRedirect(). + const transactionState = new RedirectHelper().getTransactionState(); + location.search = `?code=${MOCK_CODE}&state=${transactionState}`; + mockTokenResponse(); + + const redirectIndicator = () => + localStorage.getItem('fa-sdk-redirect-value'); + expect(redirectIndicator()).not.toBeNull(); + + const onRedirect = vi.fn(); + core.handlePostRedirect(onRedirect); + await vi.waitFor(() => expect(onRedirect).toHaveBeenCalledOnce()); + + expect(onRedirect).toHaveBeenCalledWith('my-post-redirect-state'); + expect(redirectIndicator()).toBeNull(); + }); + + it('strips code from the URL via history.replaceState() after a successful exchange', async () => { + mockDpopLoginDependencies(); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + MOCK_PROOF, + ); + const replaceState = vi.spyOn(window.history, 'replaceState'); + + const core = new SDKCore(dpopConfig); + const location = mockWindowLocation(vi); + core.startLogin('my-post-redirect-state'); + await vi.waitFor(() => expect(location.assign).toHaveBeenCalledOnce()); + const transactionState = new RedirectHelper().getTransactionState(); + location.search = `?code=${MOCK_CODE}&state=${transactionState}`; + mockTokenResponse(); + + core.handlePostRedirect(); + await vi.waitFor(() => expect(core.isLoggedIn).toBe(true)); + + expect(replaceState).toHaveBeenCalledOnce(); + const [, , url] = replaceState.mock.calls[0]; + const cleanedUrl = new URL(url as string); + expect(cleanedUrl.searchParams.get('code')).toBeNull(); + }); + + it('schedules token expiration from expires_in', async () => { + vi.useFakeTimers(); + mockDpopLoginDependencies(); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + MOCK_PROOF, + ); + + const onTokenExpiration = vi.fn(); + const core = new SDKCore({ ...dpopConfig, onTokenExpiration }); + await primePendingRedirect(core); + mockTokenResponse(); + + core.handlePostRedirect(); + await vi.waitFor(() => expect(core.isLoggedIn).toBe(true)); + + vi.advanceTimersByTime(EXPIRES_IN_SECONDS * 1000 - 1000); + expect(onTokenExpiration).not.toHaveBeenCalled(); + + vi.advanceTimersByTime(1000); + expect(onTokenExpiration).toHaveBeenCalledTimes(1); + }); + + it('schedules auto-refresh from expires_in when shouldAutoRefresh is true', async () => { + vi.useFakeTimers(); + mockDpopLoginDependencies(); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + MOCK_PROOF, + ); + const refreshToken = vi + .spyOn(SDKCore.prototype, 'refreshToken') + .mockResolvedValue(new Response(null, { status: 200 })); + + const core = new SDKCore({ + ...dpopConfig, + shouldAutoRefresh: true, + autoRefreshSecondsBeforeExpiry: 60, + }); + await primePendingRedirect(core); + mockTokenResponse(); + + core.handlePostRedirect(); + await vi.waitFor(() => expect(core.isLoggedIn).toBe(true)); + + // Refresh fires 60s before the 3600s expiry, i.e. at 3540s. + vi.advanceTimersByTime((EXPIRES_IN_SECONDS - 60) * 1000 - 1000); + expect(refreshToken).not.toHaveBeenCalled(); + + vi.advanceTimersByTime(1000); + expect(refreshToken).toHaveBeenCalledTimes(1); + }); + + it('does not schedule auto-refresh when shouldAutoRefresh is not set', async () => { + mockDpopLoginDependencies(); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + MOCK_PROOF, + ); + const refreshToken = vi.spyOn(SDKCore.prototype, 'refreshToken'); + + const core = new SDKCore(dpopConfig); // shouldAutoRefresh defaults to false + await primePendingRedirect(core); + mockTokenResponse(); + + const onRedirect = vi.fn(); + core.handlePostRedirect(onRedirect); + await vi.waitFor(() => expect(onRedirect).toHaveBeenCalledOnce()); + + expect(refreshToken).not.toHaveBeenCalled(); + }); + + it('reports an exchange failure via onLoginFailure', async () => { + mockDpopLoginDependencies(); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + MOCK_PROOF, + ); + + const onLoginFailure = vi.fn(); + const core = new SDKCore({ ...dpopConfig, onLoginFailure }); + await primePendingRedirect(core); + vi.spyOn(window, 'fetch').mockResolvedValue( + new Response('invalid_grant', { status: 400 }), + ); + + core.handlePostRedirect(); + await vi.waitFor(() => expect(onLoginFailure).toHaveBeenCalledOnce()); + + expect(core.isLoggedIn).toBe(false); + }); + + it('falls back to console.error when an exchange failure occurs and onLoginFailure is not configured', async () => { + mockDpopLoginDependencies(); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + MOCK_PROOF, + ); + const consoleError = vi + .spyOn(console, 'error') + .mockImplementation(() => {}); + + const core = new SDKCore(dpopConfig); // no onLoginFailure configured + await primePendingRedirect(core); + vi.spyOn(window, 'fetch').mockResolvedValue( + new Response('invalid_grant', { status: 400 }), + ); + + core.handlePostRedirect(); + await vi.waitFor(() => + expect(consoleError).toHaveBeenCalledWith( + 'FusionAuth SDK: handlePostRedirect failed', + expect.any(Error), + ), + ); + }); + + it('rejects a state mismatch instead of exchanging the code (CSRF protection)', async () => { + mockDpopLoginDependencies(); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + MOCK_PROOF, + ); + const onLoginFailure = vi.fn(); + const core = new SDKCore({ ...dpopConfig, onLoginFailure }); + const location = mockWindowLocation(vi); + core.startLogin('expected-state'); + await vi.waitFor(() => expect(location.assign).toHaveBeenCalledOnce()); + location.search = `?code=${MOCK_CODE}&state=attacker-supplied-state`; + const fetchMock = mockTokenResponse(); + + await core.handlePostRedirect(); + + expect(fetchMock).not.toHaveBeenCalled(); + expect(onLoginFailure).toHaveBeenCalledWith( + expect.objectContaining({ + message: expect.stringContaining('state'), + }), + ); + expect(core.isLoggedIn).toBe(false); + }); + + it('rejects a token response with a token_type other than DPoP', async () => { + mockDpopLoginDependencies(); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + MOCK_PROOF, + ); + const onLoginFailure = vi.fn(); + const core = new SDKCore({ ...dpopConfig, onLoginFailure }); + await primePendingRedirect(core); + mockTokenResponse({ token_type: 'Bearer' }); + + await core.handlePostRedirect(); + + expect(onLoginFailure).toHaveBeenCalledWith( + expect.objectContaining({ + message: expect.stringContaining('token_type'), + }), + ); + expect(core.isLoggedIn).toBe(false); + }); + + it('rejects a token response with a non-positive expires_in', async () => { + mockDpopLoginDependencies(); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + MOCK_PROOF, + ); + const onLoginFailure = vi.fn(); + const core = new SDKCore({ ...dpopConfig, onLoginFailure }); + await primePendingRedirect(core); + mockTokenResponse({ expires_in: 0 }); + + await core.handlePostRedirect(); + + expect(onLoginFailure).toHaveBeenCalledWith( + expect.objectContaining({ + message: expect.stringContaining('expires_in'), + }), + ); + expect(core.isLoggedIn).toBe(false); + }); + }); + + describe('refreshToken() in DPoP mode', () => { + const MOCK_PROOF = 'mock-dpop-refresh-proof-jwt'; + const MOCK_OLD_REFRESH_TOKEN = 'mock-old-refresh-token'; + const MOCK_NEW_ACCESS_TOKEN = 'mock-new-access-token'; + const MOCK_NEW_REFRESH_TOKEN = 'mock-new-refresh-token'; + const EXPIRES_IN_SECONDS = 3600; + + function seedExistingTokens(core: SDKCore) { + const dpopManager = (core as any).dpopManager as DPoPManager; + dpopManager.setTokens({ + accessToken: 'mock-old-access-token', + refreshToken: MOCK_OLD_REFRESH_TOKEN, + expiresAt: Date.now() + 60_000, + tokenType: 'DPoP', + }); + } + + function mockTokenResponse( + overrides: Partial<{ + access_token: string; + refresh_token?: string; + expires_in: number; + token_type: string; + }> = {}, + ) { + return vi.spyOn(window, 'fetch').mockImplementation(() => + Promise.resolve( + new Response( + JSON.stringify({ + access_token: MOCK_NEW_ACCESS_TOKEN, + refresh_token: MOCK_NEW_REFRESH_TOKEN, + expires_in: EXPIRES_IN_SECONDS, + token_type: 'DPoP', + ...overrides, + }), + { status: 200 }, + ), + ), + ); + } + + it('sends a DPoP header and refresh_token grant body to /oauth2/token', async () => { + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + MOCK_PROOF, + ); + const core = new SDKCore(dpopConfig); + seedExistingTokens(core); + const fetchMock = mockTokenResponse(); + + await core.refreshToken(); + + expect(fetchMock).toHaveBeenCalledOnce(); + const call = fetchMock.mock.calls[0]; + if (!call) throw new Error('fetch was not called'); + const [url, init] = call; + expect(new URL(url.toString()).pathname).toBe('/oauth2/token'); + expect(init?.method).toBe('POST'); + + const headers = init?.headers as Record; + expect(headers['DPoP']).toBe(MOCK_PROOF); + expect(headers['Content-Type']).toBe( + 'application/x-www-form-urlencoded', + ); + + const body = new URLSearchParams(init?.body as string); + expect(body.get('grant_type')).toBe('refresh_token'); + expect(body.get('refresh_token')).toBe(MOCK_OLD_REFRESH_TOKEN); + expect(body.get('client_id')).toBe(dpopConfig.clientId); + + expect(DPoPManager.prototype.generateProof).toHaveBeenCalledWith( + expect.stringContaining('/oauth2/token'), + 'POST', + ); + }); + + it('updates stored tokens on success and isLoggedIn remains true', async () => { + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + MOCK_PROOF, + ); + const core = new SDKCore(dpopConfig); + seedExistingTokens(core); + mockTokenResponse(); + + expect(core.isLoggedIn).toBe(true); + + await core.refreshToken(); + + expect(core.isLoggedIn).toBe(true); + expect(core.getAccessToken()).toBe(MOCK_NEW_ACCESS_TOKEN); + }); + + it('reschedules token expiration from the new expiresAt', async () => { + vi.useFakeTimers(); + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + MOCK_PROOF, + ); + const onTokenExpiration = vi.fn(); + const core = new SDKCore({ ...dpopConfig, onTokenExpiration }); + seedExistingTokens(core); + mockTokenResponse(); + + await core.refreshToken(); + + vi.advanceTimersByTime(EXPIRES_IN_SECONDS * 1000 - 1000); + expect(onTokenExpiration).not.toHaveBeenCalled(); + + vi.advanceTimersByTime(1000); + expect(onTokenExpiration).toHaveBeenCalledTimes(1); + }); + + it('reschedules auto-refresh from the new expiresAt when shouldAutoRefresh is true', async () => { + vi.useFakeTimers(); + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + MOCK_PROOF, + ); + const core = new SDKCore({ + ...dpopConfig, + shouldAutoRefresh: true, + autoRefreshSecondsBeforeExpiry: 60, + }); + seedExistingTokens(core); + mockTokenResponse(); + + const refreshTokenSpy = vi.spyOn(SDKCore.prototype, 'refreshToken'); + + await core.refreshToken(); + expect(refreshTokenSpy).toHaveBeenCalledTimes(1); + + // Auto-refresh fires 60s before the 3600s expiry + vi.advanceTimersByTime((EXPIRES_IN_SECONDS - 60) * 1000 - 1000); + expect(refreshTokenSpy).toHaveBeenCalledTimes(1); + + vi.advanceTimersByTime(1000); + expect(refreshTokenSpy).toHaveBeenCalledTimes(2); // + the auto-refresh firing + }); + + it('does not reschedule auto-refresh when shouldAutoRefresh is not set', async () => { + vi.useFakeTimers(); + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + MOCK_PROOF, + ); + const core = new SDKCore(dpopConfig); // shouldAutoRefresh defaults to false + seedExistingTokens(core); + mockTokenResponse(); + + const refreshTokenSpy = vi.spyOn(SDKCore.prototype, 'refreshToken'); + + await core.refreshToken(); + + vi.advanceTimersByTime(EXPIRES_IN_SECONDS * 1000); + expect(refreshTokenSpy).toHaveBeenCalledTimes(1); + }); + + it('throws a descriptive error when no refresh token is stored', async () => { + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + const fetchMock = vi.spyOn(window, 'fetch'); + const core = new SDKCore(dpopConfig); // no tokens stored — never logged in + + await expect(core.refreshToken()).rejects.toThrow( + 'No refresh token available. Have you called startLogin()?', + ); + expect(fetchMock).not.toHaveBeenCalled(); + }); + + it('rejects a token response with a token_type other than DPoP', async () => { + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + MOCK_PROOF, + ); + const core = new SDKCore(dpopConfig); + seedExistingTokens(core); + mockTokenResponse({ token_type: 'Bearer' }); + + await expect(core.refreshToken()).rejects.toThrow('token_type'); + }); + + it('rejects a token response with a non-positive expires_in', async () => { + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + MOCK_PROOF, + ); + const core = new SDKCore(dpopConfig); + seedExistingTokens(core); + mockTokenResponse({ expires_in: -1 }); + + await expect(core.refreshToken()).rejects.toThrow('expires_in'); + }); + }); + }); }); diff --git a/packages/core/src/SDKCore/SDKCore.ts b/packages/core/src/SDKCore/SDKCore.ts index f8629a4..3b6fba1 100644 --- a/packages/core/src/SDKCore/SDKCore.ts +++ b/packages/core/src/SDKCore/SDKCore.ts @@ -3,6 +3,7 @@ import { SDKConfig } from '../SDKConfig'; import { UserInfo } from '../SDKContext'; import { RedirectHelper } from '../RedirectHelper'; import { getAccessTokenExpirationMoment } from '../CookieHelpers'; +import { DPoPManager } from '../DPoP'; /** A class containing framework-agnostic SDK methods */ export class SDKCore { @@ -12,6 +13,7 @@ export class SDKCore { private tokenExpirationTimeout?: NodeJS.Timeout; private refreshTokenTimeout?: NodeJS.Timeout; private isDisposed = false; + private dpopManager?: DPoPManager; constructor(config: SDKConfig) { this.config = config; @@ -28,6 +30,16 @@ export class SDKCore { tokenRefreshPath: config.tokenRefreshPath, postLogoutRedirectUri: config.postLogoutRedirectUri, }); + + if (config.useDpop) { + this.dpopManager = new DPoPManager( + config.clientId, + this.urlHelper, + this.redirectHelper, + config.dpopTokenStorage, + ); + } + this.scheduleTokenExpiration(); } @@ -37,17 +49,86 @@ export class SDKCore { this.isDisposed = true; } - startLogin(state?: string) { + /** + * Initiates the login flow. + * + * In DPoP mode, this synchronously returns after starting an async chain + * that handles the DPoP login flow. + + * In hosted backend mode the processing is synchronous. + * + * @param state Optional OAuth2 state value echoed back post-login. + */ + startLogin(state?: string): void { + const dpopManager = this.dpopManager; + if (dpopManager) { + (async () => { + try { + await dpopManager.startLogin(state); + } catch (error) { + if (this.config.onLoginFailure) { + this.config.onLoginFailure(error as Error); + } else { + console.error('FusionAuth SDK: startLogin failed', error); + } + } + })(); + return; + } + this.redirectHelper.handlePreRedirect(state); window.location.assign(this.urlHelper.getLoginUrl(state)); } - startRegister(state?: string) { + /** + * Initiates the register flow. + * @param state Optional OAuth2 state value echoed back post-register. + */ + startRegister(state?: string): void { + const dpopManager = this.dpopManager; + if (dpopManager) { + (async () => { + try { + await dpopManager.startRegister(state); + } catch (error) { + if (this.config.onLoginFailure) { + this.config.onLoginFailure(error as Error); + } else { + console.error('FusionAuth SDK: startRegister failed', error); + } + } + })(); + return; + } + this.redirectHelper.handlePreRedirect(state); window.location.assign(this.urlHelper.getRegisterUrl(state)); } - startLogout() { + /** + * Initiates the logout flow. + * + * In DPoP mode, this synchronously returns after starting an + * asynchronous flow. + * + * In hosted backend mode, the flow is synchronous. + */ + startLogout(): void { + clearTimeout(this.tokenExpirationTimeout); + this.stopAutoRefresh(); + + const dpopManager = this.dpopManager; + if (dpopManager) { + (async () => { + try { + await dpopManager.startLogout(); + } catch (error) { + console.error('FusionAuth SDK: startLogout failed', error); + } + })(); + return; + } + window.location.assign(this.urlHelper.getLogoutUrl()); } @@ -55,7 +136,66 @@ export class SDKCore { window.location.assign(this.urlHelper.getAccountManagementUrl()); } - async fetchUserInfo() { + /** + * Returns the current DPoP mode access token. In hosted backend mode, tokens + * are stored in HttpOnly cookies and are never accessible to JavaScript, + * so this method throws instead. + * + * @throws {Error} if called in hosted backend mode + */ + getAccessToken(): string | null { + if (!this.dpopManager) { + throw new Error( + 'getAccessToken() is only available in DPoP mode. In hosted backend mode, tokens are stored in HttpOnly cookies and are not accessible to JavaScript.', + ); + } + return this.dpopManager.getAccessToken(); + } + + /** + * DPoP-aware `fetch()` wrapper. Automatically attaches `Authorization: DPoP + * ` and `DPoP: ` headers to the outgoing request. + * + * @throws {Error} if called in hosted backend mode (`useDpop: false`). + */ + async dpopFetch( + input: RequestInfo | URL, + init?: RequestInit, + ): Promise { + if (!this.dpopManager) { + throw new Error( + 'dpopFetch() is only available in DPoP mode. In hosted backend mode, use fetch() with credentials: "include" instead.', + ); + } + return this.dpopManager.fetch(input, init); + } + + /** + * Generates a signed DPoP proof JWT for the given request, for use cases + * (e.g. axios or other HTTP libraries) that can't use + * {@link dpopFetch}). + * + * @throws {Error} if called in hosted backend mode (`useDpop: false`). + */ + async generateProof( + htu: string, + htm: string, + accessToken?: string, + nonce?: string, + ): Promise { + if (!this.dpopManager) { + throw new Error( + 'generateProof() is only available in DPoP mode. In hosted backend mode, tokens are stored in HttpOnly cookies and DPoP proofs are not applicable.', + ); + } + return this.dpopManager.generateProof(htu, htm, accessToken, nonce); + } + + async fetchUserInfo(): Promise { + if (this.dpopManager) { + return this.dpopManager.fetchUserInfo(); + } + const userInfoResponse = await fetch(this.urlHelper.getMeUrl(), { credentials: 'include', }); @@ -71,6 +211,15 @@ export class SDKCore { } async refreshToken(): Promise { + if (this.dpopManager) { + const response = await this.dpopManager.refreshToken(); + this.scheduleTokenExpiration(); + if (this.config.shouldAutoRefresh) { + this.initAutoRefresh(); + } + return response; + } + const response = await fetch(this.urlHelper.getTokenRefreshUrl(), { method: 'POST', credentials: 'include', @@ -88,8 +237,6 @@ export class SDKCore { throw new Error(JSON.stringify(errorDetails)); } - // a successful request means that app_exp was bumped into the future. - // reschedule the access token expiration event. this.scheduleTokenExpiration(); return response; @@ -128,25 +275,66 @@ export class SDKCore { /** * Cancels a pending automatic token refresh without disposing the core. * Unlike {@link dispose}, the core remains usable and auto refresh can be - * restarted via {@link initAutoRefresh}. This makes it safe to stop/start - * across React StrictMode's mount → unmount → remount cycle. + * restarted via {@link initAutoRefresh}. */ stopAutoRefresh(): void { clearTimeout(this.refreshTokenTimeout); } - handlePostRedirect(callback?: (state?: string) => void) { + /** + * Handles the return trip from a login/register redirect. + * + * In DPoP mode (`useDpop: true`), this synchronously returns after + * kicking off an async chain, otherwise continue using Hosted + * Backend Mode. + */ + async handlePostRedirect(callback?: (state?: string) => void): Promise { + if (this.dpopManager) { + const error = await this.dpopManager.handlePostRedirect(callback); + if (error) { + if (this.config.onLoginFailure) { + this.config.onLoginFailure(error); + } else { + console.error('FusionAuth SDK: handlePostRedirect failed', error); + } + } else { + this.scheduleTokenExpiration(); + if (this.config.shouldAutoRefresh) { + this.initAutoRefresh(); + } + } + return; + } + if (this.isLoggedIn) { this.redirectHelper.handlePostRedirect(callback); } } + /** + * Whether the user is currently logged in. + * + * - DPoP mode: delegates to `DPoPManager.isLoggedIn` which checks whether + * the stored tokens exist and have not expired. + * - Hosted backend mode: reads the `app.at_exp` cookie (existing behavior). + */ get isLoggedIn() { + if (this.dpopManager) { + return this.dpopManager.isLoggedIn; + } return this.at_exp > new Date().getTime(); } - /** The moment of access token expiration in milliseconds since epoch. */ + /** + * The moment of access token expiration in milliseconds since epoch. + * + * - DPoP mode: delegates to `DPoPManager.getExpiresAt()`. + * - Hosted backend mode: reads the `app.at_exp` cookie (existing behavior). + */ private get at_exp(): number | -1 { + if (this.dpopManager) { + return this.dpopManager.getExpiresAt(); + } return getAccessTokenExpirationMoment( this.config.accessTokenExpireCookieName, this.config.cookieAdapter, @@ -156,7 +344,8 @@ export class SDKCore { /** * Schedules `onTokenExpiration` at moment of access token expiration. * SDKCore is not necessarily reactive like React, Angular, and Vue. - * so `onTokenExpiration` is for reactive frameworks to hook in and perform actions as on token expiration. + * so `onTokenExpiration` is for reactive frameworks to hook in and + * perform actions as on token expiration. */ private scheduleTokenExpiration(): void { clearTimeout(this.tokenExpirationTimeout); diff --git a/packages/core/src/UrlHelper/UrlHelper.test.ts b/packages/core/src/UrlHelper/UrlHelper.test.ts index 1775b63..4157b60 100644 --- a/packages/core/src/UrlHelper/UrlHelper.test.ts +++ b/packages/core/src/UrlHelper/UrlHelper.test.ts @@ -122,6 +122,158 @@ describe('UrlHelper', () => { expect(logout.pathname).toBe(paths.logoutPath); expect(tokenRefresh.pathname).toBe(paths.tokenRefreshPath); }); + + describe('getAuthorizeUrl', () => { + const dpopJkt = 'abc123thumbprint'; + const codeChallenge = 'E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM'; + + it('includes all required params', () => { + const authorizeUrl = urlHelper.getAuthorizeUrl(dpopJkt, codeChallenge); + expect(authorizeUrl.origin).toBe(config.serverUrl); + expect(authorizeUrl.pathname).toBe('/oauth2/authorize'); + expect(authorizeUrl.searchParams.get('response_type')).toBe('code'); + expect(authorizeUrl.searchParams.get('client_id')).toBe(config.clientId); + expect(authorizeUrl.searchParams.get('redirect_uri')).toBe( + config.redirectUri, + ); + expect(authorizeUrl.searchParams.get('scope')).toBe(config.scope); + expect(authorizeUrl.searchParams.get('dpop_jkt')).toBe(dpopJkt); + expect(authorizeUrl.searchParams.get('code_challenge')).toBe( + codeChallenge, + ); + expect(authorizeUrl.searchParams.get('code_challenge_method')).toBe( + 'S256', + ); + }); + + it('omits state when not provided', () => { + const authorizeUrl = urlHelper.getAuthorizeUrl(dpopJkt, codeChallenge); + expect(authorizeUrl.searchParams.get('state')).toBeNull(); + }); + + it('appends state when provided', () => { + const authorizeUrl = urlHelper.getAuthorizeUrl( + dpopJkt, + codeChallenge, + 'my-state', + ); + expect(authorizeUrl.searchParams.get('state')).toBe('my-state'); + }); + + it('appends all params together', () => { + const state = 'my-state'; + const authorizeUrl = urlHelper.getAuthorizeUrl( + dpopJkt, + codeChallenge, + state, + ); + expect(authorizeUrl.searchParams.get('state')).toBe(state); + expect(authorizeUrl.searchParams.get('dpop_jkt')).toBe(dpopJkt); + expect(authorizeUrl.searchParams.get('code_challenge')).toBe( + codeChallenge, + ); + expect(authorizeUrl.searchParams.get('code_challenge_method')).toBe( + 'S256', + ); + }); + + it('does not affect existing URL methods', () => { + const loginUrl = urlHelper.getLoginUrl(); + expect(loginUrl.pathname).toBe('/app/login/'); + const registerUrl = urlHelper.getRegisterUrl(); + expect(registerUrl.pathname).toBe('/app/register/'); + }); + }); + + describe('getOAuth2RegisterUrl', () => { + const dpopJkt = 'abc123thumbprint'; + const codeChallenge = 'E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM'; + + it('includes all required params, matching getAuthorizeUrl()', () => { + const registerUrl = urlHelper.getOAuth2RegisterUrl( + dpopJkt, + codeChallenge, + ); + expect(registerUrl.origin).toBe(config.serverUrl); + expect(registerUrl.pathname).toBe('/oauth2/register'); + expect(registerUrl.searchParams.get('response_type')).toBe('code'); + expect(registerUrl.searchParams.get('client_id')).toBe(config.clientId); + expect(registerUrl.searchParams.get('redirect_uri')).toBe( + config.redirectUri, + ); + expect(registerUrl.searchParams.get('scope')).toBe(config.scope); + expect(registerUrl.searchParams.get('dpop_jkt')).toBe(dpopJkt); + expect(registerUrl.searchParams.get('code_challenge')).toBe( + codeChallenge, + ); + expect(registerUrl.searchParams.get('code_challenge_method')).toBe( + 'S256', + ); + }); + + it('omits state when not provided', () => { + const registerUrl = urlHelper.getOAuth2RegisterUrl( + dpopJkt, + codeChallenge, + ); + expect(registerUrl.searchParams.get('state')).toBeNull(); + }); + + it('appends state when provided', () => { + const registerUrl = urlHelper.getOAuth2RegisterUrl( + dpopJkt, + codeChallenge, + 'my-state', + ); + expect(registerUrl.searchParams.get('state')).toBe('my-state'); + }); + }); + + describe('getTokenUrl', () => { + it('targets the FusionAuth /oauth2/token endpoint directly', () => { + const tokenUrl = urlHelper.getTokenUrl(); + expect(tokenUrl.origin).toBe(config.serverUrl); + expect(tokenUrl.pathname).toBe('/oauth2/token'); + }); + + it('has no query params — request params are sent in the POST body', () => { + const tokenUrl = urlHelper.getTokenUrl(); + expect(tokenUrl.search).toBe(''); + }); + }); + + describe('getOAuth2LogoutUrl', () => { + it('targets the FusionAuth /oauth2/logout endpoint directly', () => { + const logoutUrl = urlHelper.getOAuth2LogoutUrl(); + expect(logoutUrl.origin).toBe(config.serverUrl); + expect(logoutUrl.pathname).toBe('/oauth2/logout'); + expect(logoutUrl.searchParams.get('client_id')).toBe(config.clientId); + expect(logoutUrl.searchParams.get('post_logout_redirect_uri')).toBe( + config.postLogoutRedirectUri, + ); + }); + + it('defaults post_logout_redirect_uri to redirectUri when not configured', () => { + const urlHelperWithoutPostLogoutRedirectUri = new UrlHelper({ + serverUrl: 'http://my-server', + clientId: 'abc123', + redirectUri: 'http://my-client', + }); + const logoutUrl = + urlHelperWithoutPostLogoutRedirectUri.getOAuth2LogoutUrl(); + expect(logoutUrl.searchParams.get('post_logout_redirect_uri')).toBe( + 'http://my-client', + ); + }); + }); + + describe('getUserInfoUrl', () => { + it('targets the FusionAuth /oauth2/userinfo endpoint directly', () => { + const userInfoUrl = urlHelper.getUserInfoUrl(); + expect(userInfoUrl.origin).toBe(config.serverUrl); + expect(userInfoUrl.pathname).toBe('/oauth2/userinfo'); + }); + }); }); function getAllUrls(urlHelper: UrlHelper) { diff --git a/packages/core/src/UrlHelper/UrlHelper.ts b/packages/core/src/UrlHelper/UrlHelper.ts index 388950a..1e63cd9 100644 --- a/packages/core/src/UrlHelper/UrlHelper.ts +++ b/packages/core/src/UrlHelper/UrlHelper.ts @@ -67,12 +67,82 @@ export class UrlHelper { }); } + /** + * Builds the direct `/oauth2/logout` URL used in DPoP mode. + */ + getOAuth2LogoutUrl(): URL { + return this.generateUrl('/oauth2/logout', { + client_id: this.clientId, + post_logout_redirect_uri: this.postLogoutRedirectUri || this.redirectUri, + }); + } + getAccountManagementUrl(): URL { return this.generateUrl('/account/', { client_id: this.clientId, }); } + /** + * Builds the direct `/oauth2/authorize` URL used in DPoP mode. + * Targets FusionAuth directly (not the hosted backend mode). + * + * @param dpopJkt The DPoP public key JWK thumbprint for the `dpop_jkt` parameter. + * @param codeChallenge The PKCE code challenge value. + * @param state Optional OAuth2 `state` parameter. + */ + getAuthorizeUrl(dpopJkt: string, codeChallenge: string, state?: string): URL { + return this.generateUrl('/oauth2/authorize', { + client_id: this.clientId, + redirect_uri: this.redirectUri, + response_type: 'code', + scope: this.scope, + code_challenge: codeChallenge, + code_challenge_method: 'S256', + dpop_jkt: dpopJkt, + state, + }); + } + + /** + * Builds the direct `/oauth2/token` URL used in DPoP mode for the + * authorization code exchange and refresh token grant. + */ + getTokenUrl(): URL { + return this.generateUrl('/oauth2/token'); + } + + /** + * Builds the direct `/oauth2/register` URL used in DPoP mode. + * + * @param dpopJkt The DPoP public key JWK thumbprint for the `dpop_jkt` parameter. + * @param codeChallenge The PKCE code challenge value. + * @param state Optional OAuth2 `state` parameter. + */ + getOAuth2RegisterUrl( + dpopJkt: string, + codeChallenge: string, + state?: string, + ): URL { + return this.generateUrl('/oauth2/register', { + client_id: this.clientId, + redirect_uri: this.redirectUri, + response_type: 'code', + scope: this.scope, + code_challenge: codeChallenge, + code_challenge_method: 'S256', + dpop_jkt: dpopJkt, + state, + }); + } + + /** + * Builds the direct `/oauth2/userinfo` URL used in DPoP mode. + */ + getUserInfoUrl(): URL { + return this.generateUrl('/oauth2/userinfo'); + } + private generateUrl(path: string, params?: UrlHelperQueryParams): URL { const url = new URL(this.serverUrl); url.pathname = path; diff --git a/packages/core/src/UrlHelper/UrlHelperTypes.ts b/packages/core/src/UrlHelper/UrlHelperTypes.ts index 5f1dd4d..6f64ff5 100644 --- a/packages/core/src/UrlHelper/UrlHelperTypes.ts +++ b/packages/core/src/UrlHelper/UrlHelperTypes.ts @@ -21,7 +21,11 @@ export type UrlHelperQueryParams = { client_id: string; redirect_uri?: string; post_logout_redirect_uri?: string; + response_type?: string; scope?: string; authParams?: { [key: string]: any }[]; + code_challenge?: string; + code_challenge_method?: string; + dpop_jkt?: string; state?: string; }; diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 0dcd81f..4d9e6f4 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -3,3 +3,5 @@ export * from './SDKConfig'; export { type SDKContext } from './SDKContext'; export * from './testUtils'; export { type CookieAdapter } from './CookieHelpers'; +export * from './DPoP'; +export * from './Pkce'; diff --git a/packages/core/src/testUtils/mockWindowLocation.ts b/packages/core/src/testUtils/mockWindowLocation.ts index 9608592..f3ce4cc 100644 --- a/packages/core/src/testUtils/mockWindowLocation.ts +++ b/packages/core/src/testUtils/mockWindowLocation.ts @@ -1,8 +1,17 @@ import { VitestUtils } from 'vitest'; -function mockWindowLocation(vi: VitestUtils) { +/** + * Mocks `window.location`, stubbing `assign()` so redirects can be asserted + * on without actually navigating. + * + * @param search Optional query string (e.g. `'?code=abc123'`) to simulate + * landing on a redirect URI that carries an authorization + * `code`. Defaults to the current `window.location.search`. + */ +function mockWindowLocation(vi: VitestUtils, search?: string) { const mockedLocation = { ...window.location, + ...(search !== undefined ? { search } : {}), assign: vi.fn(), }; vi.spyOn(window, 'location', 'get').mockReturnValue(mockedLocation); diff --git a/packages/lexicon/package.json b/packages/lexicon/package.json index 031d465..6a87842 100644 --- a/packages/lexicon/package.json +++ b/packages/lexicon/package.json @@ -27,6 +27,6 @@ "@types/node": "^20.11.5", "vite": "^5.0.12", "vite-plugin-dts": "^3.7.1", - "vitest": "^1.2.1" + "vitest": "^3.2.6" } } diff --git a/packages/sdk-angular/CHANGES.md b/packages/sdk-angular/CHANGES.md index c208e89..3cb30e7 100644 --- a/packages/sdk-angular/CHANGES.md +++ b/packages/sdk-angular/CHANGES.md @@ -1,5 +1,9 @@ @fusionauth/angular-sdk Changes +Changes in 2.1.0 + +- Added support for DPoP mode. Configure with `useDpop: true` and `dpopTokenStorage`. `FusionAuthService` now exposes `dpopFetch()`, `generateProof()`, and `getAccessToken()`. + Changes in 2.0.0 - Upgraded to Angular 22. Angular 17 through 21 are no longer supported. diff --git a/packages/sdk-angular/README.md b/packages/sdk-angular/README.md index c1bc352..693ea5d 100644 --- a/packages/sdk-angular/README.md +++ b/packages/sdk-angular/README.md @@ -11,6 +11,7 @@ An SDK for using FusionAuth in Angular applications. - [Pre-built buttons](#pre-built-buttons) - [State Parameter](#state-parameter) - [SSR](#ssr) + - [DPoP Mode](#dpop-mode) - [Known issues](#known-issues) - [Documentation](#documentation) - [Releases](#releases) @@ -94,6 +95,7 @@ import { FusionAuthModule } from '@fusionauth/angular-sdk'; serverUrl: '', // The base URL of the server that performs the token exchange redirectUri: '', // The URI that the user is directed to after the login/register/logout action shouldAutoRefresh: true // option to configure the SDK to automatically handle token refresh. Defaults to false if not specified here. + // useDpop: true, // Opt-in to DPoP mode. See "DPoP Mode" below. Defaults to false. }), ], providers: [], @@ -185,6 +187,40 @@ user can be returned to that location after a successful authentication. The SDK supports Angular applications using SSR. No additional configuration is needed. +### DPoP Mode + +By default, the SDK calls a Hosted Backend that stores tokens in HttpOnly cookies (`useDpop: false`, the default). In DPoP mode, the SDK instead calls FusionAuth endpoints directly and binds tokens to a private key generated in the browser. Enable it by setting `useDpop: true` on `FusionAuthConfig`: + +```typescript +FusionAuthModule.forRoot({ + clientId: '', + serverUrl: '', + redirectUri: '', + useDpop: true, // Opt-in to DPoP mode. + dpopTokenStorage: 'localStorage', // 'localStorage' (default, persists across reloads) or 'memory'. +}), +``` + +When `useDpop: true`, `FusionAuthService` additionally exposes `dpopFetch()`, `generateProof()`, and `getAccessToken()`. These throw a descriptive error if called when `useDpop` is not enabled. + +```typescript +class AppComponent { + private fusionAuthService: FusionAuthService = inject(FusionAuthService); + + async callApi() { + // Recommended — handles attaching DPoP headers (and nonce retries) automatically. + const response = await this.fusionAuthService.dpopFetch('https://api.example.com/data', { method: 'GET' }); + + // For axios or other HTTP libraries that can't use dpopFetch. + const accessToken = this.fusionAuthService.getAccessToken(); + const proof = await this.fusionAuthService.generateProof('https://api.example.com/data', 'GET', accessToken ?? undefined); + // axios.get('https://api.example.com/data', { + // headers: { Authorization: `DPoP ${accessToken}`, DPoP: proof } + // }); + } +} +``` + ### Known Issues None. diff --git a/packages/sdk-angular/package.json b/packages/sdk-angular/package.json index fcdb974..2224ee8 100644 --- a/packages/sdk-angular/package.json +++ b/packages/sdk-angular/package.json @@ -5,8 +5,8 @@ "ng": "ng", "get-sdk-core": "node getSDKCore.js", "build": "yarn get-sdk-core && ng build && cp README.md dist/fusionauth-angular-sdk/README.md", - "test": "ng test --watch=false", - "test:watch": "ng test", + "test": "yarn get-sdk-core && ng test --watch=false", + "test:watch": "yarn get-sdk-core && ng test", "docs": "typedoc --plugin typedoc-plugin-markdown" }, "private": false, diff --git a/packages/sdk-angular/projects/fusionauth-angular-sdk/ng-package.json b/packages/sdk-angular/projects/fusionauth-angular-sdk/ng-package.json index ccbfd22..1efe30c 100644 --- a/packages/sdk-angular/projects/fusionauth-angular-sdk/ng-package.json +++ b/packages/sdk-angular/projects/fusionauth-angular-sdk/ng-package.json @@ -3,5 +3,6 @@ "dest": "../../dist/fusionauth-angular-sdk", "lib": { "entryFile": "src/public-api.ts" - } + }, + "allowedNonPeerDependencies": ["dpop"] } diff --git a/packages/sdk-angular/projects/fusionauth-angular-sdk/package.json b/packages/sdk-angular/projects/fusionauth-angular-sdk/package.json index 066fe15..466def9 100644 --- a/packages/sdk-angular/projects/fusionauth-angular-sdk/package.json +++ b/packages/sdk-angular/projects/fusionauth-angular-sdk/package.json @@ -1,12 +1,13 @@ { "name": "@fusionauth/angular-sdk", - "version": "2.0.0", + "version": "2.1.0", "peerDependencies": { "@angular/common": ">=22.0.0", "@angular/core": ">=22.0.0" }, "dependencies": { - "tslib": "^2.3.0" + "tslib": "^2.3.0", + "dpop": "^2.1.1" }, "sideEffects": false, "repository": { diff --git a/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.spec.ts b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.spec.ts index e48d08b..d419d42 100644 --- a/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.spec.ts +++ b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.spec.ts @@ -5,7 +5,12 @@ import { take } from 'rxjs'; import { FusionAuthConfig } from './types'; import { FusionAuthService } from './fusion-auth.service'; import { FusionAuthModule } from './fusion-auth.module'; -import { mockIsLoggedIn, removeAt_expCookie } from '../sdkcore'; +import { + mockIsLoggedIn, + removeAt_expCookie, + mockWindowLocation, + DPoPManager, +} from '../sdkcore'; const config: FusionAuthConfig = { clientId: 'a-client-id', @@ -13,6 +18,32 @@ const config: FusionAuthConfig = { serverUrl: 'http://localhost:9011', }; +const dpopConfig: FusionAuthConfig = { + ...config, + useDpop: true, +}; + +function seedDpopTokens( + clientId: string, + overrides: Partial<{ + accessToken: string; + refreshToken: string | undefined; + expiresAt: number; + tokenType: string; + }> = {}, +) { + localStorage.setItem( + `fusionauth-sdk:tokens:${clientId}`, + JSON.stringify({ + accessToken: 'mock-access-token', + refreshToken: 'mock-refresh-token', + expiresAt: Date.now() + 60_000, + tokenType: 'DPoP', + ...overrides, + }), + ); +} + function configureTestingModule(config: FusionAuthConfig) { TestBed.configureTestingModule({ imports: [FusionAuthModule.forRoot(config)], @@ -132,6 +163,7 @@ describe('FusionAuthService', () => { mockIsLoggedIn(); const stateValue = '/welcome-page'; + // Format: nonce:state (hosted backend mode) localStorage.setItem('fa-sdk-redirect-value', `abc123:${stateValue}`); const onRedirect = vi.fn(); @@ -139,4 +171,223 @@ describe('FusionAuthService', () => { expect(onRedirect).toHaveBeenCalledWith('/welcome-page'); }); + + describe('DPoP mode', () => { + it('dpopFetch() delegates to DPoPManager when useDpop: true', async () => { + const mockResponse = new Response(null, { status: 200 }); + const fetchSpy = vi + .spyOn(DPoPManager.prototype, 'fetch') + .mockResolvedValue(mockResponse); + + const service = configureTestingModule(dpopConfig); + const init = { method: 'GET' }; + const response = await service.dpopFetch( + 'https://api.example.com/data', + init, + ); + + expect(fetchSpy).toHaveBeenCalledWith( + 'https://api.example.com/data', + init, + ); + expect(response).toBe(mockResponse); + }); + + it('dpopFetch() throws when useDpop is not enabled', async () => { + const service = configureTestingModule(config); + + await expect( + service.dpopFetch('https://api.example.com/data'), + ).rejects.toThrow( + 'dpopFetch() is only available in DPoP mode. In hosted backend mode, use fetch() with credentials: "include" instead.', + ); + }); + + it('generateProof() delegates to DPoPManager when useDpop: true', async () => { + const generateProofSpy = vi + .spyOn(DPoPManager.prototype, 'generateProof') + .mockResolvedValue('mock-dpop-proof-jwt'); + + const service = configureTestingModule(dpopConfig); + const proof = await service.generateProof( + 'https://api.example.com/data', + 'POST', + 'mock-access-token', + 'mock-nonce', + ); + + expect(generateProofSpy).toHaveBeenCalledWith( + 'https://api.example.com/data', + 'POST', + 'mock-access-token', + 'mock-nonce', + ); + expect(proof).toBe('mock-dpop-proof-jwt'); + }); + + it('generateProof() throws when useDpop is not enabled', async () => { + const service = configureTestingModule(config); + + await expect( + service.generateProof('https://api.example.com/data', 'POST'), + ).rejects.toThrow( + 'generateProof() is only available in DPoP mode. In hosted backend mode, tokens are stored in HttpOnly cookies and DPoP proofs are not applicable.', + ); + }); + + it('getAccessToken() returns the stored access token when useDpop: true', () => { + seedDpopTokens(dpopConfig.clientId, { + accessToken: 'mock-stored-access-token', + }); + + const service = configureTestingModule(dpopConfig); + + expect(service.getAccessToken()).toBe('mock-stored-access-token'); + }); + + it('getAccessToken() returns null when logged out in DPoP mode', () => { + const service = configureTestingModule(dpopConfig); + + expect(service.getAccessToken()).toBeNull(); + }); + + it('getAccessToken() throws when useDpop is not enabled', () => { + const service = configureTestingModule(config); + + expect(() => service.getAccessToken()).toThrow( + 'getAccessToken() is only available in DPoP mode. In hosted backend mode, tokens are stored in HttpOnly cookies and are not accessible to JavaScript.', + ); + }); + + it('isLoggedInSignal reflects true once the post-redirect DPoP token exchange completes', async () => { + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + 'mock-dpop-proof-jwt', + ); + mockWindowLocation(vi, '?code=mock-authorization-code'); + localStorage.setItem( + 'fa-sdk-redirect-value', + JSON.stringify({ codeVerifier: 'mock-code-verifier' }), + ); + vi.spyOn(global, 'fetch').mockResolvedValueOnce( + new Response( + JSON.stringify({ + access_token: 'mock-access-token', + refresh_token: 'mock-refresh-token', + expires_in: 3600, + token_type: 'DPoP', + }), + { status: 200 }, + ), + ); + + const service = configureTestingModule(dpopConfig); + + expect(service.isLoggedInSignal()).toBe(false); + + await vi.waitFor(() => { + expect(service.isLoggedInSignal()).toBe(true); + }); + }); + + it('onRedirect is invoked after isLoggedInSignal is already true', async () => { + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + 'mock-dpop-proof-jwt', + ); + mockWindowLocation( + vi, + '?code=mock-authorization-code&state=mock-transaction-state', + ); + localStorage.setItem( + 'fa-sdk-redirect-value', + JSON.stringify({ + codeVerifier: 'mock-code-verifier', + // The OAuth `state` param FusionAuth echoes back is the + // SDK-generated transactionState, not the app's own state. + transactionState: 'mock-transaction-state', + state: 'redirect-state', + }), + ); + vi.spyOn(global, 'fetch').mockResolvedValueOnce( + new Response( + JSON.stringify({ + access_token: 'mock-access-token', + refresh_token: 'mock-refresh-token', + expires_in: 3600, + token_type: 'DPoP', + }), + { status: 200 }, + ), + ); + + let isLoggedInDuringOnRedirect: boolean | undefined; + const onRedirect = vi.fn(() => { + isLoggedInDuringOnRedirect = service.isLoggedInSignal(); + }); + + const service = configureTestingModule({ ...dpopConfig, onRedirect }); + + await vi.waitFor(() => expect(onRedirect).toHaveBeenCalledOnce()); + + expect(onRedirect).toHaveBeenCalledWith('redirect-state'); + expect(isLoggedInDuringOnRedirect).toBe(true); + }); + + it('refreshToken() re-syncs isLoggedInSignal after a successful DPoP refresh', async () => { + seedDpopTokens(dpopConfig.clientId, { + expiresAt: Date.now() - 1000, // already expired + }); + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + 'mock-dpop-proof-jwt', + ); + vi.spyOn(global, 'fetch').mockResolvedValueOnce( + new Response( + JSON.stringify({ + access_token: 'new-access-token', + refresh_token: 'new-refresh-token', + expires_in: 3600, + token_type: 'DPoP', + }), + { status: 200 }, + ), + ); + + const service = configureTestingModule(dpopConfig); + + expect(service.isLoggedInSignal()).toBe(false); + + await service.refreshToken(); + + expect(service.isLoggedInSignal()).toBe(true); + expect(service.getAccessToken()).toBe('new-access-token'); + }); + + it('forwards onLoginFailure to SDKCore for DPoP startLogin() failures', async () => { + const failure = new Error('crypto.subtle unavailable'); + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockRejectedValue( + failure, + ); + mockWindowLocation(vi); + + const onLoginFailure = vi.fn(); + const service = configureTestingModule({ + ...dpopConfig, + onLoginFailure, + }); + + service.startLogin(); + + await vi.waitFor(() => + expect(onLoginFailure).toHaveBeenCalledWith(failure), + ); + }); + }); }); diff --git a/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts index 85cc3ee..4e25239 100644 --- a/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts +++ b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/fusion-auth.service.ts @@ -1,6 +1,14 @@ -import { Injectable, Inject, PLATFORM_ID } from '@angular/core'; +import { + Injectable, + Inject, + PLATFORM_ID, + Signal, + signal, + WritableSignal, +} from '@angular/core'; +import { toObservable } from '@angular/core/rxjs-interop'; import { isPlatformBrowser } from '@angular/common'; -import { Observable, catchError, BehaviorSubject } from 'rxjs'; +import { Observable, catchError } from 'rxjs'; import { SDKCore } from '../sdkcore'; import { SSRCookieAdapter } from './SSRCookieAdapter'; @@ -16,7 +24,7 @@ import { FUSIONAUTH_SERVICE_CONFIG } from './injectionToken'; export class FusionAuthService { private core: SDKCore; private autoRefreshTimer?: NodeJS.Timeout; - private isLoggedInSubject: BehaviorSubject; + private isLoggedInState: WritableSignal; constructor( @Inject(FUSIONAUTH_SERVICE_CONFIG) config: FusionAuthConfig, @@ -25,15 +33,21 @@ export class FusionAuthService { this.core = new SDKCore({ ...config, onTokenExpiration: () => { - this.isLoggedInSubject.next(false); + this.isLoggedInState.set(false); }, cookieAdapter: new SSRCookieAdapter(isPlatformBrowser(platformId)), }); - this.isLoggedInSubject = new BehaviorSubject(this.core.isLoggedIn); - this.isLoggedIn$ = this.isLoggedInSubject.asObservable(); + // A signal is used here because updating a signal read in an HTML template + // is one of Angular's built-in change-detection notification mechanisms. + this.isLoggedInState = signal(this.core.isLoggedIn); + this.isLoggedInSignal = this.isLoggedInState; + this.isLoggedIn$ = toObservable(this.isLoggedInState); - this.core.handlePostRedirect(config.onRedirect); + this.core.handlePostRedirect(state => { + this.isLoggedInState.set(this.core.isLoggedIn); + config.onRedirect?.(state); + }); if (config.shouldAutoRefresh && this.core.isLoggedIn) { this.initAutoRefresh(); @@ -43,6 +57,11 @@ export class FusionAuthService { /** An observable representing whether the user is logged in. */ isLoggedIn$: Observable; + /** + * A Signal representing whether the user is logged in. + */ + isLoggedInSignal: Signal; + /** A function that returns whether the user is logged in. This returned value is non-observable. */ isLoggedIn() { return this.core.isLoggedIn; @@ -53,7 +72,9 @@ export class FusionAuthService { * Automatic token refreshing can be enabled if the SDK is configured with `shouldAutoRefresh`. */ async refreshToken(): Promise { - return await this.core.refreshToken(); + const response = await this.core.refreshToken(); + this.isLoggedInState.set(this.core.isLoggedIn); + return response; } /** @@ -133,4 +154,38 @@ export class FusionAuthService { manageAccount(): void { this.core.manageAccount(); } + + /** + * DPoP mode `fetch()` wrapper that automatically attaches DPoP proof + * headers. + * @throws {Error} if called when `useDpop` is not enabled. + */ + async dpopFetch( + input: RequestInfo | URL, + init?: RequestInit, + ): Promise { + return this.core.dpopFetch(input, init); + } + + /** + * Returns a signed DPoP proof JWT for use with axios or other + * HTTP libraries that can't use {@link dpopFetch}. + * @throws {Error} if called when `useDpop` is not enabled. + */ + async generateProof( + htu: string, + htm: string, + accessToken?: string, + nonce?: string, + ): Promise { + return this.core.generateProof(htu, htm, accessToken, nonce); + } + + /** + * Returns the stored DPoP access token, or `null` if not logged in. + * @throws {Error} if called when `useDpop` is not enabled. + */ + getAccessToken(): string | null { + return this.core.getAccessToken(); + } } diff --git a/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts index 1a5e8bd..c46c6ba 100644 --- a/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts +++ b/packages/sdk-angular/projects/fusionauth-angular-sdk/src/lib/types.ts @@ -47,6 +47,12 @@ export interface FusionAuthConfig { */ onAutoRefreshFailure?: (error: Error) => void; + /** + * Callback invoked if a DPoP mode login/register/redirect exchange fails. + * Only relevant when `useDpop: true`. + */ + onLoginFailure?: (error: Error) => void; + /** * The path to the login endpoint. */ @@ -71,6 +77,19 @@ export interface FusionAuthConfig { * The path to the me endpoint. */ mePath?: string; + + /** + * Opt-in to DPoP mode. When `true`, the SDK calls FusionAuth endpoints + * directly and stores tokens in JavaScript-accessible storage instead of + * relying on the Hosted Backend's HttpOnly cookies. Defaults to `false`. + */ + useDpop?: boolean; + + /** + * Token storage location in DPoP mode. Only meaningful when `useDpop: true`. + * Defaults to `'localStorage'`. + */ + dpopTokenStorage?: 'localStorage' | 'memory'; } export interface UserInfo { diff --git a/packages/sdk-react/CHANGES.md b/packages/sdk-react/CHANGES.md index f3844f0..0fc2849 100644 --- a/packages/sdk-react/CHANGES.md +++ b/packages/sdk-react/CHANGES.md @@ -1,5 +1,9 @@ FusionAuth React SDK Changes +Changes in 2.7.0 + +- Added support for DPoP mode. Configure with `useDpop: true` and `dpopTokenStorage`. `useFusionAuth()` now exposes `dpopFetch`, `generateProof`, and `getAccessToken` when DPoP mode is enabled. + Changes in 2.6.0 - Upgrade to React 19. The SDK is now built and tested against React 19 (^19.2.0) while maintaining compatibility with React 18.2+. diff --git a/packages/sdk-react/README.md b/packages/sdk-react/README.md index 67e2710..4e4e2b3 100644 --- a/packages/sdk-react/README.md +++ b/packages/sdk-react/README.md @@ -13,6 +13,7 @@ An SDK for using FusionAuth in React applications. - [State Parameter](#state-parameter) - [Protecting content](#protecting-content) - [UI Components](#ui-components) + - [DPoP Mode](#dpop-mode) - [Known issues](#known-issues) - [Documentation](#documentation) - [Formatting](#formatting) @@ -96,6 +97,7 @@ const config: FusionAuthProviderConfig = { shouldAutoFetchUserInfo: true, // Automatically fetch userInfo when logged in. Defaults to false. shouldAutoRefresh: true, // Enables automatic token refresh. Defaults to false. onRedirect: (state?: string) => { }, // Optional callback invoked upon redirect back from login or register. + // useDpop: true, // Opt-in to DPoP mode. See "DPoP Mode" below. Defaults to false. }; ReactDOM.createRoot(document.getElementById("my-app")).render( @@ -228,6 +230,36 @@ export const AccountPage = () => ( ); ``` +### DPoP Mode + +By default, the SDK calls a Hosted Backend that stores tokens in HttpOnly cookies (`useDpop: false`, the default). In DPoP mode, the SDK instead calls FusionAuth endpoints directly and binds tokens to a private key generated in the browser, per [RFC 9449](https://datatracker.ietf.org/doc/html/rfc9449). Enable it by setting `useDpop: true` on `FusionAuthProviderConfig`: + +```jsx +const config: FusionAuthProviderConfig = { + clientId: "", + redirectUri: "", + serverUrl: "", + useDpop: true, // Opt-in to DPoP mode. + dpopTokenStorage: 'localStorage', // 'localStorage' (default, persists across reloads) or 'memory'. +}; +``` + +When `useDpop: true`, `useFusionAuth()` additionally returns `dpopFetch`, `generateProof`, and `getAccessToken`. These are `undefined` when `useDpop` is `false` or not set. + +```jsx +const { dpopFetch, generateProof, getAccessToken } = useFusionAuth(); + +// Recommended — handles attaching DPoP headers (and nonce retries) automatically. +const response = await dpopFetch('https://api.example.com/data', { method: 'GET' }); + +// Advanced — for axios or other HTTP libraries that can't use dpopFetch. +const accessToken = getAccessToken(); +const proof = await generateProof('https://api.example.com/data', 'GET', accessToken); +// axios.get('https://api.example.com/data', { +// headers: { Authorization: `DPoP ${accessToken}`, DPoP: proof } +// }); +``` + ### Known Issues None. diff --git a/packages/sdk-react/package.json b/packages/sdk-react/package.json index 847ad70..9785612 100644 --- a/packages/sdk-react/package.json +++ b/packages/sdk-react/package.json @@ -1,6 +1,6 @@ { "name": "@fusionauth/react-sdk", - "version": "2.6.0", + "version": "2.7.0", "description": "FusionAuth solves the problem of building essential security without adding risk or distracting from your primary application", "type": "module", "scripts": { @@ -61,6 +61,6 @@ "typescript": "^5.2.2", "vite": "^5.4.17", "vite-plugin-dts": "^3.7.3", - "vitest": "^1.6.1" + "vitest": "^3.2.6" } } diff --git a/packages/sdk-react/src/components/providers/FusionAuthProvider.test.tsx b/packages/sdk-react/src/components/providers/FusionAuthProvider.test.tsx index e162335..96acb4a 100644 --- a/packages/sdk-react/src/components/providers/FusionAuthProvider.test.tsx +++ b/packages/sdk-react/src/components/providers/FusionAuthProvider.test.tsx @@ -13,6 +13,7 @@ import { mockIsLoggedIn, removeAt_expCookie, mockWindowLocation, + DPoPManager, } from '@fusionauth-sdk/core'; import { TEST_CONFIG, @@ -27,11 +28,34 @@ function renderWithWrapper(config: FusionAuthProviderConfig) { }); } +/** Seeds `localStorage` with a valid, unexpired DPoP token set for `clientId`. */ +function seedDpopTokens( + clientId: string, + overrides: Partial<{ + accessToken: string; + refreshToken: string | undefined; + expiresAt: number; + tokenType: string; + }> = {}, +) { + localStorage.setItem( + `fusionauth-sdk:tokens:${clientId}`, + JSON.stringify({ + accessToken: 'mock-access-token', + refreshToken: 'mock-refresh-token', + expiresAt: Date.now() + 60_000, + tokenType: 'DPoP', + ...overrides, + }), + ); +} + describe('FusionAuthProvider', () => { afterEach(() => { removeAt_expCookie(); localStorage.clear(); vi.clearAllMocks(); + vi.useRealTimers(); }); test('Redirects to the correct login url', () => { @@ -121,12 +145,13 @@ describe('FusionAuthProvider', () => { mockIsLoggedIn(); const stateValue = 'hello-world'; + // Format: nonce:state (hosted backend mode) localStorage.setItem('fa-sdk-redirect-value', `abc123:${stateValue}`); const onRedirect = vi.fn(); renderWithWrapper({ ...TEST_CONFIG, onRedirect }); - expect(onRedirect).toHaveBeenCalled(); + expect(onRedirect).toHaveBeenCalledWith(stateValue); }); test('Will not invoke onRedirect if no redirect value is found in localStorage', () => { @@ -327,4 +352,253 @@ describe('FusionAuthProvider', () => { ), ); }); + + describe('DPoP mode', () => { + test('dpopFetch, generateProof, and getAccessToken are functions when useDpop: true', () => { + const { result } = renderWithWrapper({ ...TEST_CONFIG, useDpop: true }); + + expect(typeof result.current.dpopFetch).toBe('function'); + expect(typeof result.current.generateProof).toBe('function'); + expect(typeof result.current.getAccessToken).toBe('function'); + }); + + test('dpopFetch, generateProof, and getAccessToken are undefined when useDpop is false', () => { + const { result } = renderWithWrapper({ ...TEST_CONFIG, useDpop: false }); + + expect(result.current.dpopFetch).toBeUndefined(); + expect(result.current.generateProof).toBeUndefined(); + expect(result.current.getAccessToken).toBeUndefined(); + }); + + test('dpopFetch, generateProof, and getAccessToken are undefined when useDpop is not set', () => { + const { result } = renderWithWrapper(TEST_CONFIG); + + expect(result.current.dpopFetch).toBeUndefined(); + expect(result.current.generateProof).toBeUndefined(); + expect(result.current.getAccessToken).toBeUndefined(); + }); + + test('getAccessToken() returns the stored access token after login', () => { + seedDpopTokens(TEST_CONFIG.clientId, { + accessToken: 'mock-stored-access-token', + }); + + const { result } = renderWithWrapper({ ...TEST_CONFIG, useDpop: true }); + + expect(result.current.getAccessToken?.()).toBe( + 'mock-stored-access-token', + ); + }); + + test('getAccessToken() returns null when logged out', () => { + const { result } = renderWithWrapper({ ...TEST_CONFIG, useDpop: true }); + + expect(result.current.getAccessToken?.()).toBeNull(); + }); + + test('isLoggedIn reflects DPoP token store state, not the app.at_exp cookie', () => { + seedDpopTokens(TEST_CONFIG.clientId); + // Explicitly confirm no cookie-based login signal is present. + removeAt_expCookie(); + + const { result } = renderWithWrapper({ ...TEST_CONFIG, useDpop: true }); + + expect(result.current.isLoggedIn).toBe(true); + }); + + test('isLoggedIn is false in DPoP mode when no tokens are stored, even if the app.at_exp cookie is set', () => { + mockIsLoggedIn(); // sets app.at_exp cookie — must be ignored in DPoP mode. + + const { result } = renderWithWrapper({ ...TEST_CONFIG, useDpop: true }); + + expect(result.current.isLoggedIn).toBe(false); + }); + + test('isLoggedIn flips to true once the post-redirect DPoP token exchange completes', async () => { + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + 'mock-dpop-proof-jwt', + ); + mockWindowLocation(vi, '?code=mock-authorization-code'); + localStorage.setItem( + 'fa-sdk-redirect-value', + JSON.stringify({ codeVerifier: 'mock-code-verifier' }), + ); + vi.spyOn(global, 'fetch').mockResolvedValueOnce( + new Response( + JSON.stringify({ + access_token: 'mock-access-token', + refresh_token: 'mock-refresh-token', + expires_in: 3600, + token_type: 'DPoP', + }), + { status: 200 }, + ), + ); + + const { result } = renderWithWrapper({ ...TEST_CONFIG, useDpop: true }); + + expect(result.current.isLoggedIn).toBe(false); + + await waitFor(() => { + expect(result.current.isLoggedIn).toBe(true); + }); + expect(result.current.getAccessToken?.()).toBe('mock-access-token'); + }); + + test('shouldAutoFetchUserInfo fetches userInfo once isLoggedIn flips to true after the DPoP redirect completes', async () => { + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + 'mock-dpop-proof-jwt', + ); + mockWindowLocation(vi, '?code=mock-authorization-code'); + localStorage.setItem( + 'fa-sdk-redirect-value', + JSON.stringify({ codeVerifier: 'mock-code-verifier' }), + ); + + // First response is the code exchange (/oauth2/token); second is the + // subsequent /oauth2/userinfo call triggered by shouldAutoFetchUserInfo. + vi.spyOn(global, 'fetch') + .mockResolvedValueOnce( + new Response( + JSON.stringify({ + access_token: 'mock-access-token', + refresh_token: 'mock-refresh-token', + expires_in: 3600, + token_type: 'DPoP', + }), + { status: 200 }, + ), + ) + .mockResolvedValueOnce( + new Response(JSON.stringify({ email: 'user@example.com' }), { + status: 200, + }), + ); + + const { result } = renderWithWrapper({ + ...TEST_CONFIG, + useDpop: true, + shouldAutoFetchUserInfo: true, + }); + + expect(result.current.isLoggedIn).toBe(false); + + await waitFor(() => { + expect(result.current.isLoggedIn).toBe(true); + }); + + await waitFor(() => { + expect(result.current.userInfo).toEqual({ email: 'user@example.com' }); + }); + }); + + test('forwards onLoginFailure to SDKCore for DPoP startLogin() failures', async () => { + const failure = new Error('crypto.subtle unavailable'); + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockRejectedValue( + failure, + ); + mockWindowLocation(vi); + + const onLoginFailure = vi.fn(); + const { result } = renderWithWrapper({ + ...TEST_CONFIG, + useDpop: true, + onLoginFailure, + }); + + act(() => { + result.current.startLogin(); + }); + + await waitFor(() => expect(onLoginFailure).toHaveBeenCalledWith(failure)); + }); + + test('onRedirect is invoked and isLoggedIn eventually reflects the completed exchange', async () => { + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + 'mock-dpop-proof-jwt', + ); + mockWindowLocation( + vi, + '?code=mock-authorization-code&state=mock-transaction-state', + ); + localStorage.setItem( + 'fa-sdk-redirect-value', + JSON.stringify({ + codeVerifier: 'mock-code-verifier', + // The OAuth `state` param FusionAuth echoes back is the SDK-generated + // transactionState — not the app's own state — per the CSRF fix in + // RedirectHelper.handlePreDpopRedirect(). + transactionState: 'mock-transaction-state', + state: 'redirect-state', + }), + ); + vi.spyOn(global, 'fetch').mockResolvedValueOnce( + new Response( + JSON.stringify({ + access_token: 'mock-access-token', + refresh_token: 'mock-refresh-token', + expires_in: 3600, + token_type: 'DPoP', + }), + { status: 200 }, + ), + ); + + const onRedirect = vi.fn(); + + const { result } = renderWithWrapper({ + ...TEST_CONFIG, + useDpop: true, + onRedirect, + }); + + await waitFor(() => + expect(onRedirect).toHaveBeenCalledWith('redirect-state'), + ); + await waitFor(() => expect(result.current.isLoggedIn).toBe(true)); + }); + + test('refreshToken() re-syncs isLoggedIn after a successful DPoP refresh', async () => { + seedDpopTokens(TEST_CONFIG.clientId, { + expiresAt: Date.now() - 1000, // already expired + }); + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + 'mock-dpop-proof-jwt', + ); + vi.spyOn(global, 'fetch').mockResolvedValueOnce( + new Response( + JSON.stringify({ + access_token: 'new-access-token', + refresh_token: 'new-refresh-token', + expires_in: 3600, + token_type: 'DPoP', + }), + { status: 200 }, + ), + ); + + const { result } = renderWithWrapper({ ...TEST_CONFIG, useDpop: true }); + + expect(result.current.isLoggedIn).toBe(false); + + await act(async () => { + await result.current.refreshToken(); + }); + + expect(result.current.isLoggedIn).toBe(true); + expect(result.current.getAccessToken?.()).toBe('new-access-token'); + }); + }); }); diff --git a/packages/sdk-react/src/components/providers/FusionAuthProvider.tsx b/packages/sdk-react/src/components/providers/FusionAuthProvider.tsx index 45d8fec..0e02693 100644 --- a/packages/sdk-react/src/components/providers/FusionAuthProvider.tsx +++ b/packages/sdk-react/src/components/providers/FusionAuthProvider.tsx @@ -4,6 +4,7 @@ import { useMemo, useState, useRef, + useCallback, } from 'react'; import { SDKConfig, SDKCore } from '@fusionauth-sdk/core'; @@ -14,6 +15,7 @@ import { useRedirecting, useUserInfo, useCookieAdapter, + useDpop, } from './hooks'; import { FusionAuthContext, UserInfo as DefaultUserInfo } from './Context'; import { FusionAuthProviderContext } from './FusionAuthProviderContext'; @@ -41,6 +43,9 @@ function FusionAuthProvider( mePath: props.mePath, accessTokenExpireCookieName: props.accessTokenExpireCookieName, onAutoRefreshFailure: props.onAutoRefreshFailure, + onLoginFailure: props.onLoginFailure, + useDpop: props.useDpop, + dpopTokenStorage: props.dpopTokenStorage, }), [ props.serverUrl, @@ -60,6 +65,9 @@ function FusionAuthProvider( props.mePath, props.accessTokenExpireCookieName, props.onAutoRefreshFailure, + props.onLoginFailure, + props.useDpop, + props.dpopTokenStorage, ], ); @@ -96,17 +104,28 @@ function FusionAuthProvider( const [isLoggedIn, setIsLoggedIn] = useState(core.isLoggedIn); + const syncIsLoggedIn = useCallback(() => { + setIsLoggedIn(core.isLoggedIn); + }, [core]); + const { manageAccount, startLogin, startLogout, startRegister } = - useRedirecting(core, config.onRedirect); + useRedirecting(core, config.onRedirect, syncIsLoggedIn); const { isFetchingUserInfo, userInfo, fetchUserInfo, error } = useUserInfo( core, config.shouldAutoFetchUserInfo ?? false, + isLoggedIn, ); const { refreshToken, initAutoRefresh } = useTokenRefresh( core, config.shouldAutoRefresh ?? false, + syncIsLoggedIn, + ); + + const { dpopFetch, generateProof, getAccessToken } = useDpop( + core, + config.useDpop ?? false, ); const providerValue: FusionAuthProviderContext = { @@ -121,6 +140,9 @@ function FusionAuthProvider( initAutoRefresh, fetchUserInfo, manageAccount, + dpopFetch, + generateProof, + getAccessToken, }; return ( diff --git a/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts b/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts index 6161bb3..10071fe 100644 --- a/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts +++ b/packages/sdk-react/src/components/providers/FusionAuthProviderConfig.ts @@ -59,6 +59,12 @@ export interface FusionAuthProviderConfig { */ onAutoRefreshFailure?: (error: Error) => void; + /** + * Callback invoked if a DPoP mode login/register/redirect exchange fails. + * Only relevant when `useDpop: true`. + */ + onLoginFailure?: (error: Error) => void; + /** * The path to the login endpoint. */ @@ -96,4 +102,17 @@ export interface FusionAuthProviderConfig { * Only set this if you are hosting server that uses a custom name for the 'app.at_exp' cookie. */ accessTokenExpireCookieName?: string; + + /** + * Opt-in to DPoP mode. When `true`, the SDK calls FusionAuth endpoints + * directly and stores tokens in JavaScript-accessible storage instead of + * relying on the Hosted Backend's HttpOnly cookies. Defaults to `false`. + */ + useDpop?: boolean; + + /** + * Token storage location in DPoP mode. Only meaningful when `useDpop: true`. + * Defaults to `'localStorage'`. + */ + dpopTokenStorage?: 'localStorage' | 'memory'; } diff --git a/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts b/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts index fde4193..e761964 100644 --- a/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts +++ b/packages/sdk-react/src/components/providers/FusionAuthProviderContext.ts @@ -62,4 +62,31 @@ export interface FusionAuthProviderContext { * This is handled automatically if the SDK is configured with `shouldAutoRefresh`. */ initAutoRefresh: () => void; + + /** + * Fetch wrapper that automatically attaches DPoP proof headers. + * Present only when `useDpop: true`. + */ + dpopFetch?: ( + input: RequestInfo | URL, + init?: RequestInit, + ) => Promise; + + /** + * Returns a signed DPoP proof JWT for use with axios or other + * HTTP libraries. Present only when `useDpop: true`. + */ + generateProof?: ( + htu: string, + htm: string, + accessToken?: string, + nonce?: string, + ) => Promise; + + /** + * Returns the stored DPoP access token, or `null` if not logged in. + * Throws a descriptive error when `useDpop: false`. + * Present only when `useDpop: true`. + */ + getAccessToken?: () => string | null; } diff --git a/packages/sdk-react/src/components/providers/hooks/index.ts b/packages/sdk-react/src/components/providers/hooks/index.ts index 6dd7c14..49d9ebf 100644 --- a/packages/sdk-react/src/components/providers/hooks/index.ts +++ b/packages/sdk-react/src/components/providers/hooks/index.ts @@ -2,3 +2,4 @@ export * from './useRedirecting'; export * from './useTokenRefresh'; export * from './useUserInfo'; export * from './useCookieAdapter'; +export * from './useDpop'; diff --git a/packages/sdk-react/src/components/providers/hooks/useDpop.ts b/packages/sdk-react/src/components/providers/hooks/useDpop.ts new file mode 100644 index 0000000..c818cd2 --- /dev/null +++ b/packages/sdk-react/src/components/providers/hooks/useDpop.ts @@ -0,0 +1,33 @@ +import { useCallback } from 'react'; +import { SDKCore } from '@fusionauth-sdk/core'; + +/** + * Exposes `dpopFetch`, `generateProof`, and `getAccessToken` from `core` + * when DPoP mode is enabled. Each is `undefined` when `useDpop` is false, + * matching `FusionAuthProviderContext`'s optional fields. + */ +export function useDpop(core: SDKCore, enabled: boolean) { + const dpopFetch = useCallback( + (input: RequestInfo | URL, init?: RequestInit) => + core.dpopFetch(input, init), + [core], + ); + + const generateProof = useCallback( + (htu: string, htm: string, accessToken?: string, nonce?: string) => + core.generateProof(htu, htm, accessToken, nonce), + [core], + ); + + const getAccessToken = useCallback(() => core.getAccessToken(), [core]); + + if (!enabled) { + return { + dpopFetch: undefined, + generateProof: undefined, + getAccessToken: undefined, + }; + } + + return { dpopFetch, generateProof, getAccessToken }; +} diff --git a/packages/sdk-react/src/components/providers/hooks/useRedirecting.ts b/packages/sdk-react/src/components/providers/hooks/useRedirecting.ts index 4635c52..07ba5bf 100644 --- a/packages/sdk-react/src/components/providers/hooks/useRedirecting.ts +++ b/packages/sdk-react/src/components/providers/hooks/useRedirecting.ts @@ -4,6 +4,7 @@ import { SDKCore } from '@fusionauth-sdk/core'; export function useRedirecting( core: SDKCore, onRedirect?: (state?: string) => void, + syncIsLoggedIn?: () => void, ) { const manageAccount = useCallback(() => core.manageAccount(), [core]); const startLogin = useCallback( @@ -17,8 +18,11 @@ export function useRedirecting( const startLogout = useCallback(() => core.startLogout(), [core]); useEffect(() => { - core.handlePostRedirect(onRedirect); - }, [core, onRedirect]); + core.handlePostRedirect(state => { + syncIsLoggedIn?.(); + onRedirect?.(state); + }); + }, [core, onRedirect, syncIsLoggedIn]); return { manageAccount, diff --git a/packages/sdk-react/src/components/providers/hooks/useTokenRefresh.ts b/packages/sdk-react/src/components/providers/hooks/useTokenRefresh.ts index 143b1bf..e1e5fa8 100644 --- a/packages/sdk-react/src/components/providers/hooks/useTokenRefresh.ts +++ b/packages/sdk-react/src/components/providers/hooks/useTokenRefresh.ts @@ -1,11 +1,16 @@ import { useEffect, useCallback } from 'react'; import { SDKCore } from '@fusionauth-sdk/core'; -export function useTokenRefresh(core: SDKCore, shouldAutoRefresh: boolean) { - const refreshToken = useCallback( - async () => await core.refreshToken(), - [core], - ); +export function useTokenRefresh( + core: SDKCore, + shouldAutoRefresh: boolean, + syncIsLoggedIn?: () => void, +) { + const refreshToken = useCallback(async () => { + const response = await core.refreshToken(); + syncIsLoggedIn?.(); + return response; + }, [core, syncIsLoggedIn]); const initAutoRefresh = useCallback(() => { core.initAutoRefresh(); diff --git a/packages/sdk-react/src/components/providers/hooks/useUserInfo.ts b/packages/sdk-react/src/components/providers/hooks/useUserInfo.ts index 3bb0569..cc18dfc 100644 --- a/packages/sdk-react/src/components/providers/hooks/useUserInfo.ts +++ b/packages/sdk-react/src/components/providers/hooks/useUserInfo.ts @@ -5,6 +5,7 @@ import { SDKCore } from '@fusionauth-sdk/core'; export function useUserInfo( core: SDKCore, shouldAutoFetchUserInfo: boolean, + isLoggedIn: boolean, ) { const [isFetchingUserInfo, setIsFetchingUserInfo] = useState(false); const [userInfo, setUserInfo] = useState(null); @@ -28,17 +29,19 @@ export function useUserInfo( const didAttemptAutoFetch = useRef(false); const handleAutoFetch = useCallback(() => { - if (!shouldAutoFetchUserInfo || didAttemptAutoFetch.current) { + if ( + !shouldAutoFetchUserInfo || + didAttemptAutoFetch.current || + !isLoggedIn + ) { return; } // ensures this effect does not run multiple times if we fail to fetch the user didAttemptAutoFetch.current = true; - if (core.isLoggedIn) { - fetchUserInfo(); - } - }, [core, fetchUserInfo, shouldAutoFetchUserInfo]); + fetchUserInfo(); + }, [fetchUserInfo, shouldAutoFetchUserInfo, isLoggedIn]); useEffect(() => { handleAutoFetch(); diff --git a/packages/sdk-react/src/testing-tools/mocks/createContextMock.ts b/packages/sdk-react/src/testing-tools/mocks/createContextMock.ts index bb14de7..d416ef0 100644 --- a/packages/sdk-react/src/testing-tools/mocks/createContextMock.ts +++ b/packages/sdk-react/src/testing-tools/mocks/createContextMock.ts @@ -19,4 +19,7 @@ export const createContextMock = ( function () { return Promise.resolve({}); }, + dpopFetch: context.dpopFetch, + generateProof: context.generateProof, + getAccessToken: context.getAccessToken, }); diff --git a/packages/sdk-vue/CHANGES.md b/packages/sdk-vue/CHANGES.md index 7d4b400..d3c91a7 100644 --- a/packages/sdk-vue/CHANGES.md +++ b/packages/sdk-vue/CHANGES.md @@ -1,5 +1,9 @@ fusionauth-vue-sdk Changes +Changes in 1.4.0 + +- Added support for DPoP mode. Configure with `useDpop: true` and `dpopTokenStorage`. `useFusionAuth()` now exposes `dpopFetch`, `generateProof`, and `getAccessToken` when DPoP mode is enabled. + Changes in 1.3.0 - Upgraded to Vue 3.5.38. The minimum supported Vue peer dependency is now `>=3.5.0`. diff --git a/packages/sdk-vue/README.md b/packages/sdk-vue/README.md index cf3c2ef..ae8333d 100644 --- a/packages/sdk-vue/README.md +++ b/packages/sdk-vue/README.md @@ -11,6 +11,7 @@ An SDK for using FusionAuth in Vue applications. - [Configuring with Nuxt](#configuring-with-nuxt) - [useFusionAuth Composable](#usefusionauth-composable) - [State parameter](#state-parameter) + - [DPoP Mode](#dpop-mode) - [UI Components](#ui-components) - [Protecting Content](#protecting-content) - [Pre-built buttons](#pre-built-buttons) @@ -98,6 +99,7 @@ const config: FusionAuthConfig = { shouldAutoFetchUserInfo: true, // Automatically fetch userInfo when logged in. Defaults to false. shouldAutoRefresh: true, // Enables automatic token refresh. Defaults to false. onRedirect: (state?: string) => { }, // Optional callback invoked upon redirect back from login or register. + // useDpop: true, // Opt-in to DPoP mode. See "DPoP Mode" below. Defaults to false. } const app = createApp(App); @@ -192,6 +194,48 @@ const welcomeMessage = computed(() => { The `login` and `register` functions accept an optional string parameter: `state`, which will be passed back to the optional `onRedirect` callback specified on your `FusionAuthConfig`. Though you may pass any value you would like for the state parameter, it is often used to indicate which page the user was on before redirecting to login or registration, so that the user can be returned to that location after a successful authentication. +#### DPoP Mode + +By default, the SDK calls a Hosted Backend that stores tokens in HttpOnly cookies (`useDpop: false`, the default). In DPoP mode, the SDK instead calls FusionAuth endpoints directly and binds tokens to a private key generated in the browser. Enable it by setting `useDpop: true` on `FusionAuthConfig`: + +```typescript +const config: FusionAuthConfig = { + clientId: "", + redirectUri: "", + serverUrl: "", + useDpop: true, // Opt-in to DPoP mode. + dpopTokenStorage: 'localStorage', // 'localStorage' (default, persists across reloads) or 'memory'. +} +``` + +When `useDpop: true`, `useFusionAuth()` additionally returns `dpopFetch`, `generateProof`, and `getAccessToken`. These are `undefined` when `useDpop` is `false` or not set. + +```html + +``` + +In DPoP mode, the login/register redirect round trip finishes asynchronously (there's no Hosted Backend to set cookies before the app reloads). `onRedirect` fires only after `isLoggedIn` and tokens are fully updated, so it's a reliable place to hook in post-login navigation: + +```typescript +const config: FusionAuthConfig = { + // ... + useDpop: true, + onRedirect: () => router.push('/account'), +} +``` + ### UI Components #### Protecting Content diff --git a/packages/sdk-vue/package.json b/packages/sdk-vue/package.json index 6f79ca5..5604ac5 100644 --- a/packages/sdk-vue/package.json +++ b/packages/sdk-vue/package.json @@ -1,6 +1,6 @@ { "name": "@fusionauth/vue-sdk", - "version": "1.3.0", + "version": "1.4.0", "description": "FusionAuth solves the problem of building essential security without adding risk or distracting from your primary application", "type": "module", "scripts": { diff --git a/packages/sdk-vue/src/createFusionAuth/createFusionAuth.test.ts b/packages/sdk-vue/src/createFusionAuth/createFusionAuth.test.ts index ec14ab3..c8ca922 100644 --- a/packages/sdk-vue/src/createFusionAuth/createFusionAuth.test.ts +++ b/packages/sdk-vue/src/createFusionAuth/createFusionAuth.test.ts @@ -6,6 +6,7 @@ import { mockWindowLocation, mockIsLoggedIn, removeAt_expCookie, + DPoPManager, } from '@fusionauth-sdk/core'; const config: FusionAuthConfig = { @@ -15,6 +16,28 @@ const config: FusionAuthConfig = { scope: 'openid offline_access', }; +/** Seeds `localStorage` with a valid, unexpired DPoP token set for `clientId`. */ +function seedDpopTokens( + clientId: string, + overrides: Partial<{ + accessToken: string; + refreshToken: string | undefined; + expiresAt: number; + tokenType: string; + }> = {}, +) { + localStorage.setItem( + `fusionauth-sdk:tokens:${clientId}`, + JSON.stringify({ + accessToken: 'mock-access-token', + refreshToken: 'mock-refresh-token', + expiresAt: Date.now() + 60_000, + tokenType: 'DPoP', + ...overrides, + }), + ); +} + describe('createFusionAuth', () => { afterEach(() => { removeAt_expCookie(); @@ -64,6 +87,7 @@ describe('createFusionAuth', () => { mockIsLoggedIn(); const onRedirect = vi.fn(); const expectedStateValue = 'redirect-callback-test'; + // Format: nonce:state (hosted backend mode) localStorage.setItem( 'fa-sdk-redirect-value', `rAnd0mStR1ng:${expectedStateValue}`, @@ -186,4 +210,229 @@ describe('createFusionAuth', () => { expect(mockedLocation.assign).toHaveBeenCalledWith(expectedUrl); }); + + describe('DPoP mode', () => { + it('dpopFetch, generateProof, and getAccessToken are functions when useDpop: true', () => { + const fusionAuth = createFusionAuth({ ...config, useDpop: true }); + + expect(typeof fusionAuth.dpopFetch).toBe('function'); + expect(typeof fusionAuth.generateProof).toBe('function'); + expect(typeof fusionAuth.getAccessToken).toBe('function'); + }); + + it('dpopFetch, generateProof, and getAccessToken are undefined when useDpop is not set', () => { + const fusionAuth = createFusionAuth(config); + + expect(fusionAuth.dpopFetch).toBeUndefined(); + expect(fusionAuth.generateProof).toBeUndefined(); + expect(fusionAuth.getAccessToken).toBeUndefined(); + }); + + it('getAccessToken() returns the stored access token after login', () => { + seedDpopTokens(config.clientId, { + accessToken: 'mock-stored-access-token', + }); + + const fusionAuth = createFusionAuth({ ...config, useDpop: true }); + + expect(fusionAuth.getAccessToken?.()).toBe('mock-stored-access-token'); + }); + + it('getAccessToken() returns null when logged out', () => { + const fusionAuth = createFusionAuth({ ...config, useDpop: true }); + + expect(fusionAuth.getAccessToken?.()).toBeNull(); + }); + + it('refreshToken() re-syncs isLoggedIn after a successful DPoP refresh', async () => { + seedDpopTokens(config.clientId, { + expiresAt: Date.now() - 1000, // already expired + }); + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + 'mock-dpop-proof-jwt', + ); + vi.spyOn(global, 'fetch').mockResolvedValueOnce( + new Response( + JSON.stringify({ + access_token: 'new-access-token', + refresh_token: 'new-refresh-token', + expires_in: 3600, + token_type: 'DPoP', + }), + { status: 200 }, + ), + ); + + const fusionAuth = createFusionAuth({ ...config, useDpop: true }); + + expect(fusionAuth.isLoggedIn.value).toBe(false); + + await fusionAuth.refreshToken(); + + expect(fusionAuth.isLoggedIn.value).toBe(true); + expect(fusionAuth.getAccessToken?.()).toBe('new-access-token'); + }); + + it('isLoggedIn flips to true once the post-redirect DPoP token exchange settles', async () => { + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + 'mock-dpop-proof-jwt', + ); + mockWindowLocation(vi, '?code=mock-authorization-code'); + localStorage.setItem( + 'fa-sdk-redirect-value', + JSON.stringify({ codeVerifier: 'mock-code-verifier' }), + ); + vi.spyOn(global, 'fetch').mockResolvedValueOnce( + new Response( + JSON.stringify({ + access_token: 'mock-access-token', + refresh_token: 'mock-refresh-token', + expires_in: 3600, + token_type: 'DPoP', + }), + { status: 200 }, + ), + ); + + const fusionAuth = createFusionAuth({ ...config, useDpop: true }); + + expect(fusionAuth.isLoggedIn.value).toBe(false); + + await vi.waitFor(() => { + expect(fusionAuth.isLoggedIn.value).toBe(true); + }); + expect(fusionAuth.getAccessToken?.()).toBe('mock-access-token'); + }); + + it('onRedirect is invoked after isLoggedIn is already true, so a handler that navigates based on isLoggedIn.value (e.g. a router guard) sees the up-to-date value', async () => { + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + 'mock-dpop-proof-jwt', + ); + mockWindowLocation( + vi, + '?code=mock-authorization-code&state=mock-transaction-state', + ); + localStorage.setItem( + 'fa-sdk-redirect-value', + JSON.stringify({ + codeVerifier: 'mock-code-verifier', + // The OAuth `state` param FusionAuth echoes back is the + // SDK-generated transactionState, not the app's own state. + transactionState: 'mock-transaction-state', + state: 'redirect-state', + }), + ); + vi.spyOn(global, 'fetch').mockResolvedValueOnce( + new Response( + JSON.stringify({ + access_token: 'mock-access-token', + refresh_token: 'mock-refresh-token', + expires_in: 3600, + token_type: 'DPoP', + }), + { status: 200 }, + ), + ); + + let isLoggedInDuringOnRedirect: boolean | undefined; + const onRedirect = vi.fn((state?: string) => { + isLoggedInDuringOnRedirect = fusionAuth.isLoggedIn.value; + expect(state).toBe('redirect-state'); + }); + + const fusionAuth = createFusionAuth({ + ...config, + useDpop: true, + onRedirect, + }); + + await vi.waitFor(() => expect(onRedirect).toHaveBeenCalledOnce()); + + expect(isLoggedInDuringOnRedirect).toBe(true); + }); + + it('shouldAutoFetchUserInfo fetches userInfo once isLoggedIn flips to true after the DPoP redirect settles (not just at construction)', async () => { + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockResolvedValue( + {} as any, + ); + vi.spyOn(DPoPManager.prototype, 'generateProof').mockResolvedValue( + 'mock-dpop-proof-jwt', + ); + mockWindowLocation(vi, '?code=mock-authorization-code'); + localStorage.setItem( + 'fa-sdk-redirect-value', + JSON.stringify({ codeVerifier: 'mock-code-verifier' }), + ); + + // First response is the code exchange (/oauth2/token); second is the + // subsequent /oauth2/userinfo call triggered by shouldAutoFetchUserInfo. + vi.spyOn(global, 'fetch') + .mockResolvedValueOnce( + new Response( + JSON.stringify({ + access_token: 'mock-access-token', + refresh_token: 'mock-refresh-token', + expires_in: 3600, + token_type: 'DPoP', + }), + { status: 200 }, + ), + ) + .mockResolvedValueOnce( + new Response(JSON.stringify({ email: 'user@example.com' }), { + status: 200, + }), + ); + + const fusionAuth = createFusionAuth({ + ...config, + useDpop: true, + shouldAutoFetchUserInfo: true, + }); + + expect(fusionAuth.isLoggedIn.value).toBe(false); + + await vi.waitFor(() => { + expect(fusionAuth.isLoggedIn.value).toBe(true); + }); + + // userInfo only becomes available asynchronously, well after + // construction — it is not fetched until the DPoP redirect settles. + await vi.waitFor(() => { + expect(fusionAuth.userInfo.value).toEqual({ + email: 'user@example.com', + }); + }); + }); + + it('forwards onLoginFailure to SDKCore for DPoP login() failures', async () => { + const failure = new Error('crypto.subtle unavailable'); + vi.spyOn(DPoPManager.prototype, 'getOrCreateKeyPair').mockRejectedValue( + failure, + ); + mockWindowLocation(vi); + + const onLoginFailure = vi.fn(); + const fusionAuth = createFusionAuth({ + ...config, + useDpop: true, + onLoginFailure, + }); + + fusionAuth.login(); + + await vi.waitFor(() => + expect(onLoginFailure).toHaveBeenCalledWith(failure), + ); + }); + }); }); diff --git a/packages/sdk-vue/src/createFusionAuth/createFusionAuth.ts b/packages/sdk-vue/src/createFusionAuth/createFusionAuth.ts index 0bc8522..47ef050 100644 --- a/packages/sdk-vue/src/createFusionAuth/createFusionAuth.ts +++ b/packages/sdk-vue/src/createFusionAuth/createFusionAuth.ts @@ -40,7 +40,9 @@ export const createFusionAuth = ( } async function refreshToken() { - return await core.refreshToken(); + const response = await core.refreshToken(); + syncIsLoggedIn(); + return response; } function initAutoRefresh() { @@ -63,15 +65,54 @@ export const createFusionAuth = ( core.manageAccount(); } - if (config.shouldAutoFetchUserInfo && core.isLoggedIn === true) { + async function dpopFetch(input: RequestInfo | URL, init?: RequestInit) { + return core.dpopFetch(input, init); + } + + async function generateProof( + htu: string, + htm: string, + accessToken?: string, + nonce?: string, + ) { + return core.generateProof(htu, htm, accessToken, nonce); + } + + function getAccessToken() { + return core.getAccessToken(); + } + + let didAttemptAutoFetch = false; + + function syncIsLoggedIn() { + isLoggedIn.value = core.isLoggedIn; + } + + function maybeAutoFetchUserInfo() { + if ( + !config.shouldAutoFetchUserInfo || + didAttemptAutoFetch || + !core.isLoggedIn + ) { + return; + } + + // ensures this does not run multiple times if we fail to fetch the user + didAttemptAutoFetch = true; getUserInfo(); } + maybeAutoFetchUserInfo(); + if (config.shouldAutoRefresh && core.isLoggedIn === true) { core.initAutoRefresh(); } - core.handlePostRedirect(config.onRedirect); + core.handlePostRedirect(state => { + syncIsLoggedIn(); + maybeAutoFetchUserInfo(); + config.onRedirect?.(state); + }); return { isLoggedIn, @@ -85,5 +126,8 @@ export const createFusionAuth = ( manageAccount, refreshToken, initAutoRefresh, + dpopFetch: config.useDpop ? dpopFetch : undefined, + generateProof: config.useDpop ? generateProof : undefined, + getAccessToken: config.useDpop ? getAccessToken : undefined, }; }; diff --git a/packages/sdk-vue/src/types.ts b/packages/sdk-vue/src/types.ts index fecd5c1..90fc470 100644 --- a/packages/sdk-vue/src/types.ts +++ b/packages/sdk-vue/src/types.ts @@ -53,6 +53,12 @@ export interface FusionAuthConfig { */ onAutoRefreshFailure?: (error: Error) => void; + /** + * Callback invoked if a DPoP mode login/register/redirect exchange fails. + * Only relevant when `useDpop: true`. + */ + onLoginFailure?: (error: Error) => void; + /** * Pass in `useCookie` from nuxt/app [useCookie](https://nuxt.com/docs/api/composables/use-cookie). * This is needed for the Vue SDK to support Nuxt/SSR. @@ -79,6 +85,19 @@ export interface FusionAuthConfig { * The path to the me endpoint. */ mePath?: string; + + /** + * Opt-in to DPoP mode. When `true`, the SDK calls FusionAuth endpoints + * directly and stores tokens in JavaScript-accessible storage instead of + * relying on the Hosted Backend's HttpOnly cookies. Defaults to `false`. + */ + useDpop?: boolean; + + /** + * Token storage location in DPoP mode. Only meaningful when `useDpop: true`. + * Defaults to `'localStorage'`. + */ + dpopTokenStorage?: 'localStorage' | 'memory'; } /** @@ -167,4 +186,31 @@ export interface FusionAuth { * Refresh is scheduled to happen at the configured `autoRefreshSecondsBeforeExpiry`. */ initAutoRefresh: () => NodeJS.Timeout | undefined; + + /** + * Fetch wrapper that automatically attaches DPoP proof headers. + * Present only when `useDpop: true`. + */ + dpopFetch?: ( + input: RequestInfo | URL, + init?: RequestInit, + ) => Promise; + + /** + * Returns a signed DPoP proof JWT for use with axios or other + * HTTP libraries. Present only when `useDpop: true`. + */ + generateProof?: ( + htu: string, + htm: string, + accessToken?: string, + nonce?: string, + ) => Promise; + + /** + * Returns the stored DPoP access token, or `null` if not logged in. + * Throws a descriptive error when `useDpop: false`. + * Present only when `useDpop: true`. + */ + getAccessToken?: () => string | null; } diff --git a/packages/sdk-vue/web-types.json b/packages/sdk-vue/web-types.json index d9782c4..276e218 100644 --- a/packages/sdk-vue/web-types.json +++ b/packages/sdk-vue/web-types.json @@ -1,7 +1,7 @@ { "framework": "vue", "name": "@fusionauth/vue-sdk", - "version": "1.2.0", + "version": "1.4.0", "contributions": { "html": { "description-markup": "markdown", diff --git a/playwright.config.ts b/playwright.config.ts index 6857c98..8217059 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -2,6 +2,7 @@ import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ testDir: './e2e', + testIgnore: ['**/dpop-endpoints.test.ts'], /* Run tests in files in parallel */ fullyParallel: true, /* Fail the build on CI if you accidentally left test.only in the source code. */ diff --git a/playwright.dpop-endpoints.config.ts b/playwright.dpop-endpoints.config.ts new file mode 100644 index 0000000..df9af4c --- /dev/null +++ b/playwright.dpop-endpoints.config.ts @@ -0,0 +1,46 @@ +/** + * Playwright config for DPoP endpoint tests. + */ + +import { defineConfig, devices } from '@playwright/test'; + +if (!process.env.PORT || !process.env.SERVER_COMMAND) { + throw new Error( + 'playwright.dpop-endpoints.config.ts requires PORT and SERVER_COMMAND environment variables.', + ); +} + +export default defineConfig({ + testDir: './e2e', + testMatch: '**/dpop-endpoints.test.ts', + fullyParallel: false, + forbidOnly: !!process.env.CI, + retries: process.env.CI ? 2 : 0, + workers: 1, + use: { + baseURL: `http://localhost:${process.env.PORT}`, + screenshot: 'on', + }, + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] }, + }, + + { + name: 'webkit', + use: { ...devices['Desktop Safari'] }, + }, + ], + webServer: { + command: `${process.env.SERVER_COMMAND}`, + url: `http://localhost:${process.env.PORT}`, + reuseExistingServer: !process.env.CI, + }, +}); diff --git a/yarn.lock b/yarn.lock index 38548bf..dac7ce9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -141,18 +141,18 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" -"@angular-devkit/architect@0.2200.3": - version "0.2200.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.2200.3.tgz#181929f38c4fcac8d725d875c7d34a3bb2d4fe82" - integrity sha512-Ru+ucNkTZr98gmeaBYjq3zZwh32yGofAeB8+GJL/ZNy0x+7NzK6b+OatdzwT4l7mCWFC5vL8iYu0B4++M66Jpg== +"@angular-devkit/architect@0.2200.8": + version "0.2200.8" + resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.2200.8.tgz#fa787d77c951cb3354b10f9ac2a6520de5daa021" + integrity sha512-LFKK2v96nO0ESM9nftlCkTy+O/66AxNkwUpG+Q1er7LLNR2S8UReZnQ1/RhMkldCWxsmp2rQzdgHWnubaY/ZfA== dependencies: - "@angular-devkit/core" "22.0.3" + "@angular-devkit/core" "22.0.8" rxjs "7.8.2" -"@angular-devkit/core@22.0.3": - version "22.0.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-22.0.3.tgz#885192f9346504d46ba5b7b5d2f38d1561bca168" - integrity sha512-pBjo1JKwI8GbNdTo/Z0g+ZekqlTBCJWmzIC5fgGW9q5eRjl1y+5N5jlX8UAyyMCeUTTwsfpQdkAM2jyi/jcvjA== +"@angular-devkit/core@22.0.8": + version "22.0.8" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-22.0.8.tgz#32ae524ffb609f682515520b189cabe9104b188a" + integrity sha512-Hnr4SCkxQM+xtq4uERC09qwTZpt97t4CwDZYzv/HbQA4pMYDfTxvIRHCyl+UHf4NbkC7ZVgyiab+KzTfuc609Q== dependencies: ajv "8.20.0" ajv-formats "3.0.1" @@ -161,33 +161,33 @@ rxjs "7.8.2" source-map "0.7.6" -"@angular-devkit/schematics@22.0.3": - version "22.0.3" - resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-22.0.3.tgz#068272d5a501714300d88b3733685ffc03a6f3e7" - integrity sha512-aIp5sQDHdhyLbeVJF/k3w079XhW91mNAo2OliZllBCjoYhkIXNnWECOx5y2nXtCChyFJA2+ZgNST7NIDvtz1/w== +"@angular-devkit/schematics@22.0.8": + version "22.0.8" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-22.0.8.tgz#2624fba7289fa8fb777ca4e58c18f232afc476c8" + integrity sha512-9WjTKnW/5oIw4hNNcd0rSYtgHRrHKKAkG6+bdLqTCY68P2brO2yEJM2JjYtMYk/WSovknb0GxUP4n3dY3IxPug== dependencies: - "@angular-devkit/core" "22.0.3" + "@angular-devkit/core" "22.0.8" jsonc-parser "3.3.1" magic-string "0.30.21" ora "9.4.0" rxjs "7.8.2" "@angular/animations@^22.0.0": - version "22.0.2" - resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-22.0.2.tgz#ddc3265a2cbac291c848f3f282e8d52ea1e2dd0a" - integrity sha512-l9lVG9k+baFMWXNsFUxwmxQaUZMkpkTn3vRpa1hs/vABzT/KnaDeweDtvvkS0NS1RYJenoxhONlMNEWuJ4VR1A== + version "22.0.8" + resolved "https://registry.yarnpkg.com/@angular/animations/-/animations-22.0.8.tgz#cfa28b35482895a984fdae2c8688c74a1e8b9f80" + integrity sha512-hdBlckl5mARzuc5gt2siydIAxeJbBiRneg8V0kazEDH6xNkNp/1siro68ZaHgTY5dCUEOec/eC4zbhB8AlSLhQ== dependencies: tslib "^2.3.0" "@angular/build@^22.0.0": - version "22.0.3" - resolved "https://registry.yarnpkg.com/@angular/build/-/build-22.0.3.tgz#009f1d82ed35e250d9af6bcad6259a4dbf1b7da8" - integrity sha512-pwFDRCp+r8JK+fCtScPldizcS75wSpn3u/4goDf2FRa4Y9wzTvq6T0XpFHqdpgq6HcIlIZWwAqqW6XqEM9/pKQ== + version "22.0.8" + resolved "https://registry.yarnpkg.com/@angular/build/-/build-22.0.8.tgz#5de35b5119190a2beda2048abcd12f4b5165ac8a" + integrity sha512-QJVVTROVb27Ixk+RU4FSKwwyRbLdtNH20zFm1CwOKzA0wQHrWfxHTqlwMhnTOsOt5Cb3eX+6IjDXoGmAfJ81mA== dependencies: "@ampproject/remapping" "2.3.0" - "@angular-devkit/architect" "0.2200.3" - "@babel/core" "7.29.0" - "@babel/helper-annotate-as-pure" "7.27.3" + "@angular-devkit/architect" "0.2200.8" + "@babel/core" "7.29.7" + "@babel/helper-annotate-as-pure" "7.29.7" "@babel/helper-split-export-declaration" "7.24.7" "@inquirer/confirm" "6.0.12" "@vitejs/plugin-basic-ssl" "2.3.0" @@ -201,29 +201,29 @@ mrmime "2.0.1" parse5-html-rewriting-stream "8.0.1" picomatch "4.0.4" - piscina "5.1.4" + piscina "5.2.0" rollup "4.60.2" sass "1.99.0" semver "7.7.4" source-map-support "0.5.21" tinyglobby "0.2.16" - vite "7.3.5" + vite "7.3.6" watchpack "2.5.1" optionalDependencies: lmdb "3.5.4" "@angular/cli@^22.0.0": - version "22.0.3" - resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-22.0.3.tgz#0cedc48ceb523cf55b265f957ebb3d9ad501933b" - integrity sha512-YgFzfQu3Il6Aka8IdH4pk7faieICaca5Wklke0jMTKBUxzLGWw82X7+J/Lox7FERb6LHtxiHpa6ttXqerCZvgg== + version "22.0.8" + resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-22.0.8.tgz#40ee23fa13d8a2f48bcb77d573b9768ee9d8cd15" + integrity sha512-kefbTsmf7sEmW5g3NIRvH0OrM18I1jjZHlB9KABgRQhsDfD/WgfLt6aSLJQeFDlAOs+ehDPzzOwd9l48wyBlFQ== dependencies: - "@angular-devkit/architect" "0.2200.3" - "@angular-devkit/core" "22.0.3" - "@angular-devkit/schematics" "22.0.3" + "@angular-devkit/architect" "0.2200.8" + "@angular-devkit/core" "22.0.8" + "@angular-devkit/schematics" "22.0.8" "@inquirer/prompts" "8.4.2" "@listr2/prompt-adapter-inquirer" "4.2.3" "@modelcontextprotocol/sdk" "1.29.0" - "@schematics/angular" "22.0.3" + "@schematics/angular" "22.0.8" "@yarnpkg/lockfile" "1.1.0" algoliasearch "5.52.0" ini "6.0.0" @@ -237,18 +237,18 @@ zod "4.4.2" "@angular/common@^22.0.0": - version "22.0.2" - resolved "https://registry.yarnpkg.com/@angular/common/-/common-22.0.2.tgz#985017d57f31af9b0ccf0f8c00f082b892d89000" - integrity sha512-XSkHYRwrM54v4GZ+fg9KU1KbSIE/iQF33VXKo5zqVNKO11MnAbJ59qzyqX/5EzSeogHyBoHApprFKACsCAKm/Q== + version "22.0.8" + resolved "https://registry.yarnpkg.com/@angular/common/-/common-22.0.8.tgz#833d0c8ad1a1b07f868dab3db28c9ceb4c969e98" + integrity sha512-FnwkXndUgAyWk1/p5flMfocIUtuuneJ01mxC1FxRc5/bdWTyNVeQDsM9Lw4PEAPc0AHu//EnblegRq8o6LGdUQ== dependencies: tslib "^2.3.0" "@angular/compiler-cli@^22.0.0": - version "22.0.2" - resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-22.0.2.tgz#20727dbf133d1928300062bd8496a15f989aad84" - integrity sha512-jBGGWdbrPQhIHWUz523CLQqEh/iYWxzZt7U9y0Ocdbas4/OlHcqaERO/K4ULkxclWX8MWYQoxal/MZbYOBfXgw== + version "22.0.8" + resolved "https://registry.yarnpkg.com/@angular/compiler-cli/-/compiler-cli-22.0.8.tgz#5617692e712e7193d6ae327eb696ebd0817a7399" + integrity sha512-shBqaUxMtqriv4UG2MHmYT8GSvDizI40mUFkOfeQ1yRJ2C9dk0TnWKPwjSO7o6bs6UiU6V8Y3uSWdmfCGVVZAA== dependencies: - "@babel/core" "7.29.0" + "@babel/core" "7.29.7" "@jridgewell/sourcemap-codec" "^1.4.14" chokidar "^5.0.0" convert-source-map "^1.5.1" @@ -258,46 +258,46 @@ yargs "^18.0.0" "@angular/compiler@^22.0.0": - version "22.0.2" - resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-22.0.2.tgz#725cfdeb5cfd80324604a4c5b4c0bad143f56a9a" - integrity sha512-5G+h/4/iCfqdTBsSgjB46Oe4oC6jXutCpFc5JYWRpnJWsbp3UfwRhwGVWIV1DBPnR8H/3QZzteRP1jINiH5+hg== + version "22.0.8" + resolved "https://registry.yarnpkg.com/@angular/compiler/-/compiler-22.0.8.tgz#ac3b7d3d8efff7a23e79cef189146f8a751526a9" + integrity sha512-ot7rvntfkZsPHmp8yl6PWUj/yG4e50X0+YeR7QYy/rEYKBiIg91w8GwjxSzaF4g5+bzJGDv7l/XnachKm0IySg== dependencies: tslib "^2.3.0" "@angular/core@^22.0.0": - version "22.0.2" - resolved "https://registry.yarnpkg.com/@angular/core/-/core-22.0.2.tgz#a1bd2c0cf86b1f350310d629ef4a80ab226e83c0" - integrity sha512-YMs6OZNeXh4tg67ePwSRN426WYvjqGdjxEwLrdOONKAruOmJAzW/Tqe328k/4SHfdbJTR87GPpRi5FzVP43DRA== + version "22.0.8" + resolved "https://registry.yarnpkg.com/@angular/core/-/core-22.0.8.tgz#583a71d7d8e589643f5e1e681bd3d38473faf271" + integrity sha512-HagZZVzbtXd+ZhMb++k/HOtr/UTiBROHHH7xutgYgnSnPRXX0kCca5EQ02OZ/OCWfsMP5liSJDfwiePFULKA6Q== dependencies: tslib "^2.3.0" "@angular/forms@^22.0.0": - version "22.0.2" - resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-22.0.2.tgz#c0bca62775ec108b5f1bd44da26cdf8d70803c45" - integrity sha512-k2WhkE8Of8/JRYEojSgfygiXbP6I7f/yZ/jgJzFGRC1FlF5w5erQMFx8KPg1J5CRE8kYPzW8rM4tSVCq7AaDUg== + version "22.0.8" + resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-22.0.8.tgz#38cb5da27c03d9f44efa0a13b5690127cd53aaea" + integrity sha512-KlLJE8rgziSBqCQy+cqCHPEQPGjJEY53i1vZbpnBoLXhnwswLJ3O0c76RHNpIrlrvr9v4p3b2/LxSE8wQmdStg== dependencies: "@standard-schema/spec" "^1.0.0" tslib "^2.3.0" zod "^4.0.10" "@angular/platform-browser-dynamic@^22.0.0": - version "22.0.2" - resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-22.0.2.tgz#fd4f85297d8070973f554947f82584af0e832758" - integrity sha512-5jDZzbesBBPCt41oq166B23TCW4ue9ZJyX4KlSRpGP/x8fjPGF22+AKASU6OPRnCNmmUsNk8DpenaBj+eFg/Sw== + version "22.0.8" + resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-22.0.8.tgz#83d6af751efe3be9949d06eca3ef29d1241bc75b" + integrity sha512-HQ5GeMoKqd2eMy9hHga1F0yumhrt4gVlhoP8YfmQnZWluVagdyinUpGdd3dNiuYjLcbHB+KXdW9c6LnqEmU+dg== dependencies: tslib "^2.3.0" "@angular/platform-browser@^22.0.0": - version "22.0.2" - resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-22.0.2.tgz#f920d696218565e67257352337fadeb18f7e88ed" - integrity sha512-xUkpJo/Jwa7rgpoSnZs5TeuOD3SDQL+CPJrMGjHivsqWMcAqzSNnIOcbNDJRSxAYkZ9zlJ1+h39JWSUk99rRBw== + version "22.0.8" + resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-22.0.8.tgz#00f73953298d4b5a0596d7a54f16812fffb075ec" + integrity sha512-FllGHCayu5Dv82HAA9ORL04Xf+In9JGMbQ1Vn4QnhrAVxBz182vm+ZwszLzRDSAwmfeIjZDeK49tKAcqHR9XNg== dependencies: tslib "^2.3.0" "@angular/router@^22.0.0": - version "22.0.2" - resolved "https://registry.yarnpkg.com/@angular/router/-/router-22.0.2.tgz#ef70a1ffa8472cb23161609e374286865f53b5a2" - integrity sha512-uiYlcbOyBliFq1v7O3nMyZtM8scDBurjk4AU2wEPWxSVAXuEjyfnAvowyPzVzGYAEKrsYtcg2TWSsQraqHUbnA== + version "22.0.8" + resolved "https://registry.yarnpkg.com/@angular/router/-/router-22.0.8.tgz#5971cb3b96c4cda4d3fe6e7fcafe75c4130e9f87" + integrity sha512-9NO5K03QqfWMWWZ+Uu4WqBSLw/YAot918cBUFdgl6mTUOfoHi/xWO5pAt0SEpbXMHmWafJBdb99GRlAGybGSTg== dependencies: tslib "^2.3.0" @@ -326,28 +326,7 @@ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.29.7.tgz#6f0237f0f36d2e51c0570a636faed9d2d0efe629" integrity sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg== -"@babel/core@7.29.0": - version "7.29.0" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.29.0.tgz#5286ad785df7f79d656e88ce86e650d16ca5f322" - integrity sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA== - dependencies: - "@babel/code-frame" "^7.29.0" - "@babel/generator" "^7.29.0" - "@babel/helper-compilation-targets" "^7.28.6" - "@babel/helper-module-transforms" "^7.28.6" - "@babel/helpers" "^7.28.6" - "@babel/parser" "^7.29.0" - "@babel/template" "^7.28.6" - "@babel/traverse" "^7.29.0" - "@babel/types" "^7.29.0" - "@jridgewell/remapping" "^2.3.5" - convert-source-map "^2.0.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.2.3" - semver "^6.3.1" - -"@babel/core@^7.29.0": +"@babel/core@7.29.7", "@babel/core@^7.29.0": version "7.29.7" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.29.7.tgz#80c10b17248082968b57a857b91640971f2070f7" integrity sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA== @@ -368,7 +347,7 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.28.5", "@babel/generator@^7.29.0", "@babel/generator@^7.29.7": +"@babel/generator@^7.28.5", "@babel/generator@^7.29.7": version "7.29.7" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.29.7.tgz#cca0b8827e6bcf3ba176788e7f3b180ad6db2fa3" integrity sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ== @@ -379,21 +358,14 @@ "@jridgewell/trace-mapping" "^0.3.28" jsesc "^3.0.2" -"@babel/helper-annotate-as-pure@7.27.3": - version "7.27.3" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz#f31fd86b915fc4daf1f3ac6976c59be7084ed9c5" - integrity sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg== - dependencies: - "@babel/types" "^7.27.3" - -"@babel/helper-annotate-as-pure@^7.29.7": +"@babel/helper-annotate-as-pure@7.29.7", "@babel/helper-annotate-as-pure@^7.29.7": version "7.29.7" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz#c70fe3c6ecbdc3fd2dd1b0f498428b88b82ce47f" integrity sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw== dependencies: "@babel/types" "^7.29.7" -"@babel/helper-compilation-targets@^7.28.6", "@babel/helper-compilation-targets@^7.29.7": +"@babel/helper-compilation-targets@^7.29.7": version "7.29.7" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz#7a1def704302401c47f64fa85589e974ae217042" integrity sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g== @@ -438,7 +410,7 @@ "@babel/traverse" "^7.29.7" "@babel/types" "^7.29.7" -"@babel/helper-module-transforms@^7.28.6", "@babel/helper-module-transforms@^7.29.7": +"@babel/helper-module-transforms@^7.29.7": version "7.29.7" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz#b062747a5997ba138637201328bbff77960574ae" integrity sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg== @@ -498,7 +470,7 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz#cf315be940213b354eb4abcc0bd01ebe3f73bc2a" integrity sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw== -"@babel/helpers@^7.28.6", "@babel/helpers@^7.29.7": +"@babel/helpers@^7.29.7": version "7.29.7" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.29.7.tgz#45abfde7548997e34376c3e69feb475cffb4a607" integrity sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg== @@ -506,7 +478,7 @@ "@babel/template" "^7.29.7" "@babel/types" "^7.29.7" -"@babel/parser@^7.24.7", "@babel/parser@^7.28.4", "@babel/parser@^7.28.5", "@babel/parser@^7.29.0", "@babel/parser@^7.29.3", "@babel/parser@^7.29.7", "@babel/parser@^7.6.0", "@babel/parser@^7.9.6": +"@babel/parser@^7.24.7", "@babel/parser@^7.28.4", "@babel/parser@^7.28.5", "@babel/parser@^7.29.3", "@babel/parser@^7.29.7", "@babel/parser@^7.6.0", "@babel/parser@^7.9.6": version "7.29.7" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.29.7.tgz#837b87387cbf5ec5530cb634b3c622f68edb9334" integrity sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg== @@ -543,7 +515,7 @@ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.29.7.tgz#12022450c45a4da6d8d8287b18a4ff2ddb23f768" integrity sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw== -"@babel/template@^7.27.2", "@babel/template@^7.28.6", "@babel/template@^7.29.7": +"@babel/template@^7.27.2", "@babel/template@^7.29.7": version "7.29.7" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.29.7.tgz#4d9d4004f645cdd304de958c725162784ecac700" integrity sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg== @@ -552,7 +524,7 @@ "@babel/parser" "^7.29.7" "@babel/types" "^7.29.7" -"@babel/traverse@^7.28.4", "@babel/traverse@^7.29.0", "@babel/traverse@^7.29.7": +"@babel/traverse@^7.28.4", "@babel/traverse@^7.29.7": version "7.29.7" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.29.7.tgz#c47b07a41b95da0907d026b5dd894d98de7d2f2d" integrity sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw== @@ -565,7 +537,7 @@ "@babel/types" "^7.29.7" debug "^4.3.1" -"@babel/types@^7.24.7", "@babel/types@^7.27.3", "@babel/types@^7.28.4", "@babel/types@^7.29.0", "@babel/types@^7.29.7", "@babel/types@^7.6.1", "@babel/types@^7.9.6": +"@babel/types@^7.24.7", "@babel/types@^7.28.4", "@babel/types@^7.29.0", "@babel/types@^7.29.7", "@babel/types@^7.6.1", "@babel/types@^7.9.6": version "7.29.7" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.29.7.tgz#8005e31d82712ee7adaef6e23c63b71a62770a92" integrity sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA== @@ -573,25 +545,25 @@ "@babel/helper-string-parser" "^7.29.7" "@babel/helper-validator-identifier" "^7.29.7" -"@bomb.sh/tab@^0.0.16": - version "0.0.16" - resolved "https://registry.yarnpkg.com/@bomb.sh/tab/-/tab-0.0.16.tgz#f4d00d5ff89c7798eb23d183f0cd8515926b9de5" - integrity sha512-xFtIH6JYVdXgkSft97gsQyJODZbjGXw+l+wkT06lBiBPuaF0CFYNulQNsgnYud7rURI7D4lyLmOQeAzRkvl1Fg== +"@bomb.sh/tab@^0.0.19": + version "0.0.19" + resolved "https://registry.yarnpkg.com/@bomb.sh/tab/-/tab-0.0.19.tgz#c22f3b75c8a391a38cd956b7391b45551587d76a" + integrity sha512-dTRfo9Q9B+lbLG3JCu8a/AGQSfD2XXcFcnakQzVjSOX+VvR/s9zpsH8TlqV3iHqazniRn1Ypwd1hcRlXcu/4BA== -"@clack/core@1.4.2": - version "1.4.2" - resolved "https://registry.yarnpkg.com/@clack/core/-/core-1.4.2.tgz#b299fdbf779f47c41c54d75aeb748663e05a714e" - integrity sha512-0Ty/1Gfm+Kb07sXcuESjyKfwEhSy4Ns1AgeEisHb/bDY5fWme0tTeTkU14T1Gmcs17YIjB/teiDe4uaCghbYqQ== +"@clack/core@1.4.3": + version "1.4.3" + resolved "https://registry.yarnpkg.com/@clack/core/-/core-1.4.3.tgz#1e831974f811d733707ec650e58f690d7d74c5fa" + integrity sha512-/kr3UWNtdJfxZtPgDqUOmG2pvwlmcLGheex5yiZKdwbzZJxhV+HMNR9QNmyY5cGwTNV6LrR7Jtp+KjhUAP1qBQ== dependencies: fast-wrap-ansi "^0.2.0" sisteransi "^1.0.5" -"@clack/prompts@^1.1.0", "@clack/prompts@^1.5.1": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@clack/prompts/-/prompts-1.6.0.tgz#e5dbfc514832ffaab1ea65d6cbd8e235e251c0f2" - integrity sha512-EYlRokl8szrP9Z25qT5aepMdBjzBvHF9ZEhzIiUBc9guz/T31EqRgvD0QSgZcpE93xiwrr+OkB4nz0BZyF6fSA== +"@clack/prompts@^1.3.0", "@clack/prompts@^1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@clack/prompts/-/prompts-1.7.0.tgz#2d6ced363a608ba23f6b9611205b8306c85bbf0d" + integrity sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A== dependencies: - "@clack/core" "1.4.2" + "@clack/core" "1.4.3" fast-string-width "^3.0.2" fast-wrap-ansi "^0.2.0" sisteransi "^1.0.5" @@ -602,9 +574,9 @@ integrity sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ== "@colordx/core@^5.4.3": - version "5.4.3" - resolved "https://registry.yarnpkg.com/@colordx/core/-/core-5.4.3.tgz#35a8d239b324a6cdf9a16de9970a32c8abc24824" - integrity sha512-kIxYSfA5T8HXjav55UaaH/o/cKivF6jCCGIb8eqtcsfI46wsvlSiT8jMDyrl779qLec3c2c2oHBZo4oAhvbjrQ== + version "5.5.0" + resolved "https://registry.yarnpkg.com/@colordx/core/-/core-5.5.0.tgz#d786dfde8781bbe56a0be9f862f9ab5d1ab4629d" + integrity sha512-3PxTH8itZzltK0U9jTwVVnjLXvnDYuq3m+QXsHkENxWiPRh4WaoLcs1SQjqgZ55kS+QyirpH5BVwzP2gMVG6EQ== "@csstools/color-helpers@^5.1.0": version "5.1.0" @@ -634,30 +606,26 @@ resolved "https://registry.yarnpkg.com/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz#333fedabc3fd1a8e5d0100013731cf19e6a8c5d3" integrity sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw== -"@dxup/nuxt@^0.4.1": - version "0.4.1" - resolved "https://registry.yarnpkg.com/@dxup/nuxt/-/nuxt-0.4.1.tgz#cd9845beb849b02cf52adaa6cbf841b705c23a35" - integrity sha512-gtYffW6OfWNvoLW+XD3Mx/K8uUq08PMGLYJoDxc92EzZAWqR0FhcR5iaLm5r/OxyGTKz+P5f5Y7Aoir9+SjYaw== +"@dxup/nuxt@^0.5.3": + version "0.5.5" + resolved "https://registry.yarnpkg.com/@dxup/nuxt/-/nuxt-0.5.5.tgz#53f6c4bafa8da2157490d25e3614bf214defe327" + integrity sha512-7GIUr0aD4klOyLjGMzLBNjsZiIbU6EPqO5de1Q1kTPdZXWMqamr5FqRCZycA/9n9lxsXRLFxENL7tcRAClMTrw== dependencies: "@dxup/unimport" "^0.1.2" - "@nuxt/kit" "^4.4.2" + "@nuxt/kit" "^4.5.0" + "@vue/compiler-dom" "^3.5.40" chokidar "^5.0.0" + knitwork "^1.3.0" + magic-string "^1.1.0" pathe "^2.0.3" - tinyglobby "^0.2.16" + tinyglobby "^0.2.17" + unplugin "^3.3.0" "@dxup/unimport@^0.1.2": version "0.1.2" resolved "https://registry.yarnpkg.com/@dxup/unimport/-/unimport-0.1.2.tgz#a08e4039efe41c50d9c36fbb39d9976b88eefa68" integrity sha512-/B8YJGPzaYq1NbsQmwgP8EZqg40NpTw4ZB3suuI0TplbxKHeK94jeaawLmVhCv+YwUnOpiWEz9U6SeThku/8JQ== -"@emnapi/core@1.10.0": - version "1.10.0" - resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.10.0.tgz#380ccc8f2412ea22d1d972df7f8ee23a3b9c7467" - integrity sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw== - dependencies: - "@emnapi/wasi-threads" "1.2.1" - tslib "^2.4.0" - "@emnapi/core@1.11.1": version "1.11.1" resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.11.1.tgz#b9e1064f3a6b1631e241e638eb48d736bfd372a6" @@ -666,11 +634,12 @@ "@emnapi/wasi-threads" "1.2.2" tslib "^2.4.0" -"@emnapi/runtime@1.10.0": - version "1.10.0" - resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.10.0.tgz#4b260c0d3534204e98c6110b8db1a987d26ec87c" - integrity sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA== +"@emnapi/core@1.11.2": + version "1.11.2" + resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.11.2.tgz#fab0a0f3c492d11f5a9ac9065d0d73955ee1c1c9" + integrity sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA== dependencies: + "@emnapi/wasi-threads" "1.2.2" tslib "^2.4.0" "@emnapi/runtime@1.11.1": @@ -680,10 +649,10 @@ dependencies: tslib "^2.4.0" -"@emnapi/wasi-threads@1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz#28fed21a1ba1ce797c44a070abc94d42f3ae8548" - integrity sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w== +"@emnapi/runtime@1.11.2": + version "1.11.2" + resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.11.2.tgz#eb22f04d76febfdf4f87fdaff54c8a53f6bf0dbd" + integrity sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA== dependencies: tslib "^2.4.0" @@ -704,11 +673,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz#80fcbe36130e58b7670511e888b8e88a259ed76c" integrity sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA== -"@esbuild/aix-ppc64@0.27.7": - version "0.27.7" - resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz#82b74f92aa78d720b714162939fb248c90addf53" - integrity sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg== - "@esbuild/aix-ppc64@0.28.1": version "0.28.1" resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz#7a01a8d2ec2fbb2dac78adad09b0fa781e4082be" @@ -724,11 +688,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz#8aa4965f8d0a7982dc21734bf6601323a66da752" integrity sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg== -"@esbuild/android-arm64@0.27.7": - version "0.27.7" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz#f78cb8a3121fc205a53285adb24972db385d185d" - integrity sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ== - "@esbuild/android-arm64@0.28.1": version "0.28.1" resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz#b540a27d14e4afd058496a4dbec4d3f414db110a" @@ -744,11 +703,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.12.tgz#300712101f7f50f1d2627a162e6e09b109b6767a" integrity sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg== -"@esbuild/android-arm@0.27.7": - version "0.27.7" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.27.7.tgz#593e10a1450bbfcac6cb321f61f468453bac209d" - integrity sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ== - "@esbuild/android-arm@0.28.1": version "0.28.1" resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.28.1.tgz#704bd297de6d762de54eabbeafbf55f6756abe2f" @@ -764,11 +718,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.12.tgz#87dfb27161202bdc958ef48bb61b09c758faee16" integrity sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg== -"@esbuild/android-x64@0.27.7": - version "0.27.7" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.27.7.tgz#453143d073326033d2d22caf9e48de4bae274b07" - integrity sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg== - "@esbuild/android-x64@0.28.1": version "0.28.1" resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.28.1.tgz#d1cb166d34b0fbf0fe8ab460a5594f24a378701e" @@ -784,11 +733,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz#79197898ec1ff745d21c071e1c7cc3c802f0c1fd" integrity sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg== -"@esbuild/darwin-arm64@0.27.7": - version "0.27.7" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz#6f23000fb9b40b7e04b7d0606c0693bd0632f322" - integrity sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw== - "@esbuild/darwin-arm64@0.28.1": version "0.28.1" resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz#1034b26457fc886368fe61bbd09f653f6afa8e54" @@ -804,11 +748,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz#146400a8562133f45c4d2eadcf37ddd09718079e" integrity sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA== -"@esbuild/darwin-x64@0.27.7": - version "0.27.7" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz#27393dd18bb1263c663979c5f1576e00c2d024be" - integrity sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ== - "@esbuild/darwin-x64@0.28.1": version "0.28.1" resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz#65556a432a1e4d72032d8218c1932fcca1a49772" @@ -824,11 +763,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz#1c5f9ba7206e158fd2b24c59fa2d2c8bb47ca0fe" integrity sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg== -"@esbuild/freebsd-arm64@0.27.7": - version "0.27.7" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz#22e4638fa502d1c0027077324c97640e3adf3a62" - integrity sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w== - "@esbuild/freebsd-arm64@0.28.1": version "0.28.1" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz#2e61e0592f9030d7e3dae18ee25ebc535918aef6" @@ -844,11 +778,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz#ea631f4a36beaac4b9279fa0fcc6ca29eaeeb2b3" integrity sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ== -"@esbuild/freebsd-x64@0.27.7": - version "0.27.7" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz#9224b8e4fea924ce2194e3efc3e9aebf822192d6" - integrity sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ== - "@esbuild/freebsd-x64@0.28.1": version "0.28.1" resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz#c95ec289959ef8079c4dca817a1e2c4be66b9bd3" @@ -864,11 +793,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz#e1066bce58394f1b1141deec8557a5f0a22f5977" integrity sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ== -"@esbuild/linux-arm64@0.27.7": - version "0.27.7" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz#4f5d1c27527d817b35684ae21419e57c2bda0966" - integrity sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A== - "@esbuild/linux-arm64@0.28.1": version "0.28.1" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz#40b22175dda06182f3ee8141186c5ff304c4a717" @@ -884,11 +808,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz#452cd66b20932d08bdc53a8b61c0e30baf4348b9" integrity sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw== -"@esbuild/linux-arm@0.27.7": - version "0.27.7" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz#b9e9d070c8c1c0449cf12b20eac37d70a4595921" - integrity sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA== - "@esbuild/linux-arm@0.28.1": version "0.28.1" resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz#c09a0f67917592ac0de892a9be4d3814debd2a6c" @@ -904,11 +823,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz#b24f8acc45bcf54192c7f2f3be1b53e6551eafe0" integrity sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA== -"@esbuild/linux-ia32@0.27.7": - version "0.27.7" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz#3f80fb696aa96051a94047f35c85b08b21c36f9e" - integrity sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg== - "@esbuild/linux-ia32@0.28.1": version "0.28.1" resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz#a580f9c676797833891e519fc7a1337c8afd8db3" @@ -924,11 +838,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz#f9cfffa7fc8322571fbc4c8b3268caf15bd81ad0" integrity sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng== -"@esbuild/linux-loong64@0.27.7": - version "0.27.7" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz#9be1f2c28210b13ebb4156221bba356fe1675205" - integrity sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q== - "@esbuild/linux-loong64@0.28.1": version "0.28.1" resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz#46452cf321dc7f9e91c2fa780a56bb56e79cd68b" @@ -944,11 +853,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz#575a14bd74644ffab891adc7d7e60d275296f2cd" integrity sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw== -"@esbuild/linux-mips64el@0.27.7": - version "0.27.7" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz#4ab5ee67a3dfcbcb5e8fd7883dae6e735b1163b8" - integrity sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw== - "@esbuild/linux-mips64el@0.28.1": version "0.28.1" resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz#4211b3184dd6608f53dcb22e39f5d34ee08852c8" @@ -964,11 +868,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz#75b99c70a95fbd5f7739d7692befe60601591869" integrity sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA== -"@esbuild/linux-ppc64@0.27.7": - version "0.27.7" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz#dac78c689f6499459c4321e5c15032c12307e7ea" - integrity sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ== - "@esbuild/linux-ppc64@0.28.1": version "0.28.1" resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz#697857c2a61cb9b0b6bb6652e40c1dc5e1ca8e5d" @@ -984,11 +883,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz#2e3259440321a44e79ddf7535c325057da875cd6" integrity sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w== -"@esbuild/linux-riscv64@0.27.7": - version "0.27.7" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz#050f7d3b355c3a98308e935bc4d6325da91b0027" - integrity sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ== - "@esbuild/linux-riscv64@0.28.1": version "0.28.1" resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz#d192943eb146a40ac4c6497d0cf7be35b986bf08" @@ -1004,11 +898,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz#17676cabbfe5928da5b2a0d6df5d58cd08db2663" integrity sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg== -"@esbuild/linux-s390x@0.27.7": - version "0.27.7" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz#d61f715ce61d43fe5844ad0d8f463f88cbe4fef6" - integrity sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw== - "@esbuild/linux-s390x@0.28.1": version "0.28.1" resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz#acea0356da0e0ebc08f97cf7b9c2e401e1e648dc" @@ -1024,11 +913,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz#0583775685ca82066d04c3507f09524d3cd7a306" integrity sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw== -"@esbuild/linux-x64@0.27.7": - version "0.27.7" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz#ca8e1aa478fc8209257bf3ac8f79c4dc2982f32a" - integrity sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA== - "@esbuild/linux-x64@0.28.1": version "0.28.1" resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz#6f0c3ce0cb64c534b70c4c45ecb2c16d34e35dfd" @@ -1039,11 +923,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz#f04c4049cb2e252fe96b16fed90f70746b13f4a4" integrity sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg== -"@esbuild/netbsd-arm64@0.27.7": - version "0.27.7" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz#1650f2c1b948deeb3ef948f2fc30614723c09690" - integrity sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w== - "@esbuild/netbsd-arm64@0.28.1": version "0.28.1" resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz#8bcd77077a0dce3378b574fedb26d2a253b73d36" @@ -1059,11 +938,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz#77da0d0a0d826d7c921eea3d40292548b258a076" integrity sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ== -"@esbuild/netbsd-x64@0.27.7": - version "0.27.7" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz#65772ab342c4b3319bf0705a211050aac1b6e320" - integrity sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw== - "@esbuild/netbsd-x64@0.28.1": version "0.28.1" resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz#e7fb2a01e99c830c94e6623cd9fefb4c8fb58347" @@ -1074,11 +948,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz#6296f5867aedef28a81b22ab2009c786a952dccd" integrity sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A== -"@esbuild/openbsd-arm64@0.27.7": - version "0.27.7" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz#37ed7cfa66549d7955852fce37d0c3de4e715ea1" - integrity sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A== - "@esbuild/openbsd-arm64@0.28.1": version "0.28.1" resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz#c52909372db8b86e2c55e05a8940033b5660a3b2" @@ -1094,11 +963,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz#f8d23303360e27b16cf065b23bbff43c14142679" integrity sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw== -"@esbuild/openbsd-x64@0.27.7": - version "0.27.7" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz#01bf3d385855ef50cb33db7c4b52f957c34cd179" - integrity sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg== - "@esbuild/openbsd-x64@0.28.1": version "0.28.1" resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz#c427b9be5a64c262ff9a7eb70b5fbbaadf446c6c" @@ -1109,11 +973,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz#49e0b768744a3924be0d7fd97dd6ce9b2923d88d" integrity sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg== -"@esbuild/openharmony-arm64@0.27.7": - version "0.27.7" - resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz#6c1f94b34086599aabda4eac8f638294b9877410" - integrity sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw== - "@esbuild/openharmony-arm64@0.28.1": version "0.28.1" resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz#dc9b147baca2e6c4b3c85571741ef4860a489097" @@ -1129,11 +988,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz#a6ed7d6778d67e528c81fb165b23f4911b9b13d6" integrity sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w== -"@esbuild/sunos-x64@0.27.7": - version "0.27.7" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz#4b0dd17ae0a6941d2d0fd35a906392517071a90d" - integrity sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA== - "@esbuild/sunos-x64@0.28.1": version "0.28.1" resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz#ce866d12df13c15e4c99f073a3d466f6e0649b3a" @@ -1149,11 +1003,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz#9ac14c378e1b653af17d08e7d3ce34caef587323" integrity sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg== -"@esbuild/win32-arm64@0.27.7": - version "0.27.7" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz#34193ab5565d6ff68ca928ac04be75102ccb2e77" - integrity sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA== - "@esbuild/win32-arm64@0.28.1": version "0.28.1" resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz#7468e3692d01d629d5941e5d83817bb80f9e39b4" @@ -1169,11 +1018,6 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz#918942dcbbb35cc14fca39afb91b5e6a3d127267" integrity sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ== -"@esbuild/win32-ia32@0.27.7": - version "0.27.7" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz#eb67f0e4482515d8c1894ede631c327a4da9fc4d" - integrity sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw== - "@esbuild/win32-ia32@0.28.1": version "0.28.1" resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz#a5bc0063fb2bcab6d0ed63f2a1537958bc269ec6" @@ -1189,20 +1033,15 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz#9bdad8176be7811ad148d1f8772359041f46c6c5" integrity sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA== -"@esbuild/win32-x64@0.27.7": - version "0.27.7" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz#8fe30b3088b89b4873c3a6cc87597ae3920c0a8b" - integrity sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg== - "@esbuild/win32-x64@0.28.1": version "0.28.1" resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz#10064ee44f4347b90c9a02b446bbf80a91632b12" integrity sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A== "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": - version "4.9.1" - resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz#4e90af67bc51ddee6cdef5284edf572ec376b595" - integrity sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ== + version "4.10.1" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz#8911bd72b2c3640a543609e0400b8c4d2e7e7cb6" + integrity sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg== dependencies: eslint-visitor-keys "^3.4.3" @@ -1242,9 +1081,9 @@ integrity sha512-sSAYhQca3rDWtQUHSAPeO7axFIUJOI6hn1gjRC5APVE1a90tuyT8f5WIgRsFhhWA7htNkju2veB9eWL6YHi/Lw== "@hono/node-server@^1.19.9": - version "1.19.14" - resolved "https://registry.yarnpkg.com/@hono/node-server/-/node-server-1.19.14.tgz#e30f844bc77e3ce7be442aac3b1f73ad8b58d181" - integrity sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw== + version "1.19.17" + resolved "https://registry.yarnpkg.com/@hono/node-server/-/node-server-1.19.17.tgz#99bd8625cdbae82652a135c71363cd6322fae483" + integrity sha512-dSneS5qhiauZWGDCeK4o695Xd9nUNjviSZCMQrj10eetr8Uln1ucn6bbphOM6UynAMMtNIzZNSpL9vnASJwrPQ== "@humanwhocodes/config-array@^0.13.0": version "0.13.0" @@ -1436,13 +1275,6 @@ dependencies: minipass "^7.0.4" -"@jest/schemas@^29.6.3": - version "29.6.3" - resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" - integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== - dependencies: - "@sinclair/typebox" "^0.27.8" - "@jridgewell/gen-mapping@^0.3.12", "@jridgewell/gen-mapping@^0.3.5": version "0.3.13" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz#6342a19f44347518c93e43b1ac69deb3c4656a1f" @@ -1561,14 +1393,14 @@ "@microsoft/tsdoc-config" "~0.16.1" "@rushstack/node-core-library" "4.0.2" -"@microsoft/api-extractor-model@7.33.8": - version "7.33.8" - resolved "https://registry.yarnpkg.com/@microsoft/api-extractor-model/-/api-extractor-model-7.33.8.tgz#d715b0090610cce62c0b248a3eb07466cb10e9f1" - integrity sha512-aIcoQggPyer3B6Ze3usz0YWC/oBwUHfRH5ETUsr+oT2BRA6SfTJl7IKPcPZkX4UR+PohowzW4uMxsvjrn8vm+w== +"@microsoft/api-extractor-model@7.33.10": + version "7.33.10" + resolved "https://registry.yarnpkg.com/@microsoft/api-extractor-model/-/api-extractor-model-7.33.10.tgz#5ccd00c18877b315322b80dabc42fb66bc9c896c" + integrity sha512-uPUK17xGxeQ3av6TN7awp+dTTSTvx8fZC0XFL1gyt7hFapYuxND3XLXH8vkmI7UjfW92oogzFAFqHSifmJROaw== dependencies: "@microsoft/tsdoc" "~0.16.0" "@microsoft/tsdoc-config" "~0.18.1" - "@rushstack/node-core-library" "5.23.1" + "@rushstack/node-core-library" "5.23.3" "@microsoft/api-extractor@7.43.0": version "7.43.0" @@ -1590,17 +1422,17 @@ typescript "5.4.2" "@microsoft/api-extractor@^7.50.1": - version "7.58.9" - resolved "https://registry.yarnpkg.com/@microsoft/api-extractor/-/api-extractor-7.58.9.tgz#d6c26dfda95fbe716b183b5f3bc5744aac487796" - integrity sha512-S2UF4yza5GoxCmf7hJQNxJNZN9ltOVuOQv8Dy+Z21aol5ERoBNMdWcQHm4MJMPPItW4H/4rZD906iaf4mUojJA== + version "7.58.12" + resolved "https://registry.yarnpkg.com/@microsoft/api-extractor/-/api-extractor-7.58.12.tgz#37c24cd672f25f7b77f6ff389c1d402b6fc7a222" + integrity sha512-VNpgC/1LaroLbn+UKmwDYspq+9r3EHyj4vJ3qUy/g8vB0rKt+1Wgs7WFj/JGpgxhG8SNyXs1XwYwe7nqkk8IDg== dependencies: - "@microsoft/api-extractor-model" "7.33.8" + "@microsoft/api-extractor-model" "7.33.10" "@microsoft/tsdoc" "~0.16.0" "@microsoft/tsdoc-config" "~0.18.1" - "@rushstack/node-core-library" "5.23.1" + "@rushstack/node-core-library" "5.23.3" "@rushstack/rig-package" "0.7.3" - "@rushstack/terminal" "0.24.0" - "@rushstack/ts-command-line" "5.3.10" + "@rushstack/terminal" "0.24.2" + "@rushstack/ts-command-line" "5.3.12" diff "~8.0.2" minimatch "10.2.3" resolve "~1.22.1" @@ -1799,12 +1631,12 @@ "@napi-rs/nice-win32-ia32-msvc" "1.1.1" "@napi-rs/nice-win32-x64-msvc" "1.1.1" -"@napi-rs/wasm-runtime@^1.1.4", "@napi-rs/wasm-runtime@^1.1.5": - version "1.1.5" - resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.5.tgz#cccd6ebc40b991dea6936f9126b1b8155b6c4c95" - integrity sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q== +"@napi-rs/wasm-runtime@^1.1.6": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.0.tgz#d7aa398845e3ab1c9c8f81ea50f527ed37d16715" + integrity sha512-kDoONqMa+VnZ4vvvu/ZUurpJ4gkZU57e7g69qpNgWhYcZFPUHZM2CEMKm+cG6ufDVALbjMvfmMjFVqaK7uEMnA== dependencies: - "@tybys/wasm-util" "^0.10.2" + "@tybys/wasm-util" "^0.10.3" "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -1908,36 +1740,36 @@ node-gyp "^12.1.0" proc-log "^6.0.0" -"@nuxt/cli@^3.35.2": - version "3.36.0" - resolved "https://registry.yarnpkg.com/@nuxt/cli/-/cli-3.36.0.tgz#ff774c501d32e41dccd006974d9949fe3bb94111" - integrity sha512-qkrADSow9WLG/26bhqkVljKd6lMO0z7FXqLINNwnehBOBclra3xz8jVK1kTDPegZehwNdc7QUSsj2Bgv9/Fw/A== +"@nuxt/cli@^3.37.0": + version "3.37.0" + resolved "https://registry.yarnpkg.com/@nuxt/cli/-/cli-3.37.0.tgz#03078372574de0deb4e9df8d2ab009603fcf77ca" + integrity sha512-Zj9NwHjEBzVrgezsgMFjpMhNqwNgROk9DzNi/dyfk1mCbXIRigV11br2xOl0Satek30bmv7oZAfMtCnDe6Ip0Q== dependencies: - "@bomb.sh/tab" "^0.0.16" - "@clack/prompts" "^1.5.1" + "@bomb.sh/tab" "^0.0.19" + "@clack/prompts" "^1.7.0" c12 "^3.3.4" citty "^0.2.2" confbox "^0.2.4" consola "^3.4.2" debug "^4.4.3" defu "^6.1.7" - exsolve "^1.0.8" + exsolve "^1.1.0" fuse.js "^7.4.2" fzf "^0.5.2" giget "^3.3.0" jiti "^2.7.0" listhen "^1.10.0" - nypm "^0.6.7" + nypm "^0.6.8" ofetch "^1.5.1" ohash "^2.0.11" pathe "^2.0.3" perfect-debounce "^2.1.0" pkg-types "^2.3.1" scule "^1.3.0" - semver "^7.8.4" - srvx "^0.11.16" - std-env "^4.1.0" - tinyclip "^0.1.14" + semver "^7.8.5" + srvx "^0.11.22" + std-env "^4.2.0" + tinyclip "^0.1.15" tinyexec "^1.2.4" ufo "^1.6.4" youch "^4.1.1" @@ -1947,78 +1779,79 @@ resolved "https://registry.yarnpkg.com/@nuxt/devalue/-/devalue-2.0.2.tgz#5749f04df13bda4c863338d8dabaf370f45ef7c7" integrity sha512-GBzP8zOc7CGWyFQS6dv1lQz8VVpz5C2yRszbXufwG/9zhStTIH50EtD87NmWbTMwXDvZLNg8GIpb1UFdH93JCA== -"@nuxt/devtools-kit@3.2.4": - version "3.2.4" - resolved "https://registry.yarnpkg.com/@nuxt/devtools-kit/-/devtools-kit-3.2.4.tgz#496004ea0f4c1647c633ffa9ece874b8ff146a4c" - integrity sha512-Yxy2Xgmq5hf3dQy983V0xh0OJV2mYwRZz9eVIGc3EaribdFGPDNGMMbYqX9qCty3Pbxn/bCF3J0UyPaNlHVayQ== +"@nuxt/devtools-kit@3.3.1": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@nuxt/devtools-kit/-/devtools-kit-3.3.1.tgz#ad2851551fd42060d1244a1aecfe8db196b70505" + integrity sha512-abn6A4UY6c4q9p7tKALEvrBeU+NXEpY/TtrTEC4PYtOUGDODxQdVTud6nIn1aqCnAF1DTY1dZXg+APXt54D4xA== dependencies: - "@nuxt/kit" "^4.4.2" + "@nuxt/kit" "^4.4.4" execa "^8.0.1" -"@nuxt/devtools-wizard@3.2.4": - version "3.2.4" - resolved "https://registry.yarnpkg.com/@nuxt/devtools-wizard/-/devtools-wizard-3.2.4.tgz#e227f6ad52319a4e50a1859ceb30d22de976336b" - integrity sha512-5tu2+Quu9XTxwtpzM8CUN0UKn/bzZIfJcoGd+at5Yy1RiUQJ4E52tRK0idW1rMSUDkbkvX3dSnu8Tpj7SAtWdQ== +"@nuxt/devtools-wizard@3.3.1": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@nuxt/devtools-wizard/-/devtools-wizard-3.3.1.tgz#aeaddd47a46a8bd77900ca0e9cdf4531b63ad152" + integrity sha512-pWT/Cm1/ktgSWYwRl1yYASwTIWNK1VfT7TU8vZOAOFha9Kj5znr9xuGQIFqJ0IDW1PNGuR/EUQO4BAPUIPguWg== dependencies: - "@clack/prompts" "^1.1.0" + "@clack/prompts" "^1.3.0" consola "^3.4.2" - diff "^8.0.3" + diff "^8.0.4" execa "^8.0.1" magicast "^0.5.2" pathe "^2.0.3" - pkg-types "^2.3.0" + pkg-types "^2.3.1" semver "^7.7.4" -"@nuxt/devtools@^3.2.4": - version "3.2.4" - resolved "https://registry.yarnpkg.com/@nuxt/devtools/-/devtools-3.2.4.tgz#42b3493b7b2cc9abaf4f2cb0f2facf9c8c173ea0" - integrity sha512-VPbFy7hlPzWpEZk4BsuVpNuHq1ZYGV9xezjb7/NGuePuNLqeNn74YZugU+PCtva7OwKhEeTXmMK0Mqo/6+nwNA== - dependencies: - "@nuxt/devtools-kit" "3.2.4" - "@nuxt/devtools-wizard" "3.2.4" - "@nuxt/kit" "^4.4.2" - "@vue/devtools-core" "^8.1.0" - "@vue/devtools-kit" "^8.1.0" +"@nuxt/devtools@^3.3.1": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@nuxt/devtools/-/devtools-3.3.1.tgz#103d09fa469feee68156abbffe02c208ebb27243" + integrity sha512-JQXSZxHeUgJ7Vh8PyK0YhO6w+iT47fJtw+Fsg8DHuL1nWd2FKlx9vUJCu52wkm9uS9PPrAd6IU8dS8sUHKJQRA== + dependencies: + "@nuxt/devtools-kit" "3.3.1" + "@nuxt/devtools-wizard" "3.3.1" + "@nuxt/kit" "^4.4.4" + "@vue/devtools-core" "^8.1.1" + "@vue/devtools-kit" "^8.1.1" birpc "^4.0.0" consola "^3.4.2" destr "^2.0.5" error-stack-parser-es "^1.0.5" execa "^8.0.1" - fast-npm-meta "^1.4.2" + fast-npm-meta "^1.5.0" get-port-please "^3.2.0" - hookable "^6.1.0" + hookable "^6.1.1" image-meta "^0.2.2" is-installed-globally "^1.0.0" - launch-editor "^2.13.1" + launch-editor "^2.13.2" local-pkg "^1.1.2" magicast "^0.5.2" - nypm "^0.6.5" + nypm "^0.6.6" ohash "^2.0.11" pathe "^2.0.3" perfect-debounce "^2.1.0" - pkg-types "^2.3.0" + pkg-types "^2.3.1" semver "^7.7.4" - simple-git "^3.33.0" + simple-git "^3.36.0" sirv "^3.0.2" structured-clone-es "^2.0.0" - tinyglobby "^0.2.15" + tinyglobby "^0.2.16" + unstorage "^1.17.5" vite-plugin-inspect "^11.3.3" vite-plugin-vue-tracer "^1.3.0" which "^6.0.1" - ws "^8.19.0" + ws "^8.20.0" -"@nuxt/kit@3.21.8": - version "3.21.8" - resolved "https://registry.yarnpkg.com/@nuxt/kit/-/kit-3.21.8.tgz#c0377a837e4c8701c5096cb4ff025a72de3bd1e7" - integrity sha512-kg63DUPY5AHPn+9XM7u8rYcdWHXjzwfUscgRDuiC5YUciQ+xdLRhdwXelYFxEAx2nxJHossliiQXbMm/Fleivw== +"@nuxt/kit@3.21.10": + version "3.21.10" + resolved "https://registry.yarnpkg.com/@nuxt/kit/-/kit-3.21.10.tgz#8d60702bb7dc3fb394e73fbbd3298898fa06c6b6" + integrity sha512-zs1+BZlRK1VlHo37TTzaMXQ+SemS1WeGRtcjWbW1ZoXpL3/ctn2VQu6nFpu6JqsJRd0QAPNS4GYmxGwLK8EHNw== dependencies: c12 "^3.3.4" consola "^3.4.2" defu "^6.1.7" destr "^2.0.5" errx "^0.1.0" - exsolve "^1.0.8" - ignore "^7.0.5" + exsolve "^1.1.0" + ignore "^7.0.6" jiti "^2.7.0" klona "^2.0.6" knitwork "^1.3.0" @@ -2028,81 +1861,82 @@ pkg-types "^2.3.1" rc9 "^3.0.1" scule "^1.3.0" - semver "^7.8.0" - tinyglobby "^0.2.16" + semver "^7.8.5" + tinyglobby "^0.2.17" ufo "^1.6.4" unctx "^2.5.0" untyped "^2.0.0" -"@nuxt/kit@^4.4.2": - version "4.4.8" - resolved "https://registry.yarnpkg.com/@nuxt/kit/-/kit-4.4.8.tgz#19e583f8e29c5363fd41f6f25995d2ae00611096" - integrity sha512-ZUlZ5iYfyfJFDPluhn6ZxFWcsuxWbLnZBc8w3MAROcQ4lYfZ+qFpALBLSNlpc0zhOa++33EE+5PEbOAdVIY+dw== +"@nuxt/kit@^4.4.4", "@nuxt/kit@^4.5.0": + version "4.5.1" + resolved "https://registry.yarnpkg.com/@nuxt/kit/-/kit-4.5.1.tgz#68f218c3ea5318ccb7e9914aa293cf3eb0d60a7d" + integrity sha512-xDXQspE2blxaZwxwGknL/BqaIbkLizl85Ov+pbSlPPd/rw2KjJGx88RHU5SwoQNwCiSC5hWZBnVAznIsq1xNHQ== dependencies: c12 "^3.3.4" consola "^3.4.2" defu "^6.1.7" destr "^2.0.5" errx "^0.1.0" - exsolve "^1.0.8" - ignore "^7.0.5" + exsolve "^1.1.0" + ignore "^7.0.6" jiti "^2.7.0" klona "^2.0.6" mlly "^1.8.2" + nostics "^1.2.0" ohash "^2.0.11" pathe "^2.0.3" pkg-types "^2.3.1" rc9 "^3.0.1" scule "^1.3.0" - semver "^7.8.1" tinyglobby "^0.2.17" ufo "^1.6.4" - unctx "^2.5.0" + unctx "^3.0.0" untyped "^2.0.0" + verkit "^0.2.0" -"@nuxt/nitro-server@3.21.8": - version "3.21.8" - resolved "https://registry.yarnpkg.com/@nuxt/nitro-server/-/nitro-server-3.21.8.tgz#df1a3a94cd97627e1ac353c9de0f59068bf03ced" - integrity sha512-GWYO2vdZhWekQHFEP7SLNzqHkQ1bVdjFtfJF4SXpl4v3w0jMa2JGIQkuQ0x/YpY1Yt0jAgqJREX8lFud8Cy2gQ== +"@nuxt/nitro-server@3.21.10": + version "3.21.10" + resolved "https://registry.yarnpkg.com/@nuxt/nitro-server/-/nitro-server-3.21.10.tgz#ba7dccf2c405774eb017a2df7223c3f3a1f662cb" + integrity sha512-24hq6O1zv+ysuK2rufqib60tHUXM7zDn99bFM5o9FfWlQi+0NaT16YKd3mImhL9cvHBgAj2wvxMPz9+TJ+kxhA== dependencies: "@nuxt/devalue" "^2.0.2" - "@nuxt/kit" "3.21.8" - "@unhead/vue" "^2.1.15" - "@vue/shared" "^3.5.34" + "@nuxt/kit" "3.21.10" + "@unhead/vue" "^2.1.16" + "@vue/shared" "^3.5.40" consola "^3.4.2" defu "^6.1.7" destr "^2.0.5" - devalue "^5.8.1" + devalue "^5.8.2" errx "^0.1.0" escape-string-regexp "^5.0.0" - exsolve "^1.0.8" + exsolve "^1.1.0" h3 "^1.15.11" - impound "^1.1.5" + impound "^1.1.6" klona "^2.0.6" mocked-exports "^0.1.1" nitropack "^2.13.4" ohash "^2.0.11" pathe "^2.0.3" pkg-types "^2.3.1" - rou3 "^0.8.1" - std-env "^4.1.0" + rou3 "^0.9.1" + std-env "^4.2.0" ufo "^1.6.4" unctx "^2.5.0" unstorage "^1.17.5" - vue "^3.5.34" - vue-bundle-renderer "^2.2.0" + vue "^3.5.40" + vue-bundle-renderer "^2.3.1" vue-devtools-stub "^0.1.0" -"@nuxt/schema@3.21.8": - version "3.21.8" - resolved "https://registry.yarnpkg.com/@nuxt/schema/-/schema-3.21.8.tgz#da1157c57b6aa6e00bde689abdaaaf9e6ec12294" - integrity sha512-BMxtf2x0E9sFji4Txz1boeMiwkhjQQFixdB6+lZXvCGpExZou4TLz82LDcIAZkpJVL0IEcfs96hTLVVBkjGulQ== +"@nuxt/schema@3.21.10": + version "3.21.10" + resolved "https://registry.yarnpkg.com/@nuxt/schema/-/schema-3.21.10.tgz#116d7fddf7d7a1a581dab48cce12ddfd8b9c4667" + integrity sha512-i356YiRQ+xmGz1K1GS8IKQsFE/mRE6vuNoHvhdkk3jSXW+ncV9jp5ap/GX7t3xOr3XqxPUiNpMV9PpzoMMbJBA== dependencies: - "@vue/shared" "^3.5.34" + "@vue/shared" "^3.5.40" defu "^6.1.7" pathe "^2.0.3" pkg-types "^2.3.1" - std-env "^4.1.0" + std-env "^4.2.0" "@nuxt/telemetry@^2.8.0": version "2.8.0" @@ -2115,467 +1949,462 @@ rc9 "^3.0.0" std-env "^4.0.0" -"@nuxt/vite-builder@3.21.8": - version "3.21.8" - resolved "https://registry.yarnpkg.com/@nuxt/vite-builder/-/vite-builder-3.21.8.tgz#aad33e01033d9508bafda9e5a1ce06f1578ad1f9" - integrity sha512-aapUWCQGuLEzUj5hx+J/lfpzqt/fBYV8hmCQ930R4SM4BvEzqMR0wVkbU0ry0CDK+uQzb/2n50qIHcEp0ywc0Q== +"@nuxt/vite-builder@3.21.10": + version "3.21.10" + resolved "https://registry.yarnpkg.com/@nuxt/vite-builder/-/vite-builder-3.21.10.tgz#f6b14d2859ae4422d006e3016419040316c977d0" + integrity sha512-360y1an7pFM4QgfspCXpJCmVrZXdxru6cUSyBKOI3B82xG6zfHMNf2eKu8NtZbVQ2c9LK144aCj5dOO19yNpcQ== dependencies: - "@nuxt/kit" "3.21.8" + "@nuxt/kit" "3.21.10" "@rollup/plugin-replace" "^6.0.3" - "@vitejs/plugin-vue" "^6.0.7" - "@vitejs/plugin-vue-jsx" "^5.1.5" - autoprefixer "^10.5.0" + "@vitejs/plugin-vue" "^6.0.8" + "@vitejs/plugin-vue-jsx" "^5.1.6" + autoprefixer "^10.5.4" consola "^3.4.2" cssnano "^7.1.9" defu "^6.1.7" escape-string-regexp "^5.0.0" - exsolve "^1.0.8" + exsolve "^1.1.0" externality "^1.0.2" + generic-names "^4.0.0" get-port-please "^3.2.0" jiti "^2.7.0" knitwork "^1.3.0" magic-string "^0.30.21" mlly "^1.8.2" mocked-exports "^0.1.1" - nypm "^0.6.6" + nypm "^0.6.8" ohash "^2.0.11" pathe "^2.0.3" perfect-debounce "^2.1.0" pkg-types "^2.3.1" - postcss "^8.5.14" - seroval "^1.5.4" - std-env "^4.1.0" + postcss "^8.5.22" + seroval "^1.5.6" + std-env "^4.2.0" ufo "^1.6.4" unenv "^2.0.0-rc.24" - vite "^7.3.3" + vite "^7.3.6" vite-node "^5.3.0" - vite-plugin-checker "^0.13.0" - vue-bundle-renderer "^2.2.0" + vite-plugin-checker "^0.14.5" + vue-bundle-renderer "^2.3.1" "@one-ini/wasm@0.1.1": version "0.1.1" resolved "https://registry.yarnpkg.com/@one-ini/wasm/-/wasm-0.1.1.tgz#6013659736c9dbfccc96e8a9c2b3de317df39323" integrity sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw== -"@oxc-minify/binding-android-arm-eabi@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-minify/binding-android-arm-eabi/-/binding-android-arm-eabi-0.132.0.tgz#e5adc38e353ab46732a8a2634793916f5e3f3396" - integrity sha512-NXxgL3FNGEBz8r+8iSl8wSdyCEMGisVmn2GVuJc5GycWgGzxiP9V9/svgD039JnO9nRAi0j+hP3FNAuDCP4aQg== - -"@oxc-minify/binding-android-arm64@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-minify/binding-android-arm64/-/binding-android-arm64-0.132.0.tgz#35ff4549b03328f313b088b5054bd4bcf9932e01" - integrity sha512-XYogHG1aSjNEMKWUfWmBWtN9rnpQ2nA4MiecdiAOfofDHTQiU5ybrPH6VvDAtRXf2kr8WtPNX7eenhC3uWFWoA== - -"@oxc-minify/binding-darwin-arm64@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-minify/binding-darwin-arm64/-/binding-darwin-arm64-0.132.0.tgz#20634dc825dcf7edb95d2e25e62ab5f44c138d48" - integrity sha512-gm/M5dgm7IvA/g9tweMqiFyD15yKrxGUX3myjFP+EYIYVW+RYuvwU5MAIZUOxXY0GnjU1/iRN/JkLhwvhZVsDQ== - -"@oxc-minify/binding-darwin-x64@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-minify/binding-darwin-x64/-/binding-darwin-x64-0.132.0.tgz#4f730b09f1613f90887facf8732cb6eedc531f89" - integrity sha512-s7ecbOJeLccy3nqQlkiq9cV0D0q8j1OyHmxRz22m8qZlcKrc3s4gmhwj5ertipA8ePn3FOXv4azf8b5gatDDug== - -"@oxc-minify/binding-freebsd-x64@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-minify/binding-freebsd-x64/-/binding-freebsd-x64-0.132.0.tgz#bd93dcaaa55bcdc93be5f2afec2b6995a8c8e749" - integrity sha512-pdYVNmY9NgKetEWzXlVIUlPm4Z3Gz979nTbZUpHlqpjU/rtulpm0fgROo6rlTk+W0HhZCCZ0Jzy1LBKgn5g3mg== - -"@oxc-minify/binding-linux-arm-gnueabihf@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-minify/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.132.0.tgz#d64aedc5d891a17185a3147c318353cad802c42e" - integrity sha512-QdV2II2mrbygZO/D+umhb+jMs+kmNO2pvQ+kahY8DN7qZVvaR2CiWBQaAxi3yuI0JvmymcUBEFhRrXsaL/lUqg== - -"@oxc-minify/binding-linux-arm-musleabihf@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-minify/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.132.0.tgz#bd158b0043e8233107fe42bbc1aad31e6eded51a" - integrity sha512-6OJMBb53luST+xxNSzzg/rRkxMnR4NFQegdu3PCuDEUtP2OEgjmpvvBrHghITpzRsUqnQ/YTl/ItDiLVeoslUA== - -"@oxc-minify/binding-linux-arm64-gnu@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-minify/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.132.0.tgz#73a794cf929a7fda58a025301206f33e4b0e94a9" - integrity sha512-ND2GZp6StGQWhSBwOfX13kCCG7O/Z6sEL/dBsWSIgZaetEDUPLOWtKIm2f+TuYUSSmU5nJTSSE5psh9kGcCweQ== - -"@oxc-minify/binding-linux-arm64-musl@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-minify/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.132.0.tgz#9c4879f69ef5f26f8badc08dfbabc1ec8c12ed09" - integrity sha512-3k8ezEKmxs9Wel4N4vfF/8u764mA57j065P8nB4cU2PO/lLKloN0OA41ynfDUrSM1f5jBuF8+mLOj++aNnu4OA== - -"@oxc-minify/binding-linux-ppc64-gnu@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-minify/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.132.0.tgz#b7d743c575c69faa8e3e4c6a0b72c9e510540cbc" - integrity sha512-vM6jZIxoHoIS5rPb3K3Di0IureL4oU+wOWBy6tLSrjwW2IHqy0442CzO/Ks2U9VCuHV1q0bUGCF0H6AxCEjJHQ== - -"@oxc-minify/binding-linux-riscv64-gnu@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-minify/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.132.0.tgz#40775fe8b681f252665ff8e07b0ae6d69f90720e" - integrity sha512-KburrmtWpeZg58uo275QRwy5bbNOXQd1WDI2tGxkY2dJBlO7N5V9+Uthvqn6KI/6RBtjd2T5NO4dCC0fgUxGvw== - -"@oxc-minify/binding-linux-riscv64-musl@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-minify/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.132.0.tgz#3d1aab92cf2de1e14be7b3cf403a1dc2da2f3c9d" - integrity sha512-MnahA2MNEtEdxWdUy24JXkMUNgGPqH285GL2L22Zz7k9ixsguFD+bTbbcR88pNqdb075nazozzv3edF83+azCA== - -"@oxc-minify/binding-linux-s390x-gnu@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-minify/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.132.0.tgz#2b06307f270f49d56ecedd096382f1680dda22cf" - integrity sha512-VE99UPZyQO2MAG4gLGXzrBumD5PGNaiWe+EakaROGCVbT0YH/d9z2ByYqbdWAMEBiTHjthyZp6UUEFVda+LnpQ== - -"@oxc-minify/binding-linux-x64-gnu@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-minify/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.132.0.tgz#c58d31143b74c1b75b75d3847b7e00196c8d99f6" - integrity sha512-FKxBkYrSAWNF4V6MacAJ/1E2SJobKKQ2CtW6Aq+pLzzEOjgk2SmxnK7I0bATlFH/O70tbTKDzWb17bySGYRcog== - -"@oxc-minify/binding-linux-x64-musl@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-minify/binding-linux-x64-musl/-/binding-linux-x64-musl-0.132.0.tgz#dcf8f0854c31f0532e77ce405a65d1064824cf5c" - integrity sha512-W8IqA2XRvg/b6l/f+2SdV45/KKmpmwTabrjiMtpg/wzJU5cmKUoHihtJXPc9NA0Ls9S/oP0wB3PMCRQoNr5J1A== - -"@oxc-minify/binding-openharmony-arm64@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-minify/binding-openharmony-arm64/-/binding-openharmony-arm64-0.132.0.tgz#37953c0bb2e7dba82f95b8d1c238f105fc4606a4" - integrity sha512-X1BL65pI9bfOesLdVUcErjbEAUA3qmzjXCwXPCYsFZT7ela7SsK85+sN3m2TJNxmX1mrFKNg5g8bH+d2zHresw== - -"@oxc-minify/binding-wasm32-wasi@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-minify/binding-wasm32-wasi/-/binding-wasm32-wasi-0.132.0.tgz#c03401cf7f180eb8484d8cc7ca892574aadf6876" - integrity sha512-QcIiwBOj+bV5ub5x39Xb+v0boviykxUtVvVJaIEbG/IH97avFzZcBXec8awYlemLDvgG4WKQwr17x7COR5zwFg== - dependencies: - "@emnapi/core" "1.10.0" - "@emnapi/runtime" "1.10.0" - "@napi-rs/wasm-runtime" "^1.1.4" - -"@oxc-minify/binding-win32-arm64-msvc@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-minify/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.132.0.tgz#4a3b57d10dd14b0ae09c84f1592429f5f20d1b9f" - integrity sha512-ahFMaa84QVTIROWpLhZcS9jKIv+CXzsJaMmgje7JtlVp1Kaar6tzVCt3EH2aPhSc8RvbGqfmnGdQu/kGwPAZVA== - -"@oxc-minify/binding-win32-ia32-msvc@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-minify/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.132.0.tgz#6b36706fb7b454415c40428b286128cffec2af0f" - integrity sha512-tpBkLklqOnaYtlIh6gjmL60pP0Kn2hwaw1Fw3sJyIKwdkCPHsOPy/MRgBUpM0a/SeGFbsZRQkHnWfZXS1GTbbQ== - -"@oxc-minify/binding-win32-x64-msvc@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-minify/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.132.0.tgz#54eaa2cdd8a49b97ef9cfeb8b40f1b4781f8f3d9" - integrity sha512-a69yKrBl2p9O8cdAHbHih56eKhcpKJRVkRu/S+CwCdR2Zsh4nnqYIllF96Lxg3jDjRQNL3t0xZNdYBDG5Vgq+w== - -"@oxc-parser/binding-android-arm-eabi@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-parser/binding-android-arm-eabi/-/binding-android-arm-eabi-0.132.0.tgz#f88d600252349b5e380e695cadf889cea896f676" - integrity sha512-KrLaPWa5c9Y7LkW+rKkaUE3y7DBDrQtaf7rlsSDfv6KAHUjgzAIRA761Lrrp6//Yd/Rlie/yEOt9YENCoJnOcw== - -"@oxc-parser/binding-android-arm64@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-parser/binding-android-arm64/-/binding-android-arm64-0.132.0.tgz#ef91deec0305c54fa6c7b519f82da63d36b49788" - integrity sha512-SThDrSeamB/kG2+NxcJ5/wSLcV6dUqDknrPLqFYQ0ST/55mtBP4M7Q/f3QbubH6aAd11wpzZn/nwbVRSdobOpg== - -"@oxc-parser/binding-darwin-arm64@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.132.0.tgz#033a8f2789c3d09509ddd1a219dcbf2fd516125f" - integrity sha512-Lc0f/TYoKBghE5/2Gsv7bLXk+TJZunx2Tf61X8hG4ARXdc8UYI26dCGccFSd1AyFbK3jfaNXtMnupggDbjPXdQ== - -"@oxc-parser/binding-darwin-x64@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-parser/binding-darwin-x64/-/binding-darwin-x64-0.132.0.tgz#56601549bad307fcee2b3e0756769e36598841f4" - integrity sha512-RG2eJIpf7C21z9HSSXFw1bTArdpKe7Y4fwcJTwRq1yCSe1vSavaN9GA1sm9KqzemTLAGVktQ+7qBTGp0vQeUZg== - -"@oxc-parser/binding-freebsd-x64@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.132.0.tgz#68140dd5670556fca3aa094f0cb7e706854b5967" - integrity sha512-wQIPntPLtJ8NcBpvKPbEv3NqzV6k8eP8tP/jE9Rg8HTg/j7urZGFSsTCPCW5k77Qfw2DM4vRvc9p3I4yq/Shvw== - -"@oxc-parser/binding-linux-arm-gnueabihf@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.132.0.tgz#84ef8af25ffb6172b02b1747bbbef668e09235c1" - integrity sha512-PixKEpeSe3yxQWqNyOCBALRYc72+Tj7ILDofUl3iXo25cVOzLA6jHUhmOINRtWIPh7dbUie3QNeabwaQpZTw6w== - -"@oxc-parser/binding-linux-arm-musleabihf@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.132.0.tgz#ca6a2dffed23143c9bcbefd8250832c71fdfb4d7" - integrity sha512-sCR+DzGHlyHKnbA2z9zWjTUhIo8Sy0enJl4RDsBwPmkxYynPatpwOAWe8W5127SlW0boqUWHGtr1NWn5UwIhXQ== - -"@oxc-parser/binding-linux-arm64-gnu@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.132.0.tgz#ed1a4718c61d05836015c8eac7395ffe74c3f94a" - integrity sha512-sQBix5P2cW+IpzTcCwYxnh9yALrKSIkKJThspBvMGcygSMnbzkSvhN7SfuX1hvBk8y1XEChsdkU3ET0V5DmzUw== - -"@oxc-parser/binding-linux-arm64-musl@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.132.0.tgz#ae32a94bb666604728fa48c568ced5bb270d1819" - integrity sha512-WozHg3Kc//8Sk756HXXgMbEAvqtG+Lzb9JOojwQzIGDtN78Az2dLttkb71akWYUF/8IgYfDSlfKh4Uot8is5Vw== - -"@oxc-parser/binding-linux-ppc64-gnu@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.132.0.tgz#0de7511156b2b5d7d4fc3574ab3badd93a07c1ae" - integrity sha512-CmX/ulNBOEwWTyVRmcpYKAcAizW6+OjtLJgo7fXoL9OqQvjF4VER8tPomv44vwzfSCy1BHbsB0ZlZYzYJNj4cA== - -"@oxc-parser/binding-linux-riscv64-gnu@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.132.0.tgz#9a4a3b3261b6ada598b65adc4521581c45aa1003" - integrity sha512-j9oQS+hM90SdhviNGWbPgT4+Rlq+ac++q/zjgwPD1mVHgxHzATvoRGtDx0sXGmFOQ9J9YkwAhYGb5MAHL6TAsA== - -"@oxc-parser/binding-linux-riscv64-musl@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.132.0.tgz#e55c1d671e41617f27535216483ccc01f1ff4a5e" - integrity sha512-bLz+Xi+Agnfmd7kWPEsSVwCn2k4EyIalZkNBcQ0OGIv9rqn8VgCPLNd03tM9mKX/5TdlvDXalz0q71BIrOPNqg== - -"@oxc-parser/binding-linux-s390x-gnu@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.132.0.tgz#2e4b692103d8ee745990c7ed5fd023387e6c93d9" - integrity sha512-U6t2qbJU0ypTfyj9QV3W1Y6mITDTL8ai/OR6NUn85vyHthOvobKWgXzU4tu0EskSzlpuVFz1g0jFGulDIUKHxQ== - -"@oxc-parser/binding-linux-x64-gnu@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.132.0.tgz#2ba1d08aeaed17247dac4cb5b9a3bc83b7bd7501" - integrity sha512-WcEaSNHFk8yz5YFlQQAlhq6jOFmZBB/RKE7uzhyCIf+pF1Lmv9gUH4221mle2Gd9iHyWT3ySNph8yZgb1xYdWg== - -"@oxc-parser/binding-linux-x64-musl@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.132.0.tgz#677889452adb283e791798faf70af0627bd493ad" - integrity sha512-iQrV4iJzQgRwK3BWRmQl1C3C6g3wYpXN2WLdQdyR+efoUnncdShZAVp9OgcojtlD3MDRbuOMGG3SjxF4fL4nlQ== - -"@oxc-parser/binding-openharmony-arm64@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-parser/binding-openharmony-arm64/-/binding-openharmony-arm64-0.132.0.tgz#2928bbd0f815a7bf11a86b1bccfb0f352b92a7b3" - integrity sha512-FWzmUGrZ6GUby4U7WIwcCtab6tdmlTO3xTRRKyb5kjIJVEiaUAT8animUG/nK8ZCA8gkRkPOTId4rl6uTqUmJQ== - -"@oxc-parser/binding-wasm32-wasi@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-parser/binding-wasm32-wasi/-/binding-wasm32-wasi-0.132.0.tgz#37df389cce33c8664763a402853a73559b882ce2" - integrity sha512-TlbMppxJI5CjWDes0QaP6G3aneVg1yikBu5QYI+DUShF9WDL66ccgKFNNGmi/Wybtszw6hxwAvv76T4DaPKnHw== - dependencies: - "@emnapi/core" "1.10.0" - "@emnapi/runtime" "1.10.0" - "@napi-rs/wasm-runtime" "^1.1.4" - -"@oxc-parser/binding-win32-arm64-msvc@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-parser/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.132.0.tgz#b1a0913ad2545c30f498ba181c05de3898240976" - integrity sha512-RH/NbFjGKqdUAUi7Oh3LQPxUk2hsWFEEQ38HSnbRQT8QjBZFKqL1fMbmsB3N4jy/KPh9iX94+9dmkEMBBbambw== - -"@oxc-parser/binding-win32-ia32-msvc@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-parser/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.132.0.tgz#13964f4b59671f7235f4f85866ab3db6e4afd6c5" - integrity sha512-JUr4jQY9jxoIB/YTLXr6XofSi5xikj6p5/Ns1h0VOBDT0j1jKU+kMsv2xxv51RwnETcXpA1Yw/9oUAfcqfaqEA== - -"@oxc-parser/binding-win32-x64-msvc@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-parser/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.132.0.tgz#468339fb08809ddb856f3bc51db718790fb51f05" - integrity sha512-2dapgHpA5X8DSXF4AU36hJWYf6zP0tKjMXFRAZFBD62pkevW/uhFDXoFH9Y/3Fd2EtDrw5ByNnR1wVE9X9y0SQ== - -"@oxc-project/types@=0.137.0": - version "0.137.0" - resolved "https://registry.yarnpkg.com/@oxc-project/types/-/types-0.137.0.tgz#56e77f8bb221fa05f18b1cd34d73f94f0954a773" - integrity sha512-WT+Gb24i8hmvo85AIv2oEYouEXkRlKAlT9WaCa3TfLgNCN+GhrJOGZuIlMouAh38Qe4QOx26eUOVsq70qXrywA== - -"@oxc-project/types@^0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-project/types/-/types-0.132.0.tgz#d77243df4fe1a0a1e60e12ac6240fa898d2363ff" - integrity sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ== - -"@oxc-transform/binding-android-arm-eabi@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-transform/binding-android-arm-eabi/-/binding-android-arm-eabi-0.132.0.tgz#930e7b0dcf8285c1902816d9c00bc7c6cb5ebd5f" - integrity sha512-UEC6fwIer1e2H8+KYXfhfYMsDgqxrG93lCj3FkrKkJ2O05rikqiJLYGd9ZntmKne+9bOMMuznVKLGErub++mAg== - -"@oxc-transform/binding-android-arm64@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-transform/binding-android-arm64/-/binding-android-arm64-0.132.0.tgz#77204489bebffb61a2cbda2f7dca6369b320ecac" - integrity sha512-sr2BbEHtc5OkAN2nt5BpWGg/MnDkyQKf6tSjaZZ6k7Bb2FOa2CzZDy2pvH6tYdg+Ch/p/OGXXhENFVV9GU7ASw== - -"@oxc-transform/binding-darwin-arm64@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-transform/binding-darwin-arm64/-/binding-darwin-arm64-0.132.0.tgz#4d7c9c792e1e9506d1b19326ada93a525f755b71" - integrity sha512-yjL1GbN9Bb1HqjE8CS8NSwoZtDWgUGy43VbuFhmT4LEDx4Ph0guzVAyUKhc2CqqA4/x60qDvcH6QxwrguaqEVA== - -"@oxc-transform/binding-darwin-x64@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-transform/binding-darwin-x64/-/binding-darwin-x64-0.132.0.tgz#8b349d8989e6ac3c05261a0f28b13a2e60938b51" - integrity sha512-e3vVXEbNw93aHr3si8eVpUgl+jWF6Ry8RgUihgSxiI+2c/VMxiPsEDghkqPcjujqsMYDRdISWJi23xk+PP72ow== - -"@oxc-transform/binding-freebsd-x64@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-transform/binding-freebsd-x64/-/binding-freebsd-x64-0.132.0.tgz#5dd318e8cc15ec844ba40f3c3bf033a2f6816e68" - integrity sha512-dIhAhkX8/It4IaKI944fN3jmfzunqv2sEG2G4fQdP5/1psycdqUHoVaY23DbpuYRIu4sWAdn/e1zQFP0GMkQOQ== - -"@oxc-transform/binding-linux-arm-gnueabihf@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-transform/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.132.0.tgz#920fc1da5ed772cdc9a5ca13a09f37d5f8c275d6" - integrity sha512-eR0dfj1us7DNbGZ6eBdAqWnLZRkLqHFqewSHudX4gV7di3By8E05+M+qsGTB/zq/78Z0BYJeK1zGWu9un6jocw== - -"@oxc-transform/binding-linux-arm-musleabihf@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-transform/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.132.0.tgz#6a60453c0d044633b9682b0bcb1f98b4c8a92d92" - integrity sha512-naNx0WaV70hKtgQ5LUS/jzRTy6XEQZ1krK7KTFZQLI1mEz+GqLrwsLCqEmtrQ6HcqLhvGvA6GAWfFrc/0mWryA== - -"@oxc-transform/binding-linux-arm64-gnu@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-transform/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.132.0.tgz#a16521ac61aabe6be1f49ae5a435f57d33e5d90d" - integrity sha512-TWk1p0tbtE1tkMEABftfgXhMEfuoz3QieqBtMBXXyijizw/2YKNzbVSndG+vV73cSZgbyfoZ346pmuz0tQMzyw== - -"@oxc-transform/binding-linux-arm64-musl@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-transform/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.132.0.tgz#f3da9374d6f81a9fa46759b4d28da90ca4916965" - integrity sha512-LxURDI0Wm2KCQm/3ynNlI+nTgPdfmAfmrl54XPx+gaIqty8S/XWNCCTvLJWaCb0e5eKqnzrcTuhMDOdawqoYIA== - -"@oxc-transform/binding-linux-ppc64-gnu@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-transform/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.132.0.tgz#05cbe73a62a2e9524e2f9755ba9e399f7b65a2bd" - integrity sha512-eKEeG6SLtj01iDvi5QgMNzyEXt/K2BNWafZ0jGECmvqTWWaO2l4qBxUW+X+sAXp5vZBoT2WO3ZnshvIWXWjtKw== - -"@oxc-transform/binding-linux-riscv64-gnu@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-transform/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.132.0.tgz#3dadb185b6cfbe96daf40947484d58113628f00f" - integrity sha512-Kz6tg1Msra7+2iGV8K5xANLO2SmpP6n+91/Yy+JJh9EagU4hvMm7loReszzz2bwhs6Xs4HPrglxIngMdqnHpXw== - -"@oxc-transform/binding-linux-riscv64-musl@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-transform/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.132.0.tgz#3862422b28e0c0b45686287bceb498d1c4ff505f" - integrity sha512-dtUSp80ElrxUhfBNmFWGkFQQ51j3tRoZkKBXxEWh+hb+S6bbEdZCW/VuCYo/gCTH3DywwyTeWiG+dtZfJiHKvg== - -"@oxc-transform/binding-linux-s390x-gnu@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-transform/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.132.0.tgz#ae0fde8122a80533927c7a1e7ce00cfd830a7a02" - integrity sha512-9qVyCbYSs8dwVPpqKKWxuUAnLJ1+LyC5A4oNMZTzymRhuQr3coqAP/XWfJ8LlhQqI9GvhK0SWCOK0iM3HFUAnA== - -"@oxc-transform/binding-linux-x64-gnu@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-transform/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.132.0.tgz#872025ca5f86135b69f60d5df4e544295601d162" - integrity sha512-dUtJkDCYndDaxcuiSMyRoSb7sXmTbcJ61rDsUjIakghP6BkKwH57lyHYvSUhT1ZswXWwCjf3ksxlT8nA0iU6ag== - -"@oxc-transform/binding-linux-x64-musl@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-transform/binding-linux-x64-musl/-/binding-linux-x64-musl-0.132.0.tgz#5ddd8f631c6f57c85918762f3f32102e311e9484" - integrity sha512-I7BkkktnrriiO7o1dF3RDgKZoSmFKX9IE0W2LE1WdfmpZcAa3fbv5BW6oVbzk40iD29hWSP69A65WT9l6dxuzg== - -"@oxc-transform/binding-openharmony-arm64@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-transform/binding-openharmony-arm64/-/binding-openharmony-arm64-0.132.0.tgz#264d58c13bdaf827643755a0fe33527b16b5a9c5" - integrity sha512-yiXaRYqgySJguURNZUFLDzSI1NTkP1jJKrowr8lQCKwY5N8DsESbQJ1RpSlEbeXGiy201puA+QC2fdr+ywQM/A== - -"@oxc-transform/binding-wasm32-wasi@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-transform/binding-wasm32-wasi/-/binding-wasm32-wasi-0.132.0.tgz#1e06a0310ffe082e4f19f850fe602944af1724ce" - integrity sha512-KNago0Mv+zl2yl5hK2G9V4Yb7Tgpn+z6lgzgaHXkGp7S+iuUtN3av+QqPCD/J+Odq6EjjyXJrFPfmyjbXXbf4Q== - dependencies: - "@emnapi/core" "1.10.0" - "@emnapi/runtime" "1.10.0" - "@napi-rs/wasm-runtime" "^1.1.4" - -"@oxc-transform/binding-win32-arm64-msvc@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-transform/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.132.0.tgz#392f0dc62312c742276d57693c8d2b2bedbcea95" - integrity sha512-3fprECrLHwPP809a1SRzszDxp8Fpp8IOg0V2EO49wS+3JmRFOo090h5c37faZvym5VnRZ12DH2tkT6ZVXwlOsA== - -"@oxc-transform/binding-win32-ia32-msvc@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-transform/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.132.0.tgz#e1a4f3128d4b07446541785ae4557e941898d98e" - integrity sha512-n616QqZ3hXasHytVoFjo6pLzIfo6hQwBEir0kOcaObKaAw0ZbncIe1h5a6IMnCOJGLP30WwnhwLW20tIV78MAA== - -"@oxc-transform/binding-win32-x64-msvc@0.132.0": - version "0.132.0" - resolved "https://registry.yarnpkg.com/@oxc-transform/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.132.0.tgz#e829a4a388c410013617804bb811d66b2bd8c6bf" - integrity sha512-P7A4Cz/0C0Oxa2zH/oCruzA/5EHr5RRz0x6KXYz3wwhS+dFqIBxP9yo8FKjXhKXHRKa+M+QHo+bqYiqqlVsEQg== - -"@parcel/watcher-android-arm64@2.5.6": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz#5f32e0dba356f4ac9a11068d2a5c134ca3ba6564" - integrity sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A== - -"@parcel/watcher-darwin-arm64@2.5.6": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz#88d3e720b59b1eceffce98dac46d7c40e8be5e8e" - integrity sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA== - -"@parcel/watcher-darwin-x64@2.5.6": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz#bf05d76a78bc15974f15ec3671848698b0838063" - integrity sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg== - -"@parcel/watcher-freebsd-x64@2.5.6": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz#8bc26e9848e7303ac82922a5ae1b1ef1bdb48a53" - integrity sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng== - -"@parcel/watcher-linux-arm-glibc@2.5.6": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz#1328fee1deb0c2d7865079ef53a2ba4cc2f8b40a" - integrity sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ== - -"@parcel/watcher-linux-arm-musl@2.5.6": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz#bad0f45cb3e2157746db8b9d22db6a125711f152" - integrity sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg== - -"@parcel/watcher-linux-arm64-glibc@2.5.6": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz#b75913fbd501d9523c5f35d420957bf7d0204809" - integrity sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA== - -"@parcel/watcher-linux-arm64-musl@2.5.6": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz#da5621a6a576070c8c0de60dea8b46dc9c3827d4" - integrity sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA== - -"@parcel/watcher-linux-x64-glibc@2.5.6": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz#ce437accdc4b30f93a090b4a221fd95cd9b89639" - integrity sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ== - -"@parcel/watcher-linux-x64-musl@2.5.6": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz#02400c54b4a67efcc7e2327b249711920ac969e2" - integrity sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg== +"@oxc-minify/binding-android-arm-eabi@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-minify/binding-android-arm-eabi/-/binding-android-arm-eabi-0.141.0.tgz#6532b7b4ff554da358a3b01c4074d115226e51f4" + integrity sha512-tt3ekadMhd/Q+9/mU1RaZWCUAJhOQgHsUD9tn0btFhEkZyeTg1rKt2+wzv+wjBE3QXlxVdV6sYMLKnbt8XdR+g== + +"@oxc-minify/binding-android-arm64@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-minify/binding-android-arm64/-/binding-android-arm64-0.141.0.tgz#670c637ee96df60b9375929a4f65adfdfbcfd728" + integrity sha512-i7OGI2bFipaSlgwap/qiXcCmPbZMhlYdKAQvUtNziX8CJamNzhlqMNw4jz7wYdVNfcKuQ1eoyi7XMYCbNnKRtg== + +"@oxc-minify/binding-darwin-arm64@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-minify/binding-darwin-arm64/-/binding-darwin-arm64-0.141.0.tgz#6990c11c06b6cb2f16ea4a8485fdce20075153f2" + integrity sha512-YOp5tcQRkLUbvII+EVwDss+Ww16b/V8XfrqNRDOTaLb/azGTb87iyS5drXfRosONv7Jp8/t8qRFC9K0aj1yYZA== + +"@oxc-minify/binding-darwin-x64@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-minify/binding-darwin-x64/-/binding-darwin-x64-0.141.0.tgz#a0af41e4fe4b1a74d6a2d688dac31d03c0d5500e" + integrity sha512-9Z25dRX02krxcFXTIoZ3ym0+CF3gZ6RiU+bbckFT4l+d5LcQePfM1tR12zEW+GDTl0atCNG2TuEu61tT4L2LIQ== + +"@oxc-minify/binding-freebsd-x64@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-minify/binding-freebsd-x64/-/binding-freebsd-x64-0.141.0.tgz#2bbd208ff8e5ec35136b8c11099f25edaca1b8d0" + integrity sha512-QtFX48viQb3Di8GkxhH9SPYZaafIwyEa51iFBALXz2x1WdYvZeAxgl33GjETq5/YXS7MiPYrZ7FNs3UHtPsTdg== + +"@oxc-minify/binding-linux-arm-gnueabihf@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-minify/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.141.0.tgz#408f32567a137b5107d79aa47a58c5dfcf9cb34c" + integrity sha512-HcgqdmJY+0qWnolOTxrvzilDTvs3q7RF2XcvO0q0iDld8SZBNARVqrWY9k5WwCMTZSJKCWfL/QqpUMBnyIHQAA== + +"@oxc-minify/binding-linux-arm-musleabihf@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-minify/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.141.0.tgz#8969a8d1120ece3510d8f89da085279b83d006b0" + integrity sha512-u8c4OPT8A6lx+mnFkMczIHCQQNqbqdEGwep2PlOoCgQhwsWR3auvs4cyD1JJW6huZQjeq0gJJ0dJtvJq3yLy+w== + +"@oxc-minify/binding-linux-arm64-gnu@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-minify/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.141.0.tgz#32793c322fd0699c64c6b691e0c762c5bd077de2" + integrity sha512-n+ljU1cOCpIqVDxYiYmNimXGKNYlPIkdWVrkC4hOQF3B7YqkSRtEWbHcvedinBqNCwUF+azynDWor5Bq3/BdDw== + +"@oxc-minify/binding-linux-arm64-musl@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-minify/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.141.0.tgz#076344251c41a2d1c51521263fac1bab5cc4eb8a" + integrity sha512-Xkb5QCOywz/YbL+8LVQSzOxuz2jhRweBjr4BnQO7CQXAtQLLCNoll7v2qLg9OCzdqdhFw9uNgZ6aTBVADBhiPg== + +"@oxc-minify/binding-linux-ppc64-gnu@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-minify/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.141.0.tgz#03f7b2b284abcb30607b6210ef8c1363fed8d6f9" + integrity sha512-IbVb+m0iL053WitFNnQbtmd8OjYGr4Xn5NTuAiYz8tJBtn82okEZFi0OgaeaHQE4aPZGOKPcSVlt1OMPtMoPCw== + +"@oxc-minify/binding-linux-riscv64-gnu@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-minify/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.141.0.tgz#6ff000e7bdf5d3c7d5428086f7f493911c828324" + integrity sha512-Sc/GAiyelxg8oXlBgmJI6OuKKHmg4rF0RvTLC8eL5V3qKDXrMdVWiJziwVBqN5oiFEog35ZM1/YNF63IZOdZjw== + +"@oxc-minify/binding-linux-riscv64-musl@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-minify/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.141.0.tgz#1a155693ed17c8c730b633fc3b8dfebce8c4c1e7" + integrity sha512-KHYS3oQJ5r1QBVAVubUy6UPRWYghqkjCOfNlGeH/sWlmfeM2OD74+Stc8eHmVm7QI2wDooOIlZfUso0Yz0jyRg== + +"@oxc-minify/binding-linux-s390x-gnu@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-minify/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.141.0.tgz#2cbbadf69d7a2adb409aa5982960146ac7ee2c60" + integrity sha512-WyacIrs13ewOnGngxNmPF00xn0+aOYHTMSSMljNN3VShSbqB0A7ZEikR7q9fmmnBTf/jloQUO6bjzK85BFfl0w== + +"@oxc-minify/binding-linux-x64-gnu@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-minify/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.141.0.tgz#6a6615407a88e444b9634568a22d33a745274f7c" + integrity sha512-mP69bh2L/VVq10UEQ3wb0EsO0472TzOIZUfS/ADmxnr4gSxAzhRbO8w5QryL3BNyyyjSaXIlrAnAKO6G3srGwg== + +"@oxc-minify/binding-linux-x64-musl@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-minify/binding-linux-x64-musl/-/binding-linux-x64-musl-0.141.0.tgz#9c8b4d3e4f0d6624b87ae834fa75f9761c37349f" + integrity sha512-B4w1uz+GPVD5iRNn9StLSG0ug5DNAy5YQVswjPy5fXNNO6JyADvmu4KZyE6tWCA6Kbz/84icD6RJ1TKVis2HSg== + +"@oxc-minify/binding-openharmony-arm64@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-minify/binding-openharmony-arm64/-/binding-openharmony-arm64-0.141.0.tgz#fe6726b3837307b0f5aed97c7c4bbc3d2bc791ed" + integrity sha512-p3nU1bo2t+QRvvqOPUqI8aEk8puhYdMq5cnjulovfKykWRi8cMcJJvuLp+RPkf45lUcTQdNG/YMFqR5eYGZfwA== + +"@oxc-minify/binding-wasm32-wasi@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-minify/binding-wasm32-wasi/-/binding-wasm32-wasi-0.141.0.tgz#32d4dbe465b4c7beed0493a7e5b4ed35468810cc" + integrity sha512-Qb72fqFRs2Xu+KvAwisc1Fxn/rd/KROnFIdkFv77dTVmrKsq2HOCjWvxlPzjHcxNIgGUUJtpmNolrs7GYcopKg== + dependencies: + "@emnapi/core" "1.11.2" + "@emnapi/runtime" "1.11.2" + "@napi-rs/wasm-runtime" "^1.1.6" + +"@oxc-minify/binding-win32-arm64-msvc@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-minify/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.141.0.tgz#cd149da38e71223cf86a84fc3701ac1b128a6a7c" + integrity sha512-C+lcoyJycCgq4MIgGe2K/xYZHKjaSfRMa+Bm88UoPK7U/mFHYoAnICbftkLh3IVnIuQAr9vGItp0w/m39VajgQ== + +"@oxc-minify/binding-win32-ia32-msvc@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-minify/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.141.0.tgz#7f14f77d8329b632d8406ab92630c5bd851e5c47" + integrity sha512-MAtLZpArekuD94sTmQYz7YAn3xDrq4wqT/71CUrv8ij2TSbYZGqDtA44ujP3977180ITcffPQYfHKXYX7arsgg== + +"@oxc-minify/binding-win32-x64-msvc@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-minify/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.141.0.tgz#f951ee5930b7ed856a65f27d8d66d50970082357" + integrity sha512-9B0SzKsstTUETz2SblLd2gZJ2H36GyBmZmwcZVwEaFOYW+luVm78yCSjZwja/xyl+PV6JsLhxQv+rgH46rpxQw== + +"@oxc-parser/binding-android-arm-eabi@0.140.0": + version "0.140.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-android-arm-eabi/-/binding-android-arm-eabi-0.140.0.tgz#1e263aca7aaf38e989000e50025b2b21834a8eda" + integrity sha512-ZfjDZ422mo7eo3b3VltqNsV9kmv1qt/sPEAMSl64iOSwhVfd0eIZ9LB79Mbs1xYXJnk7WSROwzBCKDIiVxPTvQ== + +"@oxc-parser/binding-android-arm64@0.140.0": + version "0.140.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-android-arm64/-/binding-android-arm64-0.140.0.tgz#d25051e94aa928163f36ad06616575d04a11f24b" + integrity sha512-Ia8jSvikUX6Sf+Ht+KOCUF/k1HpR0VlmqIYymubmWDebOEGtsyliHDR6JxsZ4IX3/c/GbrB1uh09aVGQv/LQmQ== + +"@oxc-parser/binding-darwin-arm64@0.140.0": + version "0.140.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.140.0.tgz#b859c87a7f4a865b00197ab56d5c257d33ca89e7" + integrity sha512-G6VK0nK61pH0d0mBjUqSZbVxGqqO5uzeginLDQj+gOO6ObfJjXRwgkD/ol0w1INcnFeAb6YGGO7qc3ueGHaycQ== + +"@oxc-parser/binding-darwin-x64@0.140.0": + version "0.140.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-darwin-x64/-/binding-darwin-x64-0.140.0.tgz#81bc59ef5cdeebd34902626b9887aed12b6e32d0" + integrity sha512-HazBOuZzd2pO1C2uMmp8Gv7mhzMHqKSKDS1OZfcLEvpIcgA+48J92HEtNanVHDIzRD9PRPCV6aS6fkZIWOVl8Q== + +"@oxc-parser/binding-freebsd-x64@0.140.0": + version "0.140.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.140.0.tgz#dd34a7927a9394a08ac374e04fc48dd5bc212036" + integrity sha512-9hSUU+HmTUyOe4JzMHxNGgLWNY7rrO+6ShicZwImNJacEAACDMIkuEQQkvXSL+WJN50jaNtLYJv8s4OcBdpyUQ== + +"@oxc-parser/binding-linux-arm-gnueabihf@0.140.0": + version "0.140.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.140.0.tgz#4142cb0ce5ec8157208c112b9fd11718233d8bd2" + integrity sha512-RAEuQsYtS0KcDFqN0ABTjyyNlokS91JeuDuoW9tEbG0JTbRNXnpQUdbYc/16JoA6Z/2ALbNrE3KmxtqDiuIjCQ== + +"@oxc-parser/binding-linux-arm-musleabihf@0.140.0": + version "0.140.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.140.0.tgz#90e0f998907f32ffbf0136fc29b5d1da1e6fb54a" + integrity sha512-c4CkHvPvqfojouredJ0w3e6+jiBq0SbFyhH61kr/zPb/7XsaYTNKQ54vmlSsopfdQbNDX40ZeK9Abs2Qet6wcw== + +"@oxc-parser/binding-linux-arm64-gnu@0.140.0": + version "0.140.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.140.0.tgz#97ec2cb371693c1e9fc5eb660c48666ace786d82" + integrity sha512-yrjmLj8ixPB25yqvPGr28meGjb+keed7m1GqqY/0uqkhZIoT4t9zmfwUgFEtC33C7dtE+UQ7TU0IaVxf97SWJg== + +"@oxc-parser/binding-linux-arm64-musl@0.140.0": + version "0.140.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.140.0.tgz#ebad7ee8c4094e51f4d138365b87a51160671bfd" + integrity sha512-ggGMQTN8Agwxp2WiLMpdY671dt0qTDJWiWlJeig3HnUwTnerRl0J2JdGVghWBeDcss2D9S2V2Js6dZHEiVabVA== + +"@oxc-parser/binding-linux-ppc64-gnu@0.140.0": + version "0.140.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.140.0.tgz#fde39c4a1460fab7144d15025fb8c40e6e976668" + integrity sha512-IgTs8xYAFgAUGNmR65tIqjlJ8vKgrfXzC515e9goSdfMyKQV4aJpd2pUUudU4u51G64H0/DSEJEXKOraxm9ZCA== + +"@oxc-parser/binding-linux-riscv64-gnu@0.140.0": + version "0.140.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.140.0.tgz#6990a42ddac6b81b0a00076e35028b514fbaf6ed" + integrity sha512-A1x+PMWZmSGaFVOx2YeNTFau8uD+QO14/vLP4GrcuvUPs3+nBkUOjy9Lus86ftHsDojjYMbvBelmKc3F7Rv08g== + +"@oxc-parser/binding-linux-riscv64-musl@0.140.0": + version "0.140.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.140.0.tgz#fe9e6a5f6514ba8bb8c32bbbdb5d11165af64542" + integrity sha512-zBqpfRo2myWPrPo5xUjeZqlnPXPXsX8BcWtWff66/eGRQdbPjhzPgXa/F+AtxT2afUViPxbuDlwscMKzQ5tg+g== + +"@oxc-parser/binding-linux-s390x-gnu@0.140.0": + version "0.140.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.140.0.tgz#9ec751995735f9452625fc18a1fdf6f430ea2eed" + integrity sha512-2M1DPm/8w9I//YzFlFC9qXw+r2tJFh5CYwRlYTq2vUJQS7qoQftEDeCZ8EnN7KHtvSiXvYj8mZI5pR7DpXmcEw== + +"@oxc-parser/binding-linux-x64-gnu@0.140.0": + version "0.140.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.140.0.tgz#246c6fd05e75a9c81a9cb2c0e7f66c6e148c640f" + integrity sha512-8aRDbZ/U/jO8N7go1MO72jtbpb4uswV8d7vOkMvt/BPgZiyEYvl1VIWK4ESxZZhnJ4tqwVldgX7dNiP/eB1Jdg== + +"@oxc-parser/binding-linux-x64-musl@0.140.0": + version "0.140.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.140.0.tgz#6a7861884ebf5236c163b323eda5e8223e6dddb3" + integrity sha512-xRqpeI8U2sQQS1W5BMWRyMTxtagkuLG2dEWruet5lFsWHTvBth11/TpSaJatHdqVVwHN0q3uuoS9zRsGinq8hg== + +"@oxc-parser/binding-openharmony-arm64@0.140.0": + version "0.140.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-openharmony-arm64/-/binding-openharmony-arm64-0.140.0.tgz#837520388be3cbcb4a5486f9e85598e0bcd1af22" + integrity sha512-GbGRe26MqAKciFRvXeHNQJ6VAHYs9R4miP89sEAncysM3n+f4lnyLWgsa9kklJNpfnxdq2yRoNYHFqwBckVimw== + +"@oxc-parser/binding-wasm32-wasi@0.140.0": + version "0.140.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-wasm32-wasi/-/binding-wasm32-wasi-0.140.0.tgz#49bd9ac61016154753f3adebf59b72aa3e754c72" + integrity sha512-vFiC1hqys+hkX1GnQkIoiTQJNiUm43Z0lO35ETKXTw0YtpW7+cN58YRRXFAQQ+TgpkIi3lrhcxdlnqz+Oi3ptQ== + dependencies: + "@emnapi/core" "1.11.2" + "@emnapi/runtime" "1.11.2" + "@napi-rs/wasm-runtime" "^1.1.6" + +"@oxc-parser/binding-win32-arm64-msvc@0.140.0": + version "0.140.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.140.0.tgz#190b972b637c5a601644fff86561c59e658a4eed" + integrity sha512-fGSQldwEYKhM+H8uLt76Op8hh5+FYaR6lvvQ1Txw3Mhn86DyQXLcI0fi1EkFlTK7F+46OCk/j0AJMzZQm6g5Xg== + +"@oxc-parser/binding-win32-ia32-msvc@0.140.0": + version "0.140.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.140.0.tgz#5d2438f810e646ab7e65b69b223ee00656cd6054" + integrity sha512-sDS2Bai+g3ZWYwfZqmosiSuFDBcVnZ3Ta6pszzsiJoLMqsJEWKcxXXbGa7b7yXr++W2lQNPb3ZRJ8czseqL7RA== + +"@oxc-parser/binding-win32-x64-msvc@0.140.0": + version "0.140.0" + resolved "https://registry.yarnpkg.com/@oxc-parser/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.140.0.tgz#fedda07f4cebf668073f8eb37b80031c5250c668" + integrity sha512-kHbE1zWyb5OQgJA6/5P4WjiuB01sYdQwtZnSSyE58FQEXDAMnyeeq4vj7KgN75i5SlBzOs8A5MrtlD3gOlDKqQ== + +"@oxc-project/types@=0.139.0": + version "0.139.0" + resolved "https://registry.yarnpkg.com/@oxc-project/types/-/types-0.139.0.tgz#38d76b9dbf934c2a02be174fb32ceebf182fe742" + integrity sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw== + +"@oxc-project/types@^0.140.0": + version "0.140.0" + resolved "https://registry.yarnpkg.com/@oxc-project/types/-/types-0.140.0.tgz#2acc1bd45ff24951059d01ce7552d26e1574c5ac" + integrity sha512-h5LUOzGArYemnW1NMz/DuuQhBi96J6JL2Bk8zE4kvqxB5Sg3jxmCiH4uyOWHDkiKSt5vWlG4FIwCR/DbstcNRQ== + +"@oxc-transform/binding-android-arm-eabi@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-transform/binding-android-arm-eabi/-/binding-android-arm-eabi-0.141.0.tgz#c6ec45363c0ed6ee2104cf2e830ded5a354f5441" + integrity sha512-FOdseb5KpV3JtkM+7TN4u3sW3aQkUSRy0bWWiKgT/qrIGqZHqzKEUpwaMybutsfwEglWBXuJgnrT9loWisPkrw== + +"@oxc-transform/binding-android-arm64@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-transform/binding-android-arm64/-/binding-android-arm64-0.141.0.tgz#54cdb92f1b7ab839d3d2a8dc629f6e8af2e01dd3" + integrity sha512-jglqGwEnSuldt1nfFSpDBHQZ/RzjCjWQEMDatPOEOWIA0ZCCYFj/9ILUOTVllZz79FI9/c0p/bctVVlQqQxxYg== + +"@oxc-transform/binding-darwin-arm64@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-transform/binding-darwin-arm64/-/binding-darwin-arm64-0.141.0.tgz#f4c3d95e7988be7d17bb03daa503874de25b6003" + integrity sha512-81jBeodJH0IRJ3/OnAgW2lBPm/kcoz603d8eGnnwgW2HbxAUs8rfw+YWaKLrWaKjT0oSIPOrGMJu9DeaKD68sQ== + +"@oxc-transform/binding-darwin-x64@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-transform/binding-darwin-x64/-/binding-darwin-x64-0.141.0.tgz#b143741c10e352d74bebc889bb2bcffff7e615dd" + integrity sha512-o2jD9E7CyPxhb3CuYbaYsnFH0Mo1hKa2R+Hfo6xJxOlyfcM8U4R73W3YXb9w6lRPUc0PBFUbCmJjtGR/k5SIYA== + +"@oxc-transform/binding-freebsd-x64@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-transform/binding-freebsd-x64/-/binding-freebsd-x64-0.141.0.tgz#4fd7a0707dd53876e026d1ff1b45bc80bae01450" + integrity sha512-DNF+Of7nckfwqu9fZin4vR8bGmF/3sWPvtw9Jc4cjeQoRB9vUuC6w9C/GxW+0Vr+PCH+gk4tR4Ygvjfx3LYOzQ== + +"@oxc-transform/binding-linux-arm-gnueabihf@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-transform/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.141.0.tgz#d211200d71038231c1b3365ce5c54d0e8035d550" + integrity sha512-nolqi5WqP68qVQJdnPFCF50JT5KzqlcpvwGFyIV+IRCLcv5Hh11gIu4InMs3Uswcf0BJnV/oLIjzb7Sycd3zJg== + +"@oxc-transform/binding-linux-arm-musleabihf@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-transform/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.141.0.tgz#a579f6cfa7583ff26e0a53b1df21d0665f3cc0d9" + integrity sha512-ytbO89DQl6KxjKCRlyCEtABgfs8njm623ambDkZZBer5J9dbTwbaV5hseZsPkVzZPxwXobu43/XS0jVZnrmCTA== + +"@oxc-transform/binding-linux-arm64-gnu@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-transform/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.141.0.tgz#52aba00e88819d36245d666c937f10da34812360" + integrity sha512-Tjj3pobBAzbzUJE8ljbS61om6yfVnarSZzS8LaFCSn0rB+hs0IZRE3jC9IzpsVPHSoJl4uhbIGebuDY2G3B6gg== + +"@oxc-transform/binding-linux-arm64-musl@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-transform/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.141.0.tgz#f2946158b0025814d5cd4b9937ab96bd3f0942ea" + integrity sha512-aUUptri02E4nqkUvyA+2oYkmU20pYnHIpNLPZOgom0kAa0Fx9X6QFKqKm1MopyucWolQ9XTgCK2PrupSSBdCdQ== + +"@oxc-transform/binding-linux-ppc64-gnu@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-transform/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.141.0.tgz#f63596fda051c0ed413c580f6643e556f15fc0c2" + integrity sha512-d28AT+SfcAYFnulI2C8HJ5OeoUa5w+eMpwy0uMzbU/3zXJpFjjFOvJlEL8FNvx7HBEENj5IfgD+aXdNzEEn1Tg== + +"@oxc-transform/binding-linux-riscv64-gnu@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-transform/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.141.0.tgz#41008d443d3b0f44e21b11eebf4026d9d966631a" + integrity sha512-P6XVhw+MJsjeliWJ6BBKdC0HU1VEiwMRHtqUADK+jK5wiqgzt3/JhIcMuRLzBPYfnOujLpe+fm63yEzKUIAcSA== + +"@oxc-transform/binding-linux-riscv64-musl@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-transform/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.141.0.tgz#2ea93648a14eade92fde70d7b316b14ecff26dcb" + integrity sha512-6QUicErqoLpCVsXPYI+OEYJ95TjiV+trvX9VeCuyVcyL5p0Opi7DFQL2c1DcGHi1c9cqz1h09mUKCZ7Y52kxfw== + +"@oxc-transform/binding-linux-s390x-gnu@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-transform/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.141.0.tgz#4b7368379224bbfdb6d4092c744086a5f7687d80" + integrity sha512-r2Jk0vfcnHnkPOjLnWvpGVTFcYDirGICBJYraCkWeplhPZ2Sgg9GvDVgah9VFOHRZVtK6XQynELP9A8EB/Ne0Q== + +"@oxc-transform/binding-linux-x64-gnu@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-transform/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.141.0.tgz#bf4d6ca9dc39262df289a3f34b6d8557d0a94199" + integrity sha512-lIsdGq4LA1IlbrZlmrhP/p0pCo4+5jrAlLp9BMzIHaV4mILBSr+ZtuTDkML4117cLHdzoWOqw0s3Rb7igOWtxw== + +"@oxc-transform/binding-linux-x64-musl@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-transform/binding-linux-x64-musl/-/binding-linux-x64-musl-0.141.0.tgz#da4a329d5831f1f51ec54f6c38640baec34b2842" + integrity sha512-y+9FbVRBhUtHBVn0xHiVcaNHkoRudIhlKhRk1+CclE1uGD6af3xznTjCOrKGB7HZ2SzlCWLZwQGm/KERpUjX1w== + +"@oxc-transform/binding-openharmony-arm64@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-transform/binding-openharmony-arm64/-/binding-openharmony-arm64-0.141.0.tgz#06d198d4af95bc0295031ae43d2ca897b8219874" + integrity sha512-Ul5Fu6zPL7kjTbtBU30HaRFHPL3bjjpdieHmAXJlJDuFukuOXqVD6dS70b314IjFy/rbqkD8OK4MQ4408eEjyg== + +"@oxc-transform/binding-wasm32-wasi@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-transform/binding-wasm32-wasi/-/binding-wasm32-wasi-0.141.0.tgz#5507fe5c913fa6a238b5f81dcf4b317ca4134eb7" + integrity sha512-GaQJvcyFJyle5lll67+iYAgv+G21bQXvWPNhD6YIYoR/bV8kS0Qm8YSL22Y/YZC/8RwsneVFWpP2y6VZJfcM/g== + dependencies: + "@emnapi/core" "1.11.2" + "@emnapi/runtime" "1.11.2" + "@napi-rs/wasm-runtime" "^1.1.6" + +"@oxc-transform/binding-win32-arm64-msvc@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-transform/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.141.0.tgz#eb1af7420e9ff70c70d64b452396a478d3f40fb2" + integrity sha512-Fbi/hC64tNa56mXEitjaWsxQoMvtJDbOe2MxO+BA1v1Ev28L9n1yMJwhKyOCA+Rm8lYK91oOb5CRv3Ct5RuvJA== + +"@oxc-transform/binding-win32-ia32-msvc@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-transform/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.141.0.tgz#a65b84e2d1fef6272872739a413fef173e3846b7" + integrity sha512-2HlslqwOXQ2nxAZjhqZIpvPxENhQGvA6b4cGwmiVD6Uh5x+dZAopOeEJRxRPpKcrr/W5KXfwwbttwx4OWbg9TA== + +"@oxc-transform/binding-win32-x64-msvc@0.141.0": + version "0.141.0" + resolved "https://registry.yarnpkg.com/@oxc-transform/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.141.0.tgz#f8ae389db95e0d45e0ee22e697b89bd56b5fec0c" + integrity sha512-JEgTv+y56FbwinH1/kqpNyD+bWRWDpbbPdSY7Ta7rCKFiRsYkUHZd1v+XWxda08cS8GAmlKS4WKcVwtrAbDUHA== + +"@parcel/watcher-android-arm64@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.6.0.tgz#99aaa3223d43807c9340af439cad7e9b6d26ada6" + integrity sha512-trgpLSCKRC/huFjXX/Smh+0sWe4+YtKfktIToiMl59ghz7z+qkH6kMvNnUbLyRs9N11t8l4svSCs1+5B3rOAhA== + +"@parcel/watcher-darwin-arm64@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.6.0.tgz#024496e586b4744f09ce532bbe89fe38ef02a64e" + integrity sha512-Y3QV0gl7Q1zbfueunkWIERICbEojQFCgpyG7YqOGNFLsckXyI1xu9mAIUpKY9QBYzBtSkN8dBPwd3yiAO9ovMw== + +"@parcel/watcher-darwin-x64@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.6.0.tgz#a4621df1359a93d39a332d9bab5ff09016a0608f" + integrity sha512-Ohv6OpzhUfKYD7Beb8kDvG0jbIxORCYY1JRdZnaBtnjjkJxgD7ZVL0nw2sCYd0yTMKTvz3nnTnOF3cDifK+kvw== + +"@parcel/watcher-freebsd-x64@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.6.0.tgz#7f565ed1a5b3a5e604e6a4799121518265d62a3d" + integrity sha512-5HmXvDgs8VK+74jF9y9/2FE3/OnlcKmc56tjmSrEuZjpSZOGL+fvAu+HKJBdPs9uwoP2hE6TlSUpXZ/C5jUFmQ== + +"@parcel/watcher-linux-arm-glibc@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.6.0.tgz#ad7d3825e67b81999165da42593022045abc0889" + integrity sha512-Ps/hui3A+vMbjdqlqAowK2ZL8+BO8dBjxeWXj6npTBs3jx4wWmbPpaLuqwrQrSqIVMCnpWo238bJ1U37GhQOYg== + +"@parcel/watcher-linux-arm-musl@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.6.0.tgz#fe7d1cccb2c483215c090e938cf5cf404d2f9a8c" + integrity sha512-9c6AUHgHoG+IY88MRIHupztQiQnrbqHYQjkM2btA+Bf/wQnQMuiD0Wfk1EVv3TlNT3x41uU71rn6E4xh/+zvkw== + +"@parcel/watcher-linux-arm64-glibc@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.6.0.tgz#7e239dcb4646c4c79f006a7131a48238249530da" + integrity sha512-yHRqS2owEXe6Hic9z6Mh1ECsCd+ODVOGvZDyciqRd21+v+o+DnXMOrw50DSpIG2sb8GPEaPPmfeCAWKPJdq46g== + +"@parcel/watcher-linux-arm64-musl@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.6.0.tgz#c58b8d9c6d8d81594be00dd83aab741c1aaf7e0e" + integrity sha512-WhB2e/V7rqdHHWZusBSPuy5Ei8S6lSz6FE5TKKQz5h3a0O+C+mhY7vxU9b/stqvMb8beLnPY82ZrFTLKs+SrKA== + +"@parcel/watcher-linux-x64-glibc@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.6.0.tgz#5184fa9a770478d86e56875f4ee163a0abdc8791" + integrity sha512-ulGE6x6Oz6iAwg75T8YQSoguBWasniIbX+QWpaYPcCnDOpdWX3k+4xbEYPZVLxOuoJI+svJJPD3sEj8G7lrQ3A== + +"@parcel/watcher-linux-x64-musl@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.6.0.tgz#2d1c55aa7246cbc7670e2612058a8a542c9cf246" + integrity sha512-tkBYKt7YQrjIJWYDnto2YgO8MRkjlMTSNoRHzsXinBqbLdeOM3L32wPZJvIZxqaLMfSlS/4sUjH/6STVP/XDLw== "@parcel/watcher-wasm@^2.5.6": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher-wasm/-/watcher-wasm-2.5.6.tgz#0edecf897e1b397782db21ef4522801c727cdb58" - integrity sha512-byAiBZ1t3tXQvc8dMD/eoyE7lTXYorhn+6uVW5AC+JGI1KtJC/LvDche5cfUE+qiefH+Ybq0bUCJU0aB1cSHUA== + version "2.6.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-wasm/-/watcher-wasm-2.6.0.tgz#1112d5314d593689e38912853d14c213313f0244" + integrity sha512-dtjbDxKSDPQ8AmA+pS4OFaHE1FKrjtGpLGBxw85uKFkRorjNbvDM/aFPgqosu40wprbp1xw2ZSxIKqghCUHe2w== dependencies: is-glob "^4.0.3" napi-wasm "^1.1.0" - picomatch "^4.0.3" - -"@parcel/watcher-win32-arm64@2.5.6": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz#caae3d3c7583ca0a7171e6bd142c34d20ea1691e" - integrity sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q== + picomatch "^4.0.4" -"@parcel/watcher-win32-ia32@2.5.6": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz#9ac922550896dfe47bfc5ae3be4f1bcaf8155d6d" - integrity sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g== +"@parcel/watcher-win32-arm64@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.6.0.tgz#15e09432040fee9e2213aa9c10ed589012526def" + integrity sha512-gIZAP23jaHjGWasY/TY6yL7NHFClf0Ga7FN+iINvk+KN94rhm94lYZhFsbYFNcA04/onvGD9kKmiJLJB2HbNwQ== -"@parcel/watcher-win32-x64@2.5.6": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz#73fdafba2e21c448f0e456bbe13178d8fe11739d" - integrity sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw== +"@parcel/watcher-win32-x64@2.6.0": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.6.0.tgz#9bee199a2a4accd557b451ac2c1c793f305ae012" + integrity sha512-cA+/pXV2YkfxlIcXOQ5fSWqAzzPyD78/x5qbK/I0vUkrlYHA8TIz+MXjAbGouguKVSI4bOmkTSJ1/poVSsgt+A== -"@parcel/watcher@^2.4.1", "@parcel/watcher@^2.5.6": - version "2.5.6" - resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.5.6.tgz#3f932828c894f06d0ad9cfefade1756ecc6ef1f1" - integrity sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ== +"@parcel/watcher@^2.4.1": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.6.0.tgz#99661f6220070b76a766aba6b7e313a087a1be4f" + integrity sha512-7FNeNl8NCE7aINx7WXiKQrPYZWC/hvrTsmk6zmxbI7LTXE7hVek/n8AfVgpe2y82zl3w0HvCHN0bVKMBoJcC0w== dependencies: detect-libc "^2.0.3" is-glob "^4.0.3" node-addon-api "^7.0.0" - picomatch "^4.0.3" + picomatch "^4.0.4" optionalDependencies: - "@parcel/watcher-android-arm64" "2.5.6" - "@parcel/watcher-darwin-arm64" "2.5.6" - "@parcel/watcher-darwin-x64" "2.5.6" - "@parcel/watcher-freebsd-x64" "2.5.6" - "@parcel/watcher-linux-arm-glibc" "2.5.6" - "@parcel/watcher-linux-arm-musl" "2.5.6" - "@parcel/watcher-linux-arm64-glibc" "2.5.6" - "@parcel/watcher-linux-arm64-musl" "2.5.6" - "@parcel/watcher-linux-x64-glibc" "2.5.6" - "@parcel/watcher-linux-x64-musl" "2.5.6" - "@parcel/watcher-win32-arm64" "2.5.6" - "@parcel/watcher-win32-ia32" "2.5.6" - "@parcel/watcher-win32-x64" "2.5.6" + "@parcel/watcher-android-arm64" "2.6.0" + "@parcel/watcher-darwin-arm64" "2.6.0" + "@parcel/watcher-darwin-x64" "2.6.0" + "@parcel/watcher-freebsd-x64" "2.6.0" + "@parcel/watcher-linux-arm-glibc" "2.6.0" + "@parcel/watcher-linux-arm-musl" "2.6.0" + "@parcel/watcher-linux-arm64-glibc" "2.6.0" + "@parcel/watcher-linux-arm64-musl" "2.6.0" + "@parcel/watcher-linux-x64-glibc" "2.6.0" + "@parcel/watcher-linux-x64-musl" "2.6.0" + "@parcel/watcher-win32-arm64" "2.6.0" + "@parcel/watcher-win32-x64" "2.6.0" "@pkgjs/parseargs@^0.11.0": version "0.11.0" @@ -2583,11 +2412,11 @@ integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== "@playwright/test@^1.44.1": - version "1.61.0" - resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.61.0.tgz#dcc3d43e581aab2985d70413309d89350e980ad8" - integrity sha512-cKA5B6lpFEMyMGjxF54QihfYpB4FkEGH+qZhtArDEG+wezQAJY8Pq6C7T1SjWz+FFzt3TbyoXBQYk/0292TdJA== + version "1.62.0" + resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.62.0.tgz#dab444563549f4cc94caacb7d6a72067bff4aac6" + integrity sha512-9zOJ6ZQRAena31MpOH9VSzIz8Ou3YJ/wtY/eQm5T2uhfhG7/U3COrMS8xOtUrZrp9OgdmzEnIYODye3nY1VqzA== dependencies: - playwright "1.61.0" + playwright "1.62.0" "@polka/url@^1.0.0-next.24": version "1.0.0-next.29" @@ -2615,84 +2444,84 @@ resolved "https://registry.yarnpkg.com/@poppinss/exception/-/exception-1.2.3.tgz#b713855e6c9fe2110fea0949455c50828145e64a" integrity sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw== -"@rolldown/binding-android-arm64@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.2.tgz#88fd6b295a411e62b7926433a45eb5e17e68bba4" - integrity sha512-2cZ+7xRS+DBcuJBJKnfzsbleumJhBqSlJVpuzHC0nTqfd3QQ7Vx2/x5YR/D7cBamKSeWplwo82Fn9lqYUDEMfA== +"@rolldown/binding-android-arm64@1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.5.tgz#f58cb9a0a8128ed0582282720528547fc5c035f3" + integrity sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ== -"@rolldown/binding-darwin-arm64@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.2.tgz#2f840f7e6501cb52370411c2fb008119f1fbf400" - integrity sha512-RkPMJnygxsgOYdkfqgpwY0/Fzm8d0VQe6HGU2/B00Xa9eqdLbrII+DOKAodbJAn3ZL1AJxGHkZRPYazgGY6Ljw== +"@rolldown/binding-darwin-arm64@1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.5.tgz#441144c05a4a831aa75269abc3a4a324374ea707" + integrity sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw== -"@rolldown/binding-darwin-x64@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.2.tgz#2ed3b66dded5140d22ca2ac58d4e1c1e3143f490" - integrity sha512-Uiczh6vFhwyfd7WNe7Q7mCA4KxAiLdz7jPE/WGizfRpIieoyFuNVMmM8HqZ9HwudTkY6/AeMQwlNJ9NJijguWw== +"@rolldown/binding-darwin-x64@1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.5.tgz#c82e30652cef52c4af925d5c66c8955a40319816" + integrity sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g== -"@rolldown/binding-freebsd-x64@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.2.tgz#d3d8603ae480a505eb8c12643c901b2a3771b875" - integrity sha512-+TpdtTRgHiJFjCVFbw311SuLk3KfytPOQQn+VlAEv+gBxYPtL7E6JS9e/tk+8CwxhIZvemJKo4rTKgfWNsKkkA== +"@rolldown/binding-freebsd-x64@1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.5.tgz#c32e9ce7fa1c0fb2b80913a2a3a05c3e907d06b0" + integrity sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA== -"@rolldown/binding-linux-arm-gnueabihf@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.2.tgz#bc36e0e33566bc80877fe4bca56fd32b241dbacb" - integrity sha512-4lv1/tkmi7ueIVHnyreaOeUpiZP26BH9rRy6hoYfR9310A2B9nUEVRDvBx69vx64Nr3eTPPRkyciqJJs+j9Jmw== +"@rolldown/binding-linux-arm-gnueabihf@1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.5.tgz#ce90b5e22316adeb502ea010582f498cd0604f27" + integrity sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw== -"@rolldown/binding-linux-arm64-gnu@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.2.tgz#6267a447e6bfc5a99eb030a6a99194ecc917a652" - integrity sha512-gBSUVO0eaWgw1JMjK3gB8BMlX2Mk148s2lTiVT3e9vjVxbl7UDfMWWY8CfIaaqiXuM9fVTMxIpUz6CAo/B6Vlw== +"@rolldown/binding-linux-arm64-gnu@1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.5.tgz#91947110c4ddaa4eefb004e52688070977085201" + integrity sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q== -"@rolldown/binding-linux-arm64-musl@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.2.tgz#68fc068f5ebc1d137eecdb651d90830f330aad48" - integrity sha512-LjQP/iZLBu8o8PjIfk4x3At0/mT6h282pvz8Z5LAyhGbu/kDezyO7ea62rF5uoqmgnIYqbN/MqJ3Si3Aymi7xQ== +"@rolldown/binding-linux-arm64-musl@1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.5.tgz#eb32b2d4108c1c702b91e8cde8a043eae5caa94d" + integrity sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA== -"@rolldown/binding-linux-ppc64-gnu@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.2.tgz#fe072f0bc3b713ae25b357651ced38d39e3d81e0" - integrity sha512-X/7bVLWelEsbyWDUSXt7zVsTniLLPIY2n1rH58qr78l9i7MNbbxBWD8gI2vRfBWf4NUXJCUuQnfZDsp32LqsfQ== +"@rolldown/binding-linux-ppc64-gnu@1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.5.tgz#ccb943c11e5a72655cbb02fc1163541ceb640782" + integrity sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg== -"@rolldown/binding-linux-s390x-gnu@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.2.tgz#9492609384775c6edec9bfbe5b1cbba9660dddcc" - integrity sha512-gb6dYKW/1KDorGXyy48glEBJs/sxVSC5pcVrox/pFGV4mvwSFeg2sK5L2tRkVsVlh7kueqOgg4GEcuipJcGuKg== +"@rolldown/binding-linux-s390x-gnu@1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.5.tgz#a33731ee567e90b75fac6e5e55307e8a2b3038f0" + integrity sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA== -"@rolldown/binding-linux-x64-gnu@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.2.tgz#74029d9f86d60fa9bcf2670b1480e22438203c98" - integrity sha512-JY4w85pU3iAiJVMh5nuk4/Mh9GjMsupe8MrIN53rwxAZW64GKrWeJBuN6SxQg9QTU5uB1cxyhDzW8jqRn1EABw== +"@rolldown/binding-linux-x64-gnu@1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.5.tgz#a74c01aaacedfc11c39b6feba33a5fa0c654949f" + integrity sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ== -"@rolldown/binding-linux-x64-musl@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.2.tgz#eb3004015027a7af12f9b0ac85ffa1634015c873" - integrity sha512-xvpA7o5KCYLB0Rwscmuylb1/zHHSUx4g4xilm4prC5jP76pEUlzBmMbgpbh7bVDbId4NcfT96gN5i6mE6UDaiw== +"@rolldown/binding-linux-x64-musl@1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.5.tgz#28cd178494fa1e65dba412229b5ce55c4dd5cbd1" + integrity sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg== -"@rolldown/binding-openharmony-arm64@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.2.tgz#6a02c49dc0f698614f97c68c6f7c21aadc7600b1" - integrity sha512-p/ts6KBLjuk49Bp21XH77poQGt02iNz7ChgHep7tudPOaLinR/De/RHdxF8w8Yj4r/bF/bqXwH6PZrB2sA+Nvw== +"@rolldown/binding-openharmony-arm64@1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.5.tgz#f7c75fa913fc20884d26a7d488d4f5c597cd71c0" + integrity sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw== -"@rolldown/binding-wasm32-wasi@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.2.tgz#3f67c083e0762b8cd6c95e8edfe1a743d7ffdf78" - integrity sha512-VMu/wmrZ9hJzYlRhbw7jK5PODlugyKZ5mOdX78+lS8OvuFkWNQdz1pFLrI2p3P0pjXOmUZ7B48o5VnMH9QOGtg== +"@rolldown/binding-wasm32-wasi@1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.5.tgz#c379581947787081df363ea106140fcd5fec252d" + integrity sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA== dependencies: "@emnapi/core" "1.11.1" "@emnapi/runtime" "1.11.1" - "@napi-rs/wasm-runtime" "^1.1.5" + "@napi-rs/wasm-runtime" "^1.1.6" -"@rolldown/binding-win32-arm64-msvc@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.2.tgz#a69c5a03b3ba36cb0b1154709293e0cefc9dd69c" - integrity sha512-xtUJqs8qEkuSviS0n1tsohaPuz3a1SPhZywOji4Oo+sgrJs8daEDMZ0QtqL0OS7dx8PoVpg2J/ZZycPY5I2+Zg== +"@rolldown/binding-win32-arm64-msvc@1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.5.tgz#f23c88694f7a729a12f395024aee38df80a16ba3" + integrity sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw== -"@rolldown/binding-win32-x64-msvc@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.2.tgz#e1d9a6ccd29de00378f8dd6e275adbde5731d30a" - integrity sha512-85YiLQqjUKgSO/Zjnf9e0XIn5Ymrh1fLDWBeAkZqpuBR/3R8TpfoHXuyblqyQrftSSgWO9qpcHN8mkyKsLraoA== +"@rolldown/binding-win32-x64-msvc@1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.5.tgz#3377c8de0e56a8857f11217561147090e874cb46" + integrity sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA== "@rolldown/pluginutils@1.0.0-beta.27": version "1.0.0-beta.27" @@ -2780,255 +2609,255 @@ resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.2.tgz#a19c645c375158cd5c50a344106f0fa18eb821c4" integrity sha512-dnlp69efPPg6Uaw2dVqzWRfAWRnYVb1XJ8CyyhIbZeaq4CA5/mLeZ1IEt9QqQxmbdvagjLIm2ZL8BxXv5lH4Yw== -"@rollup/rollup-android-arm-eabi@4.62.2": - version "4.62.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz#5e9849b661c2229cf967a08dbe2dbbe9e8c991e5" - integrity sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg== +"@rollup/rollup-android-arm-eabi@4.62.3": + version "4.62.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.3.tgz#b0ab422fb60f3583c8c789e856d64a32507f299e" + integrity sha512-c0wdcekXtQvvn5Tsrk/+op/gUArrbWaFduBnTLP2l1cKLSQs4diMWjJw3m6A0DdzT8dAAX95KpkJ3qynCePbmw== "@rollup/rollup-android-arm64@4.60.2": version "4.60.2" resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.2.tgz#1af19aa9d3ad6d00df2681f59cfcb8bf7499576b" integrity sha512-OqZTwDRDchGRHHm/hwLOL7uVPB9aUvI0am/eQuWMNyFHf5PSEQmyEeYYheA0EPPKUO/l0uigCp+iaTjoLjVoHg== -"@rollup/rollup-android-arm64@4.62.2": - version "4.62.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.2.tgz#5b0699ee5dd484b222c9ed74aff43c91ea8b17f8" - integrity sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw== +"@rollup/rollup-android-arm64@4.62.3": + version "4.62.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.3.tgz#047e967eeb440a299f1abc773579b5c2516fa48d" + integrity sha512-3YjElDdWN+qXAFbJ/CzPV+0wspLqh54k/I6GfdYtEJRqg7buSgc1yPM3B+93j1M4neobtkATHZTmxK2AMVGfnA== "@rollup/rollup-darwin-arm64@4.60.2": version "4.60.2" resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.2.tgz#3b8463e03ba2a393453fea70e7d907379c27b649" integrity sha512-UwRE7CGpvSVEQS8gUMBe1uADWjNnVgP3Iusyda1nSRwNDCsRjnGc7w6El6WLQsXmZTbLZx9cecegumcitNfpmA== -"@rollup/rollup-darwin-arm64@4.62.2": - version "4.62.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.2.tgz#8bc52c9d7a3ce8d0533c351a9c935de781daa06f" - integrity sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A== +"@rollup/rollup-darwin-arm64@4.62.3": + version "4.62.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.3.tgz#18369e67d0d3ffcb01a95561217447b791727697" + integrity sha512-Pch2pFNOxxz1hTjypIdPyRTR6riiwRl84+VcN9djS680fw+Co1nAJINrdpqp7KV0NvyuU8ilZXZCjd7ykJl1GQ== "@rollup/rollup-darwin-x64@4.60.2": version "4.60.2" resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.2.tgz#28da23d69fe117f5f0ff330a8549e51bd09f1b6a" integrity sha512-gjEtURKLCC5VXm1I+2i1u9OhxFsKAQJKTVB8WvDAHF+oZlq0GTVFOlTlO1q3AlCTE/DF32c16ESvfgqR7343/g== -"@rollup/rollup-darwin-x64@4.62.2": - version "4.62.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.2.tgz#ba2ef3e8fb310f0af35588f270cfa5aa96e48764" - integrity sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA== +"@rollup/rollup-darwin-x64@4.62.3": + version "4.62.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.3.tgz#bf23ae4c5c0f841b123bc79e3b246176c6d08fd7" + integrity sha512-LEuncFUHFiF8t4yZVZvvZA1wk0pjAscRnsrn1EfTEmN4HXotBi2YtcnLRyaK6UbuczW7xZS5ES+81Rdz8Z0T6g== "@rollup/rollup-freebsd-arm64@4.60.2": version "4.60.2" resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.2.tgz#94bacac3190f621de1355922b599f3817786044c" integrity sha512-Bcl6CYDeAgE70cqZaMojOi/eK63h5Me97ZqAQoh77VPjMysA/4ORQBRGo3rRy45x4MzVlU9uZxs8Uwy7ZaKnBw== -"@rollup/rollup-freebsd-arm64@4.62.2": - version "4.62.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.2.tgz#93b10bdbfe8ada226b8bc0c02ef6b7f544474d96" - integrity sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw== +"@rollup/rollup-freebsd-arm64@4.62.3": + version "4.62.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.3.tgz#c92a1b07d0243181f26d9deb278c3ef09e01f065" + integrity sha512-zvBUvsQUpOWALdDsk6qbS8bXf2VxmPisuudNDrY7x0p0jBdsoZl8HsHczIOgkQiZldmcacMKtBzpoGVNeIe2bQ== "@rollup/rollup-freebsd-x64@4.60.2": version "4.60.2" resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.2.tgz#8a0094f533b9fda160b5c90ad9e0c78fca341788" integrity sha512-LU+TPda3mAE2QB0/Hp5VyeKJivpC6+tlOXd1VMoXV/YFMvk/MNk5iXeBfB4MQGRWyOYVJ01625vjkr0Az98OJQ== -"@rollup/rollup-freebsd-x64@4.62.2": - version "4.62.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.2.tgz#3e8aa38ef3c9c300946871e3fdbb0c30e0a20f86" - integrity sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg== +"@rollup/rollup-freebsd-x64@4.62.3": + version "4.62.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.3.tgz#b69da0407ea06497d395be0e799cc601004b372e" + integrity sha512-C2KmNrcSem/AMg984H/dev+si0lieQGdXdR/lYGJnuumXnFb9Y7QdiI62obFdLlxRYLBv4P0eUVIDbD4c1vVvw== "@rollup/rollup-linux-arm-gnueabihf@4.60.2": version "4.60.2" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.2.tgz#3b7e901a555c7245c87f7440979bee0a1ec882bb" integrity sha512-2QxQrM+KQ7DAW4o22j+XZ6RKdxjLD7BOWTP0Bv0tmjdyhXSsr2Ul1oJDQqh9Zf5qOwTuTc7Ek83mOFaKnodPjg== -"@rollup/rollup-linux-arm-gnueabihf@4.62.2": - version "4.62.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.2.tgz#1d7994384bb0ad1bc41921b506e1642d4f9d7fc3" - integrity sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg== +"@rollup/rollup-linux-arm-gnueabihf@4.62.3": + version "4.62.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.3.tgz#1b4b63c57fc20e6ea4748a8ea864d86513328ec4" + integrity sha512-ggXnsTAEzNQx74XpunRsiZ9aBZDsI7XIa0hm2nzR9f4WzH5/f/d73ZSDaC5ejJ8YLY4NW+V3wr0tjOaeCq8hqA== "@rollup/rollup-linux-arm-musleabihf@4.60.2": version "4.60.2" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.2.tgz#ee9a09b72e8ad764cfd6188b32ff1de528ff7ebe" integrity sha512-TbziEu2DVsTEOPif2mKWkMeDMLoYjx95oESa9fkQQK7r/Orta0gnkcDpzwufEcAO2BLBsD7mZkXGFqEdMRRwfw== -"@rollup/rollup-linux-arm-musleabihf@4.62.2": - version "4.62.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.2.tgz#a6540f47cf844a56b80ca9ff95d2acdfb2cef97b" - integrity sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA== +"@rollup/rollup-linux-arm-musleabihf@4.62.3": + version "4.62.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.3.tgz#64334f5a5178cabb15e7d2a91fb592db1f8621d3" + integrity sha512-2vng+FlzNUhKZxtej3IUqJgbZoQk2M/dwQM20+ULV0R/E/8tr9/P6uEf2iiGIk4HL0zMKh5Jry7mUHdUOvyGgA== "@rollup/rollup-linux-arm64-gnu@4.60.2": version "4.60.2" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.2.tgz#ba483f4aca9be141171d086dbd01ada6ab03b58d" integrity sha512-bO/rVDiDUuM2YfuCUwZ1t1cP+/yqjqz+Xf2VtkdppefuOFS2OSeAfgafaHNkFn0t02hEyXngZkxtGqXcXwO8Rg== -"@rollup/rollup-linux-arm64-gnu@4.62.2": - version "4.62.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.2.tgz#404f2045651840cbf48da91ba6d0f490f0bc2cbf" - integrity sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA== +"@rollup/rollup-linux-arm64-gnu@4.62.3": + version "4.62.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.3.tgz#1ff299f7825f0f52a8e107dac7f15ce73009848b" + integrity sha512-LLLFZKt4/Nraf9rxDkhiU8QVgLF4WmCkfr0L4fj0fPfIZFBib0DeiFk1hhaYKd03LFAFJcxHslhDFlNJLylf5Q== "@rollup/rollup-linux-arm64-musl@4.60.2": version "4.60.2" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.2.tgz#17b595b790e6df68e91c5d02526fc832a985ce4f" integrity sha512-hr26p7e93Rl0Za+JwW7EAnwAvKkehh12BU1Llm9Ykiibg4uIr2rbpxG9WCf56GuvidlTG9KiiQT/TXT1yAWxTA== -"@rollup/rollup-linux-arm64-musl@4.62.2": - version "4.62.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.2.tgz#a3404ffddf7b474b48c99b9c893b6247bb765ba5" - integrity sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ== +"@rollup/rollup-linux-arm64-musl@4.62.3": + version "4.62.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.3.tgz#99052380e7a94fa440b9166c67a909aa3572f089" + integrity sha512-WJkdQCvS9sWNOUBJZfQRKpZGFBztRzcowI+nndmflKgU4XY+3a420FgTOSKTsVqJbnzSxeT4vaJalpOaPo2YCQ== "@rollup/rollup-linux-loong64-gnu@4.60.2": version "4.60.2" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.2.tgz#551718714075a2bfb36a2813c466e3a0e9d56abf" integrity sha512-pOjB/uSIyDt+ow3k/RcLvUAOGpysT2phDn7TTUB3n75SlIgZzM6NKAqlErPhoFU+npgY3/n+2HYIQVbF70P9/A== -"@rollup/rollup-linux-loong64-gnu@4.62.2": - version "4.62.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.2.tgz#e8aac6d549b377945e349882f199b7c8eb75ca38" - integrity sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg== +"@rollup/rollup-linux-loong64-gnu@4.62.3": + version "4.62.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.3.tgz#5f58b576b3668edf62acf0c5265826267b7d858f" + integrity sha512-PwHXCCS2n64/1Ot6rP1YEYA02MGYBcQlr8CSZZyrUG2O7NH6NklYmvr9v3Jy+5e/eDeNchc/ukmKJi9LuflMIQ== "@rollup/rollup-linux-loong64-musl@4.60.2": version "4.60.2" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.2.tgz#ba156ed1243447a3d710972001d5dcfe3827ff3d" integrity sha512-2/w+q8jszv9Ww1c+6uJT3OwqhdmGP2/4T17cu8WuwyUuuaCDDJ2ojdyYwZzCxx0GcsZBhzi3HmH+J5pZNXnd+Q== -"@rollup/rollup-linux-loong64-musl@4.62.2": - version "4.62.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.2.tgz#6e2e44ea50310b3a582078a915e5feb879c820d4" - integrity sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ== +"@rollup/rollup-linux-loong64-musl@4.62.3": + version "4.62.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.3.tgz#a8cd0337e3ff3a0c95ead67715c51af77c5aff36" + integrity sha512-vUjxINQu3RC8NZS3ykk1gN65gIz8pAopOq2HXuZhiIxHdx7TFvDG+jgrdSgInu1Eza4/Rfi2VzZgyIgEH4WOaw== "@rollup/rollup-linux-ppc64-gnu@4.60.2": version "4.60.2" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.2.tgz#6a957a709b86ac62ef68e597ac03dbd4336782b1" integrity sha512-11+aL5vKheYgczxtPVVRhdptAM2H7fcDR5Gw4/bTcteuZBlH4oP9f5s9zYO9aGZvoGeBpqXI/9TZZihZ609wKw== -"@rollup/rollup-linux-ppc64-gnu@4.62.2": - version "4.62.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.2.tgz#6898302da6d77a0537cde64b2b4c6b60659bd110" - integrity sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A== +"@rollup/rollup-linux-ppc64-gnu@4.62.3": + version "4.62.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.3.tgz#6335cec15b55a6b063e34cb7e968515fa500ffd4" + integrity sha512-wzko4aJ13+0G3kGnviCg5gnXFKd40izKsrf2uOw12US4XqprkDrmwOpeW14aSNa37V8bfPcz5Fkob6LZ3BAPmA== "@rollup/rollup-linux-ppc64-musl@4.60.2": version "4.60.2" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.2.tgz#ca4176b4ad53f3edee3b4bfa6f9ef48ff38f167b" integrity sha512-i16fokAGK46IVZuV8LIIwMdtqhin9hfYkCh8pf8iC3QU3LpwL+1FSFGej+O7l3E/AoknL6Dclh2oTdnRMpTzFQ== -"@rollup/rollup-linux-ppc64-musl@4.62.2": - version "4.62.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.2.tgz#333717c95dd5a66bef8f63e7ef8a9fd845fd18d0" - integrity sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w== +"@rollup/rollup-linux-ppc64-musl@4.62.3": + version "4.62.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.3.tgz#cf2b6fd238f0928c5657bb8a5ca7751dfc2e6ce4" + integrity sha512-8120ue0JUMSwy11stlwnfdX3pPd+WZYGCDBwEHWtIHi6pOpZmsEF5QKB7a/UN+XFdqvobxz98kv8RTqikyCEBw== "@rollup/rollup-linux-riscv64-gnu@4.60.2": version "4.60.2" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.2.tgz#4e6b08f72ebeafdb41f3ec433bd228ba8573473b" integrity sha512-49FkKS6RGQoriDSK/6E2GkAsAuU5kETFCh7pG4yD/ylj9rKhTmO3elsnmBvRD4PgJPds5W2PkhC82aVwmUcJ7A== -"@rollup/rollup-linux-riscv64-gnu@4.62.2": - version "4.62.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.2.tgz#81bc06ba380352004d01f4826eb7cdccefa05bad" - integrity sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg== +"@rollup/rollup-linux-riscv64-gnu@4.62.3": + version "4.62.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.3.tgz#df9508c8721437f7e51990caaa61d2f38db73cbf" + integrity sha512-XLFHnR3tXMjbOCh2vtVJHmxt+995uJsTERQyseFDRA0xxMxyTZPLa3OIUlyFaO4mF/Lu0FjmWHCuPXJT1n/IOg== "@rollup/rollup-linux-riscv64-musl@4.60.2": version "4.60.2" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.2.tgz#a0b8b8580c7680c8086cb3226527e5472253b895" integrity sha512-mjYNkHPfGpUR00DuM1ZZIgs64Hpf4bWcz9Z41+4Q+pgDx73UwWdAYyf6EG/lRFldmdHHzgrYyge5akFUW0D3mQ== -"@rollup/rollup-linux-riscv64-musl@4.62.2": - version "4.62.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.2.tgz#95a7cd39de21389ad6788a5284eaaa738e29ca4c" - integrity sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q== +"@rollup/rollup-linux-riscv64-musl@4.62.3": + version "4.62.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.3.tgz#0cfe93072f4c398bb9d666e5953371a22aba7f4a" + integrity sha512-se6yXvNGMIl0f+RQzyh7XAmia8/9kplQx424wnG2w0C1oi6XgO6Y8otKhdXFHbHs88Ihavzmvh1NWjuovE76BQ== "@rollup/rollup-linux-s390x-gnu@4.60.2": version "4.60.2" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.2.tgz#79fe15b92ce0bae2b609cf26dd158cd3e2b73634" integrity sha512-ALyvJz965BQk8E9Al/JDKKDLH2kfKFLTGMlgkAbbYtZuJt9LU8DW3ZoDMCtQpXAltZxwBHevXz5u+gf0yA0YoA== -"@rollup/rollup-linux-s390x-gnu@4.62.2": - version "4.62.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.2.tgz#06e6db2ec1bc48b5374c7923ef83c2eb024b2452" - integrity sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg== +"@rollup/rollup-linux-s390x-gnu@4.62.3": + version "4.62.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.3.tgz#f8e7bdf3d419866b688b09d9348253925232d1cb" + integrity sha512-gNoxRefktVIiGflpONuxWWXZAzIQG++z9qHO3xKwk4WdDMuQja3JHGfE1u0i3PfPDyvhypdk+WrgIJqLhGG7sg== "@rollup/rollup-linux-x64-gnu@4.60.2": version "4.60.2" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.2.tgz#6aa8302fa45fd3cbbc510ccd223c9c37bf67e53f" integrity sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ== -"@rollup/rollup-linux-x64-gnu@4.62.2": - version "4.62.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz#5dc818988285e09e88790c6462def72413df2da3" - integrity sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A== +"@rollup/rollup-linux-x64-gnu@4.62.3": + version "4.62.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.3.tgz#57ef7f039c4f7de0e913f1f2680385467b86bb15" + integrity sha512-V4KtWtQfAFMU7+9/A/VDps/VI8CHd3cYz0L8sgJzz8qK7eY7wI4ruFD82UYIYvW9Z4DtlTfhQcsl4XyPHW5uSg== "@rollup/rollup-linux-x64-musl@4.60.2": version "4.60.2" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.2.tgz#0c1a5e9799f80c47a66f2c3a5f1a280f38356047" integrity sha512-bTsRGj6VlSdn/XD4CGyzMnzaBs9bsRxy79eTqTCBsA8TMIEky7qg48aPkvJvFe1HyzQ5oMZdg7AnVlWQSKLTnw== -"@rollup/rollup-linux-x64-musl@4.62.2": - version "4.62.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.2.tgz#2080f4a93349e9afd34be6fc1a37e01fc8bfc80f" - integrity sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg== +"@rollup/rollup-linux-x64-musl@4.62.3": + version "4.62.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.3.tgz#6f5b5693d4beb152bf518c487d259362dbece449" + integrity sha512-LBx9LYXvj2CBkMkjLdNAWLwH0MLMin7do2VcVo9kVPibGLkY0BQQut2fv7NVqkXqZ/CrAu9LqDHVV1xHCMpCPw== "@rollup/rollup-openbsd-x64@4.60.2": version "4.60.2" resolved "https://registry.yarnpkg.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.2.tgz#5f07c863e74fd428794f1dc5749f321b661d1f17" integrity sha512-6d4Z3534xitaA1FcMWP7mQPq5zGwBmGbhphh2DwaA1aNIXUu3KTOfwrWpbwI4/Gr0uANo7NTtaykFyO2hPuFLg== -"@rollup/rollup-openbsd-x64@4.62.2": - version "4.62.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.2.tgz#21d64a8acb66221724b923e51af5333df1af044b" - integrity sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg== +"@rollup/rollup-openbsd-x64@4.62.3": + version "4.62.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.3.tgz#9909010093ed7fb2480c73bc193a8f4d44ffb9e3" + integrity sha512-ABVf3Q0RCu7NcyCCOZQI0pJ3GuSdfSl8EXcy88QtdceIMIoCUdfhsJChZ64L9zVM2aJHjde1Bhn5uqSRcX9ySA== "@rollup/rollup-openharmony-arm64@4.60.2": version "4.60.2" resolved "https://registry.yarnpkg.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.2.tgz#8e0d71324be0f423428b12b25a2eb8ea8e0a7833" integrity sha512-NetAg5iO2uN7eB8zE5qrZ3CSil+7IJt4WDFLcC75Ymywq1VZVD6qJ6EvNLjZ3rEm6gB7XW5JdT60c6MN35Z85Q== -"@rollup/rollup-openharmony-arm64@4.62.2": - version "4.62.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.2.tgz#8e0fcd9d02141e337b4c5b5cff576cb9a76b1ba0" - integrity sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA== +"@rollup/rollup-openharmony-arm64@4.62.3": + version "4.62.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.3.tgz#aba90b57725fcf4c4072c95a6dbfbcf7500a770d" + integrity sha512-+2Cy/ldweGBLlPIKsQLF8U5N44a0KDdbrk1rAjHOM9M2K+kGdIVjHLmmrZIcx+9Ny3ke/1JomCsDI1ocb11+sg== "@rollup/rollup-win32-arm64-msvc@4.60.2": version "4.60.2" resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.2.tgz#a553fdf90a785ace6d7501eed6241c468b088999" integrity sha512-NCYhOotpgWZ5kdxCZsv6Iudx0wX8980Q/oW4pNFNihpBKsDbEA1zpkfxJGC0yugsUuyDZ7gL37dbzwhR0VI7pQ== -"@rollup/rollup-win32-arm64-msvc@4.62.2": - version "4.62.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.2.tgz#bdb4cc4efd58efe808203347f0f5463f0ea16e52" - integrity sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg== +"@rollup/rollup-win32-arm64-msvc@4.62.3": + version "4.62.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.3.tgz#12cee2b2e6d37dbb83602686812e4bba290c9aa3" + integrity sha512-dtZvzc8BedpSaFNy75x6uiWwAGTH+aZHDtdrqP6qk+WcLJrfti6sGje1ZJ9UxyzDLF23d/mV+PaMwuC0hL7UVA== "@rollup/rollup-win32-ia32-msvc@4.60.2": version "4.60.2" resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.2.tgz#0fb04f0a88027fbfd323e25a446debce4773868c" integrity sha512-RXsaOqXxfoUBQoOgvmmijVxJnW2IGB0eoMO7F8FAjaj0UTywUO/luSqimWBJn04WNgUkeNhh7fs7pESXajWmkg== -"@rollup/rollup-win32-ia32-msvc@4.62.2": - version "4.62.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.2.tgz#dbaebde5afd24eae0eefe915d901632e7cb59860" - integrity sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q== +"@rollup/rollup-win32-ia32-msvc@4.62.3": + version "4.62.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.3.tgz#391a0d6f8458a675ad720cccae9bcb9a48109016" + integrity sha512-Rj8Ra4noo+aYy7sKBggCx0407mws34kAb1ySyWuq5DAtFBQdkSwnsjCgPrhPe9cvgBKZIukpE+CVHvORCS93kQ== "@rollup/rollup-win32-x64-gnu@4.60.2": version "4.60.2" resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.2.tgz#aaa9e36dbdc0f0e397e5966dcce1b4285354ede2" integrity sha512-qdAzEULD+/hzObedtmV6iBpdL5TIbKVztGiK7O3/KYSf+HIzU257+MX1EXJcyIiDbMAqmbwaufcYPvyRryeZtA== -"@rollup/rollup-win32-x64-gnu@4.62.2": - version "4.62.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.2.tgz#84109e85fea5f8f1353499f96578fdc2a0e8b138" - integrity sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg== +"@rollup/rollup-win32-x64-gnu@4.62.3": + version "4.62.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.3.tgz#3f38bb180fcf1cfa91975c4b344941e985a6ed13" + integrity sha512-vp7N084ew/odXn2gi/mzm9mUkQu9l6AiN6dt4IeUM2Uvm9o+cVmP+YkqbMOteLbiGgqBBlJZjIMYVCfOOIVbVQ== "@rollup/rollup-win32-x64-msvc@4.60.2": version "4.60.2" resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.2.tgz#3418dcf1388f2abd6b0ccc08fe1ef205ae76d696" integrity sha512-Nd/SgG27WoA9e+/TdK74KnHz852TLa94ovOYySo/yMPuTmpckK/jIF2jSwS3g7ELSKXK13/cVdmg1Z/DaCWKxA== -"@rollup/rollup-win32-x64-msvc@4.62.2": - version "4.62.2" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz#3671ce3f9b928d5c01f879792d5c0b60ae14d4ad" - integrity sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA== +"@rollup/rollup-win32-x64-msvc@4.62.3": + version "4.62.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.3.tgz#0ccafd44a8cbcb33f7feaa9e3e85033e7a52295c" + integrity sha512-MOG/3gTOn4Fwf574RVOaY61I5o6P90legkFADiTyn1hyjNydT+cerU2rLUwPdZkKKyJ+iT+K9p7WXK4LM1Ka6g== "@rollup/wasm-node@^4.24.0": - version "4.62.2" - resolved "https://registry.yarnpkg.com/@rollup/wasm-node/-/wasm-node-4.62.2.tgz#a857f4ec4e30f29d5efd569c1f8a473ac15ee21b" - integrity sha512-LseVv64SSO6S7eyc+LFGUnH36NMMFbtKN28vTUHFinRVzFKH4cVQ/BB22JfXM9Ei5l7x46AIQp+n2QzzJ9kxHg== + version "4.62.3" + resolved "https://registry.yarnpkg.com/@rollup/wasm-node/-/wasm-node-4.62.3.tgz#a302a335e148a8a37a32bd999868396ebc3b1cb7" + integrity sha512-sEOQWamme1YgXeVcE1JkB1k44RwtPWcpYpGUW1Lso7bOj+Ay9lN2Pak/CcfNeC4xqIPNhYSabQNaWYkJJR7m8Q== dependencies: "@types/estree" "1.0.9" optionalDependencies: @@ -3051,12 +2880,12 @@ semver "~7.5.4" z-schema "~5.0.2" -"@rushstack/node-core-library@5.23.1": - version "5.23.1" - resolved "https://registry.yarnpkg.com/@rushstack/node-core-library/-/node-core-library-5.23.1.tgz#2413f1b52811cf5371812474a7006a7a8c4c4eb6" - integrity sha512-wlKmIKIYCKuCASbITvOxLZXepPbwXvrv7S6ig6XNWFchSyhL/E2txmVXspHY49Wu2dzf7nI27a2k/yV5BA3EiA== +"@rushstack/node-core-library@5.23.3": + version "5.23.3" + resolved "https://registry.yarnpkg.com/@rushstack/node-core-library/-/node-core-library-5.23.3.tgz#517384a20a48a633b4a464c34ad5c554a54320dd" + integrity sha512-f6uuza7Um65bwsIJgf0MRs7IPA5IG+A+zs1AYGQvpZmLjtTGdfHowhQw4kwF0pPhJCrU4UHNhK8Qa6tLygYZCA== dependencies: - ajv "~8.18.0" + ajv "~8.20.0" ajv-draft-04 "~1.0.0" ajv-formats "~3.0.1" fs-extra "~11.3.0" @@ -3094,12 +2923,12 @@ "@rushstack/node-core-library" "4.0.2" supports-color "~8.1.1" -"@rushstack/terminal@0.24.0": - version "0.24.0" - resolved "https://registry.yarnpkg.com/@rushstack/terminal/-/terminal-0.24.0.tgz#7abb763ea58fdeece93a3054b2c59025d56f7203" - integrity sha512-8ZQS4MMaGsv27EXCBiH7WMPkRZrffeDoIevs6z9TM5dzqiY6+Hn4evfK/G+gvgBTjfvfkHIZPQQmalmI2sM4TQ== +"@rushstack/terminal@0.24.2": + version "0.24.2" + resolved "https://registry.yarnpkg.com/@rushstack/terminal/-/terminal-0.24.2.tgz#964ad39fa85e6668fc2aba652fcb042b96134425" + integrity sha512-KB7PpvzDyKMw/RGU3TxOwxTs3OwZ4gq6+WHlTJN/JfQH4ezliNtWIqver78jTaAJyz/ZAAlJGH7a/M1WyFLFSw== dependencies: - "@rushstack/node-core-library" "5.23.1" + "@rushstack/node-core-library" "5.23.3" "@rushstack/problem-matcher" "0.2.1" supports-color "~8.1.1" @@ -3113,23 +2942,23 @@ argparse "~1.0.9" string-argv "~0.3.1" -"@rushstack/ts-command-line@5.3.10": - version "5.3.10" - resolved "https://registry.yarnpkg.com/@rushstack/ts-command-line/-/ts-command-line-5.3.10.tgz#b65bba744b4b8c6ee6a96460cd5d6111557fe253" - integrity sha512-fwI076HYknC0IrMXdY6UmjDv+PH7NHhNJX3/pY2UblSE5XrXgndXZPiOe/6ZtuFpn6DvVDVNhtkIzQ+Qu/MhVQ== +"@rushstack/ts-command-line@5.3.12": + version "5.3.12" + resolved "https://registry.yarnpkg.com/@rushstack/ts-command-line/-/ts-command-line-5.3.12.tgz#7d6dd8077ae7e38d61ae9fe5b0906dc3f6cea650" + integrity sha512-Vg2n24arSf7JvUNga2DMHYTbxnVq9L5OtVCp4Gfr8YC/kmL/bmdR8FQhGcpMzMYNY9Vdw3+TaimG11Sf+z1Tpw== dependencies: - "@rushstack/terminal" "0.24.0" + "@rushstack/terminal" "0.24.2" "@types/argparse" "1.0.38" argparse "~1.0.9" string-argv "~0.3.1" -"@schematics/angular@22.0.3": - version "22.0.3" - resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-22.0.3.tgz#16ebeaf2cf76b40278a5bf21c689deb809d3dc40" - integrity sha512-iAUqIoRcK1CCHDm5E4Q1SI7rpVtsHJ+0qv5ll72wV3C1eCNdeDuGV0lX7PXEEkwd4y//s6yqI9o7f6VZZd6Fbw== +"@schematics/angular@22.0.8": + version "22.0.8" + resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-22.0.8.tgz#6c9aefbddcc4577da37fd1fbed8dc467afe78472" + integrity sha512-zD2WLe15SoKYyBZH1GTLLaVABNNObHkH4soQqXb9agN6zkrpE0naeWaBSFSWD+95VKCiMZl8LkiOXvK+6b8S6w== dependencies: - "@angular-devkit/core" "22.0.3" - "@angular-devkit/schematics" "22.0.3" + "@angular-devkit/core" "22.0.8" + "@angular-devkit/schematics" "22.0.8" jsonc-parser "3.3.1" typescript "6.0.3" @@ -3191,11 +3020,6 @@ dependencies: "@simple-git/args-pathspec" "^1.0.3" -"@sinclair/typebox@^0.27.8": - version "0.27.10" - resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.10.tgz#beefe675f1853f73676aecc915b2bd2ac98c4fc6" - integrity sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA== - "@sindresorhus/is@^7.0.2": version "7.2.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-7.2.0.tgz#7c594e1a64336d2008d99d814056d459421504d4" @@ -3216,86 +3040,86 @@ resolved "https://registry.yarnpkg.com/@standard-schema/spec/-/spec-1.1.0.tgz#a79b55dbaf8604812f52d140b2c9ab41bc150bb8" integrity sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w== -"@swc/core-darwin-arm64@1.15.43": - version "1.15.43" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.43.tgz#386294f8427dde2df1a70dd0a5826d67af70e996" - integrity sha512-v1aVuvXdo/BHxJzco9V2xpHrvwWmhfS8t6gziY5wJxd+Z2h8AeJRnAwPD8itCDaGXVBwJ/CaKfxEzTkG0Va0OA== - -"@swc/core-darwin-x64@1.15.43": - version "1.15.43" - resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.15.43.tgz#c4823529c424e2ae25b7eb786438474741521fcb" - integrity sha512-lp3d4Lamc8dt5huYdGLSR+9hLxmfr1jb0l+4XXG2zPqZwYWRN9R0U2qYoTrggiU2RWW0oV9VbWM3kBnqIc2kdQ== - -"@swc/core-linux-arm-gnueabihf@1.15.43": - version "1.15.43" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.43.tgz#c0a0ed17cffc5d4af192935667f12f05feeb39f9" - integrity sha512-JWTQQELtsG5GgphDrr/XqqmM2pDN3cZqbMS0Mrg+iTiXL3F74sn/S2IyYE/5u4h2KLkTf9qQ7dXyxsbx7YzkeA== - -"@swc/core-linux-arm64-gnu@1.15.43": - version "1.15.43" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.43.tgz#1eb2d9c5eeee5bb9d00599b475ddc31dc2870d22" - integrity sha512-B4otJRdPWIsmiSBf0uG7Z/+vMWmkufjz5MmYxubwKuZazDW14Zd3symga1N62QR4RT+kEFeHEgsXfZGyn/w0hw== - -"@swc/core-linux-arm64-musl@1.15.43": - version "1.15.43" - resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.43.tgz#ea6b5c38088f3921a57922d3931b2d74fd23a9fd" - integrity sha512-6zB6OnpViBxYy4tgY3v2i6AZY9fwkcHZ032UOwtwUuW1d19sdT07qF0kZe6/3UR1tUaK6jjg2rmVcUIBCEYVjQ== - -"@swc/core-linux-ppc64-gnu@1.15.43": - version "1.15.43" - resolved "https://registry.yarnpkg.com/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.43.tgz#538fac30bbd5f1e678bb7bac9ccc62246a6f6d7a" - integrity sha512-coxE1ZWdB3uSDVNoEtYNrRi/1epvckZx9cTJ8ICUxTMTxGk+yvQ/Twacp3ruZSaMPGCriUjP86C37VhaT6nyRg== - -"@swc/core-linux-s390x-gnu@1.15.43": - version "1.15.43" - resolved "https://registry.yarnpkg.com/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.43.tgz#ee564b45f3f578b1fc82136c4dab163189316641" - integrity sha512-lXfLhs+LpBsD5inuYx+YDH5WsPPBQ95KPUiy8P5wq9ob9xKDZFqwNfU2QW6bGO8NqRO/H9JQomTSt5Yyh+FGfA== - -"@swc/core-linux-x64-gnu@1.15.43": - version "1.15.43" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.43.tgz#e6e3bfea76921c7f5e16d50a126615f2e04ce1c8" - integrity sha512-07XnKwTmKy8TGOZG3D9fRnLWGynxPjwQnZLVmBFbo6F+7vHYzBIOuwXEhemrChBWb6yDNZsVCcMWCPX6FDD2xg== - -"@swc/core-linux-x64-musl@1.15.43": - version "1.15.43" - resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.43.tgz#539f6f2721c0cc32e5db5cf0d453c82045f6662d" - integrity sha512-TJc+bsSIaBh+hZvZ5GRtW/K1bw66TJ9vsUwvVIsZdiWxU5ObLwZvfcnZ3UpgVfMnFibRes9uriJrQNBHEEogRQ== - -"@swc/core-win32-arm64-msvc@1.15.43": - version "1.15.43" - resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.43.tgz#b7bb6b611d484ac19d0ee21469e7012d646c28b5" - integrity sha512-jfd7s2/bUQYkOHLs+LWQNKZdmDa8+sufKLllhpWAhVQ2GDCwsHe3vR/j+OSiItZNtkzFuaawa3+SAKz9y5gYfw== - -"@swc/core-win32-ia32-msvc@1.15.43": - version "1.15.43" - resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.43.tgz#e5b25722a7d27bb0c9a9bdee7863f29c8674364e" - integrity sha512-rLAE8JvucqEW1ZGohxPQrQWPBQeJG4+ypKbWfdlU/qmKScvCkxf9/Jxnzki1dkUQCQ7P5Enp13RlvqOlvx/32g== - -"@swc/core-win32-x64-msvc@1.15.43": - version "1.15.43" - resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.43.tgz#d28842621201c345383d468d40c09648b6cd6e68" - integrity sha512-h8MLDHZcfIukwQWj03rIJZx1I0E81AYj2X7J/nGErG4nz+QAv6G1Z+peotvinL3lqpbo32tLYSMFo32/ySzxKg== +"@swc/core-darwin-arm64@1.15.46": + version "1.15.46" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.46.tgz#393903c7eda790dbd89abd8fa0afdd9041543e5f" + integrity sha512-IsISIT22EfktVJrlvIpnAxG2u/A9aob9l99HMlx80x72WlFmFPk1V3UhkEzx86eJP8hw049KTFv/RISho2cq2Q== + +"@swc/core-darwin-x64@1.15.46": + version "1.15.46" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.15.46.tgz#ddf16787e320636621180df480a3490fd9a868ca" + integrity sha512-4Tj4ppVIPCmUMpmGFiGtyEriwLyJ+yi/US4WfBrP/ok8COGddDZXLEzQETnKyK46mjvr1v0jevrS23zjoff7vA== + +"@swc/core-linux-arm-gnueabihf@1.15.46": + version "1.15.46" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.46.tgz#7bee01b7311c43b913771ef9c7012931871de73b" + integrity sha512-i8tUGnNjyOgMmfmgFSg4aeJLQoFyfpIHK5FjpQAwpRyQIqEUB2w1e8zIDQzY1WhOxx8NoS1S5iUL813Un4Sf5A== + +"@swc/core-linux-arm64-gnu@1.15.46": + version "1.15.46" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.46.tgz#964596d757d18f04a02873d85a3660416c09c187" + integrity sha512-c0OnhqzdhfOvv6qhNCcByepB+sNYOGZyhtr2Qa6ZCHvAWTYhSRw4j/u92Stue9PbZ/6q74b9nHzi76+kVzqQHQ== + +"@swc/core-linux-arm64-musl@1.15.46": + version "1.15.46" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.46.tgz#213d3ece772689a8166ed51064836346c6ce1c2a" + integrity sha512-imyRpNEcUzFQFV2LE4jL68ErvmKEuZCbvZru77iQREunJ+bR4i658cupTgtG1mLYM3F1Tzy3Sb9xYb02KghWTg== + +"@swc/core-linux-ppc64-gnu@1.15.46": + version "1.15.46" + resolved "https://registry.yarnpkg.com/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.46.tgz#4d2ec554103c6bef60cc1e294f374ea5a5edaf78" + integrity sha512-ctEfcl/HcUeomK33cbySiHZm98GEDIxTm1EkpBsYCiHxElYBzvTXVeuQT2YwbUXn9XCrjiw4ipyUNk33k26qRg== + +"@swc/core-linux-s390x-gnu@1.15.46": + version "1.15.46" + resolved "https://registry.yarnpkg.com/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.46.tgz#097a19792ec22e2f51f6bfac02da1e0b3f5e5bb1" + integrity sha512-DxlMdnt84TtRVTv7WL/thWyz9+QU8QZNNoAP9rrk0P68LziuhfePp8MjQ44zIprpTHTsEwyziIuGUUN5iSC1bQ== + +"@swc/core-linux-x64-gnu@1.15.46": + version "1.15.46" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.46.tgz#39c1ca215f9ca643a4aa3ca6250cc38ba5f5c673" + integrity sha512-SKxI7J6t90XPl8hRUqtJi9NfGdunN/E/vZMc7Bc0figeRdOPDBT+Tm8g7cx9xM0T0mewh2l+8dewa3Am27/P+A== + +"@swc/core-linux-x64-musl@1.15.46": + version "1.15.46" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.46.tgz#323a720bc965fffeedacdc3167b46a291553b5e0" + integrity sha512-qj9T6B7bosI0VEsrWOVXZN1OXxS8Tp63ywyrLxNdOycnUtLdkgYcoBsN5y8ImnDDsnwrEWZOy1e+J4xSe7mA3Q== + +"@swc/core-win32-arm64-msvc@1.15.46": + version "1.15.46" + resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.46.tgz#9c2cfd2a59be74671a018097b8914f8cfbcc698d" + integrity sha512-8p7l4c3LU+eA5g9Et1JPhNeMC1oQwXTGU+uah8DPIBX7YXzqswvaBtyKVmXefVGi/DJU1x3YJsc3mbAp9aWzSQ== + +"@swc/core-win32-ia32-msvc@1.15.46": + version "1.15.46" + resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.46.tgz#bd7bd009a47b0f9826212e7ed36385d32fe193d8" + integrity sha512-tUEnfr3Bn9u6FOjUb3PN9p+09qZC2j+wNDLKHzXXZn22rqGcUqR/ohCRSS+nG9B9+X+U+3FewNEHJkTmdIvMjQ== + +"@swc/core-win32-x64-msvc@1.15.46": + version "1.15.46" + resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.46.tgz#8371845a5bdb330cf05b009f602bb8c4636c6beb" + integrity sha512-Vux7UDzBJYQggSuPfcl2w9iu+IJpgpRCxHzgCaVkELnAXAE4XZMOTX9HNcaNiwfeIDqdu2rkr69RuDm6wY8neA== "@swc/core@^1.12.11": - version "1.15.43" - resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.15.43.tgz#653e6573968fd5c74163b9885ea0a933012c9f22" - integrity sha512-1CuKjFkPxIgGdeHVuNbkxmBxkcbdc08u0aiI43pFq6yY1tTVKmXT9hFEooyyKs/sJ3xf1GPHyEwTtk9Xl8dvQw== + version "1.15.46" + resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.15.46.tgz#8acc0f68ee55010fdc876adf2a8faf0b097c681b" + integrity sha512-Ri3em2mBpq3h2zSPliCYl63otDGqek8PPEfv2nWgRQEbZ/VBCNyypVTVQ6cEbTCXBhy+WE2T3fQb08moIyuYaw== dependencies: "@swc/counter" "^0.1.3" "@swc/types" "^0.1.27" optionalDependencies: - "@swc/core-darwin-arm64" "1.15.43" - "@swc/core-darwin-x64" "1.15.43" - "@swc/core-linux-arm-gnueabihf" "1.15.43" - "@swc/core-linux-arm64-gnu" "1.15.43" - "@swc/core-linux-arm64-musl" "1.15.43" - "@swc/core-linux-ppc64-gnu" "1.15.43" - "@swc/core-linux-s390x-gnu" "1.15.43" - "@swc/core-linux-x64-gnu" "1.15.43" - "@swc/core-linux-x64-musl" "1.15.43" - "@swc/core-win32-arm64-msvc" "1.15.43" - "@swc/core-win32-ia32-msvc" "1.15.43" - "@swc/core-win32-x64-msvc" "1.15.43" + "@swc/core-darwin-arm64" "1.15.46" + "@swc/core-darwin-x64" "1.15.46" + "@swc/core-linux-arm-gnueabihf" "1.15.46" + "@swc/core-linux-arm64-gnu" "1.15.46" + "@swc/core-linux-arm64-musl" "1.15.46" + "@swc/core-linux-ppc64-gnu" "1.15.46" + "@swc/core-linux-s390x-gnu" "1.15.46" + "@swc/core-linux-x64-gnu" "1.15.46" + "@swc/core-linux-x64-musl" "1.15.46" + "@swc/core-win32-arm64-msvc" "1.15.46" + "@swc/core-win32-ia32-msvc" "1.15.46" + "@swc/core-win32-x64-msvc" "1.15.46" "@swc/counter@^0.1.3": version "0.1.3" @@ -3338,9 +3162,9 @@ pretty-format "^27.0.2" "@testing-library/jest-dom@^6.4.2": - version "6.9.1" - resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz#7613a04e146dd2976d24ddf019730d57a89d56c2" - integrity sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA== + version "6.10.0" + resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-6.10.0.tgz#8a76841e94b72d55d09d2a34b9db9d75da9cbc08" + integrity sha512-HQwu0KaB2zyT0iLzBL+8CLyZDL3KlZlZJ+2iyc9uCUnlJVskJU/UlPuVCyIPhtukjPQdT2QNoR5nCP5FqTmmDQ== dependencies: "@adobe/css-tools" "^4.4.0" aria-query "^5.0.0" @@ -3383,7 +3207,7 @@ "@tufjs/canonical-json" "2.0.0" minimatch "^10.1.1" -"@tybys/wasm-util@^0.10.2": +"@tybys/wasm-util@^0.10.3": version "0.10.3" resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.10.3.tgz#015cba9e9dd47ce14d03d2a8c5d547bfb169665d" integrity sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg== @@ -3546,17 +3370,17 @@ eslint-visitor-keys "^3.4.3" "@ungap/structured-clone@^1.2.0": - version "1.3.2" - resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.2.tgz#a03ad82cd5676414d068ba86f880c5681194aadf" - integrity sha512-5jsZFwgR5rTdKwidH9Qmat75RKwqfpKlWWB1frDkljN127mwqBu8K0PYo7/hFpF03IEJpfVPpCQDY/eDx3iHvA== + version "1.3.3" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.3.tgz#094041e1a4cb1987f038335421281ac8be390bcc" + integrity sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg== -"@unhead/vue@^2.1.15": - version "2.1.15" - resolved "https://registry.yarnpkg.com/@unhead/vue/-/vue-2.1.15.tgz#e890da2addd5d56511b1d7edc2878562cd7bc49c" - integrity sha512-SSByXfEjhzPn8gXdEdgpYqpLMPSkLUH2HVE0GxZfOtNsJ0GgOHQs0g9T67ZZ1z0kTELLKdtOtYrzrbv9+ffF7g== +"@unhead/vue@^2.1.16": + version "2.1.16" + resolved "https://registry.yarnpkg.com/@unhead/vue/-/vue-2.1.16.tgz#2cf22116e78790fbca06d297752cd86d0e5c81a2" + integrity sha512-t6QykImeMJcrUTbFB0Coy0cB/OZItHdQFRFLoH8GAVXKWmQORGPrwvueP9me7adOCuMH2uVvrv0nCkbi6zksaA== dependencies: hookable "^6.0.1" - unhead "2.1.15" + unhead "2.1.16" "@vercel/nft@^1.5.0": version "1.10.2" @@ -3589,7 +3413,7 @@ "@rolldown/pluginutils" "1.0.0-beta.27" "@swc/core" "^1.12.11" -"@vitejs/plugin-vue-jsx@^5.1.5": +"@vitejs/plugin-vue-jsx@^5.1.6": version "5.1.6" resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue-jsx/-/plugin-vue-jsx-5.1.6.tgz#a0bdaeaf9217bf57144c4c91c29336695a47cf2a" integrity sha512-YXvi4as2clxt6DFw5+a0tTA97ntiQXm/raR8ofNj3aNwwdlVGTiG2gp7EvfZW17P50acL/9bP0ccF4XnqNmlgA== @@ -3600,175 +3424,131 @@ "@rolldown/pluginutils" "^1.0.1" "@vue/babel-plugin-jsx" "^2.0.1" -"@vitejs/plugin-vue@^6.0.7": - version "6.0.7" - resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-6.0.7.tgz#194235d364a2c601c521b0410e524e521119059f" - integrity sha512-km+p+XdSz9Sxm5rqUbqcSfZYaAniKxWBj1KURl+Jr7UaPvvX7BmaWMdP69I5rrFDeQGyxAG7NXdc57vz+snhWg== +"@vitejs/plugin-vue@^6.0.7", "@vitejs/plugin-vue@^6.0.8": + version "6.0.8" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-6.0.8.tgz#1809d090b7c93b8f4ae83d3e7536655cbbb1c793" + integrity sha512-0ZjgOg7oO6farnNGup7yvoM/YXZV84OZxHAwtflItNa/6zzQyVb5LNxyea3FEKEX2XlagIKzrlH7wwxkKgtiew== dependencies: "@rolldown/pluginutils" "^1.0.1" -"@vitest/expect@1.6.1": - version "1.6.1" - resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-1.6.1.tgz#b90c213f587514a99ac0bf84f88cff9042b0f14d" - integrity sha512-jXL+9+ZNIJKruofqXuuTClf44eSpcHlgj3CiuNihUF3Ioujtmc0zIa3UJOW5RjDK1YLBJZnWBlPuqhYycLioog== - dependencies: - "@vitest/spy" "1.6.1" - "@vitest/utils" "1.6.1" - chai "^4.3.10" - -"@vitest/expect@3.2.6": - version "3.2.6" - resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-3.2.6.tgz#dc3a617acc1f29c132ed6be15456adb75c94a7a4" - integrity sha512-1+7q9BtaKzEmO+fmNT3kYvoNn5Y71XWAx2Q5HRim4tTVRQVRv4uJFAQ5FbK0OPUeNP/WmVCpxYxoJdvuHVjzBQ== +"@vitest/expect@3.2.7": + version "3.2.7" + resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-3.2.7.tgz#70a34158383d008c3bf5d802e2643317f09df6d8" + integrity sha512-E8eBXaKibuvH2pSZErOjdVb5vF4PbKYcrnluBTYxEk1l/VhhwZg1kZQsdtjq+CsF5CFydf2Rdkz7jDHKSisi3w== dependencies: "@types/chai" "^5.2.2" - "@vitest/spy" "3.2.6" - "@vitest/utils" "3.2.6" + "@vitest/spy" "3.2.7" + "@vitest/utils" "3.2.7" chai "^5.2.0" tinyrainbow "^2.0.0" -"@vitest/expect@4.1.9": - version "4.1.9" - resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-4.1.9.tgz#ba1af73ae53262e3dc9b518cb7b76fb614e0ef53" - integrity sha512-vl/rYsUKcBr3SnQn166+XR5ZQcgMx3DQhFWdfli/cWpLnLUmbxZvyrJZotLFUryib+LtArYMSTJ5RbQ57ZqrlA== +"@vitest/expect@4.1.10": + version "4.1.10" + resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-4.1.10.tgz#799c06fc44bb0cf7e2784137b627c5cc173285d4" + integrity sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA== dependencies: "@standard-schema/spec" "^1.1.0" "@types/chai" "^5.2.2" - "@vitest/spy" "4.1.9" - "@vitest/utils" "4.1.9" + "@vitest/spy" "4.1.10" + "@vitest/utils" "4.1.10" chai "^6.2.2" tinyrainbow "^3.1.0" -"@vitest/mocker@3.2.6": - version "3.2.6" - resolved "https://registry.yarnpkg.com/@vitest/mocker/-/mocker-3.2.6.tgz#fd0f2bc2a86d82b6013b3456ad662d04a3551434" - integrity sha512-EZOrpDbkKotFAP7wPAQV1UIyoGOk4oX7ynWhBhLB7v+meMHbQhU16oPpIYGTTe4oFlhpryGpgpcZP/sin3hYuw== +"@vitest/mocker@3.2.7": + version "3.2.7" + resolved "https://registry.yarnpkg.com/@vitest/mocker/-/mocker-3.2.7.tgz#331be944cb783c642dd42bd743411aca24ea0466" + integrity sha512-Trr0hYO9CM3Wj6ksWHRhK9IZpIY6wTMO5u/MqXurMxT57sWBaOPEtP3Oq60ihZuh5JsiagKfz95OcxdEP6dBrA== dependencies: - "@vitest/spy" "3.2.6" + "@vitest/spy" "3.2.7" estree-walker "^3.0.3" magic-string "^0.30.17" -"@vitest/mocker@4.1.9": - version "4.1.9" - resolved "https://registry.yarnpkg.com/@vitest/mocker/-/mocker-4.1.9.tgz#a483de79b358aba3dd8f319a0d8ab17c89f5c75d" - integrity sha512-EVkXzBjrPGM+cK8/ANWgBrkUCfJfb38/EfTSO8h7pWvKkyPkpWxvR7BkD2MyItMF62C97zAEoqdpUixwR/e+Rw== +"@vitest/mocker@4.1.10": + version "4.1.10" + resolved "https://registry.yarnpkg.com/@vitest/mocker/-/mocker-4.1.10.tgz#2413987ab4cd7fa1c2b614b404c407bf6ad1ead1" + integrity sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow== dependencies: - "@vitest/spy" "4.1.9" + "@vitest/spy" "4.1.10" estree-walker "^3.0.3" magic-string "^0.30.21" -"@vitest/pretty-format@3.2.6", "@vitest/pretty-format@^3.2.6": - version "3.2.6" - resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-3.2.6.tgz#5d1272700abe317f24b88009337b2b5cdaa68bf6" - integrity sha512-lb7XXXzmm2h2ASzFnRvQpDo6onT1NmMJA3tkGTWiBFtRJ9lxGY3d3mm/Apt36gej2bkkOVLL/yTOtufDaFa/jA== +"@vitest/pretty-format@3.2.7", "@vitest/pretty-format@^3.2.7": + version "3.2.7" + resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-3.2.7.tgz#2a7b593f8e007e9d8ef7e7343aa30ec73fdeaf29" + integrity sha512-KUHlwqVu0sRlhCdyPdQ/wBoTfRahjUky1MubOmYw9fWfIZy1gNoHpuaaQBPAaMaVYdQYHJLurzj8ECCj5OwTqA== dependencies: tinyrainbow "^2.0.0" -"@vitest/pretty-format@4.1.9": - version "4.1.9" - resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-4.1.9.tgz#885cfe9fcb6ff3df4409ea66192cc1fb23d62fae" - integrity sha512-s0iufns3iIFitdgm+YR7g1whCAaGtXz459VS9/PqyKDEEFgYIhsHOQmXgIgDuYCt7DeQmiZT0Qe2OA2p4ZPu5A== +"@vitest/pretty-format@4.1.10": + version "4.1.10" + resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-4.1.10.tgz#75542e7273a08cc10fd4d8dad4e3eb1f16cd958c" + integrity sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q== dependencies: tinyrainbow "^3.1.0" -"@vitest/runner@1.6.1": - version "1.6.1" - resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-1.6.1.tgz#10f5857c3e376218d58c2bfacfea1161e27e117f" - integrity sha512-3nSnYXkVkf3mXFfE7vVyPmi3Sazhb/2cfZGGs0JRzFsPFvAMBEcrweV1V1GsrstdXeKCTXlJbvnQwGWgEIHmOA== - dependencies: - "@vitest/utils" "1.6.1" - p-limit "^5.0.0" - pathe "^1.1.1" - -"@vitest/runner@3.2.6": - version "3.2.6" - resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-3.2.6.tgz#6d9fb047b1430431987782e779aa889819a2e964" - integrity sha512-HYcoSj1w5tcgUnzoF0HcyaAQjpA1gj9ftUJ7iSJSuipc02jW9gKkigwZbjFldAfYHA1fa8UZVRftdMY5msWM9Q== +"@vitest/runner@3.2.7": + version "3.2.7" + resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-3.2.7.tgz#c0c080228189f1fa6cda40f59be09d746b0aca51" + integrity sha512-sB9y4ovltoQP+WaUPwmSxO9WIg9Ig694Di5PalVPsYHklAdE027mehpWF2SQSVq+k6sFgaivbTjTJwZLSHbedA== dependencies: - "@vitest/utils" "3.2.6" + "@vitest/utils" "3.2.7" pathe "^2.0.3" strip-literal "^3.0.0" -"@vitest/runner@4.1.9": - version "4.1.9" - resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-4.1.9.tgz#bb742947ce4841dfb2d8984a2f9014850be10f51" - integrity sha512-KXLMDtc7oe70+3mJfGrPUWPesswH+3sTxAMAMl8DG7I8IUQT4XW718dY5ID3vPUcmlu27CcKfY4P3h3I29SLJg== +"@vitest/runner@4.1.10": + version "4.1.10" + resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-4.1.10.tgz#febf0a21a9168421422d1955370e606feab60355" + integrity sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg== dependencies: - "@vitest/utils" "4.1.9" + "@vitest/utils" "4.1.10" pathe "^2.0.3" -"@vitest/snapshot@1.6.1": - version "1.6.1" - resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-1.6.1.tgz#90414451a634bb36cd539ccb29ae0d048a8c0479" - integrity sha512-WvidQuWAzU2p95u8GAKlRMqMyN1yOJkGHnx3M1PL9Raf7AQ1kwLKg04ADlCa3+OXUZE7BceOhVZiuWAbzCKcUQ== - dependencies: - magic-string "^0.30.5" - pathe "^1.1.1" - pretty-format "^29.7.0" - -"@vitest/snapshot@3.2.6": - version "3.2.6" - resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-3.2.6.tgz#3a9cb56389289028a511e97bbfd41d914004f3f5" - integrity sha512-H+ZjNTWGpObenh0YnlBctAPnJSI20P81PL8BPzWpx54YXLLTm8hEsWawtcYLMrwvpK48hGxLLbCS+1KRXhsKhw== +"@vitest/snapshot@3.2.7": + version "3.2.7" + resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-3.2.7.tgz#a3a7e1950ce99ec4cf02395e20ddca403b6c818e" + integrity sha512-7C+MwShwtBSI5Buwoyg3s/iY1eHL9PKAf+O1wVh/TdnjXUtkoL/9YQtre90i4MtNXM6edP1wJ2zOBpfCyhIS7g== dependencies: - "@vitest/pretty-format" "3.2.6" + "@vitest/pretty-format" "3.2.7" magic-string "^0.30.17" pathe "^2.0.3" -"@vitest/snapshot@4.1.9": - version "4.1.9" - resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-4.1.9.tgz#bdfb670ae5617613ea8776e93d0666a66defeeb7" - integrity sha512-Jc7RKGNBo8Z28WYIm0Niej4xdSPByRf6mU58VpHQkd6Zh05rlnA+twjbK5HyeIGHxrzsc3mJgS43uM0CZKzaIA== +"@vitest/snapshot@4.1.10": + version "4.1.10" + resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-4.1.10.tgz#7e3e9fec7d4d47232e493cfdcbd2170de4371c04" + integrity sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw== dependencies: - "@vitest/pretty-format" "4.1.9" - "@vitest/utils" "4.1.9" + "@vitest/pretty-format" "4.1.10" + "@vitest/utils" "4.1.10" magic-string "^0.30.21" pathe "^2.0.3" -"@vitest/spy@1.6.1": - version "1.6.1" - resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-1.6.1.tgz#33376be38a5ed1ecd829eb986edaecc3e798c95d" - integrity sha512-MGcMmpGkZebsMZhbQKkAf9CX5zGvjkBTqf8Zx3ApYWXr3wG+QvEu2eXWfnIIWYSJExIp4V9FCKDEeygzkYrXMw== - dependencies: - tinyspy "^2.2.0" - -"@vitest/spy@3.2.6": - version "3.2.6" - resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-3.2.6.tgz#c255ab84df924b28d6fbec60a37a7f693db4ea41" - integrity sha512-oq6BbH68WzcWmwtBrU9nqLeaXTR4XwJF7FSLkKEZo4i6eoXcrxjcwSuTvWBIRUTC6VC72nXYunzqgZA+IKdtxg== +"@vitest/spy@3.2.7": + version "3.2.7" + resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-3.2.7.tgz#ca7fbee44019523ca450395d9a2284ce9ece1f31" + integrity sha512-Q2eQGI6d2L/hBtZ0qNuKcAGid68XK6cv1xsoaIma6PaJhHPoqcEJhYpXZ/5myCMqkNgtP6UKuBhbc0nHKnrkuQ== dependencies: tinyspy "^4.0.3" -"@vitest/spy@4.1.9": - version "4.1.9" - resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-4.1.9.tgz#bfc40d48fb9bd1a1228bfbfde7f5555e7f6b3867" - integrity sha512-fHpsS6mIi+PiEW+vcRVOMkX1oSaPKne3VOclSFICPcGOmfKgXPU5iAah+wcNcj2xPrCCmfq99IDGf+EojhhvhA== +"@vitest/spy@4.1.10": + version "4.1.10" + resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-4.1.10.tgz#5c0bfa97b56bba9e37403c976db776ff6ab56f65" + integrity sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw== -"@vitest/utils@1.6.1": - version "1.6.1" - resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-1.6.1.tgz#6d2f36cb6d866f2bbf59da854a324d6bf8040f17" - integrity sha512-jOrrUvXM4Av9ZWiG1EajNto0u96kWAhJ1LmPmJhXXQx/32MecEKd10pOLYgS2BQx1TgkGhloPU1ArDW2vvaY6g== - dependencies: - diff-sequences "^29.6.3" - estree-walker "^3.0.3" - loupe "^2.3.7" - pretty-format "^29.7.0" - -"@vitest/utils@3.2.6": - version "3.2.6" - resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-3.2.6.tgz#6fad3368e48b7a1d058827eb9b4bbc650a3f9402" - integrity sha512-lI23nIs4bnT3T8NIoh+vFaz5s2/DdP0Jgt2jxwgWljvwn82cLJtyi/If+fjFyoLMGIOz0U/fKvWE0d4jsNQEfg== +"@vitest/utils@3.2.7": + version "3.2.7" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-3.2.7.tgz#302c8126211ac4dfea87b3b5085c098d6d22e89e" + integrity sha512-x6BDOd7dyo3PFLY3I9/HJ25X/6OurhGXk2/B9gOZNPF7XDVjeBK4k01lQE5uvDpbuheErh91qYuE1E2OEjK3Rw== dependencies: - "@vitest/pretty-format" "3.2.6" + "@vitest/pretty-format" "3.2.7" loupe "^3.1.4" tinyrainbow "^2.0.0" -"@vitest/utils@4.1.9": - version "4.1.9" - resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-4.1.9.tgz#0184c7e6eb3234739b2b6b3b985f78d1ed823ee1" - integrity sha512-A51o8ymO5PpqlWNnBP9ZHPXDIpuMtTLlGSjN7la4US+LJzoUMyhwjA5QXlm39JexgwHKW4Xjs8Z2d3dLCXOeuA== +"@vitest/utils@4.1.10": + version "4.1.10" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-4.1.10.tgz#ffc71055f18bfccb1fd0586365ebc2824892e403" + integrity sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA== dependencies: - "@vitest/pretty-format" "4.1.9" + "@vitest/pretty-format" "4.1.10" convert-source-map "^2.0.0" tinyrainbow "^3.1.0" @@ -3816,9 +3596,9 @@ path-browserify "^1.0.1" "@vue-macros/common@^3.1.1": - version "3.1.2" - resolved "https://registry.yarnpkg.com/@vue-macros/common/-/common-3.1.2.tgz#6b5f71ea219732fc955fdcfb15a95a417b87a0fe" - integrity sha512-h9t4ArDdniO9ekYHAD95t9AZcAbb19lEGK+26iAjUODOIJKmObDNBSe4+6ELQAA3vtYiFPPBtHh7+cQCKi3Dng== + version "3.1.4" + resolved "https://registry.yarnpkg.com/@vue-macros/common/-/common-3.1.4.tgz#cb56f0a84bdbfacbfa640ac34d9f805667adac8c" + integrity sha512-/5Fv+6DgIcM9ajY05ZmKBv+LMX1M9A0X+IUwDRVdt67ciw8OV9bvG2r34p3RiEadlsQybjhKPRKNXDC8Bp23cw== dependencies: "@vue/compiler-sfc" "^3.5.22" ast-kit "^2.1.2" @@ -3857,47 +3637,47 @@ "@babel/parser" "^7.28.4" "@vue/compiler-sfc" "^3.5.22" -"@vue/compiler-core@3.5.38": - version "3.5.38" - resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.5.38.tgz#fb6679d50a5de198398a1df2ce9d3a49ef8e8072" - integrity sha512-s99aGxWYig9ErHbct27KXEGhrBYlRI6c4MwAgXErOAbX9xiW37/uMa+XUDO69zLz83dng8UUZ70CTOJrLrYrEQ== +"@vue/compiler-core@3.5.40": + version "3.5.40" + resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.5.40.tgz#a3e9e280ef3dccb6de4c7707ba50d7e10fd598a5" + integrity sha512-39E8IgOhTbVDnoJFMKc2DvYnypcZwUqgUhQkccva/0m6FUwtIKSGV7n1hpVmYcFaoRAwf9pBcwnKlCEsN63ZEQ== dependencies: "@babel/parser" "^7.29.7" - "@vue/shared" "3.5.38" + "@vue/shared" "3.5.40" entities "^7.0.1" estree-walker "^2.0.2" source-map-js "^1.2.1" -"@vue/compiler-dom@3.5.38", "@vue/compiler-dom@^3.2.0", "@vue/compiler-dom@^3.3.0", "@vue/compiler-dom@^3.5.0": - version "3.5.38" - resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.5.38.tgz#10ad73a70399a4c09dedf45ff6a93d42eadc861f" - integrity sha512-JTqp25l8aFfJYF7/KmsXZjAxJz7T+SjmTJLoXVjHtc2BrSgSiW2n9Aem/cWq1OPe68A8JL06B3eVdhlP0H4TVw== +"@vue/compiler-dom@3.5.40", "@vue/compiler-dom@^3.2.0", "@vue/compiler-dom@^3.3.0", "@vue/compiler-dom@^3.5.0", "@vue/compiler-dom@^3.5.40": + version "3.5.40" + resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.5.40.tgz#ac0579d4dc257bf5e10ce324a7ce0a7f9fc5c338" + integrity sha512-pwkx4vqlqOspFstrcmzwkKLePVMD3PT65imRzLhanU2V1Fj4K13g6OXjanOyzw3aTAuRk84BOmY8f3rEHqPaVA== dependencies: - "@vue/compiler-core" "3.5.38" - "@vue/shared" "3.5.38" + "@vue/compiler-core" "3.5.40" + "@vue/shared" "3.5.40" -"@vue/compiler-sfc@3.5.38", "@vue/compiler-sfc@^3.2.0", "@vue/compiler-sfc@^3.5.22": - version "3.5.38" - resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.5.38.tgz#2b02036f89c7db0a688534a2eb0d42728c7f09c1" - integrity sha512-DuA2GiZawSEW442iw/9+Fkol8hTgb4Ke5KkhmSry65QA7YuyMbIdy8p0XZRMvNwJdgRz307W8g1CSzdvS4nuNg== +"@vue/compiler-sfc@3.5.40", "@vue/compiler-sfc@^3.2.0", "@vue/compiler-sfc@^3.5.22": + version "3.5.40" + resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.5.40.tgz#22252b2e5a58a6b6a4f71565cfa91271bddbe782" + integrity sha512-gIf497P4kpuALcvs5n3AEg1Vdn0pSY4XbjASIfHNYF1/MP3T2Mf2STERTubysBxCRxzJGJYtF/O7vwJrxFB3Vw== dependencies: "@babel/parser" "^7.29.7" - "@vue/compiler-core" "3.5.38" - "@vue/compiler-dom" "3.5.38" - "@vue/compiler-ssr" "3.5.38" - "@vue/shared" "3.5.38" + "@vue/compiler-core" "3.5.40" + "@vue/compiler-dom" "3.5.40" + "@vue/compiler-ssr" "3.5.40" + "@vue/shared" "3.5.40" estree-walker "^2.0.2" magic-string "^0.30.21" - postcss "^8.5.15" + postcss "^8.5.19" source-map-js "^1.2.1" -"@vue/compiler-ssr@3.5.38": - version "3.5.38" - resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.5.38.tgz#23975aa9643752c78c0625277ffa86f58600300d" - integrity sha512-7s+W5Gc42FGxZMcuwl8H5B29T8BJPMdBT7KHFE+BbAuZ/iTEdTtv7z2XiMjiaUUw4w3ZcCEdHs36RuYJ2VA7bA== +"@vue/compiler-ssr@3.5.40": + version "3.5.40" + resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.5.40.tgz#c8c80efd22f5d85ea775d6ead787a108dc86cd58" + integrity sha512-rrE5xiXG663+vHCHa3J9p2z5OcBRjXmoqenprJxAFQxg5pSshzeBiCE6pu46axapRJ2Adk0YDA2BRZVjiHXnhg== dependencies: - "@vue/compiler-dom" "3.5.38" - "@vue/shared" "3.5.38" + "@vue/compiler-dom" "3.5.40" + "@vue/shared" "3.5.40" "@vue/compiler-vue2@^2.7.16": version "2.7.16" @@ -3912,28 +3692,28 @@ resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.6.4.tgz#cbe97fe0162b365edc1dba80e173f90492535343" integrity sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g== -"@vue/devtools-core@^8.1.0": - version "8.1.3" - resolved "https://registry.yarnpkg.com/@vue/devtools-core/-/devtools-core-8.1.3.tgz#2148e3fd0049c4f69e439d46acc8f583cdd7f3c5" - integrity sha512-xezkv5/CPH/o5C8PE2Len9MnTJMsctYYQbKbbUiNOJpKd+fRHj27nKDb/sbtYI8NSQduegeQhCJGKRgAiOV6Uw== +"@vue/devtools-core@^8.1.1": + version "8.2.1" + resolved "https://registry.yarnpkg.com/@vue/devtools-core/-/devtools-core-8.2.1.tgz#fd7b32f26f181aa2e1bd5e2f985c3c78c4ba6274" + integrity sha512-s/VfAY9oDTb/kFEWmy461jaFde2MIV1RO/gi1vwM+PAZBZ/Pc2Ndu3BNBdZUze8QDUuyYvElbEEGA83syjJfzA== dependencies: - "@vue/devtools-kit" "^8.1.3" - "@vue/devtools-shared" "^8.1.3" + "@vue/devtools-kit" "^8.2.1" + "@vue/devtools-shared" "^8.2.1" -"@vue/devtools-kit@^8.1.0", "@vue/devtools-kit@^8.1.3": - version "8.1.3" - resolved "https://registry.yarnpkg.com/@vue/devtools-kit/-/devtools-kit-8.1.3.tgz#8e597ce34995feb3e6055d09f75bc1e5c4020f65" - integrity sha512-cRn7GXiCQkMYU2Z3h3pM4YO/ndbx9FY1yLDAqIqPLcmIq4H6zAOJHein6tvZU3AfPwgrodqLiPBEF+YQaS8AxA== +"@vue/devtools-kit@^8.1.1", "@vue/devtools-kit@^8.2.1": + version "8.2.1" + resolved "https://registry.yarnpkg.com/@vue/devtools-kit/-/devtools-kit-8.2.1.tgz#ad45babb12c51931d32d1b67ffaebc251f550ce9" + integrity sha512-FIGIuq3AWReEpbAHY/cRGeHDfI0qOb8OCQ3YjbEAX04uaxIDbGc9rhkbVcG7rnfHPXE3RsU5KrWOu9V/okd8AQ== dependencies: - "@vue/devtools-shared" "^8.1.3" + "@vue/devtools-shared" "^8.2.1" birpc "^2.6.1" hookable "^5.5.3" perfect-debounce "^2.0.0" -"@vue/devtools-shared@^8.1.3": - version "8.1.3" - resolved "https://registry.yarnpkg.com/@vue/devtools-shared/-/devtools-shared-8.1.3.tgz#cfd120013cc7a4845f4aa0c73e66cdc224794e00" - integrity sha512-CM3uIPL+v+lrJUk33+pxspYo0MhuMWlCvf7zC9fybifvCPyM2jUbYRPwoYEJgYbwRqPikm5HozbUhp60MF2QuA== +"@vue/devtools-shared@^8.2.1": + version "8.2.1" + resolved "https://registry.yarnpkg.com/@vue/devtools-shared/-/devtools-shared-8.2.1.tgz#26524e9e12fd205bcd5477cf3b5e9a17b876aeac" + integrity sha512-Fkac7lUdGReh6pVOi3AYPRGe82LQqRmAfThW7RRligOAP0ZA/Z1z9XLHDM9dv34pV2HRc79DK8uKPeG2fLnA/g== "@vue/language-core@1.8.27", "@vue/language-core@^1.8.27": version "1.8.27" @@ -3964,56 +3744,57 @@ muggle-string "^0.4.1" path-browserify "^1.0.1" -"@vue/language-core@3.3.5", "@vue/language-core@^3.2.1": - version "3.3.5" - resolved "https://registry.yarnpkg.com/@vue/language-core/-/language-core-3.3.5.tgz#7f03e2c2eb48652e925ec811b048b7a17c23cc60" - integrity sha512-UkKu5nhX89fg4VhlG/FOeI10G3cj/7radKT/cy9BT4Q9qJmJlSTAc/dP63Xqs29aypN4f39xUV6PsLNk/dcD6g== +"@vue/language-core@3.3.8", "@vue/language-core@^3.2.1": + version "3.3.8" + resolved "https://registry.yarnpkg.com/@vue/language-core/-/language-core-3.3.8.tgz#0051f7a9ac3ce900e0685d706c12666ceb0b7ad6" + integrity sha512-ieGT8jJdhhy0mGzStZhsg/qPw5bQZJg5yF+3+XU6saf4sM7yo9ZXy3h+nCwrm2+b4qS/SypkNdR2jAF3uei9tA== dependencies: "@volar/language-core" "2.4.28" "@vue/compiler-dom" "^3.5.0" "@vue/shared" "^3.5.0" - alien-signals "^3.2.0" + alien-signals "^3.2.1" muggle-string "^0.4.1" path-browserify "^1.0.1" picomatch "^4.0.4" -"@vue/reactivity@3.5.38": - version "3.5.38" - resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.5.38.tgz#71cf88b764a6d5334dd27d5ac9f029c81cd4fc34" - integrity sha512-pG6LV/NDNRbKizcUjFFLAfjaL8mcv4DmR9avNcUw2gDHBzZneuS2TWCmp633ynzxz9YYKNeEPK2I8Wraqy2HUQ== +"@vue/reactivity@3.5.40": + version "3.5.40" + resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.5.40.tgz#91379172a9e9daba6737c6931382127976c830ba" + integrity sha512-B7ot9UlUZOi1zbq61/LvE88ZLTV8IlajTdiZTAEiDQgrnIMIZoPr9kGw0Zw46ObW62O9+H/Be3kMbfb7kYPQZA== dependencies: - "@vue/shared" "3.5.38" + "@vue/shared" "3.5.40" -"@vue/runtime-core@3.5.38": - version "3.5.38" - resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.5.38.tgz#26560a876b9c0251e57f7a05f9263e623f244f9c" - integrity sha512-iyW8WVfF1CpCXxncZY5Ei6rSd6oZr5DgEom//fUjRBRl56AXPD+s9ATvukRt77ZFTuYlnVA1bxY+dJB94tWVYw== +"@vue/runtime-core@3.5.40": + version "3.5.40" + resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.5.40.tgz#abdd20bc19244154eac7bcaf5ec68e95d5d8b1bc" + integrity sha512-KAZLweuZ6uUJPK1PMSQPgBU5gCjgrrfjUhSglmU9NhH+Zjepa8cnwSydPWDWHDwOgY4g3VcZ+PljbiHlURNCbw== dependencies: - "@vue/reactivity" "3.5.38" - "@vue/shared" "3.5.38" + "@vue/reactivity" "3.5.40" + "@vue/shared" "3.5.40" -"@vue/runtime-dom@3.5.38": - version "3.5.38" - resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.5.38.tgz#7aec70bd013e43166e9ccecd4a1f096fd8ca11fb" - integrity sha512-apX2wt9sdfDshS+a2xueFZLVpt0GkRJZSoPmrW/SA4yzXTznhfcMVW59gr7h4YQeY0vJhdJkk2rsIDwgfFgC5A== +"@vue/runtime-dom@3.5.40": + version "3.5.40" + resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.5.40.tgz#ed72f072c31e7868c0c59ad5883138cd7e0d88a5" + integrity sha512-ZfrX8ssZQds900L9pr8AuK05ddnMsR4MPMZr8cPN9GoqoPWcXLhjvvbIA2SMv+7a97sJ1vv9pj/zxK0Cq/eEFQ== dependencies: - "@vue/reactivity" "3.5.38" - "@vue/runtime-core" "3.5.38" - "@vue/shared" "3.5.38" + "@vue/reactivity" "3.5.40" + "@vue/runtime-core" "3.5.40" + "@vue/shared" "3.5.40" csstype "^3.2.3" -"@vue/server-renderer@3.5.38": - version "3.5.38" - resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.5.38.tgz#5d24a5305e776a53038fc772fbd9d1205c236588" - integrity sha512-vue8vbf2QlV4quHqzwmJy6dWfmRhP1J8l4wtZg60CL6VoKqcPY2oe7may3+1d9qfpedjK5PRLFqd5k3Isj9mUw== +"@vue/server-renderer@3.5.40": + version "3.5.40" + resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.5.40.tgz#94c7ccd0bf14ec3b19047e56b86f798be6736fda" + integrity sha512-XNJym9WpevhTVt1HuwOrCRJ5Q+9z4BjTMrDtjTrvx74SmUll8spNTw6whWJa9mEkO4PKn5TihI/bm/8ds2QVJw== dependencies: - "@vue/compiler-ssr" "3.5.38" - "@vue/shared" "3.5.38" + "@vue/compiler-ssr" "3.5.40" + "@vue/runtime-dom" "3.5.40" + "@vue/shared" "3.5.40" -"@vue/shared@3.5.38", "@vue/shared@^3.3.0", "@vue/shared@^3.5.0", "@vue/shared@^3.5.22", "@vue/shared@^3.5.34": - version "3.5.38" - resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.5.38.tgz#6c4be4defd86cdc35bfa2b7dd45d7b11a5d51101" - integrity sha512-FTW0AFZNaK5/mOqvGBwVfUlNLU38TiQn4+DQgIFUnrBBJQ1crMJ82yeGQLV5jyKFsO8yRukpbuP7x+nRbH6aug== +"@vue/shared@3.5.40", "@vue/shared@^3.3.0", "@vue/shared@^3.5.0", "@vue/shared@^3.5.22", "@vue/shared@^3.5.40": + version "3.5.40" + resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.5.40.tgz#fc09d1871d66cd9b01959a597b41d7cb61f716a8" + integrity sha512-WxnBtruIqOoV3rA4jeKDWzrYI5h7Cp4+pjwDi8kWGHz+IslhiN+wguLVVhtv2l8VoU02rzDCVfDjgCl1lNpZVg== "@vue/test-utils@^2.4.1", "@vue/test-utils@^2.4.11": version "2.4.11" @@ -4068,22 +3849,15 @@ acorn-jsx@^5.3.2: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn-walk@^8.3.2: - version "8.3.5" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.5.tgz#8a6b8ca8fc5b34685af15dabb44118663c296496" - integrity sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw== - dependencies: - acorn "^8.11.0" - acorn@^7.1.1: version "7.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.11.0, acorn@^8.15.0, acorn@^8.16.0, acorn@^8.6.0, acorn@^8.9.0: - version "8.17.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.17.0.tgz#1785adb84faf8d8add10369b93826fc2bd08f1fe" - integrity sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg== +acorn@^8.15.0, acorn@^8.16.0, acorn@^8.6.0, acorn@^8.9.0: + version "8.18.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.18.0.tgz#4faf01b2d6d326bfeed97aea1f52220b5f4c1940" + integrity sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ== agent-base@9.0.0: version "9.0.0" @@ -4107,7 +3881,7 @@ ajv-formats@3.0.1, ajv-formats@^3.0.1, ajv-formats@~3.0.1: dependencies: ajv "^8.0.0" -ajv@8.20.0, ajv@^8.0.0, ajv@^8.17.1: +ajv@8.20.0, ajv@^8.0.0, ajv@^8.17.1, ajv@~8.20.0: version "8.20.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.20.0.tgz#304b3636add88ba7d936760dd50ece006dea95f9" integrity sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA== @@ -4172,7 +3946,7 @@ alien-signals@^0.4.9: resolved "https://registry.yarnpkg.com/alien-signals/-/alien-signals-0.4.14.tgz#9ff8f72a272300a51692f54bd9bbbada78fbf539" integrity sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q== -alien-signals@^3.2.0: +alien-signals@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/alien-signals/-/alien-signals-3.2.1.tgz#eb66256949bce90b7d30d055e2752e62d6930c7c" integrity sha512-I8FjmltrfnDFoZedi5CG8DghVYNhzb/Ijluz7tCSJH0xpd0484Kowhbb1XDYOxfJpU1p5wnM2X54dA+IfGyD1g== @@ -4392,11 +4166,6 @@ assert-never@^1.2.1: resolved "https://registry.yarnpkg.com/assert-never/-/assert-never-1.4.0.tgz#b0d4988628c87f35eb94716cc54422a63927e175" integrity sha512-5oJg84os6NMQNl27T9LnZkvvqzvAnHu03ShCnoj6bsJwS7L8AO4lf+C/XjK/nvzEqQB744moC6V128RucQd1jA== -assertion-error@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" - integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== - assertion-error@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7" @@ -4445,13 +4214,13 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -autoprefixer@^10.5.0: - version "10.5.0" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.5.0.tgz#33d87e443430f020a0f85319d6ff1593cb291be9" - integrity sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong== +autoprefixer@^10.5.4: + version "10.5.4" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.5.4.tgz#3b7dd848b4155514a95ad1f6ce598844bea09697" + integrity sha512-MaU0U/za7N3r6brxD4YB/l4NSrFzLPlANv6wEuQVaIPlD3L4W9rFcQPbL/EilY9BHhHvhfcz3gInDLrEtWT4EA== dependencies: - browserslist "^4.28.2" - caniuse-lite "^1.0.30001787" + browserslist "^4.28.6" + caniuse-lite "^1.0.30001806" fraction.js "^5.3.4" picocolors "^1.1.1" postcss-value-parser "^4.2.0" @@ -4491,9 +4260,9 @@ bare-events@^2.5.4, bare-events@^2.7.0: integrity sha512-Z0oHEHAFDZkffN8Qc39zNZjQlMDkPJRyyyZieU1VH7u8c5S+qHZ2S8ixdKIAxEjfHO7FJxXmJWgteOghVanIsg== bare-fs@^4.5.5: - version "4.7.2" - resolved "https://registry.yarnpkg.com/bare-fs/-/bare-fs-4.7.2.tgz#0f59b317e5bdbec6a1489b519a06a203cd3fe035" - integrity sha512-aTvMFUWkBmjzKtEQMDGGDNF8bkfpD5N1b/FCwt7A3wrU4t1o/e/85Wzkluh6JlODCjqVESYCkQCdTXqZ9G7VFg== + version "4.7.4" + resolved "https://registry.yarnpkg.com/bare-fs/-/bare-fs-4.7.4.tgz#435087d42477f067eddf3c2c746e74e9db6177bc" + integrity sha512-y1kC+ffIx/tPLdTE693uNjHfzTfr+ravR5tvWlMXe25nELbkqV400S71qHDwbkAQ1FVEZobB1NFRzFbCCcyBCQ== dependencies: bare-events "^2.5.4" bare-path "^3.0.0" @@ -4501,17 +4270,10 @@ bare-fs@^4.5.5: bare-url "^2.2.2" fast-fifo "^1.3.2" -bare-os@^3.0.1: - version "3.9.1" - resolved "https://registry.yarnpkg.com/bare-os/-/bare-os-3.9.1.tgz#660228ca7ffc47a72e96b6047cdd9d8342994e2f" - integrity sha512-6M5XjcnsygQNPMCMPXSK379xrJFiZ/AEMNBmFEmQW8d/789VQATvriyi5r0HYTL9TkQ26rn3kgdTG3aisbrXkQ== - bare-path@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/bare-path/-/bare-path-3.0.1.tgz#c12c81b527936b650e87c5d00264d59ef458082c" - integrity sha512-ghj2DSK/2e99a1anTVPCV4m4YIYtrbXhfM7V3D7XZLOTsybnYyaJloymGqssQc8l/or0UoDyRtNQkmkEF/ysgQ== - dependencies: - bare-os "^3.0.1" + version "3.1.1" + resolved "https://registry.yarnpkg.com/bare-path/-/bare-path-3.1.1.tgz#d4a207c088609b4663a7556a46a97342398bf7e2" + integrity sha512-JprUlveX3QjApC1cTpsUOiscADftCGVWkzitbHsRqv84hzYwYHw2mbluddsq5TvI8mH/8Ov1f4BiMAdcB0oYnQ== bare-stream@^2.6.4: version "2.13.3" @@ -4523,9 +4285,9 @@ bare-stream@^2.6.4: teex "^1.0.1" bare-url@^2.2.2: - version "2.4.5" - resolved "https://registry.yarnpkg.com/bare-url/-/bare-url-2.4.5.tgz#50d205f8f2724eec60fd091ba9cebd675fca63aa" - integrity sha512-K+y9xF1tN+CdPu4qWwr0QiK1Al07eFPGYK5M2pDXcmHdMdgC/tT/bpmMe1hrmRHaidKLkXrC+cRNYf3XVDUhSQ== + version "2.4.6" + resolved "https://registry.yarnpkg.com/bare-url/-/bare-url-2.4.6.tgz#628f223160e03e7a3a0a5cd761f61c6444d1729b" + integrity sha512-iQxPClE07hETVpbRoX7JXX3v/ZQViCxe/SYCxylRLzdEx1xJAufPptfiOqR8tqiCtmbtMDANKWszzjLu1PMAZQ== dependencies: bare-path "^3.0.0" @@ -4534,10 +4296,10 @@ base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== -baseline-browser-mapping@^2.10.38: - version "2.10.38" - resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.10.38.tgz#c84d093c4bf7325c5053c279d90f153c66526042" - integrity sha512-31/02mVB4yuQU6adKk5SlY6m+mxDwUq5KZkyYgnLrrKl7TEm1+3PyDtDBz2kOv/wxZz41GHsvV1A/u6RmiyBvw== +baseline-browser-mapping@^2.10.44: + version "2.11.6" + resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.11.6.tgz#56934c812026ae4fcdb039fc790a94b9a7d81d63" + integrity sha512-69D/imtToCsIcAl8WBS2YaRwA4jO/j0HhU+hELqMEu9f54MoUtI6+XH5mrKU8rEFNEk/Ui1I2MK4/JkWacclGw== beasties@0.4.2: version "0.4.2" @@ -4597,24 +4359,24 @@ boolbase@^1.0.0: integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== brace-expansion@^1.1.7: - version "1.1.15" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.15.tgz#a6d90d54067236e5f42570a3b7378d594d9b7738" - integrity sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg== + version "1.1.16" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.16.tgz#723d3a30c0558c225abc9fc479a73e14e26c3c2f" + integrity sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" brace-expansion@^2.0.1, brace-expansion@^2.0.2: - version "2.1.1" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.1.1.tgz#c68b1c4111c76aae3a6fba55d496cee10c39dad8" - integrity sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA== + version "2.1.3" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.1.3.tgz#1bf69aacdf6a4380ca17c284d9f928d4aa6401bc" + integrity sha512-DRdx5neNsG/QXbniLFWi2YmC/68oeOOmKz6zOjVk6ZS1ZLXgLIKqVEc6hWsmkjBbgii0SwaBTcJ5XKj5gzY/4A== dependencies: balanced-match "^1.0.0" -brace-expansion@^5.0.2, brace-expansion@^5.0.5: - version "5.0.6" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-5.0.6.tgz#ec68fe0a641a29d8711579caf641d05bae1f2285" - integrity sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g== +brace-expansion@^5.0.2, brace-expansion@^5.0.8: + version "5.0.8" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-5.0.8.tgz#135ad0d8d808eb18eb5e0ec9a21f3a0b92ef18cf" + integrity sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg== dependencies: balanced-match "^4.0.2" @@ -4625,15 +4387,15 @@ braces@^3.0.3, braces@~3.0.2: dependencies: fill-range "^7.1.1" -browserslist@^4.0.0, browserslist@^4.24.0, browserslist@^4.26.0, browserslist@^4.28.1, browserslist@^4.28.2: - version "4.28.4" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.28.4.tgz#dd8b8167a32845ff5f8cd6ce13f5abba16cd04c9" - integrity sha512-MTc8i/x9jBQd1iMw2CFGS+rwMa07eYjLR0CCTLDACl9xhxy+nIs3KeML/biicXtk9JrZ6dnnTatmc7ErPXIxqw== +browserslist@^4.0.0, browserslist@^4.24.0, browserslist@^4.26.0, browserslist@^4.28.1, browserslist@^4.28.2, browserslist@^4.28.6: + version "4.28.7" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.28.7.tgz#409046517fccd2e51cdc20f077454b7141184028" + integrity sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw== dependencies: - baseline-browser-mapping "^2.10.38" - caniuse-lite "^1.0.30001799" - electron-to-chromium "^1.5.376" - node-releases "^2.0.48" + baseline-browser-mapping "^2.10.44" + caniuse-lite "^1.0.30001806" + electron-to-chromium "^1.5.393" + node-releases "^2.0.51" update-browserslist-db "^1.2.3" buffer-crc32@^1.0.0: @@ -4746,23 +4508,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001787, caniuse-lite@^1.0.30001799: - version "1.0.30001799" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz#5c909138c27f1a61219d3e092071c1cc7d32dc55" - integrity sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw== - -chai@^4.3.10: - version "4.5.0" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.5.0.tgz#707e49923afdd9b13a8b0b47d33d732d13812fd8" - integrity sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw== - dependencies: - assertion-error "^1.1.0" - check-error "^1.0.3" - deep-eql "^4.1.3" - get-func-name "^2.0.2" - loupe "^2.3.6" - pathval "^1.1.1" - type-detect "^4.1.0" +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001806: + version "1.0.30001806" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz#1bc8e502b723fa393455dfbedd5ccec0c29bb74e" + integrity sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw== chai@^5.2.0: version "5.3.3" @@ -4805,13 +4554,6 @@ chardet@^2.1.1: resolved "https://registry.yarnpkg.com/chardet/-/chardet-2.2.0.tgz#005d664f2cbd4961888d2e2c32c5a69e59d8eec4" integrity sha512-rddelWYNPRrXq6PtNEN2S3f6t9ILzvqaN5pVgi4kqt9jHQaXIial9PznB5iSPVlQSLNaaH22ItWz3EJtQ10+OA== -check-error@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" - integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== - dependencies: - get-func-name "^2.0.2" - check-error@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/check-error/-/check-error-2.1.3.tgz#2427361117b70cca8dc89680ead32b157019caf5" @@ -4832,7 +4574,7 @@ chokidar@^3.4.2: optionalDependencies: fsevents "~2.3.2" -chokidar@^4.0.0, chokidar@^4.0.3: +chokidar@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.3.tgz#7be37a4c03c9aee1ecfe862a4a23b2c70c205d30" integrity sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA== @@ -4851,7 +4593,7 @@ chownr@^3.0.0: resolved "https://registry.yarnpkg.com/chownr/-/chownr-3.0.0.tgz#9855e64ecd240a9cc4267ce8a4aa5d24a1da15e4" integrity sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g== -citty@^0.1.5, citty@^0.1.6: +citty@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/citty/-/citty-0.1.6.tgz#0f7904da1ed4625e1a9ea7e0fa780981aab7c5e4" integrity sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ== @@ -5133,11 +4875,6 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3, cross-spawn@^7.0.5, cross-spawn@^7.0.6: shebang-command "^2.0.0" which "^2.0.1" -"crossws@>=0.2.0 <0.5.0": - version "0.4.6" - resolved "https://registry.yarnpkg.com/crossws/-/crossws-0.4.6.tgz#3785f451c2054ae9a21e00db5545a162d58947f8" - integrity sha512-/Wxe9Z007EbJ496j88nToZEvyPZ8PY/wjZJ18Agh/GCA9cYHyLbxtrpdFlFzAw3TV20F0SUYGl0g6PzChbwUrg== - crossws@^0.3.5: version "0.3.5" resolved "https://registry.yarnpkg.com/crossws/-/crossws-0.3.5.tgz#daad331d44148ea6500098bc858869f3a5ab81a6" @@ -5145,6 +4882,11 @@ crossws@^0.3.5: dependencies: uncrypto "^0.1.3" +crossws@^0.4.10: + version "0.4.10" + resolved "https://registry.yarnpkg.com/crossws/-/crossws-0.4.10.tgz#a94d8a5cc0c4293edc3bb976f135aa45e33e5671" + integrity sha512-pz3oubH/dt12KjqsUB0IuXW4nwRDQ583iDsP4555Cpdqx0NoU7pGlWBcayyFI8f/l/idRpgjMEfwuOxSWJYlIA== + css-declaration-sorter@^7.2.0: version "7.4.0" resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-7.4.0.tgz#9c215fbda2dcf4083bae69f125688158ae847deb" @@ -5322,6 +5064,13 @@ de-indent@^1.0.2: resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d" integrity sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg== +debug@2: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + debug@4, debug@4.4.3, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.4.0, debug@^4.4.1, debug@^4.4.3: version "4.4.3" resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" @@ -5329,7 +5078,7 @@ debug@4, debug@4.4.3, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, de dependencies: ms "^2.1.3" -debug@^3.2.7: +debug@^3.2.6, debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== @@ -5341,13 +5090,6 @@ decimal.js@^10.4.3: resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.6.0.tgz#e649a43e3ab953a72192ff5983865e509f37ed9a" integrity sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg== -deep-eql@^4.1.3: - version "4.1.4" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.4.tgz#d0d3912865911bb8fac5afb4e3acfa6a28dc72b7" - integrity sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg== - dependencies: - type-detect "^4.0.0" - deep-eql@^5.0.1: version "5.0.2" resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-5.0.2.tgz#4b756d8d770a9257300825d52a2c2cff99c3a341" @@ -5463,17 +5205,12 @@ detect-libc@^2.0.0, detect-libc@^2.0.1, detect-libc@^2.0.3: resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.1.2.tgz#689c5dcdc1900ef5583a4cb9f6d7b473742074ad" integrity sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ== -devalue@^5.8.1: - version "5.8.1" - resolved "https://registry.yarnpkg.com/devalue/-/devalue-5.8.1.tgz#f27290d3a324e2eb20c2714369b01b8ec4de4c61" - integrity sha512-4CXDYRBGqN+57wVJkuXBYmpAVUSg3L6JAQa/DFqm238G73E1wuyc/JhGQJzN7vUf/CMphYau2zXbfWzDR5aTEw== - -diff-sequences@^29.6.3: - version "29.6.3" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" - integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== +devalue@^5.8.2: + version "5.8.2" + resolved "https://registry.yarnpkg.com/devalue/-/devalue-5.8.2.tgz#b09644fa07acb1e21fe1f841e0c84e328b084196" + integrity sha512-DObPPAfdtFbXjxLqK8s2Xk9ZuWz5+ZoFEhC7J76es4GU/rEiXwHTmbImoCdyoCOcBH1UF3+Cz6Z2sYD4hyl5TA== -diff@^8.0.3, diff@~8.0.2: +diff@^8.0.4, diff@~8.0.2: version "8.0.4" resolved "https://registry.yarnpkg.com/diff/-/diff-8.0.4.tgz#4f5baf3188b9b2431117b962eb20ba330fadf696" integrity sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw== @@ -5545,9 +5282,9 @@ domutils@^3.0.1, domutils@^3.2.2: domhandler "^5.0.3" dot-prop@^10.1.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-10.1.0.tgz#91dbeb6771a9d2c31eab11ade3fdb1d83c4376c4" - integrity sha512-MVUtAugQMOff5RnBy2d9N31iG0lNwg1qAoAOn7pOK5wf94WIaE3My2p3uwTQuvS2AcqchkcR3bHByjaM0mmi7Q== + version "10.2.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-10.2.0.tgz#c2689cc5991a31b4c807f0d36af683fee333db8f" + integrity sha512-BTJ9aZYL3vCfZlZOBLy9v8TUqWGQ0pzFnygKwFZt5udj6viBoFIBviKPUoZLDCPn1FoXffv6McQFDenrm5Krfw== dependencies: type-fest "^5.0.0" @@ -5556,6 +5293,11 @@ dotenv@^17.3.1: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-17.4.2.tgz#c07e54a746e11eba021dd9e1047ced5afdc1c034" integrity sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw== +dpop@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/dpop/-/dpop-2.1.1.tgz#f132df2bdf97b8fd5f13afe14ef659d072d8d051" + integrity sha512-J0Of2JTiM4h5si0tlbPQ/lkqfZ5wAEVkKYBhkwyyANnPJfWH4VsR5uIkZ+T+OSPIwDYUg1fbd5Mmodd25HjY1w== + dunder-proto@^1.0.0, dunder-proto@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" @@ -5590,10 +5332,10 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== -electron-to-chromium@^1.5.376: - version "1.5.377" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.377.tgz#69c8fed266cdd088aa6b7ede7f06cff283bb492c" - integrity sha512-cH1jZgJHoezfTnKfKwnScpHywTFVnJUNITDPREFdhNjiuD502+QFpG0Qk7G8jhsV/f+CEAFlIrzP1fT+IMb92g== +electron-to-chromium@^1.5.393: + version "1.5.397" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.397.tgz#b376f17aefc1a6dd3b9898775a4257bd53906c2a" + integrity sha512-khGTy9U9x02KEtsKM8vx5A62BsRmcOsIgDpWr1ImE32Ax8GxHGPHZf+Eu9H8zOOyHJnB0jTbseyTHbq2XCT8yw== emoji-regex@^10.3.0: version "10.6.0" @@ -5616,9 +5358,9 @@ encodeurl@^2.0.0: integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== enhanced-resolve@^5.14.1: - version "5.24.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.24.0.tgz#cf14b9768a774cb6a5087220c0dc6e55df6ec35a" - integrity sha512-SkE2t82KlkkxQRVMVLAGKxLfORGQfrkx5dkj+vlgXRVNEdPc4eZcR+J/Fvj8C+yKSFH5L0q3NFlyufOVQnCcYQ== + version "5.24.3" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.24.3.tgz#406bbf1ec20971265a30254f08030fce6a8207fe" + integrity sha512-PwKooW9JUzh5chmYfHM3IQl5OkK2u2Nm011MgeZrss3JmFraUx/fqrf78kk8GUMYoibx/14MdwTl/1WKkG7TpQ== dependencies: graceful-fs "^4.2.4" tapable "^2.3.3" @@ -5666,9 +5408,9 @@ error-stack-parser-es@^1.0.5: integrity sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA== errx@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/errx/-/errx-0.1.0.tgz#4881e411d90a3b1e1620a07604f50081dd59f3aa" - integrity sha512-fZmsRiDNv07K6s2KkKFTiD2aIvECa7++PKyD5NC32tpRw46qZA3sOz+aM+/V9V0GDHxVTKLziveV4JhzBHDp9Q== + version "0.1.2" + resolved "https://registry.yarnpkg.com/errx/-/errx-0.1.2.tgz#cd870178afe9072700d8486af4eb3c358892f40c" + integrity sha512-chfpPHmCerdo/rXr/nNvPZRkV4WwDRwzwnsJ0Uzz3tVi8Z41tDctRjduYy1138ii77AFlts1qvWtX3g/Acg91Q== es-abstract-get@^1.0.0: version "1.0.0" @@ -5766,9 +5508,9 @@ es-get-iterator@^1.1.3: stop-iteration-iterator "^1.0.0" es-iterator-helpers@^1.2.1: - version "1.3.3" - resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.3.3.tgz#0a229dc38ada0450b8cfaa85809fd73dbb34113c" - integrity sha512-0PuBxFi+4uPanB97iDxCLWuHeYud2FALrw5HFZGtAF38UpJDbDC8frwp2cnDyae692CQ0dou60UwWfhgsa4U/g== + version "1.4.0" + resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.4.0.tgz#2b4635ee3e8db2285378a47a1ea8f8dd34adb653" + integrity sha512-c/A0P0oxkACDc+cKWw8evLXK83oBKgn0qPOqCYT4x9uolpCIJAcYvJC9QYKNDRPsTeGyCrQ326jrvgZWdCdK5Q== dependencies: call-bind "^1.0.9" call-bound "^1.0.4" @@ -5793,9 +5535,9 @@ es-module-lexer@^1.7.0: integrity sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA== es-module-lexer@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-2.1.0.tgz#1dfcbb5ea3bbfb63f28e1fc3676c3676d1c9624c" - integrity sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ== + version "2.3.1" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-2.3.1.tgz#5bf2df06999dbbe5f006a5f46a11fb9f5b7b391b" + integrity sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA== es-object-atoms@^1.0.0, es-object-atoms@^1.1.1, es-object-atoms@^1.1.2: version "1.1.2" @@ -5822,17 +5564,18 @@ es-shim-unscopables@^1.0.2, es-shim-unscopables@^1.1.0: hasown "^2.0.2" es-to-primitive@^1.3.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.3.1.tgz#abd6ef5b12d7c25bcd9eb3a7ef63e568b451ba4a" - integrity sha512-CxN9N56HYfd2m/acc/NOFrZQsN9kU4eh+2kk6A707Kz1krH8tKmfrs5RnftB8WNX80T0NS7vSQsDOlg23diR2g== + version "1.3.4" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.3.4.tgz#0c854291cf0d7b439d6b9e5771ea837ffaf1f991" + integrity sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw== dependencies: es-abstract-get "^1.0.0" + es-define-property "^1.0.1" es-errors "^1.3.0" is-callable "^1.2.7" is-date-object "^1.1.0" is-symbol "^1.1.1" -esbuild@0.28.1, esbuild@^0.28.0: +esbuild@0.28.1, "esbuild@^0.27.0 || ^0.28.0", esbuild@^0.28.0: version "0.28.1" resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.28.1.tgz#ef45b4634c9c9d97a296aea4114a5f9840f95578" integrity sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw== @@ -5925,38 +5668,6 @@ esbuild@^0.25.0: "@esbuild/win32-ia32" "0.25.12" "@esbuild/win32-x64" "0.25.12" -esbuild@^0.27.0: - version "0.27.7" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.27.7.tgz#bcadce22b2f3fd76f257e3a64f83a64986fea11f" - integrity sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w== - 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" - escalade@^3.1.1, escalade@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" @@ -5997,9 +5708,9 @@ eslint-import-resolver-node@^0.3.9: resolve "^2.0.0-next.6" eslint-module-utils@^2.12.1: - version "2.13.0" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.13.0.tgz#882beaf64927567358816bf4dc0f050fd52e0fb9" - integrity sha512-bLohSkT6469rRs8czj0tLTD8vaeIS/whvPRJVjDr7IuoTT1k5DYDERlNycjDj/HkOlvQdYurmfZ/g3fG5bgeLQ== + version "2.14.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.14.0.tgz#611f8e1c6ceb29a93eb949e1cc670b8287764819" + integrity sha512-W2WCRZ9Dqntd+2u8jJcVMV2PKulc6RdLgUUoh/yQr3uB6lo/ZOeGx11sv60/8S4QFFKNslAlWhr9u0Ef7ZW6Ig== dependencies: debug "^3.2.7" @@ -6266,9 +5977,9 @@ execa@^8.0.1: strip-final-newline "^3.0.0" expect-type@^1.2.1, expect-type@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/expect-type/-/expect-type-1.3.0.tgz#0d58ed361877a31bbc4dd6cf71bbfef7faf6bd68" - integrity sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA== + version "1.4.0" + resolved "https://registry.yarnpkg.com/expect-type/-/expect-type-1.4.0.tgz#24edf7f0cc69a44d008567ba4594ab96f3c3a3d6" + integrity sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA== exponential-backoff@^3.1.1: version "3.1.3" @@ -6276,10 +5987,11 @@ exponential-backoff@^3.1.1: integrity sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA== express-rate-limit@^8.2.1: - version "8.5.2" - resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-8.5.2.tgz#5922dbf76df2124611cea955d93432b37514b2f3" - integrity sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A== + version "8.6.1" + resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-8.6.1.tgz#e0977ec8075346e207d788383362ada7c08324ae" + integrity sha512-0D493aP61w0TJ2A0wy27riRsO7FMQ7FK+KUHOKCSfPvYo0R55aiC6emCVgFUeShH0fq0ICPVzNcgoS+BsbXQCA== dependencies: + debug "^4.4.3" ip-address "^10.2.0" express@^5.2.1: @@ -6316,10 +6028,10 @@ express@^5.2.1: type-is "^2.0.1" vary "^1.1.2" -exsolve@^1.0.8: - version "1.1.0" - resolved "https://registry.yarnpkg.com/exsolve/-/exsolve-1.1.0.tgz#adefa9b18b3f3515e946d48eb2ca3bb0f2c51b4d" - integrity sha512-D+42+T12DdIlJM3uepa55qGiL3sYdLBOxIl2ifQCzCHz4c7eiolaHsi3BIqEr7JxBzxv2pYZQX9kw16ziMcEmw== +exsolve@^1.0.8, exsolve@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/exsolve/-/exsolve-1.1.1.tgz#c055418255459b6ecde4e59de0060a3e97bc7572" + integrity sha512-9U/jZUgjnSGyntRr6y5Muu1MJcwFl6kPu7k8qLF0IMNfLqvw0NZ4nnVDq0RVoZ0RvCyumib4Ez3KYrVfilrw+g== externality@^1.0.2: version "1.0.2" @@ -6331,6 +6043,11 @@ externality@^1.0.2: pathe "^1.1.1" ufo "^1.1.2" +fake-indexeddb@^6.0.0: + version "6.2.5" + resolved "https://registry.yarnpkg.com/fake-indexeddb/-/fake-indexeddb-6.2.5.tgz#74285b6821467d6c102af092f0a4517ad5521613" + integrity sha512-CGnyrvbhPlWYMngksqrSSUT1BAVP49dZocrHuK0SvtR0D5TMs5wP0o3j7jexDJW01KSadjBp1M/71o/KR3nD1w== + fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -6362,7 +6079,7 @@ fast-levenshtein@^2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== -fast-npm-meta@^1.4.2: +fast-npm-meta@^1.5.0: version "1.5.1" resolved "https://registry.yarnpkg.com/fast-npm-meta/-/fast-npm-meta-1.5.1.tgz#02657a44d508b6989b7af56b048c118b54a8a3b4" integrity sha512-tWhw7z4jFuQgZB9tbQyUh5BY9nNd/wimM+fBLfmmJjakkJDNvbJKm0nQ5ruPKC0us1HGg7L6iBk1fxpSzcgSaA== @@ -6380,9 +6097,9 @@ fast-string-width@^3.0.2: fast-string-truncated-width "^3.0.2" fast-uri@^3.0.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.1.2.tgz#8af3d4fc9d3e71b11572cc2673b514a7d1a8c8ec" - integrity sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ== + version "3.1.4" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.1.4.tgz#3b3daf9ce68f41f956df0b505132c0cfce9ec7af" + integrity sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw== fast-wrap-ansi@^0.2.0: version "0.2.2" @@ -6465,9 +6182,9 @@ flat-cache@^3.0.4: rimraf "^3.0.2" flatted@^3.2.9: - version "3.4.2" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.4.2.tgz#f5c23c107f0f37de8dbdf24f13722b3b98d52726" - integrity sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA== + version "3.4.3" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.4.3.tgz#be5c21e943b2d7a328bb23795ae28c98f0103a9e" + integrity sha512-/zipXxyO6rGvuNGDiULY9MvEGSkb2gaG4GGH4ygMi0ZZzyMHdUZBmntJmx5x1G2VuPytCwGN4xsJP6cw+sK+vQ== for-each@^0.3.3, for-each@^0.3.5: version "0.3.5" @@ -6511,9 +6228,9 @@ fresh@^2.0.0: integrity sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A== fs-extra@~11.3.0: - version "11.3.5" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.3.5.tgz#07a44eff40bea53e719909a532f91a23bf0769ff" - integrity sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg== + version "11.3.6" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.3.6.tgz#f7cb80e9df550cd1db6f537fa5cdd568d3e70d10" + integrity sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA== dependencies: graceful-fs "^4.2.0" jsonfile "^6.0.1" @@ -6576,9 +6293,9 @@ functions-have-names@^1.2.3: integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== fuse.js@^7.4.2: - version "7.4.2" - resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-7.4.2.tgz#a0513219603f1f3f09bbba587c7b919cc3ba6294" - integrity sha512-LVbzjD4WA6UP5B1UnP8wuaXJiLnqMdM/E4fiJXTJ5haJ5b/MBNsK29h2fm6swEoQaVQjvYFWKLE2RanyZIoRVQ== + version "7.5.0" + resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-7.5.0.tgz#c591b7bddad0135b9d28d190daa9415dd754c4c7" + integrity sha512-sQtrEfA+ez/3G0cCZecF70oqpCRttCexYUG4mUrtWL49ULUzUyxokt5kyqwtKzj1270RaKih+hcP3qLcumccow== fzf@^0.5.2: version "0.5.2" @@ -6590,6 +6307,13 @@ generator-function@^2.0.0: resolved "https://registry.yarnpkg.com/generator-function/-/generator-function-2.0.1.tgz#0e75dd410d1243687a0ba2e951b94eedb8f737a2" integrity sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g== +generic-names@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/generic-names/-/generic-names-4.0.0.tgz#0bd8a2fd23fe8ea16cbd0a279acd69c06933d9a3" + integrity sha512-ySFolZQfw9FoDb3ed9d80Cm9f0+r7qj+HJkWjeD9RBfpxEVTlVhol+gvaQB/78WbwYfbnNh8nWHHBSlg072y6A== + dependencies: + loader-utils "^3.2.0" + gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -6605,11 +6329,6 @@ get-east-asian-width@^1.0.0, get-east-asian-width@^1.3.1, get-east-asian-width@^ resolved "https://registry.yarnpkg.com/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz#216900f91df11a8b2c198c3e1d93d6c035a776b9" integrity sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA== -get-func-name@^2.0.1, get-func-name@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" - integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== - get-intrinsic@^1.1.3, get-intrinsic@^1.2.2, get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.2.7, get-intrinsic@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" @@ -6654,9 +6373,9 @@ get-symbol-description@^1.1.0: get-intrinsic "^1.2.6" giget@^3.2.0, giget@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/giget/-/giget-3.3.0.tgz#b70ee7a3c162c148867a8db918ee14d01b62dab7" - integrity sha512-gzi2D96p+AMfDcmJHGDj3KJ9NRiwvlFAU5yfa3ROwWZmFUjX4P43x3BcyRaOMMLto1vUo7C+86+MFhYTl6Ryiw== + version "3.3.1" + resolved "https://registry.yarnpkg.com/giget/-/giget-3.3.1.tgz#4a4e610cd112e5dc478c6035986fdc19c76dad73" + integrity sha512-r+mvuDjrjMpsdw46Kmeydb8bdHm7wOKw8wNBtTndkjbPjgAp5oUJUxRE76wZFknxIPokfWvep2qSXK37aXE6zg== glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" @@ -6745,9 +6464,9 @@ globby@^11.0.1, globby@^11.1.0: slash "^3.0.0" globby@^16.2.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-16.2.0.tgz#6ab1351fbac1d9b9e47ed423814c2ad41af308ea" - integrity sha512-QrJia2qDf5BB/V6HYlDTs0I0lBahyjLzpGQg3KT7FnCdTonAyPy2RtY802m2k4ALx6Dp752f82WsOczEVr3l6Q== + version "16.2.2" + resolved "https://registry.yarnpkg.com/globby/-/globby-16.2.2.tgz#bc1551e571775afddc8bac6313a376ea9a2753aa" + integrity sha512-NLvV9ubZ6NDsJaOpKPy3cQeJpKi9DcWiyCiFUpJPA0YihRqiE6RWaLUmgNNPr8MgPpLZjnBjSmou7uZBRJv9wA== dependencies: "@sindresorhus/merge-streams" "^4.0.0" fast-glob "^3.3.3" @@ -6859,16 +6578,16 @@ he@^1.2.0: integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== hono@^4.11.4: - version "4.12.27" - resolved "https://registry.yarnpkg.com/hono/-/hono-4.12.27.tgz#d9527b2c6e1da331731610889d1ddaea2c1d2b40" - integrity sha512-1yrb/+w6HWQJrUCLkJ2IF5jNIPvvFkblV5RNOYl6bV+OA6p9GLcMpHFFGTosSvHvcAUibuUukRqhlYI4z32C7Q== + version "4.12.32" + resolved "https://registry.yarnpkg.com/hono/-/hono-4.12.32.tgz#9489eb5507c2b90554ee7817a3f97d9b754ee1ff" + integrity sha512-XcuyW9qE2kJn07PkecMOBd5Vq/hMy7mmGw+idz1yblbg9N17ijJODrvPkn7/dwL3Kulj8LcRJ69DLOWf91dRUg== hookable@^5.5.3: version "5.5.3" resolved "https://registry.yarnpkg.com/hookable/-/hookable-5.5.3.tgz#6cfc358984a1ef991e2518cb9ed4a778bbd3215d" integrity sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ== -hookable@^6.0.1, hookable@^6.1.0: +hookable@^6.0.1, hookable@^6.1.1: version "6.1.1" resolved "https://registry.yarnpkg.com/hookable/-/hookable-6.1.1.tgz#825f966b4b426db2e622d94d7a31a70f196f9d2f" integrity sha512-U9LYDy1CwhMCnprUfeAZWZGByVbhd54hwepegYTK7Pi5NvqEj63ifz5z+xukznehT7i6NIZRu89Ay1AZmRsLEQ== @@ -6943,9 +6662,9 @@ https-proxy-agent@^7.0.1, https-proxy-agent@^7.0.5: debug "4" httpxy@^0.5.1: - version "0.5.3" - resolved "https://registry.yarnpkg.com/httpxy/-/httpxy-0.5.3.tgz#e9d4d9b584ec3a2c5d46d7d87635419e780353aa" - integrity sha512-SMS9V6Sn7VWaS11lYhoAr0ceoaiolTWf4jYdJn0NJhCdKMu9R2H9Fh0LBDWBHQF6HRLI1PmaePYsjanSpE5PEw== + version "0.5.5" + resolved "https://registry.yarnpkg.com/httpxy/-/httpxy-0.5.5.tgz#250363163cc95858dc36233bb08bf9c98a55faba" + integrity sha512-uDjmnPyp1q4Sgzf3w+J/Fc6UqcCEj0x4Wjp7OqK5dGhNeDgpyrAmnS6ey8QWrX3SWDon2DMKf9sBa5X9+CVyMA== human-signals@^5.0.0: version "5.0.0" @@ -6964,10 +6683,17 @@ iconv-lite@0.6.3, iconv-lite@^0.6.3: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" +iconv-lite@^0.4.4: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + iconv-lite@^0.7.2, iconv-lite@~0.7.0: - version "0.7.2" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.7.2.tgz#d0bdeac3f12b4835b7359c2ad89c422a4d1cc72e" - integrity sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw== + version "0.7.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.7.3.tgz#84ee12f963e7de50bc01a13e160a078b3b0f415f" + integrity sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ== dependencies: safer-buffer ">= 2.1.2 < 3.0.0" @@ -6988,25 +6714,20 @@ ignore@^5.1.1, ignore@^5.2.0, ignore@^5.3.1: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== -ignore@^7.0.5: - version "7.0.5" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.5.tgz#4cb5f6cd7d4c7ab0365738c7aea888baa6d7efd9" - integrity sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg== +ignore@^7.0.5, ignore@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.6.tgz#6a57aaef4c90df27ac3590875d29e8f11988c88e" + integrity sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw== image-meta@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/image-meta/-/image-meta-0.2.2.tgz#a88dbdf1983d7c23a80c3e71d3b8acdb5379f5e0" integrity sha512-3MOLanc3sb3LNGWQl1RlQlNWURE5g32aUphrDyFeCsxBTk08iE3VNe4CwsUZ0Qs1X+EfX0+r29Sxdpza4B+yRA== -image-size@~0.5.0: - version "0.5.5" - resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c" - integrity sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ== - immutable@^5.1.5: - version "5.1.7" - resolved "https://registry.yarnpkg.com/immutable/-/immutable-5.1.7.tgz#46460bbe4a72078eeff5cac64208607be7dd55b3" - integrity sha512-47Xb+LFbZ/ZIjQMj6Q5J3IfK7PJFuqRdFOC9FpGgRTK6U2dAEVmkR9hp58qU4FpYux5YXpneDwkj2EP6lppzFA== + version "5.1.9" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-5.1.9.tgz#ac23c3a01992ab665e14ac9ffff298f28cd74a0c" + integrity sha512-m8nVez3rwrgmWxtLMt1ZYXB2Lv7OKYn/disyxAlSDYAlKSlFoPPfIAmAM/M5xqL4m4C/wAPw7S2/CNaUii1Hxg== import-fresh@^3.2.1: version "3.3.1" @@ -7021,10 +6742,10 @@ import-lazy@~4.0.0: resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-4.0.0.tgz#e8eb627483a0a43da3c03f3e35548be5cb0cc153" integrity sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw== -impound@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/impound/-/impound-1.1.5.tgz#ce3acc2988fde76cf5c793127b89f26270302b54" - integrity sha512-5AUn+QE0UofqNHu5f2Skf6Svukdg4ehOIq8O0EtqIx4jta0CDZYBPqpIHt0zrlUTiFVYlLpeH39DoikXBjPKpA== +impound@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/impound/-/impound-1.1.6.tgz#13a54ee66cc74223a4d40080eb0ee69780b0207b" + integrity sha512-ugavDQkE74SGrBjagNIwNVHNBxX14mmfQnTm4jFGzOoWwYsgihqV698BNr5xwRY9quKK4rEg8bc6ECltllMr+w== dependencies: "@jridgewell/trace-mapping" "^0.3.31" es-module-lexer "^2.0.0" @@ -7100,9 +6821,9 @@ ioredis@^5.10.1: standard-as-callback "2.1.0" ip-address@^10.1.1, ip-address@^10.2.0: - version "10.2.0" - resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-10.2.0.tgz#805fc178b20c518bd4c8548b24fe30892d7f3206" - integrity sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA== + version "10.3.1" + resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-10.3.1.tgz#929f9629d1724f7e1b7485ce89752f3675336a10" + integrity sha512-1e9d3kb97NHJTIJDZW9rKqW2h6+dFa50Dy0fpPSMQp2ADje5gvKsXmdiK6dwY5t76TaTt5+P5N1Y/LoToIxP6g== ipaddr.js@1.9.1: version "1.9.1" @@ -7490,9 +7211,9 @@ jju@~1.4.0: integrity sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA== jose@^6.1.3: - version "6.2.3" - resolved "https://registry.yarnpkg.com/jose/-/jose-6.2.3.tgz#0975197ad973251221c658a3cddc4b951a250c2d" - integrity sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw== + version "6.2.4" + resolved "https://registry.yarnpkg.com/jose/-/jose-6.2.4.tgz#69de7346761cd04942c659e524d988feb16a4a6e" + integrity sha512-N8acGzVsQy6M/fjFcxtysNc4Q379TcM5dM/qKkNtsHFji88yANnXTr7BLeP75iPnFwBfQzM/jg2BZ9+HZrHCZA== js-beautify@^1.14.9: version "1.15.4" @@ -7526,9 +7247,9 @@ js-tokens@^9.0.1: integrity sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ== js-yaml@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.2.0.tgz#2bd9e85682dd91bd469afb809d816043b3d49524" - integrity sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw== + version "4.3.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.3.0.tgz#d1900572a7f7cf0b5f540c83673e60bad3436592" + integrity sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q== dependencies: argparse "^2.0.1" @@ -7704,7 +7425,7 @@ kolorist@^1.8.0: resolved "https://registry.yarnpkg.com/kolorist/-/kolorist-1.8.0.tgz#edddbbbc7894bc13302cdf740af6374d4a04743c" integrity sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ== -launch-editor@^2.13.1: +launch-editor@^2.13.2: version "2.14.1" resolved "https://registry.yarnpkg.com/launch-editor/-/launch-editor-2.14.1.tgz#f7e0da3f58aaea03fea01074d840b5f739ed7ddc" integrity sha512-QWBrQsMpH7gPr965dsKD/3cKWiNoTjpATQf++Xq63N6sKRGMwlVXz41O1IZTMfZQgBctD/K5Zt06+/I6pP6+HA== @@ -7720,19 +7441,19 @@ lazystream@^1.0.0: readable-stream "^2.0.5" less@^4.2.0: - version "4.6.7" - resolved "https://registry.yarnpkg.com/less/-/less-4.6.7.tgz#15adef08189a6d06ca16876ab2de174d18e3ac59" - integrity sha512-o3UxHBPPVY1HtCXx15/z1NlknQiWyafRNbtLEv+6xFaDRI2g2xPKIH43do9dSwt8bGLTsjNSaifa48N3d6odsQ== + version "4.8.1" + resolved "https://registry.yarnpkg.com/less/-/less-4.8.1.tgz#eda5a5c92f21507da6e0f88346a76c37e3403f7b" + integrity sha512-jQ3lRIo1aUtiWVYXZ7mk4+V4BjCGswF3IxTLJ+4RUta8ZiHh8lhkig2G8dya2eCcyR1dYUvzuV46EkJN8PSwww== dependencies: copy-anything "^3.0.5" parse-node-version "^1.0.1" optionalDependencies: errno "^0.1.1" graceful-fs "^4.1.2" - image-size "~0.5.0" make-dir "^5.1.0" mime "^1.4.1" needle "^3.1.0" + probe-image-size "^7.2.3" source-map "~0.6.0" levn@^0.4.1: @@ -7743,79 +7464,79 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -lightningcss-android-arm64@1.32.0: - version "1.32.0" - resolved "https://registry.yarnpkg.com/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz#f033885116dfefd9c6f54787523e3514b61e1968" - integrity sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg== - -lightningcss-darwin-arm64@1.32.0: - version "1.32.0" - resolved "https://registry.yarnpkg.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz#50b71871b01c8199584b649e292547faea7af9b5" - integrity sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ== - -lightningcss-darwin-x64@1.32.0: - version "1.32.0" - resolved "https://registry.yarnpkg.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz#35f3e97332d130b9ca181e11b568ded6aebc6d5e" - integrity sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w== - -lightningcss-freebsd-x64@1.32.0: - version "1.32.0" - resolved "https://registry.yarnpkg.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz#9777a76472b64ed6ff94342ad64c7bafd794a575" - integrity sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig== - -lightningcss-linux-arm-gnueabihf@1.32.0: - version "1.32.0" - resolved "https://registry.yarnpkg.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz#13ae652e1ab73b9135d7b7da172f666c410ad53d" - integrity sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw== - -lightningcss-linux-arm64-gnu@1.32.0: - version "1.32.0" - resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz#417858795a94592f680123a1b1f9da8a0e1ef335" - integrity sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ== - -lightningcss-linux-arm64-musl@1.32.0: - version "1.32.0" - resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz#6be36692e810b718040802fd809623cffe732133" - integrity sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg== - -lightningcss-linux-x64-gnu@1.32.0: - version "1.32.0" - resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz#0b7803af4eb21cfd38dd39fe2abbb53c7dd091f6" - integrity sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA== - -lightningcss-linux-x64-musl@1.32.0: - version "1.32.0" - resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz#88dc8ba865ddddb1ac5ef04b0f161804418c163b" - integrity sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg== - -lightningcss-win32-arm64-msvc@1.32.0: - version "1.32.0" - resolved "https://registry.yarnpkg.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz#4f30ba3fa5e925f5b79f945e8cc0d176c3b1ab38" - integrity sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw== - -lightningcss-win32-x64-msvc@1.32.0: - version "1.32.0" - resolved "https://registry.yarnpkg.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz#141aa5605645064928902bb4af045fa7d9f4220a" - integrity sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q== +lightningcss-android-arm64@1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz#9a6841f88ae50fc83502903892b41af41bc2b907" + integrity sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg== + +lightningcss-darwin-arm64@1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz#c0f2c31c0bfd19fa4dd3f18e957a1f1a152097d6" + integrity sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg== + +lightningcss-darwin-x64@1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz#cb0705965acb538c6683949ce6925fb3cdf7c361" + integrity sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ== + +lightningcss-freebsd-x64@1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz#763538828b26bab2680dadafcc84ee78b0eb502b" + integrity sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg== + +lightningcss-linux-arm-gnueabihf@1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz#6862e3176a331aedbdec1ed352b4d7d0dd0784de" + integrity sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ== + +lightningcss-linux-arm64-gnu@1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz#c6a3a2ed15141daf6bdc2628930f8e39bdf473aa" + integrity sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg== + +lightningcss-linux-arm64-musl@1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz#7fa1334971fc82845f9827df6ef8a0b20914bac6" + integrity sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ== + +lightningcss-linux-x64-gnu@1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz#8b927862ea8c2bbc6831a46509244b50d9936e55" + integrity sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg== + +lightningcss-linux-x64-musl@1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz#0c525bb077dfd94404c059cfe42dad797e96aeaf" + integrity sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw== + +lightningcss-win32-arm64-msvc@1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz#850ee1103dac989cfab50e3ac22d1a69e394e63d" + integrity sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA== + +lightningcss-win32-x64-msvc@1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz#e343ae152eed3609dc6e11949d1a3bf39a1c946f" + integrity sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA== lightningcss@^1.32.0: - version "1.32.0" - resolved "https://registry.yarnpkg.com/lightningcss/-/lightningcss-1.32.0.tgz#b85aae96486dcb1bf49a7c8571221273f4f1e4a9" - integrity sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ== + version "1.33.0" + resolved "https://registry.yarnpkg.com/lightningcss/-/lightningcss-1.33.0.tgz#c08867d71a79385c6e190214fd72fef3e5f95f0b" + integrity sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA== dependencies: detect-libc "^2.0.3" optionalDependencies: - lightningcss-android-arm64 "1.32.0" - lightningcss-darwin-arm64 "1.32.0" - lightningcss-darwin-x64 "1.32.0" - lightningcss-freebsd-x64 "1.32.0" - lightningcss-linux-arm-gnueabihf "1.32.0" - lightningcss-linux-arm64-gnu "1.32.0" - lightningcss-linux-arm64-musl "1.32.0" - lightningcss-linux-x64-gnu "1.32.0" - lightningcss-linux-x64-musl "1.32.0" - lightningcss-win32-arm64-msvc "1.32.0" - lightningcss-win32-x64-msvc "1.32.0" + lightningcss-android-arm64 "1.33.0" + lightningcss-darwin-arm64 "1.33.0" + lightningcss-darwin-x64 "1.33.0" + lightningcss-freebsd-x64 "1.33.0" + lightningcss-linux-arm-gnueabihf "1.33.0" + lightningcss-linux-arm64-gnu "1.33.0" + lightningcss-linux-arm64-musl "1.33.0" + lightningcss-linux-x64-gnu "1.33.0" + lightningcss-linux-x64-musl "1.33.0" + lightningcss-win32-arm64-msvc "1.33.0" + lightningcss-win32-x64-msvc "1.33.0" lilconfig@^3.1.3: version "3.1.3" @@ -7839,27 +7560,25 @@ lint-staged@^15.2.2: yaml "^2.7.0" listhen@^1.10.0, listhen@^1.9.1: - version "1.10.0" - resolved "https://registry.yarnpkg.com/listhen/-/listhen-1.10.0.tgz#9dfb05614a262d87feeec284a225bbd16b3f2fa5" - integrity sha512-kfz4C0OrC6IpaVMtYDJtf6PFjurxe9NBBoDAh/o2p587INryFOO4DQ9OetbCdDrWFt1m1CJKvYrzkGsuPHw8nQ== + version "1.10.1" + resolved "https://registry.yarnpkg.com/listhen/-/listhen-1.10.1.tgz#cf4c9c1b396f906b81866f5c786405ee042ea08e" + integrity sha512-6nt/86SkqUQSLW1ofz8MxC6RhRMqOl3ONISe6qqvJ3xj09aJWQx6DhgSZpugs3PX4PXdOas/WD6A9jx6J2N19A== dependencies: - "@parcel/watcher" "^2.5.6" "@parcel/watcher-wasm" "^2.5.6" citty "^0.2.2" consola "^3.4.2" - crossws ">=0.2.0 <0.5.0" + crossws "^0.4.10" defu "^6.1.7" get-port-please "^3.2.0" h3 "^1.15.11" http-shutdown "^1.2.2" - jiti "^2.6.1" - mlly "^1.8.2" + jiti "^2.7.0" node-forge "^1.4.0" pathe "^2.0.3" - std-env "^4.1.0" - tinyclip "^0.1.12" + std-env "^4.2.0" + tinyclip "^0.1.15" ufo "^1.6.4" - untun "^0.1.3" + untun "^0.2.2" uqr "^0.1.3" listr2@10.2.1: @@ -7905,13 +7624,10 @@ lmdb@3.5.4: "@lmdb/lmdb-win32-arm64" "3.5.4" "@lmdb/lmdb-win32-x64" "3.5.4" -local-pkg@^0.5.0: - version "0.5.1" - resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-0.5.1.tgz#69658638d2a95287534d4c2fff757980100dbb6d" - integrity sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ== - dependencies: - mlly "^1.7.3" - pkg-types "^1.2.1" +loader-utils@^3.2.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-3.3.1.tgz#735b9a19fd63648ca7adbd31c2327dfe281304e5" + integrity sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg== local-pkg@^1.0.0, local-pkg@^1.1.2: version "1.2.1" @@ -7990,13 +7706,6 @@ loose-envify@^1.4.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" -loupe@^2.3.6, loupe@^2.3.7: - version "2.3.7" - resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" - integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== - dependencies: - get-func-name "^2.0.1" - loupe@^3.1.0, loupe@^3.1.4: version "3.2.1" resolved "https://registry.yarnpkg.com/loupe/-/loupe-3.2.1.tgz#0095cf56dc5b7a9a7c08ff5b1a8796ec8ad17e76" @@ -8008,9 +7717,9 @@ lru-cache@^10.2.0, lru-cache@^10.4.3: integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== lru-cache@^11.0.0, lru-cache@^11.1.0, lru-cache@^11.2.1, lru-cache@^11.2.7: - version "11.5.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.5.1.tgz#f3daa3540847b9737ebc02499ddb36765e54db4a" - integrity sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A== + version "11.5.2" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.5.2.tgz#00e16665c90c620fba14a3c368732a976493f760" + integrity sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g== lru-cache@^5.1.1: version "5.1.1" @@ -8058,13 +7767,20 @@ magic-string-ast@^1.0.2: dependencies: magic-string "^0.30.19" -magic-string@0.30.21, magic-string@^0.30.17, magic-string@^0.30.19, magic-string@^0.30.21, magic-string@^0.30.3, magic-string@^0.30.5, magic-string@^0.30.8: +magic-string@0.30.21, magic-string@^0.30.17, magic-string@^0.30.19, magic-string@^0.30.21, magic-string@^0.30.3, magic-string@^0.30.8: version "0.30.21" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.21.tgz#56763ec09a0fa8091df27879fd94d19078c00d91" integrity sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ== dependencies: "@jridgewell/sourcemap-codec" "^1.5.5" +magic-string@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-1.1.0.tgz#54a8470aabf2a04b970177f26c0308cabea74a3f" + integrity sha512-kS3VHe0nEPST2saQV4Rbkchcd3UBRkVTQHo1D3h/ZTwFDhai/mfKkmtPAtD129EOI7K3HlHIsFOt0WrI2/oU9g== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.5" + magicast@^0.5.2: version "0.5.3" resolved "https://registry.yarnpkg.com/magicast/-/magicast-0.5.3.tgz#1800f6e76dd8b0dbe7257438a2c336aefabbd905" @@ -8118,9 +7834,9 @@ mdn-data@2.27.1: integrity sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ== media-typer@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-1.1.0.tgz#6ab74b8f2d3320f2064b2a87a38e7931ff3a5561" - integrity sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw== + version "1.1.1" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-1.1.1.tgz#6f035400dfe3ab9d5607bc77546ce30cc2f9c6b8" + integrity sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ== merge-descriptors@^2.0.0: version "2.0.0" @@ -8202,11 +7918,11 @@ minimatch@10.2.3: brace-expansion "^5.0.2" minimatch@^10.0.3, minimatch@^10.1.1, minimatch@^10.2.2: - version "10.2.5" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.2.5.tgz#bd48687a0be38ed2961399105600f832095861d1" - integrity sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg== + version "10.2.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.2.6.tgz#fd956bbe0b77241e9f15ac5dccb1c638060968ef" + integrity sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A== dependencies: - brace-expansion "^5.0.5" + brace-expansion "^5.0.8" minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.5" @@ -8304,7 +8020,7 @@ mkdirp@^1.0.4: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mlly@^1.3.0, mlly@^1.7.3, mlly@^1.7.4, mlly@^1.8.0, mlly@^1.8.2: +mlly@^1.3.0, mlly@^1.7.4, mlly@^1.8.0, mlly@^1.8.2: version "1.8.2" resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.8.2.tgz#e7f7919a82d13b174405613117249a3f449d78bb" integrity sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA== @@ -8324,6 +8040,11 @@ mrmime@2.0.1, mrmime@^2.0.0: resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-2.0.1.tgz#bc3e87f7987853a54c9850eeb1f1078cd44adddc" integrity sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ== +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" @@ -8365,10 +8086,10 @@ mute-stream@^3.0.0: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-3.0.0.tgz#cd8014dd2acb72e1e91bb67c74f0019e620ba2d1" integrity sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw== -nanoid@^3.3.12: - version "3.3.15" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.15.tgz#36c490fad8c6e86c824c940dfdde999b69ed4316" - integrity sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA== +nanoid@^3.3.16: + version "3.3.16" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.16.tgz#a04d8ec4b1f10009d2d533947aefe4293737816c" + integrity sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q== nanotar@^0.3.0: version "0.3.0" @@ -8385,6 +8106,15 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== +needle@^2.5.2: + version "2.9.1" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.9.1.tgz#22d1dffbe3490c2b83e301f7709b6736cd8f2684" + integrity sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ== + dependencies: + debug "^3.2.6" + iconv-lite "^0.4.4" + sax "^1.2.4" + needle@^3.1.0: version "3.5.0" resolved "https://registry.yarnpkg.com/needle/-/needle-3.5.0.tgz#aa2023642cb41b11a11babb733fd8fa952919112" @@ -8411,9 +8141,9 @@ next-client-cookies@^1.1.1: js-cookie "^3.0.5" ng-packagr@^22.0.0: - version "22.0.0" - resolved "https://registry.yarnpkg.com/ng-packagr/-/ng-packagr-22.0.0.tgz#01fbc0d8cd2f834860e43ff6c4bd89d56238dad7" - integrity sha512-2mXzUdprkDHk4j0NVDcpkVztVwdb1b3o63vLK8YQVCJqCMvCv8BBkFjBo9f1KJmuPf+CE/xuvylhyqfzXoTTqw== + version "22.0.2" + resolved "https://registry.yarnpkg.com/ng-packagr/-/ng-packagr-22.0.2.tgz#10ca6ebd7a7548d6e9665f20c928cceb61dec729" + integrity sha512-8qQ+RWm0W3gK8Sch1kmo3EzIUiCTXIOP2gS7b+vtqCMBf4KBjBP0wFBikW5qRau9lGOzRTML0GPFGoARPR4+fw== dependencies: "@ampproject/remapping" "^2.3.0" "@rollup/plugin-json" "^6.1.0" @@ -8580,14 +8310,14 @@ node-gyp@^12.1.0: which "^6.0.0" node-mock-http@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/node-mock-http/-/node-mock-http-1.0.4.tgz#21f2ab4ce2fe4fbe8a660d7c5195a1db85e042a4" - integrity sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ== + version "1.0.5" + resolved "https://registry.yarnpkg.com/node-mock-http/-/node-mock-http-1.0.5.tgz#497bc2f3dd208e6e3f7c06cbb4a3425f899fe818" + integrity sha512-KQyt/wLjG3TAc7DOUhpqWzgd4ERxR80JOlTK5VE5R1S12IaPVN5qkj4klBce9HPG1Njuup4Sb5bljaT34lIyjw== -node-releases@^2.0.48: - version "2.0.48" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.48.tgz#4da73d040ada751fc9959d993f27de48792e3b7d" - integrity sha512-1uz8041X6LoI6ZSdZacM9lVY28vuzDlSKitnpbSNK0RfKoIJkX29NBPVEFXhnuSuEOA9Ww0xnPJ+ILWbGAv8DA== +node-releases@^2.0.51: + version "2.0.51" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.51.tgz#cdc08433577f5b32ad01694481726e22eeb54aef" + integrity sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ== nopt@^7.2.1: version "7.2.1" @@ -8615,6 +8345,11 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== +nostics@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/nostics/-/nostics-1.2.0.tgz#1362df6de2ca8456b521914501abf6c52c4d7fb5" + integrity sha512-FGqEfhQjrvo1lL8KFifdTQiNwwQHJxC1jtYE1Rc54qF/jxONUNL+kC9gS1krX8Q65PgrQ5fCqH/I4NhWBvdSqg== + npm-bundled@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-5.0.0.tgz#5025d847cfd06c7b8d9432df01695d0133d9ee80" @@ -8699,20 +8434,20 @@ nth-check@^2.0.1, nth-check@^2.1.1: boolbase "^1.0.0" nuxt@^3.12.1: - version "3.21.8" - resolved "https://registry.yarnpkg.com/nuxt/-/nuxt-3.21.8.tgz#bc5617d926822f3e606697fe7720e95a63856801" - integrity sha512-RRB/MpZhdEhb/A21qaUaSI1UYDOy9bgK0vZvRRjDsA8HGY+eFBr2EvUkdeYQHOT8WKuByxWlg5ckz3H4A+QQ1w== - dependencies: - "@dxup/nuxt" "^0.4.1" - "@nuxt/cli" "^3.35.2" - "@nuxt/devtools" "^3.2.4" - "@nuxt/kit" "3.21.8" - "@nuxt/nitro-server" "3.21.8" - "@nuxt/schema" "3.21.8" + version "3.21.10" + resolved "https://registry.yarnpkg.com/nuxt/-/nuxt-3.21.10.tgz#847f06ee46d127e60281459b9ea7802a84686440" + integrity sha512-lZZT7D/H7ZRsKjAMbIdIBcBT55t18tptdUO7FqoxuKm5MwP/EhPwGFwv0wtKBwIN7dS7/bY4u+8cSCJi98PdGQ== + dependencies: + "@dxup/nuxt" "^0.5.3" + "@nuxt/cli" "^3.37.0" + "@nuxt/devtools" "^3.3.1" + "@nuxt/kit" "3.21.10" + "@nuxt/nitro-server" "3.21.10" + "@nuxt/schema" "3.21.10" "@nuxt/telemetry" "^2.8.0" - "@nuxt/vite-builder" "3.21.8" - "@unhead/vue" "^2.1.15" - "@vue/shared" "^3.5.34" + "@nuxt/vite-builder" "3.21.10" + "@unhead/vue" "^2.1.16" + "@vue/shared" "^3.5.40" c12 "^3.3.4" chokidar "^5.0.0" compatx "^0.2.0" @@ -8720,45 +8455,45 @@ nuxt@^3.12.1: cookie-es "^2.0.1" defu "^6.1.7" destr "^2.0.5" - devalue "^5.8.1" + devalue "^5.8.2" errx "^0.1.0" escape-string-regexp "^5.0.0" - exsolve "^1.0.8" + exsolve "^1.1.0" h3 "^1.15.11" hookable "^5.5.3" - ignore "^7.0.5" - impound "^1.1.5" + ignore "^7.0.6" + impound "^1.1.6" jiti "^2.7.0" klona "^2.0.6" knitwork "^1.3.0" magic-string "^0.30.21" mlly "^1.8.2" nanotar "^0.3.0" - nypm "^0.6.6" + nypm "^0.6.8" ofetch "^1.5.1" ohash "^2.0.11" on-change "^6.0.2" - oxc-minify "^0.132.0" - oxc-parser "^0.132.0" - oxc-transform "^0.132.0" + oxc-minify "^0.141.0" + oxc-parser "^0.140.0" + oxc-transform "^0.141.0" oxc-walker "^1.0.0" pathe "^2.0.3" perfect-debounce "^2.1.0" pkg-types "^2.3.1" - rou3 "^0.8.1" + rou3 "^0.9.1" scule "^1.3.0" - semver "^7.8.0" - std-env "^4.1.0" - tinyglobby "^0.2.16" + semver "^7.8.5" + std-env "^4.2.0" + tinyglobby "^0.2.17" ufo "^1.6.4" - ultrahtml "^1.6.0" + ultrahtml "^1.7.0" uncrypto "^0.1.3" unctx "^2.5.0" - unimport "^6.3.0" - unplugin "^3.0.0" + unimport "^6.3.1" + unplugin "^3.3.0" unplugin-vue-router "^0.19.2" untyped "^2.0.0" - vue "^3.5.34" + vue "^3.5.40" vue-router "^4.6.4" nwsapi@^2.2.12: @@ -8766,10 +8501,10 @@ nwsapi@^2.2.12: resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.24.tgz#f8927043d4c9b516abdebe804a32c8d1f9484d1f" integrity sha512-7YRhZ3jS45LwmSCT4b2sVFHt/WuovaktDU07QrtOBY2PXskss5a9jfmR9jptyumwXST+rFjrmppMY1KT/yn35A== -nypm@^0.6.5, nypm@^0.6.6, nypm@^0.6.7: - version "0.6.7" - resolved "https://registry.yarnpkg.com/nypm/-/nypm-0.6.7.tgz#d460433647e6d3aa6397204ea9a984f5f82a599f" - integrity sha512-s3ds97SD5pd1dULE+tHUk1DrV0cSHOnsfpcdGATJ8JpBo21DoKqN9exTH4/2nhPQNOLomBdTFMicN94S4DrZrQ== +nypm@^0.6.6, nypm@^0.6.8: + version "0.6.9" + resolved "https://registry.yarnpkg.com/nypm/-/nypm-0.6.9.tgz#d7c2a2dffd94e1ca0349c721d73d6b776e22899c" + integrity sha512-zxlE2yvSWZWmHcNdT3+5zV2lrCogeE9YOklHrR3dFjqutq5wO7GFDYLFDRXLsYnJzwvy/im9fYoxePvS0VTW0w== dependencies: citty "^0.2.2" pathe "^2.0.3" @@ -8850,9 +8585,9 @@ object.values@^1.1.6, object.values@^1.2.1: es-object-atoms "^1.0.0" obug@^2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/obug/-/obug-2.1.3.tgz#c02c60f95abd603409330e767db7f2823193331e" - integrity sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg== + version "2.1.4" + resolved "https://registry.yarnpkg.com/obug/-/obug-2.1.4.tgz#9090d8a548a522517915d2aa6aae907197ac6cf8" + integrity sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA== ofetch@^1.5.1: version "1.5.1" @@ -8964,93 +8699,94 @@ ordered-binary@^1.5.3: integrity sha512-QkCdPooczexPLiXIrbVOPYkR3VO3T6v2OyKRkR1Xbhpy7/LAVXwahnRCgRp78Oe/Ehf0C/HATAxfSr6eA1oX+w== own-keys@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/own-keys/-/own-keys-1.0.1.tgz#e4006910a2bf913585289676eebd6f390cf51358" - integrity sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg== + version "1.0.2" + resolved "https://registry.yarnpkg.com/own-keys/-/own-keys-1.0.2.tgz#31448ec1f781ecb1447f6f6aa0d6534222af59de" + integrity sha512-19YVAg7T+WTrxggPukVq7DjTv6+PJ867TmhCvBsYwmbFCsZd344rq2Ld1p0wo8f8Qrrhgp82c6FJRqdXWtSEhg== dependencies: - get-intrinsic "^1.2.6" + call-bound "^1.0.4" + get-intrinsic "^1.3.0" object-keys "^1.1.1" safe-push-apply "^1.0.0" -oxc-minify@^0.132.0: - version "0.132.0" - resolved "https://registry.yarnpkg.com/oxc-minify/-/oxc-minify-0.132.0.tgz#e85778854443cbef67c0acd4ec754eb994d00934" - integrity sha512-7h3fOlgDwkIYxxKfGwCNejaLhH90Pvx+fttdPN7nRbWHxm6QSYcxW3IKjfxQVUeg+z1X2HZdOSY3rHkVqgxH1g== +oxc-minify@^0.141.0: + version "0.141.0" + resolved "https://registry.yarnpkg.com/oxc-minify/-/oxc-minify-0.141.0.tgz#08b9fc2eabc4656c32184a78c546b2c3d7438db0" + integrity sha512-+T/r+nBaKTT7UL5WDZHH8+l0bz+IZ495jHXiY2J6DWYkJXKrBCQRBS+u+hmlnhRfC5b0Uq1poZs0FLVMiDAmbw== optionalDependencies: - "@oxc-minify/binding-android-arm-eabi" "0.132.0" - "@oxc-minify/binding-android-arm64" "0.132.0" - "@oxc-minify/binding-darwin-arm64" "0.132.0" - "@oxc-minify/binding-darwin-x64" "0.132.0" - "@oxc-minify/binding-freebsd-x64" "0.132.0" - "@oxc-minify/binding-linux-arm-gnueabihf" "0.132.0" - "@oxc-minify/binding-linux-arm-musleabihf" "0.132.0" - "@oxc-minify/binding-linux-arm64-gnu" "0.132.0" - "@oxc-minify/binding-linux-arm64-musl" "0.132.0" - "@oxc-minify/binding-linux-ppc64-gnu" "0.132.0" - "@oxc-minify/binding-linux-riscv64-gnu" "0.132.0" - "@oxc-minify/binding-linux-riscv64-musl" "0.132.0" - "@oxc-minify/binding-linux-s390x-gnu" "0.132.0" - "@oxc-minify/binding-linux-x64-gnu" "0.132.0" - "@oxc-minify/binding-linux-x64-musl" "0.132.0" - "@oxc-minify/binding-openharmony-arm64" "0.132.0" - "@oxc-minify/binding-wasm32-wasi" "0.132.0" - "@oxc-minify/binding-win32-arm64-msvc" "0.132.0" - "@oxc-minify/binding-win32-ia32-msvc" "0.132.0" - "@oxc-minify/binding-win32-x64-msvc" "0.132.0" - -oxc-parser@^0.132.0: - version "0.132.0" - resolved "https://registry.yarnpkg.com/oxc-parser/-/oxc-parser-0.132.0.tgz#4f0ffad5ccfd0235a8ba79f7e6fc988be6f45476" - integrity sha512-+0LAPHaqtfQlvWdpaAa09SmOaZZgP8C552xosEkGJ4+ruEwP1Vgx+sqBgcBCNfR6KDCmagGOZTde8wmAvcI/Hg== - dependencies: - "@oxc-project/types" "^0.132.0" + "@oxc-minify/binding-android-arm-eabi" "0.141.0" + "@oxc-minify/binding-android-arm64" "0.141.0" + "@oxc-minify/binding-darwin-arm64" "0.141.0" + "@oxc-minify/binding-darwin-x64" "0.141.0" + "@oxc-minify/binding-freebsd-x64" "0.141.0" + "@oxc-minify/binding-linux-arm-gnueabihf" "0.141.0" + "@oxc-minify/binding-linux-arm-musleabihf" "0.141.0" + "@oxc-minify/binding-linux-arm64-gnu" "0.141.0" + "@oxc-minify/binding-linux-arm64-musl" "0.141.0" + "@oxc-minify/binding-linux-ppc64-gnu" "0.141.0" + "@oxc-minify/binding-linux-riscv64-gnu" "0.141.0" + "@oxc-minify/binding-linux-riscv64-musl" "0.141.0" + "@oxc-minify/binding-linux-s390x-gnu" "0.141.0" + "@oxc-minify/binding-linux-x64-gnu" "0.141.0" + "@oxc-minify/binding-linux-x64-musl" "0.141.0" + "@oxc-minify/binding-openharmony-arm64" "0.141.0" + "@oxc-minify/binding-wasm32-wasi" "0.141.0" + "@oxc-minify/binding-win32-arm64-msvc" "0.141.0" + "@oxc-minify/binding-win32-ia32-msvc" "0.141.0" + "@oxc-minify/binding-win32-x64-msvc" "0.141.0" + +oxc-parser@^0.140.0: + version "0.140.0" + resolved "https://registry.yarnpkg.com/oxc-parser/-/oxc-parser-0.140.0.tgz#71a7219cd9e18caa06782a276336b5835d38fc3a" + integrity sha512-h6QFWd6lBMfjESqgQ27GjzrSDb0qbznp7VDQqp2zvgsrWut4vcchyMIzOVXvGQ2GMZgKw9RWrFNWv9WqGL0p7Q== + dependencies: + "@oxc-project/types" "^0.140.0" optionalDependencies: - "@oxc-parser/binding-android-arm-eabi" "0.132.0" - "@oxc-parser/binding-android-arm64" "0.132.0" - "@oxc-parser/binding-darwin-arm64" "0.132.0" - "@oxc-parser/binding-darwin-x64" "0.132.0" - "@oxc-parser/binding-freebsd-x64" "0.132.0" - "@oxc-parser/binding-linux-arm-gnueabihf" "0.132.0" - "@oxc-parser/binding-linux-arm-musleabihf" "0.132.0" - "@oxc-parser/binding-linux-arm64-gnu" "0.132.0" - "@oxc-parser/binding-linux-arm64-musl" "0.132.0" - "@oxc-parser/binding-linux-ppc64-gnu" "0.132.0" - "@oxc-parser/binding-linux-riscv64-gnu" "0.132.0" - "@oxc-parser/binding-linux-riscv64-musl" "0.132.0" - "@oxc-parser/binding-linux-s390x-gnu" "0.132.0" - "@oxc-parser/binding-linux-x64-gnu" "0.132.0" - "@oxc-parser/binding-linux-x64-musl" "0.132.0" - "@oxc-parser/binding-openharmony-arm64" "0.132.0" - "@oxc-parser/binding-wasm32-wasi" "0.132.0" - "@oxc-parser/binding-win32-arm64-msvc" "0.132.0" - "@oxc-parser/binding-win32-ia32-msvc" "0.132.0" - "@oxc-parser/binding-win32-x64-msvc" "0.132.0" - -oxc-transform@^0.132.0: - version "0.132.0" - resolved "https://registry.yarnpkg.com/oxc-transform/-/oxc-transform-0.132.0.tgz#34b275dedabf1af41445085284a8be8b1431b8ab" - integrity sha512-DmP0+4kzpXoMvv08qPCD4aI6mAIzrEq15Yt9e6wXCNtOz6jEDHPpueusDa2/pvjRAqtNV37YxUUeX7cfCI4dpA== + "@oxc-parser/binding-android-arm-eabi" "0.140.0" + "@oxc-parser/binding-android-arm64" "0.140.0" + "@oxc-parser/binding-darwin-arm64" "0.140.0" + "@oxc-parser/binding-darwin-x64" "0.140.0" + "@oxc-parser/binding-freebsd-x64" "0.140.0" + "@oxc-parser/binding-linux-arm-gnueabihf" "0.140.0" + "@oxc-parser/binding-linux-arm-musleabihf" "0.140.0" + "@oxc-parser/binding-linux-arm64-gnu" "0.140.0" + "@oxc-parser/binding-linux-arm64-musl" "0.140.0" + "@oxc-parser/binding-linux-ppc64-gnu" "0.140.0" + "@oxc-parser/binding-linux-riscv64-gnu" "0.140.0" + "@oxc-parser/binding-linux-riscv64-musl" "0.140.0" + "@oxc-parser/binding-linux-s390x-gnu" "0.140.0" + "@oxc-parser/binding-linux-x64-gnu" "0.140.0" + "@oxc-parser/binding-linux-x64-musl" "0.140.0" + "@oxc-parser/binding-openharmony-arm64" "0.140.0" + "@oxc-parser/binding-wasm32-wasi" "0.140.0" + "@oxc-parser/binding-win32-arm64-msvc" "0.140.0" + "@oxc-parser/binding-win32-ia32-msvc" "0.140.0" + "@oxc-parser/binding-win32-x64-msvc" "0.140.0" + +oxc-transform@^0.141.0: + version "0.141.0" + resolved "https://registry.yarnpkg.com/oxc-transform/-/oxc-transform-0.141.0.tgz#d5442d40b064826de2cb1d0bd4f0434d2ecffa96" + integrity sha512-CrMPblXfPl57WIvGjynrUThcyEGcS3E3YUHkPYAwXYYla23gLlaIYifVFTMQsFr5uxA/2k/XMG5n6c/XsuAvaQ== optionalDependencies: - "@oxc-transform/binding-android-arm-eabi" "0.132.0" - "@oxc-transform/binding-android-arm64" "0.132.0" - "@oxc-transform/binding-darwin-arm64" "0.132.0" - "@oxc-transform/binding-darwin-x64" "0.132.0" - "@oxc-transform/binding-freebsd-x64" "0.132.0" - "@oxc-transform/binding-linux-arm-gnueabihf" "0.132.0" - "@oxc-transform/binding-linux-arm-musleabihf" "0.132.0" - "@oxc-transform/binding-linux-arm64-gnu" "0.132.0" - "@oxc-transform/binding-linux-arm64-musl" "0.132.0" - "@oxc-transform/binding-linux-ppc64-gnu" "0.132.0" - "@oxc-transform/binding-linux-riscv64-gnu" "0.132.0" - "@oxc-transform/binding-linux-riscv64-musl" "0.132.0" - "@oxc-transform/binding-linux-s390x-gnu" "0.132.0" - "@oxc-transform/binding-linux-x64-gnu" "0.132.0" - "@oxc-transform/binding-linux-x64-musl" "0.132.0" - "@oxc-transform/binding-openharmony-arm64" "0.132.0" - "@oxc-transform/binding-wasm32-wasi" "0.132.0" - "@oxc-transform/binding-win32-arm64-msvc" "0.132.0" - "@oxc-transform/binding-win32-ia32-msvc" "0.132.0" - "@oxc-transform/binding-win32-x64-msvc" "0.132.0" + "@oxc-transform/binding-android-arm-eabi" "0.141.0" + "@oxc-transform/binding-android-arm64" "0.141.0" + "@oxc-transform/binding-darwin-arm64" "0.141.0" + "@oxc-transform/binding-darwin-x64" "0.141.0" + "@oxc-transform/binding-freebsd-x64" "0.141.0" + "@oxc-transform/binding-linux-arm-gnueabihf" "0.141.0" + "@oxc-transform/binding-linux-arm-musleabihf" "0.141.0" + "@oxc-transform/binding-linux-arm64-gnu" "0.141.0" + "@oxc-transform/binding-linux-arm64-musl" "0.141.0" + "@oxc-transform/binding-linux-ppc64-gnu" "0.141.0" + "@oxc-transform/binding-linux-riscv64-gnu" "0.141.0" + "@oxc-transform/binding-linux-riscv64-musl" "0.141.0" + "@oxc-transform/binding-linux-s390x-gnu" "0.141.0" + "@oxc-transform/binding-linux-x64-gnu" "0.141.0" + "@oxc-transform/binding-linux-x64-musl" "0.141.0" + "@oxc-transform/binding-openharmony-arm64" "0.141.0" + "@oxc-transform/binding-wasm32-wasi" "0.141.0" + "@oxc-transform/binding-win32-arm64-msvc" "0.141.0" + "@oxc-transform/binding-win32-ia32-msvc" "0.141.0" + "@oxc-transform/binding-win32-x64-msvc" "0.141.0" oxc-walker@^1.0.0: version "1.0.0" @@ -9066,13 +8802,6 @@ p-limit@^3.0.2: dependencies: yocto-queue "^0.1.0" -p-limit@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-5.0.0.tgz#6946d5b7140b649b7a33a027d89b4c625b3a5985" - integrity sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ== - dependencies: - yocto-queue "^1.0.0" - p-locate@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" @@ -9081,9 +8810,9 @@ p-locate@^5.0.0: p-limit "^3.0.2" p-map@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-7.0.4.tgz#b81814255f542e252d5729dca4d66e5ec14935b8" - integrity sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ== + version "7.0.6" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-7.0.6.tgz#5b6ee7f1a775faa48599c8d4420f6a39833cd387" + integrity sha512-I4Prw6ivkd6p8PiYR1tXASOAOBzIJwu0TB7fqaX0c/8c3QAehNYmX57EijyGGGBt3c/BIowGwV03RVBtXvHEVg== package-json-from-dist@^1.0.0: version "1.0.1" @@ -9226,11 +8955,6 @@ pathe@^2.0.1, pathe@^2.0.3: resolved "https://registry.yarnpkg.com/pathe/-/pathe-2.0.3.tgz#3ecbec55421685b70a9da872b2cff3e1cbed1716" integrity sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w== -pathval@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" - integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== - pathval@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/pathval/-/pathval-2.0.1.tgz#8855c5a2899af072d6ac05d11e46045ad0dc605d" @@ -9241,12 +8965,12 @@ perfect-debounce@^2.0.0, perfect-debounce@^2.1.0: resolved "https://registry.yarnpkg.com/perfect-debounce/-/perfect-debounce-2.1.0.tgz#e7078e38f231cb191855c3136a4423aef725d261" integrity sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g== -picocolors@1.1.1, picocolors@^1.0.0, picocolors@^1.1.1: +picocolors@1.1.1, picocolors@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== -picomatch@4.0.4, picomatch@^4.0.2, picomatch@^4.0.3, picomatch@^4.0.4: +picomatch@4.0.4: version "4.0.4" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.4.tgz#fd6f5e00a143086e074dffe4c924b8fb293b0589" integrity sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A== @@ -9256,22 +8980,27 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.2.tgz#5a942915e26b372dc0f0e6753149a16e6b1c5601" integrity sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA== +picomatch@^4.0.2, picomatch@^4.0.3, picomatch@^4.0.4, picomatch@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.5.tgz#51ea57a17d86f605f81039595fbc40ed06a55fab" + integrity sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A== + pidtree@^0.6.0: version "0.6.1" resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.1.tgz#3d03fae6183cc07091947dcc1087ce567cd3bcd3" integrity sha512-e0F9AOF1JMrCfBsyJOwU9lNvQ0WtXTq0j/4jk0BQ5JSI9VAybPXmDpPRw/2FQ3e5d3ZFN1mLh7jW99m/jjaptw== -piscina@5.1.4: - version "5.1.4" - resolved "https://registry.yarnpkg.com/piscina/-/piscina-5.1.4.tgz#86ca2b8e42bcbfc258dc7b09d918ee04b2327a67" - integrity sha512-7uU4ZnKeQq22t9AsmHGD2w4OYQGonwFnTypDypaWi7Qr2EvQIFVtG8J5D/3bE7W123Wdc9+v4CZDu5hJXVCtBg== +piscina@5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/piscina/-/piscina-5.2.0.tgz#3a9a568ab9e3a0556b5c94522ba305962de13e3b" + integrity sha512-DszUCKeVN/5G5QKo6jAVHL8fmKnkJvQ0ACiVgY7YGCq3TUB2oznAOayvZPIAdEThvhczkXR+qm3IHsNXpFCYfA== optionalDependencies: "@napi-rs/nice" "^1.0.4" piscina@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/piscina/-/piscina-5.2.0.tgz#3a9a568ab9e3a0556b5c94522ba305962de13e3b" - integrity sha512-DszUCKeVN/5G5QKo6jAVHL8fmKnkJvQ0ACiVgY7YGCq3TUB2oznAOayvZPIAdEThvhczkXR+qm3IHsNXpFCYfA== + version "5.3.0" + resolved "https://registry.yarnpkg.com/piscina/-/piscina-5.3.0.tgz#0d64ff119b2513ee1552de68ed44ab0b35ceec74" + integrity sha512-9D3tPBayfoal6l9l4Y8NrMn1jkV718qJoYrla6P51+hh9h0Q+9/1c8KgEnoBQqhguyfgjay4biADI8HJG3pkoA== optionalDependencies: "@napi-rs/nice" "^1.0.4" @@ -9287,7 +9016,7 @@ pkg-dir@^8.0.0: dependencies: find-up-simple "^1.0.0" -pkg-types@^1.2.1, pkg-types@^1.3.1: +pkg-types@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.3.1.tgz#bd7cc70881192777eef5326c19deb46e890917df" integrity sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ== @@ -9305,17 +9034,17 @@ pkg-types@^2.3.0, pkg-types@^2.3.1: exsolve "^1.0.8" pathe "^2.0.3" -playwright-core@1.61.0: - version "1.61.0" - resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.61.0.tgz#caf8078b2a39cd7738dc75ec11cb3b47f385c3f0" - integrity sha512-caX7TrY3Ml6egyDX0WUcTHDxodl/b51y5wJOdCEA36QviK/s2g081hvmGs8eaE3DWb6NYZQ6BjO/QkNRPenoPA== +playwright-core@1.62.0: + version "1.62.0" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.62.0.tgz#66f50795fa22d4ccb1a6f70d82264f07171fa3b5" + integrity sha512-nsNRyq0r2zsG8AcRHWknc9QRA5XCueC7gWMrs+Gx2tlZn9hcl8zudfh00lhJPY1DE7NmZ6bDsT9g2yey8mXljA== -playwright@1.61.0, playwright@^1.44.1: - version "1.61.0" - resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.61.0.tgz#7082df3df08ffa82b11420ea5fae84a40bd16e3f" - integrity sha512-Z+7BeeqQPRRzklHsVFP4KTGIyMxKUmfeRA4WisM6G3/XW6nwGeX6fX9qYaDa+CiUqpOkb2f6X3nar05R3kSuJQ== +playwright@1.62.0, playwright@^1.44.1: + version "1.62.0" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.62.0.tgz#eddedb94b0e492a6c7425a602b0eadea35c71526" + integrity sha512-Z14dG305dgaLu6foB1TXQagFiW8JfSUIUaUuPaKQ6NtBPKF1P/qXcqfh6c6K/icPqdy37JmjbiBXf6JNg6Sylw== dependencies: - playwright-core "1.61.0" + playwright-core "1.62.0" optionalDependencies: fsevents "2.3.2" @@ -9548,12 +9277,12 @@ postcss-value-parser@^4.2.0: resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@^8.4.43, postcss@^8.4.47, postcss@^8.4.49, postcss@^8.5.14, postcss@^8.5.15, postcss@^8.5.3, postcss@^8.5.6: - version "8.5.15" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.15.tgz#d1eaf677a324e9ec02196da2d3fecf4a0b9a735c" - integrity sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A== +postcss@^8.4.43, postcss@^8.4.47, postcss@^8.4.49, postcss@^8.5.17, postcss@^8.5.19, postcss@^8.5.22, postcss@^8.5.3, postcss@^8.5.6: + version "8.5.24" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.24.tgz#01d8b032451e1b9ec41ae66eaf02843f42a720d2" + integrity sha512-8RyVklq0owXUTa4xlpzu4l9AaVKIdQvAcOHZWaMh98HgySsUtxRVf/chRe3dsSLqb6i40BzGRzEUddRaI+9TSw== dependencies: - nanoid "^3.3.12" + nanoid "^3.3.16" picocolors "^1.1.1" source-map-js "^1.2.1" @@ -9568,14 +9297,14 @@ prelude-ls@^1.2.1: integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== prettier@^3.2.5: - version "3.8.4" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.8.4.tgz#f334f013ac04a96676f24dabc23c1c4ae1bae411" - integrity sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q== + version "3.9.6" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.9.6.tgz#b3ea5146515d40fc53f18aa63f74dfab1e10dbf6" + integrity sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g== pretty-bytes@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-7.1.0.tgz#d788c9906241dbdcd4defab51b6d7470243db9bd" - integrity sha512-nODzvTiYVRGRqAOvE84Vk5JDPyyxsVk0/fbA/bq7RqlnhksGpset09XTxbpvLTIjoaF7K8Z8DG8yHtKGTPSYRw== + version "7.1.1" + resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-7.1.1.tgz#f1dd1a294396b78d6d1698a034bf447eed060b3c" + integrity sha512-X+vn9z8nOFZQlxOLmfJ0iKDdMD7jYTsTW12OAlCpdoE3Igik6L37pugIZi+N3usuyp5McfgKPWi12q3zvHLeGQ== pretty-format@^27.0.2: version "27.5.1" @@ -9586,14 +9315,14 @@ pretty-format@^27.0.2: ansi-styles "^5.0.0" react-is "^17.0.1" -pretty-format@^29.7.0: - version "29.7.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" - integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== +probe-image-size@^7.2.3: + version "7.3.0" + resolved "https://registry.yarnpkg.com/probe-image-size/-/probe-image-size-7.3.0.tgz#a07df2e2cffc1057026d5a1bda3a5b11ee970034" + integrity sha512-7CaDeBwiAbh6ohXsvLbAZhO7wzsZAmaevfxe39qvCwRh8LyaZfDlBGGLU1CCTgrTLtCOdwBBhjOrIHaIIimHfQ== dependencies: - "@jest/schemas" "^29.6.3" - ansi-styles "^5.0.0" - react-is "^18.0.0" + lodash.merge "^4.6.2" + needle "^2.5.2" + stream-parser "~0.3.1" proc-log@^6.0.0, proc-log@^6.1.0: version "6.1.0" @@ -9769,11 +9498,12 @@ punycode@^2.1.0, punycode@^2.1.1, punycode@^2.3.1: integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== qs@^6.14.0, qs@^6.15.2: - version "6.15.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.15.2.tgz#fd55426d710403ddccc45e0f9eab16db7727ece9" - integrity sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw== + version "6.15.3" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.15.3.tgz#76852132a58ed5c7c0ef67e4441b9bb5d6061b3b" + integrity sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A== dependencies: - side-channel "^1.1.0" + es-define-property "^1.0.1" + side-channel "^1.1.1" quansync@^0.2.11: version "0.2.11" @@ -9796,9 +9526,9 @@ radix3@^1.1.2: integrity sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA== range-parser@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + version "1.3.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.3.0.tgz#d7f19be812bb62721472b45d3be219ef09572b47" + integrity sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw== raw-body@^3.0.0, raw-body@^3.0.2: version "3.0.2" @@ -9819,9 +9549,9 @@ rc9@^3.0.0, rc9@^3.0.1: destr "^2.0.5" react-dom@^19.2.0: - version "19.2.7" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.2.7.tgz#0450dc9ae9ddbff76ef196401cd8b8c7fb466ccc" - integrity sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ== + version "19.2.8" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.2.8.tgz#3b46b9eeda877cdff2cf13d2770fff4ae36c2ec2" + integrity sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ== dependencies: scheduler "^0.27.0" @@ -9835,15 +9565,10 @@ react-is@^17.0.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== -react-is@^18.0.0: - version "18.3.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" - integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== - react@^19.2.0: - version "19.2.7" - resolved "https://registry.yarnpkg.com/react/-/react-19.2.7.tgz#1f47a1bfc06f8ec885752c6f4af14369a9f8260b" - integrity sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ== + version "19.2.8" + resolved "https://registry.yarnpkg.com/react/-/react-19.2.8.tgz#a80663dbb58d69c6fe3fd291d3cb324e8a7dff2d" + integrity sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw== readable-stream@^2.0.5: version "2.3.8" @@ -9894,9 +9619,9 @@ readdirp@~3.6.0: picomatch "^2.2.1" recast@^0.23.1: - version "0.23.11" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.23.11.tgz#8885570bb28cf773ba1dc600da7f502f7883f73f" - integrity sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA== + version "0.23.12" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.23.12.tgz#3df7589ae1877d0a634c6c7ccc995a7c053850a9" + integrity sha512-dEWRjcINDu/F4l2dYx57ugBtD7HV9KXESyxhzw/MqWLeglJrsjJKqACPyUPg+6AF8mIgm+Zi0dZ3ACoIg+QtpA== dependencies: ast-types "^0.16.1" esprima "~4.0.0" @@ -10045,29 +9770,29 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" -rolldown@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/rolldown/-/rolldown-1.1.2.tgz#accb41e26c872ad2c5198a39c1281c7b6b844097" - integrity sha512-x0CrQQqCXWGeI8dTvFfN/Dnv3yMKT9hv5jFjlOreKAx9wqLq9wz7VvLLHyaAXC90/CpggTu9SisSbsJJTPSjNQ== +rolldown@~1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/rolldown/-/rolldown-1.1.5.tgz#339aae250844351fc55b74e2652d3ebd6fba389d" + integrity sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA== dependencies: - "@oxc-project/types" "=0.137.0" + "@oxc-project/types" "=0.139.0" "@rolldown/pluginutils" "^1.0.0" optionalDependencies: - "@rolldown/binding-android-arm64" "1.1.2" - "@rolldown/binding-darwin-arm64" "1.1.2" - "@rolldown/binding-darwin-x64" "1.1.2" - "@rolldown/binding-freebsd-x64" "1.1.2" - "@rolldown/binding-linux-arm-gnueabihf" "1.1.2" - "@rolldown/binding-linux-arm64-gnu" "1.1.2" - "@rolldown/binding-linux-arm64-musl" "1.1.2" - "@rolldown/binding-linux-ppc64-gnu" "1.1.2" - "@rolldown/binding-linux-s390x-gnu" "1.1.2" - "@rolldown/binding-linux-x64-gnu" "1.1.2" - "@rolldown/binding-linux-x64-musl" "1.1.2" - "@rolldown/binding-openharmony-arm64" "1.1.2" - "@rolldown/binding-wasm32-wasi" "1.1.2" - "@rolldown/binding-win32-arm64-msvc" "1.1.2" - "@rolldown/binding-win32-x64-msvc" "1.1.2" + "@rolldown/binding-android-arm64" "1.1.5" + "@rolldown/binding-darwin-arm64" "1.1.5" + "@rolldown/binding-darwin-x64" "1.1.5" + "@rolldown/binding-freebsd-x64" "1.1.5" + "@rolldown/binding-linux-arm-gnueabihf" "1.1.5" + "@rolldown/binding-linux-arm64-gnu" "1.1.5" + "@rolldown/binding-linux-arm64-musl" "1.1.5" + "@rolldown/binding-linux-ppc64-gnu" "1.1.5" + "@rolldown/binding-linux-s390x-gnu" "1.1.5" + "@rolldown/binding-linux-x64-gnu" "1.1.5" + "@rolldown/binding-linux-x64-musl" "1.1.5" + "@rolldown/binding-openharmony-arm64" "1.1.5" + "@rolldown/binding-wasm32-wasi" "1.1.5" + "@rolldown/binding-win32-arm64-msvc" "1.1.5" + "@rolldown/binding-win32-x64-msvc" "1.1.5" rollup-plugin-dts@^6.4.0: version "6.4.1" @@ -10126,43 +9851,43 @@ rollup@4.60.2: fsevents "~2.3.2" rollup@^4.20.0, rollup@^4.24.0, rollup@^4.34.9, rollup@^4.43.0, rollup@^4.60.2: - version "4.62.2" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.62.2.tgz#d90fc4cb811f071303c890b779595634f35f9541" - integrity sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA== + version "4.62.3" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.62.3.tgz#03ee99e2b5b0744dd99be6d4238b2fcd4087b4f6" + integrity sha512-Gu0c0iH9FzgX1L1t7ByIbbS3Vmdz+6KHm/EsqmmC71gUQ82yvZRkTK6XzrFObSka91WUVdynqp6nsfilzr5k6Q== dependencies: "@types/estree" "1.0.9" optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.62.2" - "@rollup/rollup-android-arm64" "4.62.2" - "@rollup/rollup-darwin-arm64" "4.62.2" - "@rollup/rollup-darwin-x64" "4.62.2" - "@rollup/rollup-freebsd-arm64" "4.62.2" - "@rollup/rollup-freebsd-x64" "4.62.2" - "@rollup/rollup-linux-arm-gnueabihf" "4.62.2" - "@rollup/rollup-linux-arm-musleabihf" "4.62.2" - "@rollup/rollup-linux-arm64-gnu" "4.62.2" - "@rollup/rollup-linux-arm64-musl" "4.62.2" - "@rollup/rollup-linux-loong64-gnu" "4.62.2" - "@rollup/rollup-linux-loong64-musl" "4.62.2" - "@rollup/rollup-linux-ppc64-gnu" "4.62.2" - "@rollup/rollup-linux-ppc64-musl" "4.62.2" - "@rollup/rollup-linux-riscv64-gnu" "4.62.2" - "@rollup/rollup-linux-riscv64-musl" "4.62.2" - "@rollup/rollup-linux-s390x-gnu" "4.62.2" - "@rollup/rollup-linux-x64-gnu" "4.62.2" - "@rollup/rollup-linux-x64-musl" "4.62.2" - "@rollup/rollup-openbsd-x64" "4.62.2" - "@rollup/rollup-openharmony-arm64" "4.62.2" - "@rollup/rollup-win32-arm64-msvc" "4.62.2" - "@rollup/rollup-win32-ia32-msvc" "4.62.2" - "@rollup/rollup-win32-x64-gnu" "4.62.2" - "@rollup/rollup-win32-x64-msvc" "4.62.2" + "@rollup/rollup-android-arm-eabi" "4.62.3" + "@rollup/rollup-android-arm64" "4.62.3" + "@rollup/rollup-darwin-arm64" "4.62.3" + "@rollup/rollup-darwin-x64" "4.62.3" + "@rollup/rollup-freebsd-arm64" "4.62.3" + "@rollup/rollup-freebsd-x64" "4.62.3" + "@rollup/rollup-linux-arm-gnueabihf" "4.62.3" + "@rollup/rollup-linux-arm-musleabihf" "4.62.3" + "@rollup/rollup-linux-arm64-gnu" "4.62.3" + "@rollup/rollup-linux-arm64-musl" "4.62.3" + "@rollup/rollup-linux-loong64-gnu" "4.62.3" + "@rollup/rollup-linux-loong64-musl" "4.62.3" + "@rollup/rollup-linux-ppc64-gnu" "4.62.3" + "@rollup/rollup-linux-ppc64-musl" "4.62.3" + "@rollup/rollup-linux-riscv64-gnu" "4.62.3" + "@rollup/rollup-linux-riscv64-musl" "4.62.3" + "@rollup/rollup-linux-s390x-gnu" "4.62.3" + "@rollup/rollup-linux-x64-gnu" "4.62.3" + "@rollup/rollup-linux-x64-musl" "4.62.3" + "@rollup/rollup-openbsd-x64" "4.62.3" + "@rollup/rollup-openharmony-arm64" "4.62.3" + "@rollup/rollup-win32-arm64-msvc" "4.62.3" + "@rollup/rollup-win32-ia32-msvc" "4.62.3" + "@rollup/rollup-win32-x64-gnu" "4.62.3" + "@rollup/rollup-win32-x64-msvc" "4.62.3" fsevents "~2.3.2" -rou3@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/rou3/-/rou3-0.8.1.tgz#d18c9dae42bdd9cd4fffa77bc6731d5cfe92129a" - integrity sha512-ePa+XGk00/3HuCqrEnK3LxJW7I0SdNg6EFzKUJG73hMAdDcOUC/i/aSz7LSDwLrGr33kal/rqOGydzwl6U7zBA== +rou3@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/rou3/-/rou3-0.9.1.tgz#12e9a0d00aa513443e7fa4d171dfd38db0324ea8" + integrity sha512-z/sSmzvtwMDDnxsPVhfWMuG6F6mbmhFDXoVqLmMfbpDD9qfV3GDmSQpf0+W296/ZDIpW2wcMmBfpVFzcnOi/nA== router@^2.2.0: version "2.2.0" @@ -10242,7 +9967,7 @@ safe-regex-test@^1.1.0: es-errors "^1.3.0" is-regex "^1.2.1" -"safer-buffer@>= 2.1.2 < 3.0.0": +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -10259,9 +9984,9 @@ sass@1.99.0: "@parcel/watcher" "^2.4.1" sass@^1.101.0, sass@^1.56.1, sass@^1.81.0: - version "1.101.0" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.101.0.tgz#c2db5bbf2f956be7277f6223b899d0d4be3c899b" - integrity sha512-OL3GoQyoUdDt843DpVmDO6y2k1sc5IhUDSpu8XucEI+35neq5QivZ1iuegnpraEVTJXlQGK1gl27zKcTLEPbQw== + version "1.102.0" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.102.0.tgz#4ed9378f37ca4186a76d6d1f52a6680c92b6bd80" + integrity sha512-NSOyTnaQF7rTAEOtI2fwb386vL+akyiQLBZu8Na7hXCb+umJy0GAqlcMIaqACZ6Z1VgTBS4K9PG6B3IdjHGJsw== dependencies: chokidar "^5.0.0" immutable "^5.1.5" @@ -10270,9 +9995,9 @@ sass@^1.101.0, sass@^1.56.1, sass@^1.81.0: "@parcel/watcher" "^2.4.1" sax@^1.2.4, sax@^1.5.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.6.0.tgz#da59637629307b97e7c4cb28e080a7bc38560d5b" - integrity sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA== + version "1.6.1" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.6.1.tgz#4c23cf608c0b693ab54b4b5888e92cfe977b9843" + integrity sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q== saxes@^6.0.0: version "6.0.0" @@ -10301,7 +10026,7 @@ semver@^6.1.0, semver@^6.3.1: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.0.0, semver@^7.1.1, semver@^7.3.5, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.7.4, semver@^7.8.0, semver@^7.8.1, semver@^7.8.4: +semver@^7.0.0, semver@^7.1.1, semver@^7.3.5, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.7.4, semver@^7.8.5: version "7.8.5" resolved "https://registry.yarnpkg.com/semver/-/semver-7.8.5.tgz#39b646037dd50c14fb451e7e4cac58ed8b863f69" integrity sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA== @@ -10331,14 +10056,14 @@ send@^1.1.0, send@^1.2.0: statuses "^2.0.2" serialize-javascript@^7.0.3: - version "7.0.6" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-7.0.6.tgz#f2f20c8af0757e4d8fa329d0210636da0682ddef" - integrity sha512-ATTK5Q4gFVg0YDp1my2vqygyvhcklD/UV5GIlYHooGTn/NogJqIzpetkD6E5kmuVULqz/S9inUL25XcAgDRJQg== + version "7.0.7" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-7.0.7.tgz#06ec40576d4cea96d68010a534520bff1f948a72" + integrity sha512-YAy8Od6KV+uuwUuU50np8fGB/Aues6Y0nAhA9y/hId74PlKUcme4pXcBD46NWKr1Q4osN/iseZ17YqO1XfmI8g== -seroval@^1.5.4: - version "1.5.4" - resolved "https://registry.yarnpkg.com/seroval/-/seroval-1.5.4.tgz#9d0cedae244f8213bbbbbcc99c497eb7c945d961" - integrity sha512-46uFvgrXTVxZcUorgSSRZ4y+ieqLLQRMlG4bnCZKW3qI6BZm7Rg4ntMW4p1mILEEBZWrFlcpp0AyIIlM6jD9iw== +seroval@^1.5.6: + version "1.5.6" + resolved "https://registry.yarnpkg.com/seroval/-/seroval-1.5.6.tgz#68d4f6a05c3bde25daaaea6b7220146ff42353ca" + integrity sha512-rVQVWjjSvlINzaQPZH5JFqsqEsIWdTxY3iJZCnTL/5gQbXIRooVZKI60tVCkOVfzcRPejboxO2t0P89dg5mQaA== serve-placeholder@^2.0.2: version "2.0.2" @@ -10406,9 +10131,9 @@ shebang-regex@^3.0.0: integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== shell-quote@^1.8.4: - version "1.8.4" - resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.4.tgz#2edd9a4dcefc96649e2e2cb12f637b1f1d92a190" - integrity sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ== + version "1.10.0" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.10.0.tgz#482033e192e4f5c07151521ffa03400ec71b1b0f" + integrity sha512-w1aiOKwKuRgtwAReIIj89puqg+I7GvX4IbLrvmhXbzQsj1+Zwi4VO3+fa6ZF91TWSjIxoEkKnMeHcLEODK5ZXA== shiki@^0.14.7: version "0.14.7" @@ -10449,7 +10174,7 @@ side-channel-weakmap@^1.0.2: object-inspect "^1.13.3" side-channel-map "^1.0.1" -side-channel@^1.0.4, side-channel@^1.1.0: +side-channel@^1.0.4, side-channel@^1.1.0, side-channel@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.1.tgz#ea02c62e05dc4bea67d4442f0fb71ee192f8e0ab" integrity sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ== @@ -10487,7 +10212,7 @@ sigstore@^4.0.0: "@sigstore/tuf" "^4.0.2" "@sigstore/verify" "^3.1.1" -simple-git@^3.33.0: +simple-git@^3.36.0: version "3.36.0" resolved "https://registry.yarnpkg.com/simple-git/-/simple-git-3.36.0.tgz#019b28c0a35847ee34299c6fb63770ab1b2dffb7" integrity sha512-cGQjLjK8bxJw4QuYT7gxHw3/IouVESbhahSsHrX97MzCL1gu2u7oy38W6L2ZIGECEfIBG4BabsWDPjBxJENv9Q== @@ -10619,10 +10344,10 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== -srvx@^0.11.16: - version "0.11.17" - resolved "https://registry.yarnpkg.com/srvx/-/srvx-0.11.17.tgz#ac59840fb8ab64fc539ef6e622d84e0add22f6c9" - integrity sha512-43yM4luKfCJamyCMhrUeHUPOrf8TdZe7kN8s5zayZCH5OeprYqi49Aso5ZvHXR4aB+DHaRNO/diNFgZSMNG8Xw== +srvx@^0.11.22: + version "0.11.22" + resolved "https://registry.yarnpkg.com/srvx/-/srvx-0.11.22.tgz#f83413628014eb37416ba4609e10b4bb38472295" + integrity sha512-LqZxxBDMKuMAZzFzJnDCkFOrs9MZQZr0LvHiO/SuSZVdQaXD7xQ5UWTUxheJrQPve1qk9MG2B/yttUvJxw8egQ== ssri@^13.0.0: version "13.0.1" @@ -10646,15 +10371,15 @@ statuses@^2.0.1, statuses@^2.0.2, statuses@~2.0.2: resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.2.tgz#8f75eecef765b5e1cfcdc080da59409ed424e382" integrity sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw== -std-env@^3.5.0, std-env@^3.9.0: +std-env@^3.9.0: version "3.10.0" resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.10.0.tgz#d810b27e3a073047b2b5e40034881f5ea6f9c83b" integrity sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg== -std-env@^4.0.0, std-env@^4.0.0-rc.1, std-env@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/std-env/-/std-env-4.1.0.tgz#45899abc590d86d682e87f0acd1033a75084cd3f" - integrity sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ== +std-env@^4.0.0, std-env@^4.0.0-rc.1, std-env@^4.1.0, std-env@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-4.2.0.tgz#8ebe0ec60485668ab47227b312f4254cdf80c9d3" + integrity sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw== stdin-discarder@^0.3.2: version "0.3.2" @@ -10669,6 +10394,13 @@ stop-iteration-iterator@^1.0.0, stop-iteration-iterator@^1.1.0: es-errors "^1.3.0" internal-slot "^1.1.0" +stream-parser@~0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/stream-parser/-/stream-parser-0.3.1.tgz#1618548694420021a1182ff0af1911c129761773" + integrity sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ== + dependencies: + debug "2" + streamx@^2.12.5, streamx@^2.15.0, streamx@^2.25.0: version "2.28.0" resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.28.0.tgz#035ab56057b7ed2211b51d532e6973f0f99fbf11" @@ -10719,10 +10451,10 @@ string-width@^7.0.0, string-width@^7.2.0: get-east-asian-width "^1.0.0" strip-ansi "^7.1.0" -string-width@^8.1.0, string-width@^8.2.0: - version "8.2.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-8.2.1.tgz#165089cfa527cc88fbc23dd73313f5e334af1ea1" - integrity sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA== +string-width@^8.1.0, string-width@^8.2.0, string-width@^8.2.1: + version "8.2.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-8.2.2.tgz#7310516493df575742fe98af6fae87d85d5ed0ac" + integrity sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg== dependencies: get-east-asian-width "^1.5.0" strip-ansi "^7.1.2" @@ -10844,13 +10576,6 @@ strip-json-comments@^3.1.1, strip-json-comments@~3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -strip-literal@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/strip-literal/-/strip-literal-2.1.1.tgz#26906e65f606d49f748454a08084e94190c2e5ad" - integrity sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q== - dependencies: - js-tokens "^9.0.1" - strip-literal@^3.0.0, strip-literal@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/strip-literal/-/strip-literal-3.1.0.tgz#222b243dd2d49c0bcd0de8906adbd84177196032" @@ -10896,9 +10621,9 @@ supports-preserve-symlinks-flag@^1.0.0: integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== svgo@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-4.0.1.tgz#c82dacd04ee9f1d55cd4e0b7f9a214c86670e3ee" - integrity sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w== + version "4.0.2" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-4.0.2.tgz#a62246f0a9d671c0314d04f3cc15f78b1bd0667f" + integrity sha512-ekx94z1rRc5LDi6oSUaeRnYhd0UOJxdtQCL2rF8xpWxD3TPAsISWOrxezqGovqS38GRZOdpDfvQe3ts6F7nsng== dependencies: commander "^11.1.0" css-select "^5.1.0" @@ -10934,9 +10659,9 @@ tar-stream@^3.0.0: streamx "^2.15.0" tar@^7.4.0, tar@^7.4.3, tar@^7.5.4: - version "7.5.16" - resolved "https://registry.yarnpkg.com/tar/-/tar-7.5.16.tgz#f11e063afed4554f758049d082909e37d6b53ced" - integrity sha512-56adEpPMouktRlBLXiaYFFzZ/3+JXa8P9n7WbR+ibIjtviN55mEaOkiysCnPnWm+7kkui1Dn8J9l+g6zV8731w== + version "7.5.22" + resolved "https://registry.yarnpkg.com/tar/-/tar-7.5.22.tgz#a696f998136e71487dc3f869a85bba2c67971ba9" + integrity sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA== dependencies: "@isaacs/fs-minipass" "^4.0.0" chownr "^3.0.0" @@ -10952,9 +10677,9 @@ teex@^1.0.1: streamx "^2.12.5" terser@^5.17.4: - version "5.48.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.48.0.tgz#8b391171cfbb7ac4a88f9f04ba1cfabc54f643db" - integrity sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q== + version "5.49.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.49.0.tgz#30b341fdf70cfc98486965125ae660fda8403670" + integrity sha512-SNiDnXyHSrxVcIOtVbULzcTmniUiwcV7Nwdyj1twVubeTmbjoa8p69KKDpfkdoOavuM4/GRm1+ykI8qqnavHoA== dependencies: "@jridgewell/source-map" "^0.3.3" acorn "^8.15.0" @@ -10978,12 +10703,12 @@ tiny-invariant@^1.3.3: resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127" integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg== -tinybench@^2.5.1, tinybench@^2.9.0: +tinybench@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.9.0.tgz#103c9f8ba6d7237a47ab6dd1dcff77251863426b" integrity sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg== -tinyclip@^0.1.12, tinyclip@^0.1.14: +tinyclip@^0.1.15: version "0.1.15" resolved "https://registry.yarnpkg.com/tinyclip/-/tinyclip-0.1.15.tgz#db35eaa2bd5fe627b3ef2ea38d8b0407f2bc2def" integrity sha512-uo33abH+Ays0xYaDysoBt494Hb3hsEczMpcC0MwFl773pazORx4fmvKhclhR1wonUbB6vvpRsvVMwnhfqeMc+A== @@ -11014,11 +10739,6 @@ tinyglobby@^0.2.12, tinyglobby@^0.2.13, tinyglobby@^0.2.14, tinyglobby@^0.2.15, fdir "^6.5.0" picomatch "^4.0.4" -tinypool@^0.8.3: - version "0.8.4" - resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-0.8.4.tgz#e217fe1270d941b39e98c625dcecebb1408c9aa8" - integrity sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ== - tinypool@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-1.1.1.tgz#059f2d042bd37567fbc017d3d426bdd2a2612591" @@ -11030,14 +10750,9 @@ tinyrainbow@^2.0.0: integrity sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw== tinyrainbow@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/tinyrainbow/-/tinyrainbow-3.1.0.tgz#1d8a623893f95cf0a2ddb9e5d11150e191409421" - integrity sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw== - -tinyspy@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-2.2.1.tgz#117b2342f1f38a0dbdcc73a50a454883adf861d1" - integrity sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A== + version "3.1.1" + resolved "https://registry.yarnpkg.com/tinyrainbow/-/tinyrainbow-3.1.1.tgz#c0168387d3d8d70b6b3c2c0936de5fee738cea20" + integrity sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw== tinyspy@^4.0.3: version "4.0.4" @@ -11148,20 +10863,15 @@ type-check@^0.4.0, type-check@~0.4.0: dependencies: prelude-ls "^1.2.1" -type-detect@^4.0.0, type-detect@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.1.0.tgz#deb2453e8f08dcae7ae98c626b13dddb0155906c" - integrity sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw== - type-fest@^0.20.2: version "0.20.2" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== type-fest@^5.0.0: - version "5.7.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-5.7.0.tgz#bae586d3b7c2596bd9c7e62195f33c7fcada1c91" - integrity sha512-1URUxUqfHFM1c+zfSPsa3gnkO7Aq21qyH75SIduNYz4SzY964rn1X2vCMQaHSHhktiw+0kPa2iyb6PUpXqB6Vg== + version "5.8.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-5.8.0.tgz#6d517998257c33159db4d4da6f18efa33bd47df3" + integrity sha512-YGYEVz3Fm5iy/AybuA0oyNFq7H4CgQNfRp/qfe8nurE1kuCeNm3/vfm9X4Mtl+qLyaKJUh5xrFZwogr41SMjYA== dependencies: tagged-tag "^1.0.0" @@ -11266,10 +10976,10 @@ uglify-js@^3.1.4: resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.19.3.tgz#82315e9bbc6f2b25888858acd1fff8441035b77f" integrity sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ== -ultrahtml@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/ultrahtml/-/ultrahtml-1.6.0.tgz#0d1aad7bbfeae512438d30e799c11622127a1ac8" - integrity sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw== +ultrahtml@^1.6.0, ultrahtml@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/ultrahtml/-/ultrahtml-1.7.0.tgz#8e7d597e338a481ea82852a9ba5e8021c54aed10" + integrity sha512-2xRd0VHoAQE4M+vF/DvFFB7pUV0ZxTW1TLi7lHQWnF/Sb5TPeEUV/l+hxcNnGO00ZXGnR0voCMmYRKQf+rvJ2g== unbox-primitive@^1.1.0: version "1.1.0" @@ -11296,6 +11006,11 @@ unctx@^2.5.0: magic-string "^0.30.21" unplugin "^2.3.11" +unctx@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/unctx/-/unctx-3.0.0.tgz#82e2f20c8f9db13a443871caddfdd1af7af2eff1" + integrity sha512-DoXdZVeyi2jyEsn86i8MO5RTItm1kffUkH9/+DQORn3Q688AMOy2551CIl6AdGL2UpwD675wtbNOl75wIQN/uA== + undici-types@~5.26.4: version "5.26.5" resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" @@ -11307,9 +11022,9 @@ undici-types@~6.21.0: integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== undici@^6.25.0: - version "6.27.0" - resolved "https://registry.yarnpkg.com/undici/-/undici-6.27.0.tgz#41f9e48f7c5a40d27376caaead8c9a9fc7bca9c4" - integrity sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg== + version "6.28.0" + resolved "https://registry.yarnpkg.com/undici/-/undici-6.28.0.tgz#9f0e385744fef5021d6596c5bccd783f61193c1c" + integrity sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA== unenv@2.0.0-rc.24, unenv@^2.0.0-rc.24: version "2.0.0-rc.24" @@ -11318,10 +11033,10 @@ unenv@2.0.0-rc.24, unenv@^2.0.0-rc.24: dependencies: pathe "^2.0.3" -unhead@2.1.15: - version "2.1.15" - resolved "https://registry.yarnpkg.com/unhead/-/unhead-2.1.15.tgz#73f051d93cffda0808212f80d4e5a1089fdd58c8" - integrity sha512-MCt5T90mCWyr3Z6pUCdM9lVRXoMoVBlL7z7U4CYVIiaDiuzad/UCfLuMqz5MeNmpZUgoBCQnrucJimU7EZR+XA== +unhead@2.1.16: + version "2.1.16" + resolved "https://registry.yarnpkg.com/unhead/-/unhead-2.1.16.tgz#31dd226a959c1cc3d15b8c38a1faf8d515f7ea0b" + integrity sha512-cD2Q4a6SQHhW9/bPp17NT4GJ1yS0DSLe75WEHKQ8bKa/wjB6cIki3KeL86hhllNBcpv8i6bxdwtwQunneXPqKQ== dependencies: hookable "^6.0.1" @@ -11335,10 +11050,10 @@ unicorn-magic@^0.4.0: resolved "https://registry.yarnpkg.com/unicorn-magic/-/unicorn-magic-0.4.0.tgz#78c6a090fd6d07abd2468b83b385603e00dfdb24" integrity sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw== -unimport@^6.2.0, unimport@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/unimport/-/unimport-6.3.0.tgz#6b5d55ca2d53897036578a0ce11a2eb8b12a89fb" - integrity sha512-M+Dxk5W9WRd+8j56W9tp8lGW/dmMc7g5zj7BWQnEjKQhryBstqsi1V0izb0zHwSkEN8cSYV7K75/bykairV2tA== +unimport@^6.2.0, unimport@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/unimport/-/unimport-6.3.1.tgz#5245283b052778674ef471403e6c31d2ff2fbbe6" + integrity sha512-43BV4iELfhpZ0JNSedMNdBqomAIaJwBrmTqIUYRb8ly3XVQihcRPAVIOSwb23XVCJgtjSf+f82d5Qpdsxqh8iQ== dependencies: acorn "^8.16.0" escape-string-regexp "^5.0.0" @@ -11376,12 +11091,12 @@ unpipe@~1.0.0: integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== unplugin-utils@^0.3.0, unplugin-utils@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/unplugin-utils/-/unplugin-utils-0.3.1.tgz#ef2873670a6a2a21bd2c9d31307257cc863a709c" - integrity sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog== + version "0.3.2" + resolved "https://registry.yarnpkg.com/unplugin-utils/-/unplugin-utils-0.3.2.tgz#22f6856408880b0b2d7dd974084faf94094613ef" + integrity sha512-xVToRh2CTmLk2HnEG7ac4rl1MJTT3RFkpS8B++/SnB0kXvuaavD+n3m/vrzyWQOdJNSZQACnbz01pnppbwV5BA== dependencies: pathe "^2.0.3" - picomatch "^4.0.3" + picomatch "^4.0.4" unplugin-vue-router@^0.19.2: version "0.19.2" @@ -11416,13 +11131,13 @@ unplugin@^2.3.11: picomatch "^4.0.3" webpack-virtual-modules "^0.6.2" -unplugin@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-3.0.0.tgz#01e40c474bf74d363744f4cb262569d26dd9bb43" - integrity sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg== +unplugin@^3.0.0, unplugin@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-3.3.0.tgz#18de476b6130a6cde94db87f70ac32b97757f3c9" + integrity sha512-qa66K+crbfyE6JK10GjvbJeRrOsuC/JpbnHctfyp/i4oBTxWOzJfRZyDiOk1PtErMFRu8JhsU/wPvOdBNWe5Rg== dependencies: "@jridgewell/remapping" "^2.3.5" - picomatch "^4.0.3" + picomatch "^4.0.4" webpack-virtual-modules "^0.6.2" unstorage@^1.17.5: @@ -11439,14 +11154,10 @@ unstorage@^1.17.5: ofetch "^1.5.1" ufo "^1.6.3" -untun@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/untun/-/untun-0.1.3.tgz#5d10dee37a3a5737ff03d158be877dae0a0e58a6" - integrity sha512-4luGP9LMYszMRZwsvyUd9MrxgEGZdZuZgpVQHEEX0lCYFESasVRvZd0EYpCkOIbJKHMuv0LskpXc/8Un+MJzEQ== - dependencies: - citty "^0.1.5" - consola "^3.2.3" - pathe "^1.1.1" +untun@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/untun/-/untun-0.2.2.tgz#46c36e2d8f0c611a293d00083864b7e152a68db7" + integrity sha512-+NnOJcSiEtYsVgJmXUzQbJeRAFXJC4yPJYuh6kF9B0Rm6zunXcs/3GZOTllyocSbUDIxD6Bj7e/4ATw7sph1Sw== untyped@^2.0.0: version "2.0.0" @@ -11519,6 +11230,11 @@ vary@^1, vary@^1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== +verkit@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/verkit/-/verkit-0.2.0.tgz#23d545800c8d918f31cf67e761149b80b0249a90" + integrity sha512-6M8R2xSKplkQ+0mAm07IMh548GLLPUnRQZJCCe/W4rfk/SXW2bs8ZJSWa5kjdIdsx3hLG5oLWROJ4+N5hpX08g== + vite-dev-rpc@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/vite-dev-rpc/-/vite-dev-rpc-2.0.0.tgz#fd12621897f551d49a0b1a31ae7085aba77192aa" @@ -11532,17 +11248,6 @@ vite-hot-client@^2.2.0: resolved "https://registry.yarnpkg.com/vite-hot-client/-/vite-hot-client-2.2.0.tgz#284fa1afa63cc8781d079515884eb49d2890ac2f" integrity sha512-76Zs9zrHbH7M7wqeyooGQKdX+yg0pQ0xuQ1PbFp4z5a0Lzn2e5IPFoCswnmqZ4GiwqB4Jo3WcDAMO9jARTJl8w== -vite-node@1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-1.6.1.tgz#fff3ef309296ea03ceaa6ca4bb660922f5416c57" - integrity sha512-YAXkfvGtuTzwWbDSACdJSg4A4DZiAqckWe90Zapc/sEX3XvHcw1NdurM/6od8J207tSDqNbSsgdCacBgvJKFuA== - dependencies: - cac "^6.7.14" - debug "^4.3.4" - pathe "^1.1.1" - picocolors "^1.0.0" - vite "^5.0.0" - vite-node@3.2.4: version "3.2.4" resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-3.2.4.tgz#f3676d94c4af1e76898c162c92728bca65f7bb07" @@ -11565,20 +11270,18 @@ vite-node@^5.3.0: pathe "^2.0.3" vite "^7.3.1" -vite-plugin-checker@^0.13.0: - version "0.13.0" - resolved "https://registry.yarnpkg.com/vite-plugin-checker/-/vite-plugin-checker-0.13.0.tgz#5593c19281a201546c81ee66c79e0c097ba5140a" - integrity sha512-14EkOZmfinVZNxRmg2uCNDwtqGc/33lU/UEJansHgu27+ad+r6mMBf1Xtnq57jGZWiO/xzwtiEKPYsganw7ZFQ== +vite-plugin-checker@^0.14.5: + version "0.14.5" + resolved "https://registry.yarnpkg.com/vite-plugin-checker/-/vite-plugin-checker-0.14.5.tgz#b809a65bbec0195d932bfee4bb3a49cdd2907640" + integrity sha512-c9lQ92eisUO+F7Fd93aelojmiOS+NQpPgQ1XR2LTQHox1/laZf4yAoQj+L3RA9Vgh10e2nFd9b8r2LLyYZsbpA== dependencies: - "@babel/code-frame" "^7.27.1" - chokidar "^4.0.3" + "@babel/code-frame" "^7.29.0" + chokidar "^5.0.0" npm-run-path "^6.0.0" picocolors "^1.1.1" picomatch "^4.0.4" proper-lockfile "^4.1.2" tiny-invariant "^1.3.3" - tinyglobby "^0.2.15" - vscode-uri "^3.1.0" vite-plugin-dts@^3.7.1, vite-plugin-dts@^3.7.3, vite-plugin-dts@^3.8.0: version "3.9.1" @@ -11634,12 +11337,12 @@ vite-plugin-vue-tracer@^1.3.0: pathe "^2.0.3" source-map-js "^1.2.1" -vite@7.3.5, "vite@^5.0.0 || ^6.0.0 || ^7.0.0-0", vite@^7.3.1, vite@^7.3.3: - version "7.3.5" - resolved "https://registry.yarnpkg.com/vite/-/vite-7.3.5.tgz#90c2d0b7b94a224e7e7dcf22d2912ff0b5291165" - integrity sha512-KuOaNhcnGFN2zIPGA7wRmzF+lJA1sea7rHq17aiJ++9lzY1WWG6Jpwqwe1KNbRVPIqHmr8GLYx7jbrQcN/7/ww== +vite@7.3.6, "vite@^5.0.0 || ^6.0.0 || ^7.0.0-0", vite@^7.3.1, vite@^7.3.6: + version "7.3.6" + resolved "https://registry.yarnpkg.com/vite/-/vite-7.3.6.tgz#0547a395e68d3746e9a505f1fd4469fe09b49cc4" + integrity sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg== dependencies: - esbuild "^0.27.0" + esbuild "^0.27.0 || ^0.28.0" fdir "^6.5.0" picomatch "^4.0.3" postcss "^8.5.6" @@ -11648,7 +11351,7 @@ vite@7.3.5, "vite@^5.0.0 || ^6.0.0 || ^7.0.0-0", vite@^7.3.1, vite@^7.3.3: optionalDependencies: fsevents "~2.3.3" -vite@^5.0.0, vite@^5.0.12, vite@^5.2.0, vite@^5.4.17: +vite@^5.0.12, vite@^5.2.0, vite@^5.4.17: version "5.4.21" resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.21.tgz#84a4f7c5d860b071676d39ba513c0d598fdc7027" integrity sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw== @@ -11674,57 +11377,31 @@ vite@^6.0.0: fsevents "~2.3.3" "vite@^6.0.0 || ^7.0.0 || ^8.0.0": - version "8.1.0" - resolved "https://registry.yarnpkg.com/vite/-/vite-8.1.0.tgz#0734dc1a48faeb2bd5f5b16b66dcbfae484fec55" - integrity sha512-BuJcQK/56NQTWDGn4ABea3q4SSBdNPWwNZKTkkUpcMPnLoquSYH8llRtSUIgoL1KSCpHt5eghLShn50mH36y7Q== + version "8.1.5" + resolved "https://registry.yarnpkg.com/vite/-/vite-8.1.5.tgz#ccffce3ee487b1886223b24ebb27b91674827d30" + integrity sha512-7ULLwsCdYx/nRyrpiEwvqb5TFHrMVZyBt+rg/OAXT7rgj/z+DtTDyKFeLAdDkubDVDKD8jOsndmy7m55XcfUsw== dependencies: lightningcss "^1.32.0" - picomatch "^4.0.4" - postcss "^8.5.15" - rolldown "~1.1.2" + picomatch "^4.0.5" + postcss "^8.5.17" + rolldown "~1.1.5" tinyglobby "^0.2.17" optionalDependencies: fsevents "~2.3.3" -vitest@^1.2.1, vitest@^1.4.0, vitest@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/vitest/-/vitest-1.6.1.tgz#b4a3097adf8f79ac18bc2e2e0024c534a7a78d2f" - integrity sha512-Ljb1cnSJSivGN0LqXd/zmDbWEM0RNNg2t1QW/XUhYl/qPqyu7CsqeWtqQXHVaJsecLPuDoak2oJcZN2QoRIOag== - dependencies: - "@vitest/expect" "1.6.1" - "@vitest/runner" "1.6.1" - "@vitest/snapshot" "1.6.1" - "@vitest/spy" "1.6.1" - "@vitest/utils" "1.6.1" - acorn-walk "^8.3.2" - chai "^4.3.10" - debug "^4.3.4" - execa "^8.0.1" - local-pkg "^0.5.0" - magic-string "^0.30.5" - pathe "^1.1.1" - picocolors "^1.0.0" - std-env "^3.5.0" - strip-literal "^2.0.0" - tinybench "^2.5.1" - tinypool "^0.8.3" - vite "^5.0.0" - vite-node "1.6.1" - why-is-node-running "^2.2.2" - vitest@^3.2.6: - version "3.2.6" - resolved "https://registry.yarnpkg.com/vitest/-/vitest-3.2.6.tgz#de42ebfb58e16faba4e5a314fe35e146e03cb340" - integrity sha512-xejya+bT/j/+R/AGa1XOfRxLmNUlLtlwjRsFUILF+xHfzElmGcmFydy2gqqIrd62ptIEfwVMofd19uNWD9L7Nw== + version "3.2.7" + resolved "https://registry.yarnpkg.com/vitest/-/vitest-3.2.7.tgz#1944b6ed013a25fd26a73d18e1af92c10a57af6c" + integrity sha512-KrxIJ62Fd89gfysR4WotlgZABiz2dqFPgqGzX7s+CwsqLFomRH7777ZcrOD6+WVAh7khPQP41A+BKbpcJFrdEg== dependencies: "@types/chai" "^5.2.2" - "@vitest/expect" "3.2.6" - "@vitest/mocker" "3.2.6" - "@vitest/pretty-format" "^3.2.6" - "@vitest/runner" "3.2.6" - "@vitest/snapshot" "3.2.6" - "@vitest/spy" "3.2.6" - "@vitest/utils" "3.2.6" + "@vitest/expect" "3.2.7" + "@vitest/mocker" "3.2.7" + "@vitest/pretty-format" "^3.2.7" + "@vitest/runner" "3.2.7" + "@vitest/snapshot" "3.2.7" + "@vitest/spy" "3.2.7" + "@vitest/utils" "3.2.7" chai "^5.2.0" debug "^4.4.1" expect-type "^1.2.1" @@ -11742,17 +11419,17 @@ vitest@^3.2.6: why-is-node-running "^2.3.0" vitest@^4.0.0: - version "4.1.9" - resolved "https://registry.yarnpkg.com/vitest/-/vitest-4.1.9.tgz#98f22fbd70e2a18c4a92bb20624bc92e5dfac5f3" - integrity sha512-nE3/LEyc0z87uHYLZebqCUOaJr2hdtuPp7BQ4BosVFnfltxgAvMG08NyrSGlPpOUWvR27c5flSmYFTNr78L9GQ== - dependencies: - "@vitest/expect" "4.1.9" - "@vitest/mocker" "4.1.9" - "@vitest/pretty-format" "4.1.9" - "@vitest/runner" "4.1.9" - "@vitest/snapshot" "4.1.9" - "@vitest/spy" "4.1.9" - "@vitest/utils" "4.1.9" + version "4.1.10" + resolved "https://registry.yarnpkg.com/vitest/-/vitest-4.1.10.tgz#7e9285efe264b1167050b7a3a7ff34788e1b7afc" + integrity sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw== + dependencies: + "@vitest/expect" "4.1.10" + "@vitest/mocker" "4.1.10" + "@vitest/pretty-format" "4.1.10" + "@vitest/runner" "4.1.10" + "@vitest/snapshot" "4.1.10" + "@vitest/spy" "4.1.10" + "@vitest/utils" "4.1.10" es-module-lexer "^2.0.0" expect-type "^1.3.0" magic-string "^0.30.21" @@ -11782,12 +11459,12 @@ vscode-textmate@^8.0.0: resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-8.0.0.tgz#2c7a3b1163ef0441097e0b5d6389cd5504b59e5d" integrity sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg== -vscode-uri@^3.0.8, vscode-uri@^3.1.0: +vscode-uri@^3.0.8: version "3.1.0" resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.1.0.tgz#dd09ec5a66a38b5c3fffc774015713496d14e09c" integrity sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ== -vue-bundle-renderer@^2.2.0: +vue-bundle-renderer@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/vue-bundle-renderer/-/vue-bundle-renderer-2.3.1.tgz#e14cfd4fc0b05fd91ad67bbe67f2ea6c77c23ed7" integrity sha512-7F4LNMopUw5RgYWo4zCmVUHCc6aQRC6dCKHUYkM/n+fux4AUGdL1x6m5A515WWyFysRRN7cx3hBzVqoisfRfzw== @@ -11795,9 +11472,9 @@ vue-bundle-renderer@^2.2.0: ufo "^1.6.4" vue-component-type-helpers@^3.0.0: - version "3.3.5" - resolved "https://registry.yarnpkg.com/vue-component-type-helpers/-/vue-component-type-helpers-3.3.5.tgz#1761c8edb0f79888d593c3675adc46ad2a45d1c7" - integrity sha512-Fe1jyPJoUGpJOYKOri44jduR7My4yYINOMJISuMAbmrs+L5LbIDUc8NTWZYY3EJLK0yPLuCmcd5zoCsE4k2/KA== + version "3.3.8" + resolved "https://registry.yarnpkg.com/vue-component-type-helpers/-/vue-component-type-helpers-3.3.8.tgz#4b9ee9e71c482439a725a3c4fcc0f9f4b27b71b2" + integrity sha512-troqCMmQodQDqUqn63NQaFi+CDSclSe7sc8VEBFqf5GFLqmGR2Ph3P2WEC7qwpRVyEWsTi/aAr4vyOe/B1hU3g== vue-devtools-stub@^0.1.0: version "0.1.0" @@ -11863,23 +11540,23 @@ vue-tsc@^1.8.27: semver "^7.5.4" vue-tsc@^3.3.5: - version "3.3.5" - resolved "https://registry.yarnpkg.com/vue-tsc/-/vue-tsc-3.3.5.tgz#080783e24add23cf860647e905a7f0506c70c21e" - integrity sha512-Rzh/G2MmNlMSAMTiQEjDrsb4dgB/jbtEM47rVN2NtidF1dfb/q4w4QvpQBtW5+y3y5H27Hjh7deVwk+YB02fNg== + version "3.3.8" + resolved "https://registry.yarnpkg.com/vue-tsc/-/vue-tsc-3.3.8.tgz#a4c89e57359d135a9bb6ebdb7aa75a85555b1b12" + integrity sha512-xXmYlVQpcwJDWyGlqbHrGVOl1h3UOsASymRibrHc+iy9j/UNnOrOn4u+fntHz4D6Cs74RtapeqVV6CzJeg+UlA== dependencies: "@volar/typescript" "2.4.28" - "@vue/language-core" "3.3.5" + "@vue/language-core" "3.3.8" -vue@^3.5.34, vue@^3.5.38: - version "3.5.38" - resolved "https://registry.yarnpkg.com/vue/-/vue-3.5.38.tgz#8a6d52f1768e197545e937920d6c197fe76fc2db" - integrity sha512-vAMKHfImQlYSy0C+PBue4s3ERZ2xGKfgZg5GXAsLInq1dyh2H78ILVP5sK0KPFPVW4kv+OGCIvBEondcjpZp7A== +vue@^3.5.38, vue@^3.5.40: + version "3.5.40" + resolved "https://registry.yarnpkg.com/vue/-/vue-3.5.40.tgz#c4a9d4c62f98ea33aa811a75c3fbd476dc782184" + integrity sha512-+8PJ4SJXdn/cHGImF4CKdxlWHIN5Dkt7DoufRREM6h6uVCx2m7QxgcEQmmzyOK8A9mcafg7sFbJFYsdFVubTig== dependencies: - "@vue/compiler-dom" "3.5.38" - "@vue/compiler-sfc" "3.5.38" - "@vue/runtime-dom" "3.5.38" - "@vue/server-renderer" "3.5.38" - "@vue/shared" "3.5.38" + "@vue/compiler-dom" "3.5.40" + "@vue/compiler-sfc" "3.5.40" + "@vue/runtime-dom" "3.5.40" + "@vue/server-renderer" "3.5.40" + "@vue/shared" "3.5.40" w3c-xmlserializer@^5.0.0: version "5.0.0" @@ -12011,7 +11688,7 @@ which@^6.0.0, which@^6.0.1: dependencies: isexe "^4.0.0" -why-is-node-running@^2.2.2, why-is-node-running@^2.3.0: +why-is-node-running@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/why-is-node-running/-/why-is-node-running-2.3.0.tgz#a3f69a97107f494b3cdc3bdddd883a7d65cebf04" integrity sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w== @@ -12080,10 +11757,10 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -ws@^8.18.0, ws@^8.19.0: - version "8.21.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.21.0.tgz#012e413fc07429945121b0c153158c4343086951" - integrity sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g== +ws@^8.18.0, ws@^8.20.0: + version "8.21.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.21.1.tgz#045650cd4b1207809e7547146223c3814a9af586" + integrity sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw== wsl-utils@^0.3.0: version "0.3.1" @@ -12133,7 +11810,7 @@ yargs-parser@^22.0.0: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-22.0.0.tgz#87b82094051b0567717346ecd00fd14804b357c8" integrity sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw== -yargs@18.0.0, yargs@^18.0.0: +yargs@18.0.0: version "18.0.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-18.0.0.tgz#6c84259806273a746b09f579087b68a3c2d25bd1" integrity sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg== @@ -12145,20 +11822,27 @@ yargs@18.0.0, yargs@^18.0.0: y18n "^5.0.5" yargs-parser "^22.0.0" +yargs@^18.0.0: + version "18.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-18.1.0.tgz#cd7e98c703ef51695bbbf062ed58f28e94291b56" + integrity sha512-2rAgRKu54VsHkqI0/tYkmluGXHD4KW7yZoycuqDQ15QOTnc2VVfy0nN/1eMhnQLO00A+dwtK20xuCnc1YGeUyg== + dependencies: + cliui "^9.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + string-width "^8.2.1" + y18n "^5.0.5" + yargs-parser "^22.0.0" + yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== -yocto-queue@^1.0.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.2.2.tgz#3e09c95d3f1aa89a58c114c99223edf639152c00" - integrity sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ== - yoctocolors@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/yoctocolors/-/yoctocolors-2.1.2.tgz#d795f54d173494e7d8db93150cec0ed7f678c83a" - integrity sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug== + version "2.2.0" + resolved "https://registry.yarnpkg.com/yoctocolors/-/yoctocolors-2.2.0.tgz#c4b68ee477f3982c33e4de24a5aa4a354be506d3" + integrity sha512-xYqdZFUK/VYazNl/oCDYN+3WloWQwMfZxBoiNt6qNyk+xfOdi598muWE42rNZFp1kNOiqW936q5RhUdnpqElSg== youch-core@^0.3.3: version "0.3.3"