diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml new file mode 100644 index 000000000..e73f453e3 --- /dev/null +++ b/.github/workflows/e2e.yaml @@ -0,0 +1,82 @@ +name: E2E + +on: + push: + branches: + - main + paths: + - "packages/**" + - "examples/**" + - "e2e/**" + - "scripts/**" + - "firebase.json" + - ".github/workflows/e2e.yaml" + - ".github/workflows/test.yaml" + - "package.json" + - "pnpm-lock.yaml" + - "pnpm-workspace.yaml" + pull_request: + paths: + - "packages/**" + - "examples/**" + - "e2e/**" + - "scripts/**" + - "firebase.json" + - ".github/workflows/e2e.yaml" + - ".github/workflows/test.yaml" + - "package.json" + - "pnpm-lock.yaml" + - "pnpm-workspace.yaml" + +permissions: + contents: read + +jobs: + ui-e2e: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + + - name: Setup pnpm + uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 + with: + version: 10.34.4 + + - name: Setup node + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: 22.13.0 + cache: pnpm + cache-dependency-path: pnpm-lock.yaml + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Resolve Playwright version + id: playwright-version + run: | + version="$(pnpm --filter=e2e exec node -p "require('@playwright/test/package.json').version")" + echo "playwright-version=${version}" >> "$GITHUB_OUTPUT" + + - name: Cache Playwright browsers + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 + with: + path: ~/.cache/ms-playwright + key: playwright-${{ runner.os }}-${{ steps.playwright-version.outputs.playwright-version }} + + - name: Install Playwright browsers + run: pnpm --filter=e2e exec playwright install --with-deps chromium + + - name: Run UI e2e smoke + run: pnpm test:e2e + + - name: Upload Playwright report and coverage + if: always() + uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 + with: + name: e2e-artifacts + path: | + e2e/playwright-report/ + e2e/coverage-report/ + if-no-files-found: ignore diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 09a6ecd6f..d9174650b 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -6,24 +6,27 @@ on: - main pull_request: +permissions: + contents: read + jobs: lint: name: Lint and Format Check runs-on: ubuntu-latest - + steps: - name: Checkout code - uses: actions/checkout@v4 - + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: '22.13.0' - + - name: Setup pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 with: - version: 10 + version: 10.34.4 - name: Install addlicense run: | diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 597c6a9af..f64e77d9f 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -6,23 +6,26 @@ on: - main pull_request: +permissions: + contents: read + jobs: test: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Setup node - uses: actions/setup-node@v4 + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: 22.13.0 check-latest: true - name: Setup pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 with: - version: 10 + version: 10.34.4 - name: Install addlicense run: | diff --git a/.gitignore b/.gitignore index 80a073e53..205ae75fb 100644 --- a/.gitignore +++ b/.gitignore @@ -24,9 +24,19 @@ packages/angular/src/version.ts # Coverage coverage +# Playwright +e2e/test-results/ +e2e/.state/ +e2e/playwright-report/ +e2e/coverage-report/ +playwright-report/ + # Firebase .firebase +# Agent ephemeral output +.agents/reports/ + # Editor directories and files .vscode/* !.vscode/extensions.json diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..876137592 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,12 @@ +# Agent entry point + +Start at [developer-docs/index.md](developer-docs/index.md). + +**Before editing documentation:** read [developer-docs/documentation-policy.md](developer-docs/documentation-policy.md). + +For architecture or testing work, also read: + +* [developer-docs/decisions.md](developer-docs/decisions.md) — `AD-` decision log +* [developer-docs/work-queues/playwright-e2e-smoke.md](developer-docs/work-queues/playwright-e2e-smoke.md) — active Playwright backlog + +Human onboarding (commands, emulator): [LOCAL_DEVELOPMENT.md](LOCAL_DEVELOPMENT.md) owns that content; do not duplicate here. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ee83fab03..0700cc98d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,6 +28,8 @@ This is a monorepo managed with pnpm, containing both `packages` and `examples` For a step-by-step guide on running the project locally (emulator setup, watch mode, example apps), see [LOCAL_DEVELOPMENT.md](LOCAL_DEVELOPMENT.md). +Architecture decisions, testing strategy, and agent-oriented docs live in the [developer-docs/](developer-docs/index.md) OKF bundle. Read [developer-docs/documentation-policy.md](developer-docs/documentation-policy.md) before editing that tree. + #### Building Build all packages: diff --git a/LOCAL_DEVELOPMENT.md b/LOCAL_DEVELOPMENT.md index c32149bb8..72a6467b8 100644 --- a/LOCAL_DEVELOPMENT.md +++ b/LOCAL_DEVELOPMENT.md @@ -116,6 +116,7 @@ if (import.meta.env.MODE === "development") { ``` Each framework detects dev mode differently: + - **Vite examples** (react, shadcn): `import.meta.env.MODE === "development"` - **Next.js examples**: `process.env.NODE_ENV === "development"` - **Angular**: `isDevMode()` from `@angular/core` @@ -124,27 +125,39 @@ All automatic when using the `dev` / `start` scripts. ## Which example app should I use? -| I'm working on... | Use this example | -|---|---| -| Core auth logic, sign-in flows, state | `react` | -| React components, hooks, UI | `react` | -| Angular components or DI | `angular` | -| Shadcn components or theming | `shadcn` | -| Server-side rendering, server components | `nextjs-ssr` | -| Static Next.js / client-only | `nextjs` | -| Translations or CSS | `react` (easiest) | -| Custom OAuth flows | `custom-auth-server` (see [CUSTOM_AUTHENTICATION.md](CUSTOM_AUTHENTICATION.md)) | +| I'm working on... | Use this example | +| ---------------------------------------- | ------------------------------------------------------------------------------- | +| Core auth logic, sign-in flows, state | `react` | +| React components, hooks, UI | `react` | +| Angular components or DI | `angular` | +| Shadcn components or theming | `shadcn` | +| Server-side rendering, server components | `nextjs-ssr` | +| Static Next.js / client-only | `nextjs` | +| Translations or CSS | `react` (easiest) | +| Custom OAuth flows | `custom-auth-server` (see [CUSTOM_AUTHENTICATION.md](CUSTOM_AUTHENTICATION.md)) | The `react` example is recommended as the default — it has the fastest reload cycle. ## Running tests -Start the emulator first, then: +Start the emulator first (or let `pnpm test:e2e` start it via Playwright `globalSetup` when it is not already running), then: ```bash -# All tests: +# Package unit tests: pnpm test +# Example smoke (all six examples, serial): +pnpm test:e2e + +# Single example smoke: +pnpm test:e2e:react +pnpm test:e2e:angular +# … see root package.json for test:e2e: scripts +``` + +E2E scope and CI layers: [developer-docs/architecture/testing-strategy.md](developer-docs/architecture/testing-strategy.md). + +```bash # Watch mode (core, react, angular): pnpm test:watch diff --git a/developer-docs/architecture/examples-inventory.md b/developer-docs/architecture/examples-inventory.md new file mode 100644 index 000000000..90e90bb7f --- /dev/null +++ b/developer-docs/architecture/examples-inventory.md @@ -0,0 +1,57 @@ +--- +type: Reference +title: Examples inventory +description: How each monorepo example is started, which port it uses, and emulator requirements. +resource: firebaseui-web/examples/ +tags: [examples, monorepo, emulator] +timestamp: 2026-07-01T00:00:00Z +--- + +# Workspace layout + +pnpm workspace members: `packages/*`, `examples/*` ([pnpm-workspace.yaml](../../pnpm-workspace.yaml)). Examples consume `@firebase-oss/ui-*` via `workspace:*`. + +# Examples in scope for e2e smoke + +| Example | pnpm filter | Dev command | Default port | E2E port | Emulator in dev | Smoke type | +| ------------------ | -------------------- | --------------------------------------------- | ------------- | -------- | -------------------------------------------------- | -------------------------- | +| react | `react` | `vite` | 5173 | 5173 | `import.meta.env.MODE === "development"` → `:9099` | browser (S1–S3) | +| shadcn | `shadcn` | `vite` | 5173 | 5174 | same as react | browser (S1–S3) | +| nextjs (SSG) | `nextjs` | `next dev --turbopack` | 3000 | 3000 | `NODE_ENV === "development"` → `:9099` | browser (S1–S3) | +| nextjs-ssr | `nextjs-ssr` | `next dev` | 3000 | 3001 | same as nextjs | browser (S1–S3) | +| angular-example | `angular-example` | `run start --port 4200` (`clean && ng serve`) | 4200 | 4200 | `isDevMode()` → `:9099` | browser (S1–S3) | +| custom-auth-server | `custom-auth-server` | `start` (built Express) | 4000 (`PORT`) | 4001 | n/a (uses `firebase-admin`) | HTTP boot + `fetch`/`curl` | + +**Port configurability:** not pinned in `vite.config.ts` / `next.config.ts`. All examples accept CLI/`PORT` overrides for e2e; Playwright's top-level `webServer` (selected by `E2E_PROJECT`) owns lifecycle. Exact e2e commands: `e2e/fixtures/example-meta.ts`. See [AD-4](../decisions.md#ad-4-playwright-managed-dev-servers-serial-shared-emulator). + +**custom-auth-server port:** default `:4000` collides with the Firebase Emulator UI (`:4000`), so e2e binds `:4001` — [AD-6](../decisions.md#ad-6-custom-auth-server-binds-4001-for-e2e). Its smoke is non-browser (boot + HTTP assert); it is not in root `pnpm build`. + +**Angular:** e2e reuses the package `start` script (`pnpm clean && ng serve`) so the `.angular/cache` clean is not duplicated — [AD-4](../decisions.md#ad-4-playwright-managed-dev-servers-serial-shared-emulator). + +**Auth behaviors affecting smoke:** react/shadcn use `oneTapSignIn`; nextjs/nextjs-ssr use `autoAnonymousLogin`. Neither hides the sign-in form (`SignInAuthScreen` renders regardless of auth state), so E2E flags are optional — [AD-5](../decisions.md#ad-5-auth-behavior-e2e-flags-are-optional-only-if-flaky). The One Tap external script is blocked in the harness. + +**Next.js paths:** both nextjs (SSG) and nextjs-ssr use `trailingSlash: true` — e2e URLs end with `/` (e.g. `/screens/sign-in-auth-screen-w-handlers/`). + +**Forgot-password route varies per example** (S3 asserts rendered UI, not a fixed path): + +| Example | Forgot-password route from sign-in-with-handlers | +| ---------------------- | ------------------------------------------------ | +| react, angular-example | `/screens/forgot-password-auth-screen` | +| shadcn | `/screens/forgot-password-screen` | +| nextjs, nextjs-ssr | `/screens/forgot-password-auth-screen` | + +# Shared prerequisites + +1. `pnpm install` +2. `pnpm build:packages` (or full `pnpm build` in CI) +3. Auth emulator: `pnpm emulators` → `http://localhost:9099` ([firebase.json](../../firebase.json)) + +Procedural steps: [LOCAL_DEVELOPMENT.md](../../LOCAL_DEVELOPMENT.md) (owner for command copy-paste). + +# Smoke test entry path (all UI examples) + +Deep-link: `/screens/sign-in-auth-screen-w-handlers` (with trailing slash for Next). Smoke scope: [AD-3](../decisions.md#ad-3-playwright-example-smoke-tests-mvp-scope-dev-server). + +# Citations + +[1] [LOCAL_DEVELOPMENT.md](../../LOCAL_DEVELOPMENT.md) diff --git a/developer-docs/architecture/testing-strategy.md b/developer-docs/architecture/testing-strategy.md new file mode 100644 index 000000000..f823c7029 --- /dev/null +++ b/developer-docs/architecture/testing-strategy.md @@ -0,0 +1,34 @@ +--- +type: Reference +title: Testing strategy +description: Verification layers for firebaseui-web packages and examples. +tags: [testing, ci, playwright] +timestamp: 2026-07-03T00:00:00Z +--- + +# Layers + +| Layer | Command | Owner doc | Catches | +|-------|---------|-----------|---------| +| Package unit tests | `pnpm test` | [CONTRIBUTING.md](../../CONTRIBUTING.md) | Core/react/angular/shadcn/translations/styles logic | +| Compile (packages + examples) | `pnpm build` | [CONTRIBUTING.md](../../CONTRIBUTING.md) | TS, bundler, framework build errors | +| Lint / format | `pnpm lint:check`, `pnpm format:check` | [CONTRIBUTING.md](../../CONTRIBUTING.md) | Style regressions | +| Example smoke (browser + HTTP) | `pnpm test:e2e` | [AD-3](../decisions.md#ad-3-playwright-example-smoke-tests-mvp-scope-dev-server), [AD-4](../decisions.md#ad-4-playwright-managed-dev-servers-serial-shared-emulator), [AD-6](../decisions.md#ad-6-custom-auth-server-binds-4001-for-e2e) | Dev-server UI interactivity (five UI examples) and `custom-auth-server` HTTP boot | +| Security audit | `pnpm audit` | [playbooks/dependency-update-verification.md](../playbooks/dependency-update-verification.md) | Known CVEs in lockfile | + +# CI today + +[`.github/workflows/test.yaml`](../../.github/workflows/test.yaml): `pnpm build`, Auth emulator start, `pnpm test`. + +[`.github/workflows/e2e.yaml`](../../.github/workflows/e2e.yaml): `pnpm test:e2e` (six examples), Playwright Chromium, HTML/coverage artifacts — [AD-7](../decisions.md#ad-7-e2e-runs-in-a-separate-ci-workflow-with-broad-triggers). Auth emulator is ensured by Playwright `globalSetup` (reuse-aware). + +# Gaps + +* Skipped package integration tests (`describe.skip`). +* `custom-auth-server` not built by root `pnpm build` (e2e builds it on demand). +* Production build artifacts not exercised by e2e — deferred, [AD-8](../decisions.md#ad-8-production-artifact-e2e-deferred-future-phase). +* `pnpm audit` not gated in CI. + +# Post-dependency-update gate (target) + +See [playbooks/dependency-update-verification.md](../playbooks/dependency-update-verification.md). diff --git a/developer-docs/decisions.md b/developer-docs/decisions.md new file mode 100644 index 000000000..4d21dbff2 --- /dev/null +++ b/developer-docs/decisions.md @@ -0,0 +1,59 @@ +--- +type: Decision Log +title: Architecture decisions +description: Sequential decision log for firebaseui-web. Entries use AD-number identifiers. +tags: [adr, architecture] +timestamp: 2026-07-01T00:00:00Z +--- + +Decisions follow the shape in [ADR format (mattpocock)](https://github.com/mattpocock/skills/blob/main/skills/engineering/domain-modeling/ADR-FORMAT.md) (read that spec only during documentation maintenance runs). + +--- + +## AD-1: Dependabot cooldown per ecosystem + +Dependabot version-update PRs use a **7-day cooldown** on all ecosystems. Semver cooldown fields (`semver-major-days`, `semver-minor-days`, `semver-patch-days`) are set to 7 only where [GitHub documents SemVer-bump support](https://docs.github.com/en/code-security/reference/supply-chain-security/dependabot-options-reference#cooldown) for that package manager. GitHub Actions blocks use `default-days: 7` only. Initial config PRs (#1378 Android/iOS) merged without full cooldown; follow-ups align configs (#1380 web, #2355 Android, #1367 iOS). + +--- + +## AD-2: developer-docs OKF bundle at repository root + +Durable human+agent knowledge lives in `developer-docs/` as an [OKF v0.1](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md) bundle. Root guides (`LOCAL_DEVELOPMENT.md`, etc.) remain the owners for contributor onboarding commands; this bundle owns architecture, decisions, playbooks, and work queues. Agents should start at [developer-docs/index.md](index.md) or [AGENTS.md](../AGENTS.md). + +--- + +## AD-3: Playwright example smoke tests (MVP scope, dev-server) + +Example apps are verified with **Playwright smoke tests**, not full user-flow e2e. MVP per UI example (react, shadcn, nextjs, nextjs-ssr, angular): deep-link to the sign-in-with-handlers screen, assert form render, empty submit shows validation, and the forgot-password control navigates to a rendered forgot-password screen. Assertions target **rendered UI**, not exact URLs, because the forgot-password route differs per example ([examples-inventory.md](architecture/examples-inventory.md)). `custom-auth-server` is covered by a **non-browser boot + HTTP smoke** ([AD-6](#ad-6-custom-auth-server-binds-4001-for-e2e)), not a browser flow. Smoke runs against **dev servers**, which auto-connect the Auth emulator in dev mode; production build artifacts are out of MVP ([AD-8](#ad-8-production-artifact-e2e-deferred-future-phase)). Out of MVP: OAuth, phone/MFA, real sign-in. Package unit tests (`pnpm test`) and compile checks (`pnpm build`) remain necessary but insufficient for runtime UI regression. + +--- + +## AD-4: Playwright-managed dev servers, serial, shared emulator + +Each example has a **unique e2e port** — see [examples-inventory.md](architecture/examples-inventory.md). Playwright's **top-level** `webServer` (one at a time, selected via `E2E_PROJECT`) starts each UI example's dev server, waits for its URL, and stops it — replacing hand-rolled preflight/postflight/PID scripts. Execution is **serial** (`workers: 1`) for resource predictability and clean logs; because ports are unique, parallelization is possible later but deferred ([Deferred](work-queues/playwright-e2e-smoke.md#deferred)). **`globalSetup`** builds packages (`build:packages`, asserting `dist/` exists — examples consume built `@firebase-oss/ui-*`), ensures a single Auth emulator on `:9099` for the whole run (reuse-aware), and starts it when not already running; **`globalTeardown`** stops what globalSetup started unless the serial runner is mid-suite (`E2E_KEEP_EMULATOR=1`). Angular reuses its package `start` semantics (`pnpm clean && ng serve`) rather than duplicating the `.angular/cache` clean. + +--- + +## AD-5: Auth-behavior E2E flags are optional (only if flaky) + +`SignInAuthScreen` renders the email/password form **regardless of auth state** (verified: no redirect or hide on `currentUser`; it only fires an `onSignIn` callback). Therefore `autoAnonymousLogin` (nextjs, nextjs-ssr) and `oneTapSignIn` (react, shadcn) do **not** block the smoke form-render assertions, and the E2E env flags (`VITE_E2E` / `NEXT_PUBLIC_E2E`) that skip these behaviors are a **flakiness mitigation, not a prerequisite** — decoupled from the test phase. The external One Tap script (`accounts.google.com`) is neutralized in the harness via a **documented Playwright `page.route` block**; the env flags are a backup only if that proves insufficient. Owner for emulator connection rules: [architecture/examples-inventory.md](architecture/examples-inventory.md). + +--- + +## AD-6: custom-auth-server binds :4001 for e2e + +The Express `custom-auth-server` defaults to `:4000`, which collides with the **Firebase Emulator UI** (`:4000`). For e2e it binds **`:4001`** (via its `PORT` env) so it never conflicts with emulator services. Its smoke is a **non-browser boot + HTTP assertion** — build the example, start the built server, assert it responds, tear down — not a Playwright browser flow. This brings every monorepo example (including `custom-auth-server`) under automated e2e coverage. + +**Lifecycle:** Playwright's `webServer` readiness poll accepts only HTTP status `< 400`. Without credentials, `GET /auth/snapchat/config` returns `500`, so the HTTP smoke spec manages build/boot/poll/teardown itself (detached process group, `:4001` via `PORT`). UI examples continue to use Playwright `webServer` as in [AD-4](#ad-4-playwright-managed-dev-servers-serial-shared-emulator). + +--- + +## AD-7: e2e runs in a separate CI workflow with broad triggers + +Browser smoke runs in its **own workflow**, not folded into the unit `test.yaml`. Path-filtering is intentionally **broad**: examples depend on `packages/**` (built `@firebase-oss/ui-*`), `scripts/**` (serial runner), `firebase.json` (emulator config), the root `package.json`, `pnpm-lock.yaml`, and the `pnpm-workspace.yaml` catalog, so narrow `examples/**`-only filters would miss real regressions. Triggers therefore include packages, examples, scripts, root manifests, lockfile, workspace catalog, emulator config, and the e2e/workflow files themselves. Playwright browser binaries are **cached keyed on the resolved Playwright version** so the cache restores the actual browser artifact; Chromium-only for MVP. + +--- + +## AD-8: Production-artifact e2e deferred (future phase) + +MVP validates **dev-server runtime only**. Validating built/deployed artifacts — Next.js SSG `output: "export"`, Angular production build, `next start` SSR, and `firebase.json` hosting rewrites — is a recognized gap: dev mode auto-connects the emulator via `import.meta.env.MODE` / `process.env.NODE_ENV` / `isDevMode()`, so production builds would need explicit emulator wiring. This is tracked as a **future design phase and is intentionally NOT in the MVP work queue** ([work-queues/playwright-e2e-smoke.md](work-queues/playwright-e2e-smoke.md)). diff --git a/developer-docs/documentation-policy.md b/developer-docs/documentation-policy.md new file mode 100644 index 000000000..8bd82d00e --- /dev/null +++ b/developer-docs/documentation-policy.md @@ -0,0 +1,43 @@ +--- +type: Policy +title: Documentation policy +description: Rules for authoring and maintaining firebaseui-web documentation for humans and agents. +tags: [documentation, agents, okf] +timestamp: 2026-07-01T00:00:00Z +--- + +# Scope + +Applies to all durable documentation in this repository: the [developer-docs](index.md) OKF bundle, root markdown guides, package READMEs, and inline doc comments when they carry architectural meaning. + +**Read this document before editing any documentation.** + +# Principles + +* **Be concise.** Prefer short sentences, tables, and lists over long prose. If a fact fits in one line, do not use a paragraph. +* **Durable artifacts only.** Commits, code, and docs are long-lived. Do not store ephemeral work-queue state, session notes, or "current sprint" references in them unless the file lives under [work-queues/](work-queues/) and is explicitly treated as a living backlog. +* **Single owner per fact (document contract).** Each information item is owned by exactly one document (which may be outside this bundle). Other documents **refer** to that owner with a link; they do not duplicate the content. When the fact changes, update the owner only. + +# OKF bundle conventions + +* Bundle root: `developer-docs/` ([index.md](index.md)). +* Concept files: YAML frontmatter with required `type`; see [OKF v0.1](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md) (consult the spec only during documentation maintenance runs, not on every code change). +* Decisions: append to [decisions.md](decisions.md) as `AD-` entries. ADR shape follows [mattpocock ADR format](https://github.com/mattpocock/skills/blob/main/skills/engineering/domain-modeling/ADR-FORMAT.md) (consult that spec only during documentation maintenance runs). +* Work queues: living backlogs under [work-queues/](work-queues/); may name phases and task IDs; not cited as normative architecture. + +# Where to put new content + +| Content | Owner document | +|---------|----------------| +| Architecture shape, inventories | `developer-docs/architecture/` | +| Hard-to-reverse decisions | `developer-docs/decisions.md` | +| Step-by-step procedures | `developer-docs/playbooks/` or root guides (pick one owner) | +| Implementation backlogs | `developer-docs/work-queues/` | +| Contributor onboarding | [CONTRIBUTING.md](../CONTRIBUTING.md) | +| Local dev commands | [LOCAL_DEVELOPMENT.md](../LOCAL_DEVELOPMENT.md) | +| Agent ephemeral output | `.agents/reports/` (gitignored) | + +# Citations + +[1] [Open Knowledge Format v0.1](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md) +[2] [ADR format (mattpocock)](https://github.com/mattpocock/skills/blob/main/skills/engineering/domain-modeling/ADR-FORMAT.md) diff --git a/developer-docs/index.md b/developer-docs/index.md new file mode 100644 index 000000000..0711291ca --- /dev/null +++ b/developer-docs/index.md @@ -0,0 +1,40 @@ +--- +type: Index +title: developer-docs +description: OKF knowledge bundle entry point for firebaseui-web. +tags: [okf, documentation] +okf_version: "0.1" +timestamp: 2026-07-03T00:00:00Z +--- + +# developer-docs + +OKF knowledge bundle for firebaseui-web: architecture, decisions, playbooks, and work queues. + +**Before editing any file in this bundle:** read [documentation-policy.md](documentation-policy.md). + +# Start here + +- [documentation-policy.md](documentation-policy.md) — rules for writing and maintaining docs in this repo +- [decisions.md](decisions.md) — architecture decision log (`AD-` entries) + +# Architecture + +- [architecture/examples-inventory.md](architecture/examples-inventory.md) — example apps, ports, dev commands, emulator wiring +- [architecture/testing-strategy.md](architecture/testing-strategy.md) — unit, build, and e2e verification layers + +# Playbooks + +- [playbooks/dependency-update-verification.md](playbooks/dependency-update-verification.md) — verify monorepo after dependency bumps + +# Work queues + +Living implementation backlogs under [work-queues/](work-queues/). Task IDs and phases may change; do not treat as normative architecture — see [documentation-policy.md](documentation-policy.md). + +- [work-queues/playwright-e2e-smoke.md](work-queues/playwright-e2e-smoke.md) — Playwright example smoke tests and CI + +# Related docs (outside this bundle) + +- [LOCAL_DEVELOPMENT.md](../LOCAL_DEVELOPMENT.md) — human onboarding: emulator, dev servers, package watch +- [GETTING_STARTED.md](../GETTING_STARTED.md) — library consumer getting started +- [CONTRIBUTING.md](../CONTRIBUTING.md) — contribution workflow and CI expectations diff --git a/developer-docs/playbooks/dependency-update-verification.md b/developer-docs/playbooks/dependency-update-verification.md new file mode 100644 index 000000000..e0e35ac53 --- /dev/null +++ b/developer-docs/playbooks/dependency-update-verification.md @@ -0,0 +1,32 @@ +--- +type: Playbook +title: Dependency update verification +description: Steps to validate firebaseui-web after updating dependencies to current stable. +tags: [dependencies, security, e2e] +timestamp: 2026-07-03T00:00:00Z +--- + +# When to use + +After bumping dependencies in the monorepo root, `packages/*`, `examples/*`, or `pnpm-workspace.yaml` catalog. + +# Steps + +1. `pnpm install` +2. `pnpm build` — compile all packages and five UI examples +3. `pnpm test` — package unit tests (emulator optional for skipped integration tests) +4. `pnpm lint:check` && `pnpm format:check` +5. `pnpm audit` — triage high/critical; example-path advisories called out in PR +6. `pnpm test:e2e` — serial example smoke across all examples incl. `custom-auth-server` HTTP boot + +# CI parity + +Match [`.github/workflows/test.yaml`](../../.github/workflows/test.yaml) and [`.github/workflows/e2e.yaml`](../../.github/workflows/e2e.yaml). + +# Owners + +| Topic | Document | +| -------------------------- | --------------------------------------------------------------------------- | +| Example ports and commands | [architecture/examples-inventory.md](../architecture/examples-inventory.md) | +| E2E scope | [decisions.md](../decisions.md) (AD-3, AD-4) | +| Local emulator setup | [LOCAL_DEVELOPMENT.md](../../LOCAL_DEVELOPMENT.md) | diff --git a/developer-docs/work-queues/playwright-e2e-smoke.md b/developer-docs/work-queues/playwright-e2e-smoke.md new file mode 100644 index 000000000..2ec94adde --- /dev/null +++ b/developer-docs/work-queues/playwright-e2e-smoke.md @@ -0,0 +1,216 @@ +--- +type: Work Queue +title: Playwright example e2e smoke +description: Phased, orchestrator-processable backlog to add Playwright smoke tests for every monorepo example, run them locally and in CI, then harden dependencies. +tags: [playwright, e2e, work-queue] +timestamp: 2026-07-03T00:00:00Z +status: active +--- + +# Goal + +A fully automated e2e framework that validates each monorepo example **loads and responds to basic interaction**, runnable by **local invocation and in CI**, with one minimum-viable smoke per example. Normative scope: [AD-3](../decisions.md#ad-3-playwright-example-smoke-tests-mvp-scope-dev-server). Execution model: [AD-4](../decisions.md#ad-4-playwright-managed-dev-servers-serial-shared-emulator). Production-artifact validation is deferred: [AD-8](../decisions.md#ad-8-production-artifact-e2e-deferred-future-phase). + +# Work-queue conventions + +Ephemeral tracker; policy: [documentation-policy.md](../documentation-policy.md). This queue records **state** (gates, next step) using neutral OKF work-queue field conventions — not agent roles, dispatch, or session choreography. + +**Work types** (`next_work_type`): `gap-analysis` (read-only feasibility) · `implementation` (author code + tests) · `independent-review` (verify a frozen diff) · `documentation` (durable doc/OKF updates) · `commit` (one focused commit). + +**Validation tiers** (`validation_tier`), mapped to this repo: + +| Tier | Meaning here | +| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | +| `unit-focused` | Fast local check while authoring: `pnpm build:packages`, the targeted example's spec (`pnpm test:e2e:`), `pnpm lint:check` on the diff | +| `area-focused` | Full smoke for the changed example(s) on a frozen tree, plus `pnpm test` / lint / format as applicable | +| `full` | `pnpm build` + `pnpm test` + whole `pnpm test:e2e` across all examples before merge | + +**Gates** (`open` | `closed` | `deferred`): `implementation_gate` (implementation complete + `unit-focused` green) · `review_gate` (independent review complete on frozen tree + `area-focused` green) · `commit_gate` (durable commit exists whose subject matches `commit_subject`). `deferred` = optional work parked until a trigger (e.g. flakiness) re-opens it. Code with `review_gate: open` is untrusted until review closes it. `commit_subject` is the planned Conventional Commit subject, set **before** `git commit` and staged in the same commit; never record SHAs. + +# Smoke scenarios (MVP) + +Per UI example, one shared spec (parameterized per project). Assert on **rendered UI, not exact URLs** — the forgot-password route differs per example ([examples-inventory.md](../architecture/examples-inventory.md)); [AD-3](../decisions.md#ad-3-playwright-example-smoke-tests-mvp-scope-dev-server). + +| Step | Action | Pass criterion | +| ---- | --------------------------------- | ----------------------------------------------------------------------------- | +| S1 | `goto` sign-in-with-handlers path | Email + password fields and submit button visible | +| S2 | Click submit (empty) | Validation feedback (no successful auth required) | +| S3 | Click forgot-password control | Forgot-password screen renders (assert heading/email field, not a fixed path) | + +`custom-auth-server` is **not** a browser flow: boot the built Express server on `:4001` and assert an HTTP response ([AD-6](../decisions.md#ad-6-custom-auth-server-binds-4001-for-e2e)). + +# Orchestration model + +Playwright manages each example's dev server; no hand-rolled preflight/postflight/PID scripts ([AD-4](../decisions.md#ad-4-playwright-managed-dev-servers-serial-shared-emulator)). + +``` +scripts/e2e-run.mjs (pnpm test:e2e) + → build:packages once (assert dist/) + → start Auth emulator once (:9099, shared) + → for each example in [react, shadcn, nextjs, nextjs-ssr, angular-example, custom-auth-server]: + playwright test (E2E_PROJECT=, E2E_KEEP_EMULATOR=1) + → globalSetup: assert packages built + ensure Auth emulator on :9099 (start if needed) + → top-level webServer selected by E2E_PROJECT (UI examples only; custom-auth-server boots in spec) + → run smoke spec(s) for the project + → webServer: stop dev server (UI examples) + → globalTeardown: keep emulator alive when E2E_KEEP_EMULATOR=1 + → stop emulator if globalSetup started it (e2e-run.mjs postflight) +``` + +- **Serial:** `workers: 1`; `E2E_PROJECT` selects both the single Playwright project and the top-level `webServer`, so one dev server is up at a time. +- **Emulator:** `globalSetup` ensures `:9099` is reachable (starts via `npx firebase-tools` when not already running); serial runner sets `E2E_KEEP_EMULATOR=1` so teardown does not stop it between examples; `pnpm emulators` remains the first-class manual target ([LOCAL_DEVELOPMENT.md](../../LOCAL_DEVELOPMENT.md)). +- **Per-example debug:** `pnpm test:e2e:react` runs one project; `globalSetup` starts the emulator with reuse if not already running. + +# Example ports, commands, and root scripts + +Owner: [architecture/examples-inventory.md](../architecture/examples-inventory.md) (human reference) and `e2e/fixtures/example-meta.ts` (runtime). Root `package.json` defines `test:e2e` (serial runner) and `test:e2e:` debug entrypoints. + +# CI coverage + +See [architecture/testing-strategy.md](../architecture/testing-strategy.md) and [`.github/workflows/e2e.yaml`](../../.github/workflows/e2e.yaml). Workflow runs `pnpm test:e2e` with broad path triggers — [AD-7](../decisions.md#ad-7-e2e-runs-in-a-separate-ci-workflow-with-broad-triggers). + +# Per-item iteration protocol + +Each item runs one serial loop; the queue records the outcome after each step. + +| Step | Work type | Closes gate | +| ---- | -------------------- | ------------------------------------------------------------------------------------- | +| 1 | `implementation` | `implementation_gate` (`unit-focused` green) | +| 2 | `independent-review` | `review_gate` (frozen tree, `area-focused` green; blocking findings → back to step 1) | +| 3 | `documentation` | — (only if durable docs/OKF changed) | +| 4 | `commit` | `commit_gate` (set `commit_subject`, stage queue with product change) | + +# Work items + +## Phase 1 — React vertical slice (infra + first test + CI proof) + +Prove the whole model end-to-end on one example before generalizing ([review finding #13](#review-notes)). + +| ID | Task | Depends | Done when | +| --- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------------------------------------------------------------- | +| 1.1 | `e2e/` workspace package; `@playwright/test` pinned via pnpm catalog; skeleton `playwright.config.ts` | — | Package installs; empty config runs | +| 1.2 | `globalSetup`/`globalTeardown`: run `build:packages` and assert `dist/`; ensure/start shared Auth emulator on `:9099`; stop what it started | 1.1 | Setup fails fast with clear errors; emulator reused if already up | +| 1.3 | `e2e/fixtures/example-meta.ts`: seed react (baseURL, sign-in path, trailing-slash rule, forgot-password target) | 1.1 | Per-example path rules centralized | +| 1.4 | react project `webServer` (`vite --port 5173 --strictPort`); harness `page.route` block of `accounts.google.com` **with a comment explaining why** (One Tap external/flaky — [AD-5](../decisions.md#ad-5-auth-behavior-e2e-flags-are-optional-only-if-flaky)) | 1.2, 1.3 | react dev server managed by Playwright; One Tap script never loaded | +| 1.5 | `e2e/tests/sign-in-handlers.spec.ts` S1–S3, asserting rendered UI, parameterized per project | 1.4 | react smoke green locally | +| 1.6 | Minimal CI job proving react e2e runs green (browser install + emulator + `test:e2e:react`) | 1.5 | react smoke green in CI | + +## Phase 2 — Generalize Vite/Next examples + serial runner + +| ID | Task | Depends | Done when | +| --- | ------------------------------------------------------------------------------------------------------------- | ------- | -------------------------------------------------------------- | +| 2.1 | shadcn project + meta (`vite --port 5174`; forgot-password → `/screens/forgot-password-screen`) | 1.5 | shadcn smoke green | +| 2.2 | nextjs project + meta (`next dev -p 3000`; `trailingSlash`) | 1.5 | nextjs smoke green | +| 2.3 | nextjs-ssr project + meta (`next dev -p 3001`; generous `webServer.timeout`) | 1.5 | nextjs-ssr smoke green | +| 2.5 | `scripts/e2e-run.mjs` serial runner + root `test:e2e` / `test:e2e:` scripts; CI runs `pnpm test:e2e` | 2.1–2.3 | `pnpm test:e2e` covers all wired UI examples locally and in CI | + +## Phase 2b — Angular-example e2e + +Split from Phase 2 when bootstrap failed under workspace linking; resolved via peer-resolved injected workspace dependency and provider factory cleanup in `@firebase-oss/ui-angular`. + +| ID | Task | Depends | Done when | +| ---- | ------------------------------------------------------------------------------------------- | ------- | ------------------------------------------------- | +| 2b.1 | angular-example project + meta (reuse `run start -- --port 4200`, i.e. `clean && ng serve`) | 2.5 | meta + `test:e2e:angular` wired | +| 2b.2 | Fix client bootstrap so sign-in form renders in Playwright | 2b.1 | S1–S3 pass locally | +| 2b.3 | Add angular-example to `e2e-run.mjs` + `pnpm test:e2e` | 2b.2 | serial runner includes angular (five UI examples) | +| 2b.4 | Confirm `pnpm test:e2e` in CI includes angular | 2b.3 | CI serial smoke includes angular | + +## Phase 3 — CI hardening + +Depends on Phase 2 CI baseline ([2.5](#phase-2--generalize-vitenext-examples--serial-runner)). + +| ID | Task | Depends | Done when | +| --- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------- | -------------------------------------------------------------- | +| 3.1 | E2e workflow hardening: `playwright install --with-deps chromium` with **browser cache keyed on resolved Playwright version**; confirm `pnpm test:e2e` green in CI | 2.5 | e2e green on PRs; browsers cached across runs | +| 3.2 | Broad path triggers: `packages/**`, `examples/**`, root `package.json`, `pnpm-lock.yaml`, `pnpm-workspace.yaml`, `e2e/**`, workflow file ([AD-7](../decisions.md#ad-7-e2e-runs-in-a-separate-ci-workflow-with-broad-triggers)) | 3.1 | Relevant PRs trigger e2e; shared-dependency changes not missed | + +## Phase 4 — custom-auth-server smoke + +| ID | Task | Depends | Done when | +| --- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | ------------------------------------------------------------- | +| 4.1 | Bind `custom-auth-server` to `:4001` for e2e; boot built server + assert HTTP response (non-browser); wire into runner + CI ([AD-6](../decisions.md#ad-6-custom-auth-server-binds-4001-for-e2e)) | 2.5, 3.1 | custom-auth-server smoke in `pnpm test:e2e` locally and in CI | + +## Phase 5 — Optional auth-behavior flags (deferred) + +Deferred — no flakiness observed; `page.route` One Tap block is sufficient ([AD-5](../decisions.md#ad-5-auth-behavior-e2e-flags-are-optional-only-if-flaky)). Re-open only if smoke becomes unstable. + +| ID | Task | Depends | Done when | +| --- | ----------------------------------------------------------------------- | ------- | --------------------------------------- | +| 5.1 | react + shadcn: skip `oneTapSignIn` when `VITE_E2E=1` | 2.1 | Only if `page.route` block insufficient | +| 5.2 | nextjs + nextjs-ssr: skip `autoAnonymousLogin` when `NEXT_PUBLIC_E2E=1` | 2.3 | Only if anon sign-in destabilizes smoke | + +## Phase 6 — Dependency hardening (after smoke green) + +Includes **package/catalog deps and CI workflow deps** (Node version, GitHub Actions pins) in one bump pass — not package deps alone. + +| ID | Task | Depends | Done when | +| --- | ------------------------------------------------------------------------------------------------------------ | ------- | ---------------------- | +| 6.1 | Align catalog/example deps, root `packageManager`, **and** CI workflow toolchain (Node LTS, pinned actions in test/lint/e2e) to current stable | 3.1 | CVE audit improved; one Node version across workflows | +| 6.2 | Run [dependency-update-verification.md](../playbooks/dependency-update-verification.md) including `test:e2e` | 6.1 | Smoke passes on dep PR | +| 6.3 | Optional `pnpm audit --audit-level=high` in CI | 6.2 | Team decision | +| 6.4 | Instrumented e2e coverage: Istanbul-instrumented package/example builds, line-resolved NYC/LCOV report, CI artifact | 6.2 | Per-package line coverage from smoke; guides test gap analysis | + +# Gate tracker + +Update immediately after each step closes a gate. All items start `open` / `implementation`. + +| Phase | Item | `implementation_gate` | `review_gate` | `commit_gate` | `commit_subject` | `next_work_type` | `validation_tier` | Notes | +| ----- | ------------------------------------------- | --------------------- | ------------- | ------------- | ----------------------------------------------------------------------- | ---------------- | ----------------- | ------------------------------- | +| 1 | 1.1–1.6 Phase 1 (react vertical slice) | closed | closed | closed | test(e2e): install/configure playwright, implement react e2e smoke test | — | — | | +| 2 | 2.1–2.3 shadcn, nextjs, nextjs-ssr | closed | closed | closed | test: working e2e tests for shadcn, nextjs, and nextjs-ssr | — | — | | +| 2 | 2.5 serial runner + root scripts | closed | closed | closed | test: working e2e tests for shadcn, nextjs, and nextjs-ssr | — | — | | +| 2b | 2b.1–2b.4 angular-example e2e | closed | closed | closed | test(angular): e2e test for angular example | — | — | | +| 3 | 3.1–3.2 CI hardening | closed | closed | closed | ci(e2e): harden workflow triggers and browser cache | — | — | | +| 4 | 4.1 custom-auth-server HTTP smoke (:4001) | closed | closed | closed | test(e2e): add custom-auth-server HTTP smoke on :4001 | — | — | | +| 5 | 5.1 VITE_E2E skip oneTapSignIn | deferred | deferred | deferred | — | — | — | optional; no flakiness observed | +| 5 | 5.2 NEXT_PUBLIC_E2E skip autoAnonymousLogin | deferred | deferred | deferred | — | — | — | optional; no flakiness observed | +| 6 | 6.1 align catalog + CI workflow deps | open | open | open | — | implementation | area-focused | Node/actions with package bump | +| 6 | 6.2 dep-update playbook incl. test:e2e | open | open | open | — | implementation | full | | +| 6 | 6.3 optional audit gate | open | open | open | — | implementation | unit-focused | team decision | +| 6 | 6.4 instrumented e2e line coverage | open | open | open | — | implementation | area-focused | Istanbul + LCOV artifact | + +# File layout (target) + +``` +e2e/ +├── package.json +├── playwright.config.ts # projects + top-level webServer selected by E2E_PROJECT; globalSetup/teardown +├── global-setup.ts # build:packages assert + start/reuse emulator +├── global-teardown.ts # stop emulator if started here +├── fixtures/ +│ └── example-meta.ts # per-example routing and server metadata (ui | http kind) +└── tests/ + ├── sign-in-handlers.spec.ts + └── custom-auth-server.spec.ts +scripts/ +└── e2e-run.mjs # serial per-example runner for `pnpm test:e2e` +``` + +# Deferred + +| Item | Reason | +| -------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | +| Auth-behavior E2E flags (`VITE_E2E`, `NEXT_PUBLIC_E2E`) | No flakiness observed; `page.route` block sufficient — [AD-5](../decisions.md#ad-5-auth-behavior-e2e-flags-are-optional-only-if-flaky) | +| Istanbul line coverage from e2e smoke | Phase 6.4; interim V8 byte metrics in `e2e/coverage-report/` | +| Production-artifact e2e (SSG export, SSR `next start`, Angular prod build, hosting rewrites) | Future design phase; MVP is dev-server only — [AD-8](../decisions.md#ad-8-production-artifact-e2e-deferred-future-phase) | +| Parallel multi-example e2e | Unique ports make it possible later; serial sufficient for MVP — [AD-4](../decisions.md#ad-4-playwright-managed-dev-servers-serial-shared-emulator) | +| Real emulator sign-in flows | Post-MVP user scenarios | +| Multi-browser matrix | Chromium only for MVP | +| Angular-SSR smoke | Angular tested via CSR `ng serve`; SSR path deferred | + +# Review notes + +Feasibility review (verified against code) that shaped this queue: + +- Deep-link `/screens/sign-in-auth-screen-w-handlers` exists in all five UI examples; forgot-password target differs (shadcn `/screens/forgot-password-screen` vs react/angular `/screens/forgot-password-auth-screen`) → S3 asserts rendered UI. +- `SignInAuthScreen` renders the form regardless of auth state → auth-behavior flags decoupled (Phase 5, optional). +- Playwright top-level `webServer` selected by `E2E_PROJECT` + `globalSetup` replace hand-rolled orchestration (biggest simplification). +- `custom-auth-server` default `:4000` collides with Emulator UI → `:4001`. +- CI path-filtering must be broad (examples depend on `packages/**`, root manifests, lockfile, catalog). +- #13: react-only vertical slice first, to validate the model cheaply. + +# Related + +- [architecture/examples-inventory.md](../architecture/examples-inventory.md) +- [architecture/testing-strategy.md](../architecture/testing-strategy.md) +- [playbooks/dependency-update-verification.md](../playbooks/dependency-update-verification.md) diff --git a/e2e/firebase.emulator.json b/e2e/firebase.emulator.json new file mode 100644 index 000000000..0e0829334 --- /dev/null +++ b/e2e/firebase.emulator.json @@ -0,0 +1,8 @@ +{ + "emulators": { + "auth": { + "port": 9099 + }, + "singleProjectMode": true + } +} diff --git a/e2e/fixtures/coverage-artifacts.mjs b/e2e/fixtures/coverage-artifacts.mjs new file mode 100644 index 000000000..4673b34cc --- /dev/null +++ b/e2e/fixtures/coverage-artifacts.mjs @@ -0,0 +1,28 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { existsSync, rmSync } from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const E2E_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); +export const COVERAGE_DIR = path.join(E2E_DIR, "coverage-report"); + +export function resetCoverageArtifacts() { + if (existsSync(COVERAGE_DIR)) { + rmSync(COVERAGE_DIR, { recursive: true, force: true }); + } +} diff --git a/e2e/fixtures/example-meta.ts b/e2e/fixtures/example-meta.ts new file mode 100644 index 000000000..736c69d5e --- /dev/null +++ b/e2e/fixtures/example-meta.ts @@ -0,0 +1,129 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Whether an example is exercised through the browser (UI smoke S1–S3) or as a + * non-browser HTTP boot smoke (custom-auth-server). See AD-6. + */ +export type ExampleKind = "ui" | "http"; + +/** Shared server/startup metadata for every Playwright project. */ +type BaseExampleMeta = { + /** Playwright project name (matches pnpm filter where applicable). */ + name: string; + /** Server origin used as Playwright baseURL. */ + baseURL: string; + /** Optional server command for Playwright webServer. */ + webServerCommand?: string; + /** Optional Playwright webServer startup timeout (ms). */ + webServerTimeoutMs?: number; + /** URL Playwright polls until the server is ready (defaults to baseURL). */ + webServerHealthURL?: string; +}; + +/** Browser example: rendered UI smoke over the sign-in-with-handlers flow. */ +export type UiExampleMeta = BaseExampleMeta & { + kind: "ui"; + /** Deep-link path for the sign-in-with-handlers smoke entry screen. */ + signInWithHandlersPath: string; + /** Whether URLs for this example require a trailing slash (Next.js). */ + trailingSlash: boolean; + /** Forgot-password route from sign-in-with-handlers (S3 asserts UI, not this path). */ + forgotPasswordPath: string; +}; + +/** Non-browser example: boot the server and assert an HTTP response. */ +export type HttpExampleMeta = BaseExampleMeta & { + kind: "http"; + /** Path probed by the HTTP smoke (relative to baseURL). */ + smokePath: string; +}; + +export type ExampleMeta = UiExampleMeta | HttpExampleMeta; + +export const exampleMeta: Record = { + react: { + kind: "ui", + name: "react", + baseURL: "http://localhost:5173", + signInWithHandlersPath: "/screens/sign-in-auth-screen-w-handlers", + trailingSlash: false, + forgotPasswordPath: "/screens/forgot-password-auth-screen", + webServerCommand: "pnpm --filter=react exec vite --port 5173 --strictPort", + }, + shadcn: { + kind: "ui", + name: "shadcn", + baseURL: "http://localhost:5174", + signInWithHandlersPath: "/screens/sign-in-auth-screen-w-handlers", + trailingSlash: false, + forgotPasswordPath: "/screens/forgot-password-screen", + webServerCommand: "pnpm --filter=shadcn exec vite --port 5174 --strictPort", + }, + nextjs: { + kind: "ui", + name: "nextjs", + baseURL: "http://localhost:3000", + signInWithHandlersPath: "/screens/sign-in-auth-screen-w-handlers", + trailingSlash: true, + forgotPasswordPath: "/screens/forgot-password-auth-screen", + webServerCommand: "pnpm --filter=nextjs exec next dev --turbopack -p 3000", + webServerTimeoutMs: 180_000, + }, + "nextjs-ssr": { + kind: "ui", + name: "nextjs-ssr", + baseURL: "http://localhost:3001", + signInWithHandlersPath: "/screens/sign-in-auth-screen-w-handlers", + trailingSlash: true, + forgotPasswordPath: "/screens/forgot-password-auth-screen", + webServerCommand: "pnpm --filter=nextjs-ssr exec next dev -p 3001", + webServerTimeoutMs: 180_000, + }, + "angular-example": { + kind: "ui", + name: "angular-example", + baseURL: "http://localhost:4200", + signInWithHandlersPath: "/screens/sign-in-auth-screen-w-handlers", + trailingSlash: false, + forgotPasswordPath: "/screens/forgot-password-auth-screen", + webServerCommand: "pnpm --filter=angular-example run start --port 4200", + webServerTimeoutMs: 240_000, + }, + // AD-6: non-browser HTTP smoke; lifecycle in custom-auth-server.spec.ts + "custom-auth-server": { + kind: "http", + name: "custom-auth-server", + baseURL: "http://localhost:4001", + smokePath: "/auth/snapchat/config", + }, +}; + +/** UI examples (browser smoke S1–S3), narrowed by discriminant. */ +export const uiExampleEntries: [string, UiExampleMeta][] = Object.entries(exampleMeta).filter( + (entry): entry is [string, UiExampleMeta] => entry[1].kind === "ui" +); + +/** Returns the sign-in-with-handlers path respecting per-example trailing-slash rules. */ +export function signInWithHandlersUrl(meta: UiExampleMeta): string { + const { signInWithHandlersPath, trailingSlash } = meta; + + if (trailingSlash) { + return signInWithHandlersPath.endsWith("/") ? signInWithHandlersPath : `${signInWithHandlersPath}/`; + } + + return signInWithHandlersPath.endsWith("/") ? signInWithHandlersPath.slice(0, -1) : signInWithHandlersPath; +} diff --git a/e2e/fixtures/test-harness.ts b/e2e/fixtures/test-harness.ts new file mode 100644 index 000000000..2eef0d186 --- /dev/null +++ b/e2e/fixtures/test-harness.ts @@ -0,0 +1,36 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { test as base, expect } from "@playwright/test"; +import { startV8Coverage, stopV8Coverage } from "./v8-coverage"; + +export const test = base.extend({ + page: async ({ page }, use, testInfo) => { + // Block Google One Tap (accounts.google.com): external script is flaky in e2e and + // unnecessary for sign-in form smoke tests (AD-5). Prefer route blocking over app flags. + await page.route("**/*accounts.google.com/**", (route) => route.abort()); + + const coverageSession = testInfo.project.name !== "custom-auth-server" ? await startV8Coverage(page) : null; + + await use(page); + + if (coverageSession) { + await stopV8Coverage(coverageSession, testInfo.title, testInfo.project.name); + } + }, +}); + +export { expect }; diff --git a/e2e/fixtures/v8-coverage.ts b/e2e/fixtures/v8-coverage.ts new file mode 100644 index 000000000..224095b11 --- /dev/null +++ b/e2e/fixtures/v8-coverage.ts @@ -0,0 +1,135 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; +import path from "node:path"; +import type { CDPSession, Page } from "@playwright/test"; +import { COVERAGE_DIR, resetCoverageArtifacts } from "./coverage-artifacts.mjs"; + +export { resetCoverageArtifacts }; + +const RAW_FILE = path.join(COVERAGE_DIR, "raw.jsonl"); +const SUMMARY_FILE = path.join(COVERAGE_DIR, "summary.json"); + +type CoverageEntry = { + label: string; + project: string; + urlCount: number; + /** Sum of (range byte length × execution count) across V8 scripts — not raw byte size. */ + weightedExecUnits: number; + timestamp: string; +}; + +export async function startV8Coverage(page: Page): Promise { + try { + const client = await page.context().newCDPSession(page); + await client.send("Profiler.enable"); + await client.send("Profiler.startPreciseCoverage", { callCount: true, detailed: true }); + return client; + } catch { + return null; + } +} + +type CoverageScript = { + url: string; + functions: Array<{ + ranges: Array<{ startOffset: number; endOffset: number; count: number }>; + }>; +}; + +function weightedExecUnits(scripts: CoverageScript[]): number { + return scripts.reduce( + (sum, script) => + sum + + script.functions.reduce( + (fnSum, fn) => + fnSum + + fn.ranges.reduce( + (rangeSum, range) => + range.count > 0 ? rangeSum + (range.endOffset - range.startOffset) * range.count : rangeSum, + 0 + ), + 0 + ), + 0 + ); +} + +export async function stopV8Coverage(client: CDPSession, label: string, project: string): Promise { + try { + const { result } = await client.send("Profiler.takePreciseCoverage"); + await client.send("Profiler.stopPreciseCoverage"); + await client.detach(); + + mkdirSync(COVERAGE_DIR, { recursive: true }); + const scripts = result as CoverageScript[]; + const urlCount = scripts.length; + const entry: CoverageEntry = { + label, + project, + urlCount, + weightedExecUnits: weightedExecUnits(scripts), + timestamp: new Date().toISOString(), + }; + // raw.jsonl is highly compressible (repetitive JSON); upload-artifact zips it. + appendFileSync(RAW_FILE, `${JSON.stringify({ entry, result })}\n`, "utf8"); + } catch { + // Coverage is best-effort proof-of-exercise, not a gate. + } +} + +/** Writes a run-level summary for artifact comparison across CI runs. */ +export function finalizeCoverageReport(): void { + if (!existsSync(RAW_FILE)) { + return; + } + + const lines = readFileSync(RAW_FILE, "utf8") + .split("\n") + .filter(Boolean) + .map((line) => JSON.parse(line) as { entry: CoverageEntry }); + + const byProject = new Map(); + + for (const { entry } of lines) { + const current = byProject.get(entry.project) ?? { tests: 0, urlCount: 0, weightedExecUnits: 0 }; + current.tests += 1; + current.urlCount += entry.urlCount; + current.weightedExecUnits += entry.weightedExecUnits; + byProject.set(entry.project, current); + } + + mkdirSync(COVERAGE_DIR, { recursive: true }); + writeFileSync( + SUMMARY_FILE, + JSON.stringify( + { + generatedAt: new Date().toISOString(), + note: "V8 precise coverage from browser smoke tests; weightedExecUnits compares exercised script volume across runs, not Istanbul line coverage of package sources.", + projects: Object.fromEntries(byProject), + totals: { + tests: lines.length, + urlCount: [...byProject.values()].reduce((sum, row) => sum + row.urlCount, 0), + weightedExecUnits: [...byProject.values()].reduce((sum, row) => sum + row.weightedExecUnits, 0), + }, + }, + null, + 2 + ), + "utf8" + ); +} diff --git a/e2e/global-setup.ts b/e2e/global-setup.ts new file mode 100644 index 000000000..0c211ceb4 --- /dev/null +++ b/e2e/global-setup.ts @@ -0,0 +1,196 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { execSync, spawn, type ChildProcess } from "node:child_process"; +import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; +import net from "node:net"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const E2E_DIR = path.dirname(fileURLToPath(import.meta.url)); +const REPO_ROOT = path.resolve(E2E_DIR, ".."); +const STATE_DIR = path.join(E2E_DIR, ".state"); +const STATE_FILE = path.join(STATE_DIR, "emulator.json"); +/** Auth-only config — avoids root firebase.json framework hosting and global webframeworks experiment. */ +const EMULATOR_CONFIG = path.join(E2E_DIR, "firebase.emulator.json"); +const TEST_WORKFLOW = path.join(REPO_ROOT, ".github/workflows/test.yaml"); +const AUTH_EMULATOR_URL = "http://127.0.0.1:9099"; +const EMULATOR_WAIT_MS = 240_000; + +/** Core library packages built by `build:packages`; examples import these artifacts. */ +const REQUIRED_DIST_ARTIFACTS = [ + "packages/translations/dist/index.js", + "packages/styles/dist/index.js", + "packages/core/dist/index.js", + "packages/react/dist/index.js", + "packages/angular/dist/fesm2022/firebase-oss-ui-angular.mjs", +] as const; + +type EmulatorState = { + startedBySetup: boolean; + pid?: number; +}; + +/** DRY: firebase-tools version is owned by `.github/workflows/test.yaml` (Install Firebase CLI step). */ +function readFirebaseToolsVersion(): string { + const content = readFileSync(TEST_WORKFLOW, "utf8"); + const match = content.match(/firebase-tools@(\d+\.\d+\.\d+)/); + const version = match?.[1]; + if (!version) { + throw new Error(`Could not parse firebase-tools version from ${TEST_WORKFLOW}`); + } + return version; +} + +function readEmulatorState(): EmulatorState | null { + try { + return JSON.parse(readFileSync(STATE_FILE, "utf8")) as EmulatorState; + } catch { + return null; + } +} + +async function isAuthEmulatorReachable(): Promise { + return new Promise((resolve) => { + const socket = net.connect({ port: 9099, host: "127.0.0.1" }); + socket.once("connect", () => { + socket.destroy(); + resolve(true); + }); + socket.once("error", () => resolve(false)); + socket.setTimeout(2_000, () => { + socket.destroy(); + resolve(false); + }); + }); +} + +async function waitForAuthEmulator(timeoutMs = EMULATOR_WAIT_MS): Promise { + const deadline = Date.now() + timeoutMs; + + while (Date.now() < deadline) { + if (await isAuthEmulatorReachable()) { + return; + } + + await new Promise((resolve) => setTimeout(resolve, 2_000)); + } + + throw new Error(`Auth emulator did not become reachable at ${AUTH_EMULATOR_URL} within ${timeoutMs / 1000}s`); +} + +function assertPackagesBuilt(): void { + const missing = REQUIRED_DIST_ARTIFACTS.filter((artifact) => !existsSync(path.join(REPO_ROOT, artifact))); + + if (missing.length > 0) { + throw new Error( + `Expected built package artifacts are missing after build:packages:\n${missing.map((entry) => ` - ${entry}`).join("\n")}` + ); + } +} + +function runBuildPackages(): void { + try { + execSync("pnpm build:packages", { + cwd: REPO_ROOT, + stdio: "inherit", + }); + } catch { + throw new Error("pnpm build:packages failed — examples require built @firebase-oss/ui-* packages"); + } + + assertPackagesBuilt(); +} + +function writeEmulatorState(state: EmulatorState): void { + mkdirSync(STATE_DIR, { recursive: true }); + writeFileSync(STATE_FILE, JSON.stringify(state, null, 2)); +} + +function ensureFirebaseToolsCached(version: string): void { + try { + execSync(`npx --yes firebase-tools@${version} --version`, { + cwd: REPO_ROOT, + stdio: "pipe", + }); + } catch { + throw new Error(`Failed to cache firebase-tools@${version} via npx — Auth emulator cannot start`); + } +} + +function startAuthEmulator(version: string): ChildProcess { + const child = spawn( + "npx", + [ + "--yes", + `firebase-tools@${version}`, + "emulators:start", + "--config", + EMULATOR_CONFIG, + "--only", + "auth", + "--project", + "demo-test", + ], + { + cwd: REPO_ROOT, + detached: true, + stdio: "ignore", + } + ); + + if (child.pid === undefined) { + throw new Error("Failed to start Auth emulator: spawn returned no PID"); + } + + child.unref(); + return child; +} + +export default async function globalSetup(): Promise { + if (process.env.E2E_SKIP_BUILD_PACKAGES === "1") { + assertPackagesBuilt(); + } else { + runBuildPackages(); + } + + if (await isAuthEmulatorReachable()) { + const existing = readEmulatorState(); + writeEmulatorState({ + startedBySetup: existing?.startedBySetup ?? false, + pid: existing?.pid, + }); + return; + } + + const firebaseToolsVersion = readFirebaseToolsVersion(); + ensureFirebaseToolsCached(firebaseToolsVersion); + const emulatorProcess = startAuthEmulator(firebaseToolsVersion); + + try { + await waitForAuthEmulator(); + } catch (error) { + try { + process.kill(-emulatorProcess.pid!, "SIGTERM"); + } catch { + // Process may already have exited. + } + + throw error; + } + + writeEmulatorState({ startedBySetup: true, pid: emulatorProcess.pid }); +} diff --git a/e2e/global-teardown.ts b/e2e/global-teardown.ts new file mode 100644 index 000000000..586323dc7 --- /dev/null +++ b/e2e/global-teardown.ts @@ -0,0 +1,61 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { readFileSync, rmSync } from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { finalizeCoverageReport } from "./fixtures/v8-coverage"; + +const E2E_DIR = path.dirname(fileURLToPath(import.meta.url)); +const STATE_FILE = path.join(E2E_DIR, ".state", "emulator.json"); + +type EmulatorState = { + startedBySetup: boolean; + pid?: number; +}; + +function readEmulatorState(): EmulatorState | null { + try { + return JSON.parse(readFileSync(STATE_FILE, "utf8")) as EmulatorState; + } catch { + return null; + } +} + +export default async function globalTeardown(): Promise { + finalizeCoverageReport(); + + // Serial runner keeps the emulator alive between projects; it performs final stop. + if (process.env.E2E_KEEP_EMULATOR === "1") { + return; + } + + const state = readEmulatorState(); + + if (state?.startedBySetup && state.pid !== undefined) { + try { + process.kill(-state.pid, "SIGTERM"); + } catch { + // Emulator may already have stopped. + } + } + + try { + rmSync(path.dirname(STATE_FILE), { recursive: true, force: true }); + } catch { + // Best-effort cleanup of ephemeral setup state. + } +} diff --git a/e2e/package.json b/e2e/package.json new file mode 100644 index 000000000..4ad728b65 --- /dev/null +++ b/e2e/package.json @@ -0,0 +1,12 @@ +{ + "name": "e2e", + "private": true, + "type": "module", + "scripts": { + "test": "node ../scripts/e2e-run.mjs" + }, + "devDependencies": { + "@firebase-oss/ui-translations": "workspace:*", + "@playwright/test": "catalog:" + } +} diff --git a/e2e/playwright.config.ts b/e2e/playwright.config.ts new file mode 100644 index 000000000..3f43f3afb --- /dev/null +++ b/e2e/playwright.config.ts @@ -0,0 +1,75 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { defineConfig } from "@playwright/test"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { exampleMeta, type ExampleMeta } from "./fixtures/example-meta"; + +const REPO_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); + +const DEFAULT_WEB_SERVER_TIMEOUT_MS = 120_000; +// Dev-server cold starts and client-side hydration vary widely (Angular ng serve, Next turbopack, +// etc.); a generous expect timeout avoids post-navigation assertion flakes without per-project tuning. +const EXPECT_TIMEOUT_MS = 30_000; + +function webServerForMeta(meta: ExampleMeta) { + if (!meta.webServerCommand) { + return undefined; + } + + return { + command: meta.webServerCommand, + url: meta.webServerHealthURL ?? meta.baseURL, + cwd: REPO_ROOT, + reuseExistingServer: !process.env.CI, + timeout: meta.webServerTimeoutMs ?? DEFAULT_WEB_SERVER_TIMEOUT_MS, + }; +} + +/** Playwright only reads top-level webServer (not per-project). Serial runner sets E2E_PROJECT. */ +function resolveWebServerMeta() { + if (process.env.E2E_PROJECT) { + return exampleMeta[process.env.E2E_PROJECT]; + } + + return Object.values(exampleMeta).find((meta) => meta.webServerCommand); +} + +const webServerMeta = resolveWebServerMeta(); +const webServer = webServerMeta ? webServerForMeta(webServerMeta) : undefined; + +export default defineConfig({ + testDir: "./tests", + workers: 1, + globalSetup: "./global-setup.ts", + globalTeardown: "./global-teardown.ts", + reporter: [ + ["list"], + ["html", { outputFolder: "playwright-report", open: "never" }], + ["json", { outputFile: "playwright-report/results.json" }], + ], + ...(webServer ? { webServer } : {}), + projects: Object.values(exampleMeta).map((meta) => ({ + name: meta.name, + timeout: meta.name === "angular-example" ? 90_000 : undefined, + expect: { timeout: EXPECT_TIMEOUT_MS }, + use: { + baseURL: meta.baseURL, + actionTimeout: meta.name === "angular-example" ? 15_000 : undefined, + }, + })), +}); diff --git a/e2e/tests/custom-auth-server.spec.ts b/e2e/tests/custom-auth-server.spec.ts new file mode 100644 index 000000000..e8d15bc7e --- /dev/null +++ b/e2e/tests/custom-auth-server.spec.ts @@ -0,0 +1,120 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { spawn, spawnSync, type ChildProcess } from "node:child_process"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { expect, request, test } from "@playwright/test"; +import { exampleMeta, type HttpExampleMeta } from "../fixtures/example-meta"; + +/** HTTP boot smoke for custom-auth-server — AD-6. */ +const PROJECT = "custom-auth-server"; +const PORT = "4001"; +const REPO_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", ".."); +const CUSTOM_AUTH_SERVER_DIR = path.join(REPO_ROOT, "examples", "custom-auth-server"); +/** Canonical start command: examples/custom-auth-server/package.json `"start": "node build/index.js"`. */ +const SERVER_ENTRY = path.join(CUSTOM_AUTH_SERVER_DIR, "build", "index.js"); + +const meta = exampleMeta[PROJECT]; +if (meta.kind !== "http") { + throw new Error(`Expected ${PROJECT} to be an http example, got kind "${meta.kind}"`); +} +const httpMeta: HttpExampleMeta = meta; + +let server: ChildProcess | undefined; + +function stopServer(): void { + if (!server || server.pid === undefined || server.exitCode !== null) { + return; + } + // Spawned detached so teardown can signal the process group (AD-6). + try { + process.kill(-server.pid, "SIGTERM"); + } catch { + server.kill("SIGTERM"); + } +} + +async function waitForServer(url: string, timeoutMs = 60_000): Promise { + const context = await request.newContext(); + const deadline = Date.now() + timeoutMs; + + try { + while (Date.now() < deadline) { + if (server?.exitCode != null) { + throw new Error(`custom-auth-server exited early with code ${server.exitCode}`); + } + try { + // Any HTTP response means the server is listening (AD-6). + await context.get(url, { timeout: 2_000 }); + return; + } catch { + await new Promise((resolve) => setTimeout(resolve, 500)); + } + } + throw new Error(`custom-auth-server did not respond at ${url} within ${timeoutMs}ms`); + } finally { + await context.dispose(); + } +} + +test.describe(`custom-auth-server HTTP smoke (${PROJECT})`, () => { + test.beforeAll(async ({}, testInfo) => { + test.skip(testInfo.project.name !== PROJECT, `runs only on the ${PROJECT} project`); + test.setTimeout(120_000); + + const build = spawnSync("pnpm", ["--filter=custom-auth-server", "run", "build"], { + cwd: REPO_ROOT, + stdio: "inherit", + }); + expect(build.status, "custom-auth-server build failed").toBe(0); + + server = spawn(process.execPath, [SERVER_ENTRY], { + cwd: CUSTOM_AUTH_SERVER_DIR, + stdio: "inherit", + detached: true, + env: { ...process.env, PORT }, + }); + server.unref(); + + await waitForServer(`${httpMeta.baseURL}${httpMeta.smokePath}`); + }); + + test.afterAll(async () => { + stopServer(); + }); + + test("H1: server responds on the config route", async () => { + const context = await request.newContext({ baseURL: httpMeta.baseURL }); + + try { + const response = await context.get(httpMeta.smokePath); + + // 500 without SNAPCHAT_CLIENT_ID (default env); 200 when credentials are present. + expect([200, 500]).toContain(response.status()); + + const body = await response.json(); + + if (response.status() === 500) { + expect(body).toMatchObject({ error: "Server missing Snapchat client ID" }); + } else { + expect(body).toMatchObject({ clientId: expect.any(String) }); + } + } finally { + await context.dispose(); + } + }); +}); diff --git a/e2e/tests/sign-in-handlers.spec.ts b/e2e/tests/sign-in-handlers.spec.ts new file mode 100644 index 000000000..37c90614c --- /dev/null +++ b/e2e/tests/sign-in-handlers.spec.ts @@ -0,0 +1,64 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { enUs } from "@firebase-oss/ui-translations"; +import { signInWithHandlersUrl, uiExampleEntries } from "../fixtures/example-meta"; +import { expect, test } from "../fixtures/test-harness"; + +const { labels, errors } = enUs.translations; + +async function waitForSignInForm(page: import("@playwright/test").Page): Promise { + await page.waitForSelector('input[name="email"]', { state: "visible", timeout: 30_000 }); +} + +for (const [projectName, meta] of uiExampleEntries) { + test.describe(`sign-in with handlers smoke (${projectName})`, () => { + test.beforeEach(({}, testInfo) => { + test.skip(testInfo.project.name !== projectName, `runs only on the ${projectName} project`); + }); + + test("S1: sign-in form shows email, password, and submit", async ({ page }) => { + await page.goto(signInWithHandlersUrl(meta)); + await waitForSignInForm(page); + + await expect(page.getByLabel(labels.emailAddress)).toBeVisible(); + await expect(page.getByLabel(labels.password)).toBeVisible(); + await expect(page.getByRole("button", { name: labels.signIn, exact: true })).toBeVisible(); + }); + + test("S2: empty submit shows email validation feedback", async ({ page }) => { + await page.goto(signInWithHandlersUrl(meta)); + await waitForSignInForm(page); + + await page.getByRole("button", { name: labels.signIn, exact: true }).click(); + + // React uses role="alert"; shadcn FormMessage renders as

— assert visible copy, not role. + await expect(page.getByText(errors.invalidEmail)).toBeVisible(); + }); + + test("S3: forgot-password navigates to reset screen", async ({ page }) => { + await page.goto(signInWithHandlersUrl(meta)); + await waitForSignInForm(page); + + await page.getByRole("button", { name: labels.forgotPassword }).click(); + + // React CardTitle is

; shadcn CardTitle is a styled
— assert screen chrome + email field. + await expect(page.getByText(labels.resetPassword).first()).toBeVisible(); + await expect(page.getByLabel(labels.emailAddress)).toBeVisible(); + await expect(page.getByRole("button", { name: labels.resetPassword })).toBeVisible(); + }); + }); +} diff --git a/examples/angular/package.json b/examples/angular/package.json index 85d8fcb05..1901b2b47 100644 --- a/examples/angular/package.json +++ b/examples/angular/package.json @@ -45,6 +45,11 @@ "tslib": "^2.3.0", "zone.js": "~0.15.0" }, + "dependenciesMeta": { + "@firebase-oss/ui-angular": { + "injected": true + } + }, "devDependencies": { "@angular-devkit/build-angular": "catalog:", "@angular-devkit/core": "catalog:", @@ -70,6 +75,7 @@ "nanostores": "^0.11.3", "ng-packagr": "^20.2.0", "prettier": "^3.1.1", + "rimraf": "catalog:", "typescript": "^5.9.2" } } diff --git a/examples/nextjs-ssr/app/screens/sign-in-auth-screen-w-handlers/page.tsx b/examples/nextjs-ssr/app/screens/sign-in-auth-screen-w-handlers/page.tsx index d5c825393..7dd0277d2 100644 --- a/examples/nextjs-ssr/app/screens/sign-in-auth-screen-w-handlers/page.tsx +++ b/examples/nextjs-ssr/app/screens/sign-in-auth-screen-w-handlers/page.tsx @@ -17,10 +17,16 @@ "use client"; import { SignInAuthScreen } from "@firebase-oss/ui-react"; +import { useRouter } from "next/navigation"; export default function SignInAuthScreenWithHandlersPage() { + const router = useRouter(); + return ( { + router.push("/screens/forgot-password-auth-screen"); + }} onSignIn={(credential) => { console.log(credential); }} diff --git a/examples/nextjs-ssr/package-lock.json b/examples/nextjs-ssr/package-lock.json deleted file mode 100644 index ba54bbb78..000000000 --- a/examples/nextjs-ssr/package-lock.json +++ /dev/null @@ -1,3341 +0,0 @@ -{ - "name": "nextjs", - "version": "0.1.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "nextjs", - "version": "0.1.0", - "dependencies": { - "@invertase/firebaseui-core": "^0.0.1", - "@invertase/firebaseui-react": "^0.0.1", - "@invertase/firebaseui-styles": "^0.0.1", - "@invertase/firebaseui-translations": "^0.0.1", - "firebase": "^11.3.1", - "next": "15.1.7", - "react": "^19.0.0", - "react-dom": "^19.0.0", - "server-only": "^0.0.1" - }, - "devDependencies": { - "@tailwindcss/postcss": "^4.0.6", - "@types/node": "^20", - "@types/react": "^19", - "@types/react-dom": "^19", - "postcss": "^8.5.2", - "postcss-load-config": "^6.0.1", - "tailwindcss": "^4.0.6", - "typescript": "^5" - } - }, - "node_modules/@alloc/quick-lru": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", - "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.6.0.tgz", - "integrity": "sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA==", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@firebase/ai": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@firebase/ai/-/ai-1.4.1.tgz", - "integrity": "sha512-bcusQfA/tHjUjBTnMx6jdoPMpDl3r8K15Z+snHz9wq0Foox0F/V+kNLXucEOHoTL2hTc9l+onZCyBJs2QoIC3g==", - "dependencies": { - "@firebase/app-check-interop-types": "0.3.3", - "@firebase/component": "0.6.18", - "@firebase/logger": "0.4.4", - "@firebase/util": "1.12.1", - "tslib": "^2.1.0" - }, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "@firebase/app": "0.x", - "@firebase/app-types": "0.x" - } - }, - "node_modules/@firebase/analytics": { - "version": "0.10.17", - "resolved": "https://registry.npmjs.org/@firebase/analytics/-/analytics-0.10.17.tgz", - "integrity": "sha512-n5vfBbvzduMou/2cqsnKrIes4auaBjdhg8QNA2ZQZ59QgtO2QiwBaXQZQE4O4sgB0Ds1tvLgUUkY+pwzu6/xEg==", - "dependencies": { - "@firebase/component": "0.6.18", - "@firebase/installations": "0.6.18", - "@firebase/logger": "0.4.4", - "@firebase/util": "1.12.1", - "tslib": "^2.1.0" - }, - "peerDependencies": { - "@firebase/app": "0.x" - } - }, - "node_modules/@firebase/analytics-compat": { - "version": "0.2.23", - "resolved": "https://registry.npmjs.org/@firebase/analytics-compat/-/analytics-compat-0.2.23.tgz", - "integrity": "sha512-3AdO10RN18G5AzREPoFgYhW6vWXr3u+OYQv6pl3CX6Fky8QRk0AHurZlY3Q1xkXO0TDxIsdhO3y65HF7PBOJDw==", - "dependencies": { - "@firebase/analytics": "0.10.17", - "@firebase/analytics-types": "0.8.3", - "@firebase/component": "0.6.18", - "@firebase/util": "1.12.1", - "tslib": "^2.1.0" - }, - "peerDependencies": { - "@firebase/app-compat": "0.x" - } - }, - "node_modules/@firebase/analytics-types": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/@firebase/analytics-types/-/analytics-types-0.8.3.tgz", - "integrity": "sha512-VrIp/d8iq2g501qO46uGz3hjbDb8xzYMrbu8Tp0ovzIzrvJZ2fvmj649gTjge/b7cCCcjT0H37g1gVtlNhnkbg==" - }, - "node_modules/@firebase/app": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.13.2.tgz", - "integrity": "sha512-jwtMmJa1BXXDCiDx1vC6SFN/+HfYG53UkfJa6qeN5ogvOunzbFDO3wISZy5n9xgYFUrEP6M7e8EG++riHNTv9w==", - "dependencies": { - "@firebase/component": "0.6.18", - "@firebase/logger": "0.4.4", - "@firebase/util": "1.12.1", - "idb": "7.1.1", - "tslib": "^2.1.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@firebase/app-check": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@firebase/app-check/-/app-check-0.10.1.tgz", - "integrity": "sha512-MgNdlms9Qb0oSny87pwpjKush9qUwCJhfmTJHDfrcKo4neLGiSeVE4qJkzP7EQTIUFKp84pbTxobSAXkiuQVYQ==", - "dependencies": { - "@firebase/component": "0.6.18", - "@firebase/logger": "0.4.4", - "@firebase/util": "1.12.1", - "tslib": "^2.1.0" - }, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "@firebase/app": "0.x" - } - }, - "node_modules/@firebase/app-check-compat": { - "version": "0.3.26", - "resolved": "https://registry.npmjs.org/@firebase/app-check-compat/-/app-check-compat-0.3.26.tgz", - "integrity": "sha512-PkX+XJMLDea6nmnopzFKlr+s2LMQGqdyT2DHdbx1v1dPSqOol2YzgpgymmhC67vitXVpNvS3m/AiWQWWhhRRPQ==", - "dependencies": { - "@firebase/app-check": "0.10.1", - "@firebase/app-check-types": "0.5.3", - "@firebase/component": "0.6.18", - "@firebase/logger": "0.4.4", - "@firebase/util": "1.12.1", - "tslib": "^2.1.0" - }, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "@firebase/app-compat": "0.x" - } - }, - "node_modules/@firebase/app-check-interop-types": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@firebase/app-check-interop-types/-/app-check-interop-types-0.3.3.tgz", - "integrity": "sha512-gAlxfPLT2j8bTI/qfe3ahl2I2YcBQ8cFIBdhAQA4I2f3TndcO+22YizyGYuttLHPQEpWkhmpFW60VCFEPg4g5A==" - }, - "node_modules/@firebase/app-check-types": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@firebase/app-check-types/-/app-check-types-0.5.3.tgz", - "integrity": "sha512-hyl5rKSj0QmwPdsAxrI5x1otDlByQ7bvNvVt8G/XPO2CSwE++rmSVf3VEhaeOR4J8ZFaF0Z0NDSmLejPweZ3ng==" - }, - "node_modules/@firebase/app-compat": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.4.2.tgz", - "integrity": "sha512-LssbyKHlwLeiV8GBATyOyjmHcMpX/tFjzRUCS1jnwGAew1VsBB4fJowyS5Ud5LdFbYpJeS+IQoC+RQxpK7eH3Q==", - "dependencies": { - "@firebase/app": "0.13.2", - "@firebase/component": "0.6.18", - "@firebase/logger": "0.4.4", - "@firebase/util": "1.12.1", - "tslib": "^2.1.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@firebase/app-types": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.3.tgz", - "integrity": "sha512-kRVpIl4vVGJ4baogMDINbyrIOtOxqhkZQg4jTq3l8Lw6WSk0xfpEYzezFu+Kl4ve4fbPl79dvwRtaFqAC/ucCw==" - }, - "node_modules/@firebase/auth": { - "version": "1.10.8", - "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.10.8.tgz", - "integrity": "sha512-GpuTz5ap8zumr/ocnPY57ZanX02COsXloY6Y/2LYPAuXYiaJRf6BAGDEdRq1BMjP93kqQnKNuKZUTMZbQ8MNYA==", - "dependencies": { - "@firebase/component": "0.6.18", - "@firebase/logger": "0.4.4", - "@firebase/util": "1.12.1", - "tslib": "^2.1.0" - }, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "@firebase/app": "0.x", - "@react-native-async-storage/async-storage": "^1.18.1" - }, - "peerDependenciesMeta": { - "@react-native-async-storage/async-storage": { - "optional": true - } - } - }, - "node_modules/@firebase/auth-compat": { - "version": "0.5.28", - "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.28.tgz", - "integrity": "sha512-HpMSo/cc6Y8IX7bkRIaPPqT//Jt83iWy5rmDWeThXQCAImstkdNo3giFLORJwrZw2ptiGkOij64EH1ztNJzc7Q==", - "dependencies": { - "@firebase/auth": "1.10.8", - "@firebase/auth-types": "0.13.0", - "@firebase/component": "0.6.18", - "@firebase/util": "1.12.1", - "tslib": "^2.1.0" - }, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "@firebase/app-compat": "0.x" - } - }, - "node_modules/@firebase/auth-interop-types": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@firebase/auth-interop-types/-/auth-interop-types-0.2.4.tgz", - "integrity": "sha512-JPgcXKCuO+CWqGDnigBtvo09HeBs5u/Ktc2GaFj2m01hLarbxthLNm7Fk8iOP1aqAtXV+fnnGj7U28xmk7IwVA==" - }, - "node_modules/@firebase/auth-types": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@firebase/auth-types/-/auth-types-0.13.0.tgz", - "integrity": "sha512-S/PuIjni0AQRLF+l9ck0YpsMOdE8GO2KU6ubmBB7P+7TJUCQDa3R1dlgYm9UzGbbePMZsp0xzB93f2b/CgxMOg==", - "peerDependencies": { - "@firebase/app-types": "0.x", - "@firebase/util": "1.x" - } - }, - "node_modules/@firebase/component": { - "version": "0.6.18", - "resolved": "https://registry.npmjs.org/@firebase/component/-/component-0.6.18.tgz", - "integrity": "sha512-n28kPCkE2dL2U28fSxZJjzPPVpKsQminJ6NrzcKXAI0E/lYC8YhfwpyllScqVEvAI3J2QgJZWYgrX+1qGI+SQQ==", - "dependencies": { - "@firebase/util": "1.12.1", - "tslib": "^2.1.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@firebase/data-connect": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/@firebase/data-connect/-/data-connect-0.3.10.tgz", - "integrity": "sha512-VMVk7zxIkgwlVQIWHOKFahmleIjiVFwFOjmakXPd/LDgaB/5vzwsB5DWIYo+3KhGxWpidQlR8geCIn39YflJIQ==", - "dependencies": { - "@firebase/auth-interop-types": "0.2.4", - "@firebase/component": "0.6.18", - "@firebase/logger": "0.4.4", - "@firebase/util": "1.12.1", - "tslib": "^2.1.0" - }, - "peerDependencies": { - "@firebase/app": "0.x" - } - }, - "node_modules/@firebase/database": { - "version": "1.0.20", - "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.20.tgz", - "integrity": "sha512-H9Rpj1pQ1yc9+4HQOotFGLxqAXwOzCHsRSRjcQFNOr8lhUt6LeYjf0NSRL04sc4X0dWe8DsCvYKxMYvFG/iOJw==", - "dependencies": { - "@firebase/app-check-interop-types": "0.3.3", - "@firebase/auth-interop-types": "0.2.4", - "@firebase/component": "0.6.18", - "@firebase/logger": "0.4.4", - "@firebase/util": "1.12.1", - "faye-websocket": "0.11.4", - "tslib": "^2.1.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@firebase/database-compat": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-2.0.11.tgz", - "integrity": "sha512-itEsHARSsYS95+udF/TtIzNeQ0Uhx4uIna0sk4E0wQJBUnLc/G1X6D7oRljoOuwwCezRLGvWBRyNrugv/esOEw==", - "dependencies": { - "@firebase/component": "0.6.18", - "@firebase/database": "1.0.20", - "@firebase/database-types": "1.0.15", - "@firebase/logger": "0.4.4", - "@firebase/util": "1.12.1", - "tslib": "^2.1.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@firebase/database-types": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.15.tgz", - "integrity": "sha512-XWHJ0VUJ0k2E9HDMlKxlgy/ZuTa9EvHCGLjaKSUvrQnwhgZuRU5N3yX6SZ+ftf2hTzZmfRkv+b3QRvGg40bKNw==", - "dependencies": { - "@firebase/app-types": "0.9.3", - "@firebase/util": "1.12.1" - } - }, - "node_modules/@firebase/firestore": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.8.0.tgz", - "integrity": "sha512-QSRk+Q1/CaabKyqn3C32KSFiOdZpSqI9rpLK5BHPcooElumOBooPFa6YkDdiT+/KhJtel36LdAacha9BptMj2A==", - "dependencies": { - "@firebase/component": "0.6.18", - "@firebase/logger": "0.4.4", - "@firebase/util": "1.12.1", - "@firebase/webchannel-wrapper": "1.0.3", - "@grpc/grpc-js": "~1.9.0", - "@grpc/proto-loader": "^0.7.8", - "tslib": "^2.1.0" - }, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "@firebase/app": "0.x" - } - }, - "node_modules/@firebase/firestore-compat": { - "version": "0.3.53", - "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.53.tgz", - "integrity": "sha512-qI3yZL8ljwAYWrTousWYbemay2YZa+udLWugjdjju2KODWtLG94DfO4NALJgPLv8CVGcDHNFXoyQexdRA0Cz8Q==", - "dependencies": { - "@firebase/component": "0.6.18", - "@firebase/firestore": "4.8.0", - "@firebase/firestore-types": "3.0.3", - "@firebase/util": "1.12.1", - "tslib": "^2.1.0" - }, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "@firebase/app-compat": "0.x" - } - }, - "node_modules/@firebase/firestore-types": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.3.tgz", - "integrity": "sha512-hD2jGdiWRxB/eZWF89xcK9gF8wvENDJkzpVFb4aGkzfEaKxVRD1kjz1t1Wj8VZEp2LCB53Yx1zD8mrhQu87R6Q==", - "peerDependencies": { - "@firebase/app-types": "0.x", - "@firebase/util": "1.x" - } - }, - "node_modules/@firebase/functions": { - "version": "0.12.9", - "resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.12.9.tgz", - "integrity": "sha512-FG95w6vjbUXN84Ehezc2SDjGmGq225UYbHrb/ptkRT7OTuCiQRErOQuyt1jI1tvcDekdNog+anIObihNFz79Lg==", - "dependencies": { - "@firebase/app-check-interop-types": "0.3.3", - "@firebase/auth-interop-types": "0.2.4", - "@firebase/component": "0.6.18", - "@firebase/messaging-interop-types": "0.2.3", - "@firebase/util": "1.12.1", - "tslib": "^2.1.0" - }, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "@firebase/app": "0.x" - } - }, - "node_modules/@firebase/functions-compat": { - "version": "0.3.26", - "resolved": "https://registry.npmjs.org/@firebase/functions-compat/-/functions-compat-0.3.26.tgz", - "integrity": "sha512-A798/6ff5LcG2LTWqaGazbFYnjBW8zc65YfID/en83ALmkhu2b0G8ykvQnLtakbV9ajrMYPn7Yc/XcYsZIUsjA==", - "dependencies": { - "@firebase/component": "0.6.18", - "@firebase/functions": "0.12.9", - "@firebase/functions-types": "0.6.3", - "@firebase/util": "1.12.1", - "tslib": "^2.1.0" - }, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "@firebase/app-compat": "0.x" - } - }, - "node_modules/@firebase/functions-types": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/@firebase/functions-types/-/functions-types-0.6.3.tgz", - "integrity": "sha512-EZoDKQLUHFKNx6VLipQwrSMh01A1SaL3Wg6Hpi//x6/fJ6Ee4hrAeswK99I5Ht8roiniKHw4iO0B1Oxj5I4plg==" - }, - "node_modules/@firebase/installations": { - "version": "0.6.18", - "resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.6.18.tgz", - "integrity": "sha512-NQ86uGAcvO8nBRwVltRL9QQ4Reidc/3whdAasgeWCPIcrhOKDuNpAALa6eCVryLnK14ua2DqekCOX5uC9XbU/A==", - "dependencies": { - "@firebase/component": "0.6.18", - "@firebase/util": "1.12.1", - "idb": "7.1.1", - "tslib": "^2.1.0" - }, - "peerDependencies": { - "@firebase/app": "0.x" - } - }, - "node_modules/@firebase/installations-compat": { - "version": "0.2.18", - "resolved": "https://registry.npmjs.org/@firebase/installations-compat/-/installations-compat-0.2.18.tgz", - "integrity": "sha512-aLFohRpJO5kKBL/XYL4tN+GdwEB/Q6Vo9eZOM/6Kic7asSUgmSfGPpGUZO1OAaSRGwF4Lqnvi1f/f9VZnKzChw==", - "dependencies": { - "@firebase/component": "0.6.18", - "@firebase/installations": "0.6.18", - "@firebase/installations-types": "0.5.3", - "@firebase/util": "1.12.1", - "tslib": "^2.1.0" - }, - "peerDependencies": { - "@firebase/app-compat": "0.x" - } - }, - "node_modules/@firebase/installations-types": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.5.3.tgz", - "integrity": "sha512-2FJI7gkLqIE0iYsNQ1P751lO3hER+Umykel+TkLwHj6plzWVxqvfclPUZhcKFVQObqloEBTmpi2Ozn7EkCABAA==", - "peerDependencies": { - "@firebase/app-types": "0.x" - } - }, - "node_modules/@firebase/logger": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.4.4.tgz", - "integrity": "sha512-mH0PEh1zoXGnaR8gD1DeGeNZtWFKbnz9hDO91dIml3iou1gpOnLqXQ2dJfB71dj6dpmUjcQ6phY3ZZJbjErr9g==", - "dependencies": { - "tslib": "^2.1.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@firebase/messaging": { - "version": "0.12.22", - "resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.12.22.tgz", - "integrity": "sha512-GJcrPLc+Hu7nk+XQ70Okt3M1u1eRr2ZvpMbzbc54oTPJZySHcX9ccZGVFcsZbSZ6o1uqumm8Oc7OFkD3Rn1/og==", - "dependencies": { - "@firebase/component": "0.6.18", - "@firebase/installations": "0.6.18", - "@firebase/messaging-interop-types": "0.2.3", - "@firebase/util": "1.12.1", - "idb": "7.1.1", - "tslib": "^2.1.0" - }, - "peerDependencies": { - "@firebase/app": "0.x" - } - }, - "node_modules/@firebase/messaging-compat": { - "version": "0.2.22", - "resolved": "https://registry.npmjs.org/@firebase/messaging-compat/-/messaging-compat-0.2.22.tgz", - "integrity": "sha512-5ZHtRnj6YO6f/QPa/KU6gryjmX4Kg33Kn4gRpNU6M1K47Gm8kcQwPkX7erRUYEH1mIWptfvjvXMHWoZaWjkU7A==", - "dependencies": { - "@firebase/component": "0.6.18", - "@firebase/messaging": "0.12.22", - "@firebase/util": "1.12.1", - "tslib": "^2.1.0" - }, - "peerDependencies": { - "@firebase/app-compat": "0.x" - } - }, - "node_modules/@firebase/messaging-interop-types": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@firebase/messaging-interop-types/-/messaging-interop-types-0.2.3.tgz", - "integrity": "sha512-xfzFaJpzcmtDjycpDeCUj0Ge10ATFi/VHVIvEEjDNc3hodVBQADZ7BWQU7CuFpjSHE+eLuBI13z5F/9xOoGX8Q==" - }, - "node_modules/@firebase/performance": { - "version": "0.7.7", - "resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.7.7.tgz", - "integrity": "sha512-JTlTQNZKAd4+Q5sodpw6CN+6NmwbY72av3Lb6wUKTsL7rb3cuBIhQSrslWbVz0SwK3x0ZNcqX24qtRbwKiv+6w==", - "dependencies": { - "@firebase/component": "0.6.18", - "@firebase/installations": "0.6.18", - "@firebase/logger": "0.4.4", - "@firebase/util": "1.12.1", - "tslib": "^2.1.0", - "web-vitals": "^4.2.4" - }, - "peerDependencies": { - "@firebase/app": "0.x" - } - }, - "node_modules/@firebase/performance-compat": { - "version": "0.2.20", - "resolved": "https://registry.npmjs.org/@firebase/performance-compat/-/performance-compat-0.2.20.tgz", - "integrity": "sha512-XkFK5NmOKCBuqOKWeRgBUFZZGz9SzdTZp4OqeUg+5nyjapTiZ4XoiiUL8z7mB2q+63rPmBl7msv682J3rcDXIQ==", - "dependencies": { - "@firebase/component": "0.6.18", - "@firebase/logger": "0.4.4", - "@firebase/performance": "0.7.7", - "@firebase/performance-types": "0.2.3", - "@firebase/util": "1.12.1", - "tslib": "^2.1.0" - }, - "peerDependencies": { - "@firebase/app-compat": "0.x" - } - }, - "node_modules/@firebase/performance-types": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@firebase/performance-types/-/performance-types-0.2.3.tgz", - "integrity": "sha512-IgkyTz6QZVPAq8GSkLYJvwSLr3LS9+V6vNPQr0x4YozZJiLF5jYixj0amDtATf1X0EtYHqoPO48a9ija8GocxQ==" - }, - "node_modules/@firebase/remote-config": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@firebase/remote-config/-/remote-config-0.6.5.tgz", - "integrity": "sha512-fU0c8HY0vrVHwC+zQ/fpXSqHyDMuuuglV94VF6Yonhz8Fg2J+KOowPGANM0SZkLvVOYpTeWp3ZmM+F6NjwWLnw==", - "dependencies": { - "@firebase/component": "0.6.18", - "@firebase/installations": "0.6.18", - "@firebase/logger": "0.4.4", - "@firebase/util": "1.12.1", - "tslib": "^2.1.0" - }, - "peerDependencies": { - "@firebase/app": "0.x" - } - }, - "node_modules/@firebase/remote-config-compat": { - "version": "0.2.18", - "resolved": "https://registry.npmjs.org/@firebase/remote-config-compat/-/remote-config-compat-0.2.18.tgz", - "integrity": "sha512-YiETpldhDy7zUrnS8e+3l7cNs0sL7+tVAxvVYU0lu7O+qLHbmdtAxmgY+wJqWdW2c9nDvBFec7QiF58pEUu0qQ==", - "dependencies": { - "@firebase/component": "0.6.18", - "@firebase/logger": "0.4.4", - "@firebase/remote-config": "0.6.5", - "@firebase/remote-config-types": "0.4.0", - "@firebase/util": "1.12.1", - "tslib": "^2.1.0" - }, - "peerDependencies": { - "@firebase/app-compat": "0.x" - } - }, - "node_modules/@firebase/remote-config-types": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@firebase/remote-config-types/-/remote-config-types-0.4.0.tgz", - "integrity": "sha512-7p3mRE/ldCNYt8fmWMQ/MSGRmXYlJ15Rvs9Rk17t8p0WwZDbeK7eRmoI1tvCPaDzn9Oqh+yD6Lw+sGLsLg4kKg==" - }, - "node_modules/@firebase/storage": { - "version": "0.13.14", - "resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.13.14.tgz", - "integrity": "sha512-xTq5ixxORzx+bfqCpsh+o3fxOsGoDjC1nO0Mq2+KsOcny3l7beyBhP/y1u5T6mgsFQwI1j6oAkbT5cWdDBx87g==", - "dependencies": { - "@firebase/component": "0.6.18", - "@firebase/util": "1.12.1", - "tslib": "^2.1.0" - }, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "@firebase/app": "0.x" - } - }, - "node_modules/@firebase/storage-compat": { - "version": "0.3.24", - "resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.24.tgz", - "integrity": "sha512-XHn2tLniiP7BFKJaPZ0P8YQXKiVJX+bMyE2j2YWjYfaddqiJnROJYqSomwW6L3Y+gZAga35ONXUJQju6MB6SOQ==", - "dependencies": { - "@firebase/component": "0.6.18", - "@firebase/storage": "0.13.14", - "@firebase/storage-types": "0.8.3", - "@firebase/util": "1.12.1", - "tslib": "^2.1.0" - }, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "@firebase/app-compat": "0.x" - } - }, - "node_modules/@firebase/storage-types": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.3.tgz", - "integrity": "sha512-+Muk7g9uwngTpd8xn9OdF/D48uiQ7I1Fae7ULsWPuKoCH3HU7bfFPhxtJYzyhjdniowhuDpQcfPmuNRAqZEfvg==", - "peerDependencies": { - "@firebase/app-types": "0.x", - "@firebase/util": "1.x" - } - }, - "node_modules/@firebase/util": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@firebase/util/-/util-1.12.1.tgz", - "integrity": "sha512-zGlBn/9Dnya5ta9bX/fgEoNC3Cp8s6h+uYPYaDieZsFOAdHP/ExzQ/eaDgxD3GOROdPkLKpvKY0iIzr9adle0w==", - "hasInstallScript": true, - "dependencies": { - "tslib": "^2.1.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@firebase/webchannel-wrapper": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-1.0.3.tgz", - "integrity": "sha512-2xCRM9q9FlzGZCdgDMJwc0gyUkWFtkosy7Xxr6sFgQwn+wMNIWd7xIvYNauU1r64B5L5rsGKy/n9TKJ0aAFeqQ==" - }, - "node_modules/@grpc/grpc-js": { - "version": "1.9.15", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.15.tgz", - "integrity": "sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ==", - "dependencies": { - "@grpc/proto-loader": "^0.7.8", - "@types/node": ">=12.12.47" - }, - "engines": { - "node": "^8.13.0 || >=10.10.0" - } - }, - "node_modules/@grpc/proto-loader": { - "version": "0.7.15", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.15.tgz", - "integrity": "sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==", - "dependencies": { - "lodash.camelcase": "^4.3.0", - "long": "^5.0.0", - "protobufjs": "^7.2.5", - "yargs": "^17.7.2" - }, - "bin": { - "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", - "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.0.4" - } - }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", - "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.0.4" - } - }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", - "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", - "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", - "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", - "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", - "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", - "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", - "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", - "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", - "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.0.5" - } - }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", - "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.0.4" - } - }, - "node_modules/@img/sharp-linux-s390x": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", - "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.0.4" - } - }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", - "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.0.4" - } - }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", - "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" - } - }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", - "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.0.4" - } - }, - "node_modules/@img/sharp-wasm32": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", - "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", - "cpu": [ - "wasm32" - ], - "optional": true, - "dependencies": { - "@emnapi/runtime": "^1.2.0" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-ia32": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", - "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", - "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@invertase/firebaseui-core": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@invertase/firebaseui-core/-/firebaseui-core-0.0.1.tgz", - "integrity": "sha512-ZoXsh0uEo13dc+GL21+jL4rBu/euZheXcGbPFLXdCgPHKX9vKhf6GkGEKghpuCV9SmEs4q66ZECS81DYW3aLxw==", - "dependencies": { - "@invertase/firebaseui-translations": "0.0.1", - "nanostores": "^0.11.3", - "zod": "^3.24.1" - }, - "peerDependencies": { - "firebase": "^11" - } - }, - "node_modules/@invertase/firebaseui-react": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@invertase/firebaseui-react/-/firebaseui-react-0.0.1.tgz", - "integrity": "sha512-ioFiM2cxZxXDIl5VLIYkray1qajTKEHEN9A+od20s3Qwkzn4LbpLHdOeKm58yct2BJOmIkMxD/Kem2eOpsruag==", - "dependencies": { - "@nanostores/react": "^0.8.4", - "@tanstack/react-form": "^0.41.3", - "clsx": "^2.1.1", - "firebase": "^11.2.0", - "nanostores": "^0.11.3", - "react": "^19.0.0", - "react-dom": "^19.0.0", - "tailwind-merge": "^3.0.1", - "zod": "^3.24.1" - }, - "peerDependencies": { - "@invertase/firebaseui-core": "0.0.1", - "@invertase/firebaseui-styles": "0.0.1" - } - }, - "node_modules/@invertase/firebaseui-styles": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@invertase/firebaseui-styles/-/firebaseui-styles-0.0.1.tgz", - "integrity": "sha512-fgG4W1iN7VdhepxywWDMPqxZLIcD5P9xu2f24bcS2VUawjzg76aQekBWOVw5WsfsYKGiXW0NUyIXm+14WSZNgg==" - }, - "node_modules/@invertase/firebaseui-translations": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@invertase/firebaseui-translations/-/firebaseui-translations-0.0.1.tgz", - "integrity": "sha512-g6N0Ik8l5ydaMZ4vpW3Oa9/rUm6AdbfwG8oqMt985wulRUUfm2n8IQE1wcLNCQjXqySgZwtTMSvQ9aa1uOup1g==" - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@nanostores/react": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/@nanostores/react/-/react-0.8.4.tgz", - "integrity": "sha512-EciHSzDXg7GmGODjegGG1VldPEinbAK+12/Uz5+MAdHmxf082Rl6eXqKFxAAu4pZAcr5dNTpv6wMfEe7XacjkQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "peerDependencies": { - "nanostores": "^0.9.0 || ^0.10.0 || ^0.11.0", - "react": ">=18.0.0" - } - }, - "node_modules/@next/env": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/@next/env/-/env-15.1.7.tgz", - "integrity": "sha512-d9jnRrkuOH7Mhi+LHav2XW91HOgTAWHxjMPkXMGBc9B2b7614P7kjt8tAplRvJpbSt4nbO1lugcT/kAaWzjlLQ==" - }, - "node_modules/@next/swc-darwin-arm64": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.1.7.tgz", - "integrity": "sha512-hPFwzPJDpA8FGj7IKV3Yf1web3oz2YsR8du4amKw8d+jAOHfYHYFpMkoF6vgSY4W6vB29RtZEklK9ayinGiCmQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-darwin-x64": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.1.7.tgz", - "integrity": "sha512-2qoas+fO3OQKkU0PBUfwTiw/EYpN+kdAx62cePRyY1LqKtP09Vp5UcUntfZYajop5fDFTjSxCHfZVRxzi+9FYQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-gnu": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.1.7.tgz", - "integrity": "sha512-sKLLwDX709mPdzxMnRIXLIT9zaX2w0GUlkLYQnKGoXeWUhcvpCrK+yevcwCJPdTdxZEUA0mOXGLdPsGkudGdnA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-musl": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.1.7.tgz", - "integrity": "sha512-zblK1OQbQWdC8fxdX4fpsHDw+VSpBPGEUX4PhSE9hkaWPrWoeIJn+baX53vbsbDRaDKd7bBNcXRovY1hEhFd7w==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-gnu": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.1.7.tgz", - "integrity": "sha512-GOzXutxuLvLHFDAPsMP2zDBMl1vfUHHpdNpFGhxu90jEzH6nNIgmtw/s1MDwpTOiM+MT5V8+I1hmVFeAUhkbgQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-musl": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.1.7.tgz", - "integrity": "sha512-WrZ7jBhR7ATW1z5iEQ0ZJfE2twCNSXbpCSaAunF3BKcVeHFADSI/AW1y5Xt3DzTqPF1FzQlwQTewqetAABhZRQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-arm64-msvc": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.1.7.tgz", - "integrity": "sha512-LDnj1f3OVbou1BqvvXVqouJZKcwq++mV2F+oFHptToZtScIEnhNRJAhJzqAtTE2dB31qDYL45xJwrc+bLeKM2Q==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.1.7.tgz", - "integrity": "sha512-dC01f1quuf97viOfW05/K8XYv2iuBgAxJZl7mbCKEjMgdQl5JjAKJ0D2qMKZCgPWDeFbFT0Q0nYWwytEW0DWTQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" - }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" - }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" - }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" - }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" - }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" - }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" - }, - "node_modules/@remix-run/node": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/@remix-run/node/-/node-2.17.1.tgz", - "integrity": "sha512-pHmHTuLE1Lwazulx3gjrHobgBCsa+Xiq8WUO0ruLeDfEw2DU0c0SNSiyNkugu3rIZautroBwRaOoy7CWJL9xhQ==", - "dependencies": { - "@remix-run/server-runtime": "2.17.1", - "@remix-run/web-fetch": "^4.4.2", - "@web3-storage/multipart-parser": "^1.0.0", - "cookie-signature": "^1.1.0", - "source-map-support": "^0.5.21", - "stream-slice": "^0.1.2", - "undici": "^6.21.2" - }, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "typescript": "^5.1.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@remix-run/router": { - "version": "1.23.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.0.tgz", - "integrity": "sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@remix-run/server-runtime": { - "version": "2.17.1", - "resolved": "https://registry.npmjs.org/@remix-run/server-runtime/-/server-runtime-2.17.1.tgz", - "integrity": "sha512-d1Vp9FxX4KafB111vP2E5C1fmWzPI+gHZ674L1drq+N8Bp9U6FBspi7GAZSU5K5Kxa4T6UF+aE1gK6pVi9R8sw==", - "dependencies": { - "@remix-run/router": "1.23.0", - "@types/cookie": "^0.6.0", - "@web3-storage/multipart-parser": "^1.0.0", - "cookie": "^0.7.2", - "set-cookie-parser": "^2.4.8", - "source-map": "^0.7.3", - "turbo-stream": "2.4.1" - }, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "typescript": "^5.1.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@remix-run/web-blob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@remix-run/web-blob/-/web-blob-3.1.0.tgz", - "integrity": "sha512-owGzFLbqPH9PlKb8KvpNJ0NO74HWE2euAn61eEiyCXX/oteoVzTVSN8mpLgDjaxBf2btj5/nUllSUgpyd6IH6g==", - "dependencies": { - "@remix-run/web-stream": "^1.1.0", - "web-encoding": "1.1.5" - } - }, - "node_modules/@remix-run/web-fetch": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@remix-run/web-fetch/-/web-fetch-4.4.2.tgz", - "integrity": "sha512-jgKfzA713/4kAW/oZ4bC3MoLWyjModOVDjFPNseVqcJKSafgIscrYL9G50SurEYLswPuoU3HzSbO0jQCMYWHhA==", - "dependencies": { - "@remix-run/web-blob": "^3.1.0", - "@remix-run/web-file": "^3.1.0", - "@remix-run/web-form-data": "^3.1.0", - "@remix-run/web-stream": "^1.1.0", - "@web3-storage/multipart-parser": "^1.0.0", - "abort-controller": "^3.0.0", - "data-uri-to-buffer": "^3.0.1", - "mrmime": "^1.0.0" - }, - "engines": { - "node": "^10.17 || >=12.3" - } - }, - "node_modules/@remix-run/web-file": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@remix-run/web-file/-/web-file-3.1.0.tgz", - "integrity": "sha512-dW2MNGwoiEYhlspOAXFBasmLeYshyAyhIdrlXBi06Duex5tDr3ut2LFKVj7tyHLmn8nnNwFf1BjNbkQpygC2aQ==", - "dependencies": { - "@remix-run/web-blob": "^3.1.0" - } - }, - "node_modules/@remix-run/web-form-data": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@remix-run/web-form-data/-/web-form-data-3.1.0.tgz", - "integrity": "sha512-NdeohLMdrb+pHxMQ/Geuzdp0eqPbea+Ieo8M8Jx2lGC6TBHsgHzYcBvr0LyPdPVycNRDEpWpiDdCOdCryo3f9A==", - "dependencies": { - "web-encoding": "1.1.5" - } - }, - "node_modules/@remix-run/web-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@remix-run/web-stream/-/web-stream-1.1.0.tgz", - "integrity": "sha512-KRJtwrjRV5Bb+pM7zxcTJkhIqWWSy+MYsIxHK+0m5atcznsf15YwUBWHWulZerV2+vvHH1Lp1DD7pw6qKW8SgA==", - "dependencies": { - "web-streams-polyfill": "^3.1.1" - } - }, - "node_modules/@swc/counter": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", - "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==" - }, - "node_modules/@swc/helpers": { - "version": "0.5.15", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", - "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", - "dependencies": { - "tslib": "^2.8.0" - } - }, - "node_modules/@tailwindcss/node": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.16.tgz", - "integrity": "sha512-BX5iaSsloNuvKNHRN3k2RcCuTEgASTo77mofW0vmeHkfrDWaoFAFvNHpEgtu0eqyypcyiBkDWzSMxJhp3AUVcw==", - "dev": true, - "dependencies": { - "@jridgewell/remapping": "^2.3.4", - "enhanced-resolve": "^5.18.3", - "jiti": "^2.6.1", - "lightningcss": "1.30.2", - "magic-string": "^0.30.19", - "source-map-js": "^1.2.1", - "tailwindcss": "4.1.16" - } - }, - "node_modules/@tailwindcss/oxide": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.16.tgz", - "integrity": "sha512-2OSv52FRuhdlgyOQqgtQHuCgXnS8nFSYRp2tJ+4WZXKgTxqPy7SMSls8c3mPT5pkZ17SBToGM5LHEJBO7miEdg==", - "dev": true, - "engines": { - "node": ">= 10" - }, - "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.1.16", - "@tailwindcss/oxide-darwin-arm64": "4.1.16", - "@tailwindcss/oxide-darwin-x64": "4.1.16", - "@tailwindcss/oxide-freebsd-x64": "4.1.16", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.16", - "@tailwindcss/oxide-linux-arm64-gnu": "4.1.16", - "@tailwindcss/oxide-linux-arm64-musl": "4.1.16", - "@tailwindcss/oxide-linux-x64-gnu": "4.1.16", - "@tailwindcss/oxide-linux-x64-musl": "4.1.16", - "@tailwindcss/oxide-wasm32-wasi": "4.1.16", - "@tailwindcss/oxide-win32-arm64-msvc": "4.1.16", - "@tailwindcss/oxide-win32-x64-msvc": "4.1.16" - } - }, - "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.16.tgz", - "integrity": "sha512-8+ctzkjHgwDJ5caq9IqRSgsP70xhdhJvm+oueS/yhD5ixLhqTw9fSL1OurzMUhBwE5zK26FXLCz2f/RtkISqHA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.16.tgz", - "integrity": "sha512-C3oZy5042v2FOALBZtY0JTDnGNdS6w7DxL/odvSny17ORUnaRKhyTse8xYi3yKGyfnTUOdavRCdmc8QqJYwFKA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.16.tgz", - "integrity": "sha512-vjrl/1Ub9+JwU6BP0emgipGjowzYZMjbWCDqwA2Z4vCa+HBSpP4v6U2ddejcHsolsYxwL5r4bPNoamlV0xDdLg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.16.tgz", - "integrity": "sha512-TSMpPYpQLm+aR1wW5rKuUuEruc/oOX3C7H0BTnPDn7W/eMw8W+MRMpiypKMkXZfwH8wqPIRKppuZoedTtNj2tg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.16.tgz", - "integrity": "sha512-p0GGfRg/w0sdsFKBjMYvvKIiKy/LNWLWgV/plR4lUgrsxFAoQBFrXkZ4C0w8IOXfslB9vHK/JGASWD2IefIpvw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.16.tgz", - "integrity": "sha512-DoixyMmTNO19rwRPdqviTrG1rYzpxgyYJl8RgQvdAQUzxC1ToLRqtNJpU/ATURSKgIg6uerPw2feW0aS8SNr/w==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.16.tgz", - "integrity": "sha512-H81UXMa9hJhWhaAUca6bU2wm5RRFpuHImrwXBUvPbYb+3jo32I9VIwpOX6hms0fPmA6f2pGVlybO6qU8pF4fzQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.16.tgz", - "integrity": "sha512-ZGHQxDtFC2/ruo7t99Qo2TTIvOERULPl5l0K1g0oK6b5PGqjYMga+FcY1wIUnrUxY56h28FxybtDEla+ICOyew==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.16.tgz", - "integrity": "sha512-Oi1tAaa0rcKf1Og9MzKeINZzMLPbhxvm7rno5/zuP1WYmpiG0bEHq4AcRUiG2165/WUzvxkW4XDYCscZWbTLZw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.16.tgz", - "integrity": "sha512-B01u/b8LteGRwucIBmCQ07FVXLzImWESAIMcUU6nvFt/tYsQ6IHz8DmZ5KtvmwxD+iTYBtM1xwoGXswnlu9v0Q==", - "bundleDependencies": [ - "@napi-rs/wasm-runtime", - "@emnapi/core", - "@emnapi/runtime", - "@tybys/wasm-util", - "@emnapi/wasi-threads", - "tslib" - ], - "cpu": [ - "wasm32" - ], - "dev": true, - "optional": true, - "dependencies": { - "@emnapi/core": "^1.5.0", - "@emnapi/runtime": "^1.5.0", - "@emnapi/wasi-threads": "^1.1.0", - "@napi-rs/wasm-runtime": "^1.0.7", - "@tybys/wasm-util": "^0.10.1", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.16.tgz", - "integrity": "sha512-zX+Q8sSkGj6HKRTMJXuPvOcP8XfYON24zJBRPlszcH1Np7xuHXhWn8qfFjIujVzvH3BHU+16jBXwgpl20i+v9A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.16.tgz", - "integrity": "sha512-m5dDFJUEejbFqP+UXVstd4W/wnxA4F61q8SoL+mqTypId2T2ZpuxosNSgowiCnLp2+Z+rivdU0AqpfgiD7yCBg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/postcss": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.16.tgz", - "integrity": "sha512-Qn3SFGPXYQMKR/UtqS+dqvPrzEeBZHrFA92maT4zijCVggdsXnDBMsPFJo1eArX3J+O+Gi+8pV4PkqjLCNBk3A==", - "dev": true, - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "@tailwindcss/node": "4.1.16", - "@tailwindcss/oxide": "4.1.16", - "postcss": "^8.4.41", - "tailwindcss": "4.1.16" - } - }, - "node_modules/@tanstack/form-core": { - "version": "0.41.4", - "resolved": "https://registry.npmjs.org/@tanstack/form-core/-/form-core-0.41.4.tgz", - "integrity": "sha512-XZJtN7mWJmi3apsc2J+GpWbcsXbv0pWBkZKP47ZW1QD/2Tj1UWsM6JjcaAkzIlrBdaoEFYmrHToLKr/Ddk8BVg==", - "dependencies": { - "@tanstack/store": "^0.7.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@tanstack/react-form": { - "version": "0.41.4", - "resolved": "https://registry.npmjs.org/@tanstack/react-form/-/react-form-0.41.4.tgz", - "integrity": "sha512-uIfIDZJNqR1dLW03TNByK/woyKd2jfXIrEBq6DPJbqupqyfYXTDo5TMd/7koTYLO4dgTM5wd+2v3uBX3M2bRaA==", - "dependencies": { - "@remix-run/node": "^2.15.0", - "@tanstack/form-core": "0.41.4", - "@tanstack/react-store": "^0.7.0", - "decode-formdata": "^0.8.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "@tanstack/start": "^1.43.13", - "react": "^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@tanstack/start": { - "optional": true - } - } - }, - "node_modules/@tanstack/react-store": { - "version": "0.7.7", - "resolved": "https://registry.npmjs.org/@tanstack/react-store/-/react-store-0.7.7.tgz", - "integrity": "sha512-qqT0ufegFRDGSof9D/VqaZgjNgp4tRPHZIJq2+QIHkMUtHjaJ0lYrrXjeIUJvjnTbgPfSD1XgOMEt0lmANn6Zg==", - "dependencies": { - "@tanstack/store": "0.7.7", - "use-sync-external-store": "^1.5.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/@tanstack/store": { - "version": "0.7.7", - "resolved": "https://registry.npmjs.org/@tanstack/store/-/store-0.7.7.tgz", - "integrity": "sha512-xa6pTan1bcaqYDS9BDpSiS63qa6EoDkPN9RsRaxHuDdVDNntzq3xNwR5YKTU/V3SkSyC9T4YVOPh2zRQN0nhIQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@types/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==" - }, - "node_modules/@types/node": { - "version": "20.19.23", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.23.tgz", - "integrity": "sha512-yIdlVVVHXpmqRhtyovZAcSy0MiPcYWGkoO4CGe/+jpP0hmNuihm4XhHbADpK++MsiLHP5MVlv+bcgdF99kSiFQ==", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@types/react": { - "version": "19.2.2", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", - "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", - "dev": true, - "dependencies": { - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "19.2.2", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.2.tgz", - "integrity": "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw==", - "dev": true, - "peerDependencies": { - "@types/react": "^19.2.0" - } - }, - "node_modules/@web3-storage/multipart-parser": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@web3-storage/multipart-parser/-/multipart-parser-1.0.0.tgz", - "integrity": "sha512-BEO6al7BYqcnfX15W2cnGR+Q566ACXAT9UQykORCWW80lmkpWsnEob6zJS1ZVBKsSJC8+7vJkHwlp+lXG1UCdw==" - }, - "node_modules/@zxing/text-encoding": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz", - "integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==", - "optional": true - }, - "node_modules/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" - }, - "node_modules/busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", - "dependencies": { - "streamsearch": "^1.1.0" - }, - "engines": { - "node": ">=10.16.0" - } - }, - "node_modules/call-bind": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", - "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001751", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001751.tgz", - "integrity": "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/client-only": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", - "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/color": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", - "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", - "optional": true, - "dependencies": { - "color-convert": "^2.0.1", - "color-string": "^1.9.0" - }, - "engines": { - "node": ">=12.5.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "optional": true, - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "engines": { - "node": ">=6.6.0" - } - }, - "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true - }, - "node_modules/data-uri-to-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz", - "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/decode-formdata": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/decode-formdata/-/decode-formdata-0.8.0.tgz", - "integrity": "sha512-iUzDgnWsw5ToSkFY7VPFA5Gfph6ROoOxOB7Ybna4miUSzLZ4KaSJk6IAB2AdW6+C9vCVWhjjNA4gjT6wF3eZHQ==" - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "devOptional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/enhanced-resolve": { - "version": "5.18.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", - "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", - "dependencies": { - "websocket-driver": ">=0.5.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/firebase": { - "version": "11.10.0", - "resolved": "https://registry.npmjs.org/firebase/-/firebase-11.10.0.tgz", - "integrity": "sha512-nKBXoDzF0DrXTBQJlZa+sbC5By99ysYU1D6PkMRYknm0nCW7rJly47q492Ht7Ndz5MeYSBuboKuhS1e6mFC03w==", - "dependencies": { - "@firebase/ai": "1.4.1", - "@firebase/analytics": "0.10.17", - "@firebase/analytics-compat": "0.2.23", - "@firebase/app": "0.13.2", - "@firebase/app-check": "0.10.1", - "@firebase/app-check-compat": "0.3.26", - "@firebase/app-compat": "0.4.2", - "@firebase/app-types": "0.9.3", - "@firebase/auth": "1.10.8", - "@firebase/auth-compat": "0.5.28", - "@firebase/data-connect": "0.3.10", - "@firebase/database": "1.0.20", - "@firebase/database-compat": "2.0.11", - "@firebase/firestore": "4.8.0", - "@firebase/firestore-compat": "0.3.53", - "@firebase/functions": "0.12.9", - "@firebase/functions-compat": "0.3.26", - "@firebase/installations": "0.6.18", - "@firebase/installations-compat": "0.2.18", - "@firebase/messaging": "0.12.22", - "@firebase/messaging-compat": "0.2.22", - "@firebase/performance": "0.7.7", - "@firebase/performance-compat": "0.2.20", - "@firebase/remote-config": "0.6.5", - "@firebase/remote-config-compat": "0.2.18", - "@firebase/storage": "0.13.14", - "@firebase/storage-compat": "0.3.24", - "@firebase/util": "1.12.1" - } - }, - "node_modules/for-each": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", - "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", - "dependencies": { - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/generator-function": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", - "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/http-parser-js": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", - "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==" - }, - "node_modules/idb": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", - "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==" - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/is-arguments": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", - "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", - "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-arrayish": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz", - "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==", - "optional": true - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-function": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", - "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", - "dependencies": { - "call-bound": "^1.0.4", - "generator-function": "^2.0.0", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", - "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", - "dependencies": { - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/jiti": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", - "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", - "dev": true, - "bin": { - "jiti": "lib/jiti-cli.mjs" - } - }, - "node_modules/lightningcss": { - "version": "1.30.2", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz", - "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==", - "dev": true, - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.30.2", - "lightningcss-darwin-arm64": "1.30.2", - "lightningcss-darwin-x64": "1.30.2", - "lightningcss-freebsd-x64": "1.30.2", - "lightningcss-linux-arm-gnueabihf": "1.30.2", - "lightningcss-linux-arm64-gnu": "1.30.2", - "lightningcss-linux-arm64-musl": "1.30.2", - "lightningcss-linux-x64-gnu": "1.30.2", - "lightningcss-linux-x64-musl": "1.30.2", - "lightningcss-win32-arm64-msvc": "1.30.2", - "lightningcss-win32-x64-msvc": "1.30.2" - } - }, - "node_modules/lightningcss-android-arm64": { - "version": "1.30.2", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz", - "integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.30.2", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz", - "integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.30.2", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz", - "integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.30.2", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz", - "integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.30.2", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz", - "integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.30.2", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz", - "integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.30.2", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz", - "integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.30.2", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz", - "integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.30.2", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz", - "integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.30.2", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz", - "integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.30.2", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz", - "integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" - }, - "node_modules/long": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", - "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==" - }, - "node_modules/magic-string": { - "version": "0.30.19", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz", - "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/mrmime": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", - "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", - "engines": { - "node": ">=10" - } - }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/nanostores": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/nanostores/-/nanostores-0.11.4.tgz", - "integrity": "sha512-k1oiVNN4hDK8NcNERSZLQiMfRzEGtfnvZvdBvey3SQbgn8Dcrk0h1I6vpxApjb10PFUflZrgJ2WEZyJQ+5v7YQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "engines": { - "node": "^18.0.0 || >=20.0.0" - } - }, - "node_modules/next": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/next/-/next-15.1.7.tgz", - "integrity": "sha512-GNeINPGS9c6OZKCvKypbL8GTsT5GhWPp4DM0fzkXJuXMilOO2EeFxuAY6JZbtk6XIl6Ws10ag3xRINDjSO5+wg==", - "dependencies": { - "@next/env": "15.1.7", - "@swc/counter": "0.1.3", - "@swc/helpers": "0.5.15", - "busboy": "1.6.0", - "caniuse-lite": "^1.0.30001579", - "postcss": "8.4.31", - "styled-jsx": "5.1.6" - }, - "bin": { - "next": "dist/bin/next" - }, - "engines": { - "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" - }, - "optionalDependencies": { - "@next/swc-darwin-arm64": "15.1.7", - "@next/swc-darwin-x64": "15.1.7", - "@next/swc-linux-arm64-gnu": "15.1.7", - "@next/swc-linux-arm64-musl": "15.1.7", - "@next/swc-linux-x64-gnu": "15.1.7", - "@next/swc-linux-x64-musl": "15.1.7", - "@next/swc-win32-arm64-msvc": "15.1.7", - "@next/swc-win32-x64-msvc": "15.1.7", - "sharp": "^0.33.5" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.1.0", - "@playwright/test": "^1.41.2", - "babel-plugin-react-compiler": "*", - "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", - "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", - "sass": "^1.3.0" - }, - "peerDependenciesMeta": { - "@opentelemetry/api": { - "optional": true - }, - "@playwright/test": { - "optional": true - }, - "babel-plugin-react-compiler": { - "optional": true - }, - "sass": { - "optional": true - } - } - }, - "node_modules/next/node_modules/postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" - }, - "node_modules/possible-typed-array-names": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", - "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-load-config": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", - "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "lilconfig": "^3.1.1" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "jiti": ">=1.21.0", - "postcss": ">=8.0.9", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - }, - "postcss": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/protobufjs": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz", - "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==", - "hasInstallScript": true, - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/react": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", - "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", - "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", - "dependencies": { - "scheduler": "^0.27.0" - }, - "peerDependencies": { - "react": "^19.2.0" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safe-regex-test": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", - "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-regex": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==" - }, - "node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "optional": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/server-only": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/server-only/-/server-only-0.0.1.tgz", - "integrity": "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==" - }, - "node_modules/set-cookie-parser": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", - "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==" - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/sharp": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", - "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", - "hasInstallScript": true, - "optional": true, - "dependencies": { - "color": "^4.2.3", - "detect-libc": "^2.0.3", - "semver": "^7.6.3" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.33.5", - "@img/sharp-darwin-x64": "0.33.5", - "@img/sharp-libvips-darwin-arm64": "1.0.4", - "@img/sharp-libvips-darwin-x64": "1.0.4", - "@img/sharp-libvips-linux-arm": "1.0.5", - "@img/sharp-libvips-linux-arm64": "1.0.4", - "@img/sharp-libvips-linux-s390x": "1.0.4", - "@img/sharp-libvips-linux-x64": "1.0.4", - "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", - "@img/sharp-libvips-linuxmusl-x64": "1.0.4", - "@img/sharp-linux-arm": "0.33.5", - "@img/sharp-linux-arm64": "0.33.5", - "@img/sharp-linux-s390x": "0.33.5", - "@img/sharp-linux-x64": "0.33.5", - "@img/sharp-linuxmusl-arm64": "0.33.5", - "@img/sharp-linuxmusl-x64": "0.33.5", - "@img/sharp-wasm32": "0.33.5", - "@img/sharp-win32-ia32": "0.33.5", - "@img/sharp-win32-x64": "0.33.5" - } - }, - "node_modules/simple-swizzle": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", - "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==", - "optional": true, - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/source-map": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", - "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", - "engines": { - "node": ">= 12" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stream-slice": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/stream-slice/-/stream-slice-0.1.2.tgz", - "integrity": "sha512-QzQxpoacatkreL6jsxnVb7X5R/pGw9OUv2qWTYWnmLpg4NdN31snPy/f3TdQE1ZUXaThRvj1Zw4/OGg0ZkaLMA==" - }, - "node_modules/streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/styled-jsx": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", - "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", - "dependencies": { - "client-only": "0.0.1" - }, - "engines": { - "node": ">= 12.0.0" - }, - "peerDependencies": { - "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "babel-plugin-macros": { - "optional": true - } - } - }, - "node_modules/tailwind-merge": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.1.tgz", - "integrity": "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/dcastil" - } - }, - "node_modules/tailwindcss": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.16.tgz", - "integrity": "sha512-pONL5awpaQX4LN5eiv7moSiSPd/DLDzKVRJz8Q9PgzmAdd1R4307GQS2ZpfiN7ZmekdQrfhZZiSE5jkLR4WNaA==", - "dev": true - }, - "node_modules/tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" - }, - "node_modules/turbo-stream": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.1.tgz", - "integrity": "sha512-v8kOJXpG3WoTN/+at8vK7erSzo6nW6CIaeOvNOkHQVDajfz1ZVeSxCbc6tOH4hrGZW7VUCV0TOXd8CPzYnYkrw==" - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "devOptional": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici": { - "version": "6.22.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.22.0.tgz", - "integrity": "sha512-hU/10obOIu62MGYjdskASR3CUAiYaFTtC9Pa6vHyf//mAipSvSQg6od2CnJswq7fvzNS3zJhxoRkgNVaHurWKw==", - "engines": { - "node": ">=18.17" - } - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==" - }, - "node_modules/use-sync-external-store": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", - "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/util": { - "version": "0.12.5", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", - "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", - "dependencies": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "which-typed-array": "^1.1.2" - } - }, - "node_modules/web-encoding": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/web-encoding/-/web-encoding-1.1.5.tgz", - "integrity": "sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==", - "dependencies": { - "util": "^0.12.3" - }, - "optionalDependencies": { - "@zxing/text-encoding": "0.9.0" - } - }, - "node_modules/web-streams-polyfill": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", - "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/web-vitals": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.4.tgz", - "integrity": "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==" - }, - "node_modules/websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", - "dependencies": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.19", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", - "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "for-each": "^0.3.5", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "engines": { - "node": ">=12" - } - }, - "node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - } - } -} diff --git a/examples/nextjs/app/screens/sign-in-auth-screen-w-handlers/page.tsx b/examples/nextjs/app/screens/sign-in-auth-screen-w-handlers/page.tsx index d5c825393..7dd0277d2 100644 --- a/examples/nextjs/app/screens/sign-in-auth-screen-w-handlers/page.tsx +++ b/examples/nextjs/app/screens/sign-in-auth-screen-w-handlers/page.tsx @@ -17,10 +17,16 @@ "use client"; import { SignInAuthScreen } from "@firebase-oss/ui-react"; +import { useRouter } from "next/navigation"; export default function SignInAuthScreenWithHandlersPage() { + const router = useRouter(); + return ( { + router.push("/screens/forgot-password-auth-screen"); + }} onSignIn={(credential) => { console.log(credential); }} diff --git a/package.json b/package.json index 33892e091..570ec467c 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "@firebase-oss/ui-root", "private": true, "type": "module", + "packageManager": "pnpm@10.34.4", "scripts": { "emulators": "firebase emulators:start --only auth --project demo-test", "build": "pnpm --filter=@firebase-oss/ui-translations run build && pnpm --filter=@firebase-oss/ui-styles run build && pnpm --filter=@firebase-oss/ui-core run build && pnpm --filter=@firebase-oss/ui-react run build && pnpm --filter=@firebase-oss/ui-angular run build && pnpm --filter=@firebase-oss/ui-shadcn run build && pnpm --filter react run build && pnpm --filter nextjs run build && pnpm --filter nextjs-ssr run build && pnpm --filter angular-example run build && pnpm --filter shadcn run build", @@ -12,6 +13,13 @@ "format:check": "prettier --check **/{src,tests}/**/*.{ts,tsx}", "format:write": "prettier --write **/{src,tests}/**/*.{ts,tsx}", "test": "pnpm --filter=@firebase-oss/ui-core run test && pnpm --filter=@firebase-oss/ui-translations run test && pnpm --filter=@firebase-oss/ui-styles run test && pnpm --filter=@firebase-oss/ui-react run test && pnpm --filter=@firebase-oss/ui-shadcn run test && pnpm --filter=@firebase-oss/ui-angular run test", + "test:e2e": "node scripts/e2e-run.mjs", + "test:e2e:react": "E2E_PROJECT=react pnpm --filter=e2e exec playwright test --project=react", + "test:e2e:shadcn": "E2E_PROJECT=shadcn pnpm --filter=e2e exec playwright test --project=shadcn", + "test:e2e:nextjs": "E2E_PROJECT=nextjs pnpm --filter=e2e exec playwright test --project=nextjs", + "test:e2e:nextjs-ssr": "E2E_PROJECT=nextjs-ssr pnpm --filter=e2e exec playwright test --project=nextjs-ssr", + "test:e2e:angular": "E2E_PROJECT=angular-example pnpm --filter=e2e exec playwright test --project=angular-example", + "test:e2e:custom-auth-server": "E2E_PROJECT=custom-auth-server pnpm --filter=e2e exec playwright test --project=custom-auth-server", "test:watch": "pnpm --filter=@firebase-oss/ui-core run test:unit:watch & pnpm --filter=@firebase-oss/ui-react run test:unit:watch & pnpm --filter=@firebase-oss/ui-angular run test:watch", "version:bump:all": "pnpm --filter=@firebase-oss/ui-core run version:bump && pnpm --filter=@firebase-oss/ui-translations run version:bump && pnpm --filter=@firebase-oss/ui-react run version:bump && pnpm --filter=@firebase-oss/ui-styles run version:bump && pnpm --filter=@firebase-oss/ui-angular run version:bump", "publish:tags:all": "pnpm i && pnpm --filter=@firebase-oss/ui-core run publish:tags && pnpm --filter=@firebase-oss/ui-translations run publish:tags && pnpm --filter=@firebase-oss/ui-react run publish:tags && pnpm --filter=@firebase-oss/ui-styles run publish:tags && pnpm --filter=@firebase-oss/ui-angular run publish:tags", diff --git a/packages/angular/src/lib/provider.ts b/packages/angular/src/lib/provider.ts index 70843c55e..78fe6a700 100644 --- a/packages/angular/src/lib/provider.ts +++ b/packages/angular/src/lib/provider.ts @@ -82,8 +82,7 @@ export function provideFirebaseUI(uiFactory: (apps: FirebaseApps) => FirebaseUIS { provide: FIREBASE_UI_STORE, deps: [FirebaseApps, [new Optional(), Auth]], - useFactory: () => { - const apps = inject(FirebaseApps); + useFactory: (apps: FirebaseApps) => { if (!apps || apps.length === 0) { throw new Error("No Firebase apps found"); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 321f45f12..55353b043 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -57,6 +57,9 @@ catalogs: '@nanostores/deepmap': specifier: ^0.0.1 version: 0.0.1 + '@playwright/test': + specifier: 1.61.1 + version: 1.61.1 '@tailwindcss/vite': specifier: ^4.1.14 version: 4.1.16 @@ -142,6 +145,9 @@ catalogs: specifier: ^0.15.0 version: 0.15.1 +overrides: + firebase-tools: '-' + importers: .: @@ -177,6 +183,15 @@ importers: specifier: ^8.45.0 version: 8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3) + e2e: + devDependencies: + '@firebase-oss/ui-translations': + specifier: workspace:* + version: link:../packages/translations + '@playwright/test': + specifier: 'catalog:' + version: 1.61.1 + examples/angular: dependencies: '@angular/animations': @@ -214,7 +229,7 @@ importers: version: 20.3.26(cf5d6e644c41e8ccd7f957989714a299) '@firebase-oss/ui-angular': specifier: workspace:* - version: link:../../packages/angular + version: file:packages/angular(@angular/common@20.3.25(@angular/core@20.3.25(@angular/compiler@20.3.25)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.25(@angular/compiler@20.3.25)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/fire@20.0.1(224a9fe38983fbc914b248dcbaf6f32b)) '@firebase-oss/ui-core': specifier: workspace:* version: link:../../packages/core @@ -245,13 +260,16 @@ importers: zone.js: specifier: ~0.15.0 version: 0.15.1 + dependenciesMeta: + '@firebase-oss/ui-angular': + injected: true devDependencies: '@angular-devkit/architect': specifier: 'catalog:' version: 0.2003.26(chokidar@4.0.3) '@angular-devkit/build-angular': specifier: 'catalog:' - version: 20.3.26(3e5f368b1c7a3c24585f0991739387fe) + version: 20.3.26(8785e174638123b2037b72df31a63ffb) '@angular-devkit/core': specifier: 'catalog:' version: 20.3.26(chokidar@4.0.3) @@ -312,15 +330,18 @@ importers: prettier: specifier: ^3.1.1 version: 3.6.2 + rimraf: + specifier: 'catalog:' + version: 6.0.1 typescript: specifier: ^5.9.2 version: 5.9.3 vite: specifier: 'catalog:' - version: 7.3.2(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6) + version: 7.3.2(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.9.0) vitest: specifier: 'catalog:' - version: 3.2.4(@types/node@20.19.24)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@25.0.1)(less@4.4.0)(lightningcss@1.30.2)(msw@2.11.6(@types/node@20.19.24)(typescript@5.9.3))(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6) + version: 3.2.4(@types/node@20.19.24)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@25.0.1)(less@4.4.0)(lightningcss@1.30.2)(msw@2.11.6(@types/node@20.19.24)(typescript@5.9.3))(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.9.0) examples/custom-auth-server: dependencies: @@ -372,7 +393,7 @@ importers: version: 11.10.0 next: specifier: 'catalog:' - version: 15.5.18(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.97.3) + version: 15.5.18(@opentelemetry/api@1.9.0)(@playwright/test@1.61.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.97.3) react: specifier: 'catalog:' version: 19.2.3 @@ -400,7 +421,7 @@ importers: version: 8.5.14 postcss-load-config: specifier: ^6.0.1 - version: 6.0.1(jiti@2.6.1)(postcss@8.5.14)(tsx@4.20.6) + version: 6.0.1(jiti@2.6.1)(postcss@8.5.14)(tsx@4.20.6)(yaml@2.9.0) tailwindcss: specifier: ^4.0.6 version: 4.1.16 @@ -427,7 +448,7 @@ importers: version: 11.10.0 next: specifier: 'catalog:' - version: 15.5.18(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.97.3) + version: 15.5.18(@opentelemetry/api@1.9.0)(@playwright/test@1.61.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.97.3) react: specifier: 'catalog:' version: 19.2.3 @@ -455,7 +476,7 @@ importers: version: 8.5.14 postcss-load-config: specifier: ^6.0.1 - version: 6.0.1(jiti@2.6.1)(postcss@8.5.14)(tsx@4.20.6) + version: 6.0.1(jiti@2.6.1)(postcss@8.5.14)(tsx@4.20.6)(yaml@2.9.0) tailwindcss: specifier: ^4.0.6 version: 4.1.16 @@ -464,7 +485,7 @@ importers: version: 5.9.3 vite: specifier: 'catalog:' - version: 7.3.2(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6) + version: 7.3.2(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0) examples/react: dependencies: @@ -498,7 +519,7 @@ importers: version: 9.38.0 '@tailwindcss/vite': specifier: ^4.1.4 - version: 4.1.16(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)) + version: 4.1.16(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0)) '@types/react': specifier: 'catalog:' version: 19.2.7 @@ -507,7 +528,7 @@ importers: version: 19.2.3(@types/react@19.2.7) '@vitejs/plugin-react': specifier: 'catalog:' - version: 5.1.0(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)) + version: 5.1.0(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0)) eslint: specifier: ^9.22.0 version: 9.38.0(jiti@2.6.1) @@ -528,7 +549,7 @@ importers: version: 4.1.16 vite: specifier: 'catalog:' - version: 7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6) + version: 7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0) examples/shadcn: dependencies: @@ -691,7 +712,7 @@ importers: devDependencies: '@tailwindcss/vite': specifier: 'catalog:' - version: 4.1.16(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)) + version: 4.1.16(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0)) '@types/node': specifier: 'catalog:' version: 24.9.2 @@ -706,7 +727,7 @@ importers: version: 21.0.3 '@vitejs/plugin-react': specifier: 'catalog:' - version: 5.1.0(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)) + version: 5.1.0(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0)) tailwindcss: specifier: 'catalog:' version: 4.1.16 @@ -721,7 +742,7 @@ importers: version: 5.9.3 vite: specifier: 'catalog:' - version: 7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6) + version: 7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0) yargs-parser: specifier: ^22.0.0 version: 22.0.0 @@ -746,7 +767,7 @@ importers: devDependencies: '@angular-devkit/build-angular': specifier: 'catalog:' - version: 20.3.26(a053227dddd84e327a6ac3dd5622eac8) + version: 20.3.26(354cd8b8691501a425f00b11a2e47416) '@angular/cli': specifier: 'catalog:' version: 20.3.26(@types/node@24.9.2)(chokidar@4.0.3) @@ -867,16 +888,16 @@ importers: version: 6.0.1 tsup: specifier: 'catalog:' - version: 8.5.0(jiti@2.6.1)(postcss@8.5.14)(tsx@4.20.6)(typescript@5.9.3) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.14)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.9.0) typescript: specifier: 'catalog:' version: 5.9.3 vite: specifier: 'catalog:' - version: 7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6) + version: 7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0) vitest: specifier: 'catalog:' - version: 3.2.4(@types/node@24.9.2)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(less@4.4.2)(lightningcss@1.30.2)(msw@2.11.6(@types/node@24.9.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6) + version: 3.2.4(@types/node@24.9.2)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(less@4.4.2)(lightningcss@1.30.2)(msw@2.11.6(@types/node@24.9.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0) packages/react: dependencies: @@ -928,7 +949,7 @@ importers: version: 19.2.3(@types/react@19.2.7) '@vitejs/plugin-react': specifier: 'catalog:' - version: 5.1.0(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)) + version: 5.1.0(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0)) firebase: specifier: 'catalog:' version: 11.10.0 @@ -946,19 +967,19 @@ importers: version: 19.2.3(react@19.2.3) tsup: specifier: 'catalog:' - version: 8.5.0(jiti@2.6.1)(postcss@8.5.14)(tsx@4.20.6)(typescript@5.9.3) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.14)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.9.0) typescript: specifier: 'catalog:' version: 5.9.3 vite: specifier: 'catalog:' - version: 7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6) + version: 7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0) vite-plugin-svgr: specifier: ^4.5.0 - version: 4.5.0(rollup@4.62.0)(typescript@5.9.3)(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)) + version: 4.5.0(rollup@4.62.0)(typescript@5.9.3)(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0)) vitest: specifier: 'catalog:' - version: 3.2.4(@types/node@24.9.2)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(less@4.4.2)(lightningcss@1.30.2)(msw@2.11.6(@types/node@24.9.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6) + version: 3.2.4(@types/node@24.9.2)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(less@4.4.2)(lightningcss@1.30.2)(msw@2.11.6(@types/node@24.9.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0) packages/shadcn: dependencies: @@ -1010,7 +1031,7 @@ importers: version: link:../translations '@tailwindcss/vite': specifier: 'catalog:' - version: 4.1.16(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)) + version: 4.1.16(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0)) '@testing-library/jest-dom': specifier: 'catalog:' version: 6.9.1 @@ -1031,7 +1052,7 @@ importers: version: 21.0.3 '@vitejs/plugin-react': specifier: 'catalog:' - version: 5.1.0(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)) + version: 5.1.0(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0)) firebase: specifier: 'catalog:' version: 11.10.0 @@ -1049,7 +1070,7 @@ importers: version: 4.1.16 tsup: specifier: 'catalog:' - version: 8.5.0(jiti@2.6.1)(postcss@8.5.14)(tsx@4.20.6)(typescript@5.9.3) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.14)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.9.0) tsx: specifier: ^4.20.6 version: 4.20.6 @@ -1061,13 +1082,13 @@ importers: version: 5.9.3 vite: specifier: 'catalog:' - version: 7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6) + version: 7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0) vite-plugin-run: specifier: ^0.6.1 version: 0.6.1 vitest: specifier: 'catalog:' - version: 3.2.4(@types/node@24.9.2)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(less@4.4.2)(lightningcss@1.30.2)(msw@2.11.6(@types/node@24.9.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6) + version: 3.2.4(@types/node@24.9.2)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(less@4.4.2)(lightningcss@1.30.2)(msw@2.11.6(@types/node@24.9.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0) yargs-parser: specifier: ^22.0.0 version: 22.0.0 @@ -1086,13 +1107,13 @@ importers: version: 4.1.16 tsup: specifier: 'catalog:' - version: 8.5.0(jiti@2.6.1)(postcss@8.5.14)(tsx@4.20.6)(typescript@5.9.3) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.14)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.9.0) typescript: specifier: 'catalog:' version: 5.9.3 vitest: specifier: 'catalog:' - version: 3.2.4(@types/node@24.9.2)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(less@4.4.2)(lightningcss@1.30.2)(msw@2.11.6(@types/node@24.9.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6) + version: 3.2.4(@types/node@24.9.2)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(less@4.4.2)(lightningcss@1.30.2)(msw@2.11.6(@types/node@24.9.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0) zshy: specifier: 0.7.0 version: 0.7.0(typescript@5.9.3) @@ -1104,13 +1125,13 @@ importers: version: 6.0.1 tsup: specifier: 'catalog:' - version: 8.5.0(jiti@2.6.1)(postcss@8.5.14)(tsx@4.20.6)(typescript@5.9.3) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.14)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.9.0) typescript: specifier: 'catalog:' version: 5.9.3 vitest: specifier: 'catalog:' - version: 3.2.4(@types/node@24.9.2)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(less@4.4.2)(lightningcss@1.30.2)(msw@2.11.6(@types/node@24.9.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6) + version: 3.2.4(@types/node@24.9.2)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(less@4.4.2)(lightningcss@1.30.2)(msw@2.11.6(@types/node@24.9.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0) packages: @@ -1423,7 +1444,7 @@ packages: '@angular/platform-browser': ^20.0.0 '@angular/platform-browser-dynamic': ^20.0.0 '@angular/platform-server': ^20.0.0 - firebase-tools: ^14.0.0 + firebase-tools: '*' rxjs: ~7.8.0 peerDependenciesMeta: '@angular/platform-server': @@ -2792,6 +2813,11 @@ packages: '@fastify/busboy@3.2.0': resolution: {integrity: sha512-m9FVDXU3GT2ITSe0UaMA5rU3QkfC/UXtCU8y0gSN/GugTqtVldOBWIB5V6V3sbmenVZUIpU6f+mPEO2+m5iTaA==} + '@firebase-oss/ui-angular@file:packages/angular': + resolution: {directory: packages/angular, type: directory} + peerDependencies: + '@angular/fire': catalog:peerDependencies + '@firebase/ai@1.4.1': resolution: {integrity: sha512-bcusQfA/tHjUjBTnMx6jdoPMpDl3r8K15Z+snHz9wq0Foox0F/V+kNLXucEOHoTL2hTc9l+onZCyBJs2QoIC3g==} engines: {node: '>=18.0.0'} @@ -3239,10 +3265,6 @@ packages: cpu: [x64] os: [win32] - '@inquirer/ansi@1.0.1': - resolution: {integrity: sha512-yqq0aJW/5XPhi5xOAL1xRCpe1eh8UFVgYFpFsjEqmIR8rKLyP+HINvFXwUaxYICflJrVlxnp7lLN6As735kVpw==} - engines: {node: '>=18'} - '@inquirer/ansi@1.0.2': resolution: {integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==} engines: {node: '>=18'} @@ -3265,15 +3287,6 @@ packages: '@types/node': optional: true - '@inquirer/confirm@5.1.19': - resolution: {integrity: sha512-wQNz9cfcxrtEnUyG5PndC8g3gZ7lGDBzmWiXZkX8ot3vfZ+/BLjR8EvyGX4YzQLeVqtAlY/YScZpW7CW8qMoDQ==} - engines: {node: '>=18'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - '@inquirer/confirm@5.1.21': resolution: {integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==} engines: {node: '>=18'} @@ -3283,15 +3296,6 @@ packages: '@types/node': optional: true - '@inquirer/core@10.3.0': - resolution: {integrity: sha512-Uv2aPPPSK5jeCplQmQ9xadnFx2Zhj9b5Dj7bU6ZeCdDNNY11nhYy4btcSdtDguHqCT2h5oNeQTcUNSGGLA7NTA==} - engines: {node: '>=18'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - '@inquirer/core@10.3.2': resolution: {integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==} engines: {node: '>=18'} @@ -3328,10 +3332,6 @@ packages: '@types/node': optional: true - '@inquirer/figures@1.0.14': - resolution: {integrity: sha512-DbFgdt+9/OZYFM+19dbpXOSeAstPy884FPy1KjDu4anWwymZeOYhMY1mdFri172htv6mvc/uvIAAi7b7tvjJBQ==} - engines: {node: '>=18'} - '@inquirer/figures@1.0.15': resolution: {integrity: sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==} engines: {node: '>=18'} @@ -3408,23 +3408,6 @@ packages: '@types/node': optional: true - '@inquirer/type@3.0.9': - resolution: {integrity: sha512-QPaNt/nmE2bLGQa9b7wwyRJoLZ7pN6rcyXvzU0YCmivmJyq1BVo94G98tStRWkoD1RgDX5C+dPlhhHzNdu/W/w==} - engines: {node: '>=18'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@isaacs/balanced-match@4.0.1': - resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} - engines: {node: 20 || >=22} - - '@isaacs/brace-expansion@5.0.0': - resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} - engines: {node: 20 || >=22} - '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -4125,6 +4108,11 @@ packages: resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@playwright/test@1.61.1': + resolution: {integrity: sha512-8nKv6+0RJSL9FE4jYOEGXnPeM/Hg12qZpmqzZjRh3qM0Y7c3z1mrOTfFLids72RDQYVh9WpLEfR5WdpNX4fkig==} + engines: {node: '>=18'} + hasBin: true + '@polka/url@1.0.0-next.29': resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} @@ -7459,6 +7447,11 @@ packages: fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -7841,10 +7834,6 @@ packages: resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} engines: {node: '>=12'} - ip-address@10.0.1: - resolution: {integrity: sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==} - engines: {node: '>= 12'} - ip-address@10.2.0: resolution: {integrity: sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==} engines: {node: '>= 12'} @@ -8757,10 +8746,6 @@ packages: minimalistic-assert@1.0.1: resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} - minimatch@10.1.1: - resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} - engines: {node: 20 || >=22} - minimatch@10.2.5: resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} engines: {node: 18 || 20 || >=22} @@ -9220,10 +9205,6 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} - path-scurry@2.0.0: - resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} - engines: {node: 20 || >=22} - path-scurry@2.0.2: resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} engines: {node: 18 || 20 || >=22} @@ -9290,6 +9271,16 @@ packages: pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + playwright-core@1.61.1: + resolution: {integrity: sha512-h7Qlt6m4REp25qvIdvbDtVmD4LqVXfpRxhORv9L0jzETM05p4fuPJ3dKyuSXQxDSbXnmS79HAgi9589lGSpLkg==} + engines: {node: '>=18'} + hasBin: true + + playwright@1.61.1: + resolution: {integrity: sha512-DWnY5o3YbLWK4GovuAVwpqL+1VwGNdUGrRr++8j8PtQQzvAVZUIMjKQ90fY689sEJZJBbZVw1rXaOKSTitkzPQ==} + engines: {node: '>=18'} + hasBin: true + possible-typed-array-names@1.1.0: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} @@ -11005,6 +10996,11 @@ packages: resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} engines: {node: '>=18'} + yaml@2.9.0: + resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} + engines: {node: '>= 14.6'} + hasBin: true + yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} @@ -11170,13 +11166,13 @@ snapshots: transitivePeerDependencies: - chokidar - '@angular-devkit/build-angular@20.3.26(3e5f368b1c7a3c24585f0991739387fe)': + '@angular-devkit/build-angular@20.3.26(354cd8b8691501a425f00b11a2e47416)': dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.2003.26(chokidar@4.0.3) - '@angular-devkit/build-webpack': 0.2003.26(chokidar@4.0.3)(webpack-dev-server@5.2.2(webpack@5.105.0))(webpack@5.105.0(esbuild@0.28.0)) + '@angular-devkit/build-webpack': 0.2003.26(chokidar@4.0.3)(webpack-dev-server@5.2.2(webpack@5.105.0(esbuild@0.28.0)))(webpack@5.105.0(esbuild@0.28.0)) '@angular-devkit/core': 20.3.26(chokidar@4.0.3) - '@angular/build': 20.3.26(29b2aeca659b30afaf64f347b8d0b9ab) + '@angular/build': 20.3.26(892459dd01d51d39f98ca810f1824ad1) '@angular/compiler-cli': 20.3.21(@angular/compiler@20.3.25)(typescript@5.9.3) '@babel/core': 7.28.3 '@babel/generator': 7.28.3 @@ -11225,7 +11221,7 @@ snapshots: typescript: 5.9.3 webpack: 5.105.0(esbuild@0.28.0) webpack-dev-middleware: 7.4.2(webpack@5.105.0(esbuild@0.28.0)) - webpack-dev-server: 5.2.2(webpack@5.105.0) + webpack-dev-server: 5.2.2(webpack@5.105.0(esbuild@0.28.0)) webpack-merge: 6.0.1 webpack-subresource-integrity: 5.1.0(webpack@5.105.0(esbuild@0.28.0)) optionalDependencies: @@ -11234,7 +11230,7 @@ snapshots: '@angular/platform-server': 20.3.25(@angular/common@20.3.25(@angular/core@20.3.25(@angular/compiler@20.3.25)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.25)(@angular/core@20.3.25(@angular/compiler@20.3.25)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.21(@angular/animations@20.3.21(@angular/core@20.3.25(@angular/compiler@20.3.25)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.25(@angular/core@20.3.25(@angular/compiler@20.3.25)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.25(@angular/compiler@20.3.25)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2) '@angular/ssr': 20.3.26(cf5d6e644c41e8ccd7f957989714a299) esbuild: 0.28.0 - jest: 30.2.0(@types/node@20.19.24) + jest: 30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)) jest-environment-jsdom: 30.2.0 ng-packagr: 20.3.0(@angular/compiler-cli@20.3.21(@angular/compiler@20.3.25)(typescript@5.9.3))(tailwindcss@4.1.16)(tslib@2.8.1)(typescript@5.9.3) tailwindcss: 4.1.16 @@ -11261,13 +11257,13 @@ snapshots: - webpack-cli - yaml - '@angular-devkit/build-angular@20.3.26(a053227dddd84e327a6ac3dd5622eac8)': + '@angular-devkit/build-angular@20.3.26(8785e174638123b2037b72df31a63ffb)': dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.2003.26(chokidar@4.0.3) - '@angular-devkit/build-webpack': 0.2003.26(chokidar@4.0.3)(webpack-dev-server@5.2.2(webpack@5.105.0))(webpack@5.105.0(esbuild@0.28.0)) + '@angular-devkit/build-webpack': 0.2003.26(chokidar@4.0.3)(webpack-dev-server@5.2.2(webpack@5.105.0(esbuild@0.28.0)))(webpack@5.105.0(esbuild@0.28.0)) '@angular-devkit/core': 20.3.26(chokidar@4.0.3) - '@angular/build': 20.3.26(30015dc94060e12dd9676286e19705fc) + '@angular/build': 20.3.26(cbb794e594450ca1eb21d6401ae650ab) '@angular/compiler-cli': 20.3.21(@angular/compiler@20.3.25)(typescript@5.9.3) '@babel/core': 7.28.3 '@babel/generator': 7.28.3 @@ -11316,7 +11312,7 @@ snapshots: typescript: 5.9.3 webpack: 5.105.0(esbuild@0.28.0) webpack-dev-middleware: 7.4.2(webpack@5.105.0(esbuild@0.28.0)) - webpack-dev-server: 5.2.2(webpack@5.105.0) + webpack-dev-server: 5.2.2(webpack@5.105.0(esbuild@0.28.0)) webpack-merge: 6.0.1 webpack-subresource-integrity: 5.1.0(webpack@5.105.0(esbuild@0.28.0)) optionalDependencies: @@ -11325,7 +11321,7 @@ snapshots: '@angular/platform-server': 20.3.25(@angular/common@20.3.25(@angular/core@20.3.25(@angular/compiler@20.3.25)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/compiler@20.3.25)(@angular/core@20.3.25(@angular/compiler@20.3.25)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@20.3.21(@angular/animations@20.3.21(@angular/core@20.3.25(@angular/compiler@20.3.25)(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@20.3.25(@angular/core@20.3.25(@angular/compiler@20.3.25)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.25(@angular/compiler@20.3.25)(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2) '@angular/ssr': 20.3.26(cf5d6e644c41e8ccd7f957989714a299) esbuild: 0.28.0 - jest: 30.2.0(@types/node@24.9.2)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)) + jest: 30.2.0(@types/node@20.19.24)(ts-node@10.9.2(@types/node@20.19.24)(typescript@5.9.3)) jest-environment-jsdom: 30.2.0 ng-packagr: 20.3.0(@angular/compiler-cli@20.3.21(@angular/compiler@20.3.25)(typescript@5.9.3))(tailwindcss@4.1.16)(tslib@2.8.1)(typescript@5.9.3) tailwindcss: 4.1.16 @@ -11352,12 +11348,12 @@ snapshots: - webpack-cli - yaml - '@angular-devkit/build-webpack@0.2003.26(chokidar@4.0.3)(webpack-dev-server@5.2.2(webpack@5.105.0))(webpack@5.105.0(esbuild@0.28.0))': + '@angular-devkit/build-webpack@0.2003.26(chokidar@4.0.3)(webpack-dev-server@5.2.2(webpack@5.105.0(esbuild@0.28.0)))(webpack@5.105.0(esbuild@0.28.0))': dependencies: '@angular-devkit/architect': 0.2003.26(chokidar@4.0.3) rxjs: 7.8.2 webpack: 5.105.0(esbuild@0.28.0) - webpack-dev-server: 5.2.2(webpack@5.105.0) + webpack-dev-server: 5.2.2(webpack@5.105.0(esbuild@0.28.0)) transitivePeerDependencies: - chokidar @@ -11482,7 +11478,7 @@ snapshots: '@angular/core': 20.3.25(@angular/compiler@20.3.25)(rxjs@7.8.2)(zone.js@0.15.1) tslib: 2.8.1 - '@angular/build@20.3.26(29b2aeca659b30afaf64f347b8d0b9ab)': + '@angular/build@20.3.26(892459dd01d51d39f98ca810f1824ad1)': dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.2003.26(chokidar@4.0.3) @@ -11491,8 +11487,8 @@ snapshots: '@babel/core': 7.28.3 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-split-export-declaration': 7.24.7 - '@inquirer/confirm': 5.1.14(@types/node@20.19.24) - '@vitejs/plugin-basic-ssl': 2.1.0(vite@7.3.2(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)) + '@inquirer/confirm': 5.1.14(@types/node@24.9.2) + '@vitejs/plugin-basic-ssl': 2.1.0(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.9.0)) beasties: 0.3.5 browserslist: 4.28.1 esbuild: 0.28.0 @@ -11512,7 +11508,7 @@ snapshots: tinyglobby: 0.2.14 tslib: 2.8.1 typescript: 5.9.3 - vite: 7.3.2(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6) + vite: 7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.9.0) watchpack: 2.4.4 optionalDependencies: '@angular/core': 20.3.25(@angular/compiler@20.3.25)(rxjs@7.8.2)(zone.js@0.15.1) @@ -11524,7 +11520,7 @@ snapshots: ng-packagr: 20.3.0(@angular/compiler-cli@20.3.21(@angular/compiler@20.3.25)(typescript@5.9.3))(tailwindcss@4.1.16)(tslib@2.8.1)(typescript@5.9.3) postcss: 8.5.12 tailwindcss: 4.1.16 - vitest: 3.2.4(@types/node@20.19.24)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@25.0.1)(less@4.4.0)(lightningcss@1.30.2)(msw@2.11.6(@types/node@20.19.24)(typescript@5.9.3))(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6) + vitest: 3.2.4(@types/node@24.9.2)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@25.0.1)(less@4.4.2)(lightningcss@1.30.2)(msw@2.11.6(@types/node@24.9.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0) transitivePeerDependencies: - '@types/node' - chokidar @@ -11538,7 +11534,7 @@ snapshots: - tsx - yaml - '@angular/build@20.3.26(30015dc94060e12dd9676286e19705fc)': + '@angular/build@20.3.26(cbb794e594450ca1eb21d6401ae650ab)': dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.2003.26(chokidar@4.0.3) @@ -11547,8 +11543,8 @@ snapshots: '@babel/core': 7.28.3 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-split-export-declaration': 7.24.7 - '@inquirer/confirm': 5.1.14(@types/node@24.9.2) - '@vitejs/plugin-basic-ssl': 2.1.0(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)) + '@inquirer/confirm': 5.1.14(@types/node@20.19.24) + '@vitejs/plugin-basic-ssl': 2.1.0(vite@7.3.2(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.9.0)) beasties: 0.3.5 browserslist: 4.28.1 esbuild: 0.28.0 @@ -11568,7 +11564,7 @@ snapshots: tinyglobby: 0.2.14 tslib: 2.8.1 typescript: 5.9.3 - vite: 7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6) + vite: 7.3.2(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.9.0) watchpack: 2.4.4 optionalDependencies: '@angular/core': 20.3.25(@angular/compiler@20.3.25)(rxjs@7.8.2)(zone.js@0.15.1) @@ -11580,7 +11576,7 @@ snapshots: ng-packagr: 20.3.0(@angular/compiler-cli@20.3.21(@angular/compiler@20.3.25)(typescript@5.9.3))(tailwindcss@4.1.16)(tslib@2.8.1)(typescript@5.9.3) postcss: 8.5.12 tailwindcss: 4.1.16 - vitest: 3.2.4(@types/node@24.9.2)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@25.0.1)(less@4.4.2)(lightningcss@1.30.2)(msw@2.11.6(@types/node@24.9.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6) + vitest: 3.2.4(@types/node@20.19.24)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@25.0.1)(less@4.4.0)(lightningcss@1.30.2)(msw@2.11.6(@types/node@20.19.24)(typescript@5.9.3))(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.9.0) transitivePeerDependencies: - '@types/node' - chokidar @@ -11825,7 +11821,7 @@ snapshots: '@babel/core@7.29.0': dependencies: - '@babel/code-frame': 7.29.0 + '@babel/code-frame': 7.29.7 '@babel/generator': 7.29.1 '@babel/helper-compilation-targets': 7.28.6 '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) @@ -11967,7 +11963,7 @@ snapshots: dependencies: '@babel/core': 7.28.3 '@babel/helper-module-imports': 7.28.6 - '@babel/helper-validator-identifier': 7.28.5 + '@babel/helper-validator-identifier': 7.29.7 '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color @@ -11976,7 +11972,7 @@ snapshots: dependencies: '@babel/core': 7.29.0 '@babel/helper-module-imports': 7.28.6 - '@babel/helper-validator-identifier': 7.28.5 + '@babel/helper-validator-identifier': 7.29.7 '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color @@ -12687,7 +12683,7 @@ snapshots: '@babel/template@7.28.6': dependencies: - '@babel/code-frame': 7.29.0 + '@babel/code-frame': 7.29.7 '@babel/parser': 7.29.2 '@babel/types': 7.29.0 @@ -12705,7 +12701,7 @@ snapshots: '@babel/traverse@7.29.0': dependencies: - '@babel/code-frame': 7.29.0 + '@babel/code-frame': 7.29.7 '@babel/generator': 7.29.1 '@babel/helper-globals': 7.28.0 '@babel/parser': 7.29.2 @@ -12723,7 +12719,7 @@ snapshots: '@babel/types@7.29.0': dependencies: '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 + '@babel/helper-validator-identifier': 7.29.7 '@bcoe/v8-coverage@0.2.3': {} @@ -13075,6 +13071,18 @@ snapshots: '@fastify/busboy@3.2.0': {} + '@firebase-oss/ui-angular@file:packages/angular(@angular/common@20.3.25(@angular/core@20.3.25(@angular/compiler@20.3.25)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.25(@angular/compiler@20.3.25)(rxjs@7.8.2)(zone.js@0.15.1))(@angular/fire@20.0.1(224a9fe38983fbc914b248dcbaf6f32b))': + dependencies: + '@angular/fire': 20.0.1(224a9fe38983fbc914b248dcbaf6f32b) + '@firebase-oss/ui-core': link:packages/core + '@firebase-oss/ui-styles': link:packages/styles + '@tanstack/angular-form': 1.23.8(@angular/common@20.3.25(@angular/core@20.3.25(@angular/compiler@20.3.25)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.25(@angular/compiler@20.3.25)(rxjs@7.8.2)(zone.js@0.15.1)) + nanostores: 1.1.0 + tslib: 2.8.1 + transitivePeerDependencies: + - '@angular/common' + - '@angular/core' + '@firebase/ai@1.4.1(@firebase/app-types@0.9.3)(@firebase/app@0.13.2)': dependencies: '@firebase/app': 0.13.2 @@ -13601,8 +13609,6 @@ snapshots: '@img/sharp-win32-x64@0.34.5': optional: true - '@inquirer/ansi@1.0.1': {} - '@inquirer/ansi@1.0.2': {} '@inquirer/checkbox@4.3.0(@types/node@20.19.24)': @@ -13639,21 +13645,6 @@ snapshots: optionalDependencies: '@types/node': 24.9.2 - '@inquirer/confirm@5.1.19(@types/node@20.19.24)': - dependencies: - '@inquirer/core': 10.3.0(@types/node@20.19.24) - '@inquirer/type': 3.0.9(@types/node@20.19.24) - optionalDependencies: - '@types/node': 20.19.24 - optional: true - - '@inquirer/confirm@5.1.19(@types/node@24.9.2)': - dependencies: - '@inquirer/core': 10.3.0(@types/node@24.9.2) - '@inquirer/type': 3.0.9(@types/node@24.9.2) - optionalDependencies: - '@types/node': 24.9.2 - '@inquirer/confirm@5.1.21(@types/node@20.19.24)': dependencies: '@inquirer/core': 10.3.2(@types/node@20.19.24) @@ -13668,33 +13659,6 @@ snapshots: optionalDependencies: '@types/node': 24.9.2 - '@inquirer/core@10.3.0(@types/node@20.19.24)': - dependencies: - '@inquirer/ansi': 1.0.1 - '@inquirer/figures': 1.0.14 - '@inquirer/type': 3.0.9(@types/node@20.19.24) - cli-width: 4.1.0 - mute-stream: 2.0.0 - signal-exit: 4.1.0 - wrap-ansi: 6.2.0 - yoctocolors-cjs: 2.1.3 - optionalDependencies: - '@types/node': 20.19.24 - optional: true - - '@inquirer/core@10.3.0(@types/node@24.9.2)': - dependencies: - '@inquirer/ansi': 1.0.1 - '@inquirer/figures': 1.0.14 - '@inquirer/type': 3.0.9(@types/node@24.9.2) - cli-width: 4.1.0 - mute-stream: 2.0.0 - signal-exit: 4.1.0 - wrap-ansi: 6.2.0 - yoctocolors-cjs: 2.1.3 - optionalDependencies: - '@types/node': 24.9.2 - '@inquirer/core@10.3.2(@types/node@20.19.24)': dependencies: '@inquirer/ansi': 1.0.2 @@ -13756,19 +13720,17 @@ snapshots: '@inquirer/external-editor@1.0.2(@types/node@20.19.24)': dependencies: chardet: 2.1.0 - iconv-lite: 0.7.0 + iconv-lite: 0.7.2 optionalDependencies: '@types/node': 20.19.24 '@inquirer/external-editor@1.0.2(@types/node@24.9.2)': dependencies: chardet: 2.1.0 - iconv-lite: 0.7.0 + iconv-lite: 0.7.2 optionalDependencies: '@types/node': 24.9.2 - '@inquirer/figures@1.0.14': {} - '@inquirer/figures@1.0.15': {} '@inquirer/input@4.2.5(@types/node@20.19.24)': @@ -13907,21 +13869,6 @@ snapshots: optionalDependencies: '@types/node': 24.9.2 - '@inquirer/type@3.0.9(@types/node@20.19.24)': - optionalDependencies: - '@types/node': 20.19.24 - optional: true - - '@inquirer/type@3.0.9(@types/node@24.9.2)': - optionalDependencies: - '@types/node': 24.9.2 - - '@isaacs/balanced-match@4.0.1': {} - - '@isaacs/brace-expansion@5.0.0': - dependencies: - '@isaacs/balanced-match': 4.0.1 - '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -13933,7 +13880,7 @@ snapshots: '@isaacs/fs-minipass@4.0.1': dependencies: - minipass: 7.1.2 + minipass: 7.1.3 '@istanbuljs/load-nyc-config@1.1.0': dependencies: @@ -13954,6 +13901,43 @@ snapshots: jest-util: 30.2.0 slash: 3.0.0 + '@jest/core@30.2.0(ts-node@10.9.2(@types/node@20.19.24)(typescript@5.9.3))': + dependencies: + '@jest/console': 30.2.0 + '@jest/pattern': 30.0.1 + '@jest/reporters': 30.2.0 + '@jest/test-result': 30.2.0 + '@jest/transform': 30.2.0 + '@jest/types': 30.2.0 + '@types/node': 20.19.24 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 4.3.1 + exit-x: 0.2.2 + graceful-fs: 4.2.11 + jest-changed-files: 30.2.0 + jest-config: 30.2.0(@types/node@20.19.24)(ts-node@10.9.2(@types/node@20.19.24)(typescript@5.9.3)) + jest-haste-map: 30.2.0 + jest-message-util: 30.2.0 + jest-regex-util: 30.0.1 + jest-resolve: 30.2.0 + jest-resolve-dependencies: 30.2.0 + jest-runner: 30.2.0 + jest-runtime: 30.2.0 + jest-snapshot: 30.2.0 + jest-util: 30.2.0 + jest-validate: 30.2.0 + jest-watcher: 30.2.0 + micromatch: 4.0.8 + pretty-format: 30.2.0 + slash: 3.0.0 + transitivePeerDependencies: + - babel-plugin-macros + - esbuild-register + - supports-color + - ts-node + optional: true + '@jest/core@30.2.0(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3))': dependencies: '@jest/console': 30.2.0 @@ -14646,6 +14630,10 @@ snapshots: '@pkgr/core@0.2.9': {} + '@playwright/test@1.61.1': + dependencies: + playwright: 1.61.1 + '@polka/url@1.0.0-next.29': {} '@protobufjs/aspromise@1.1.2': {} @@ -15775,12 +15763,12 @@ snapshots: postcss: 8.5.14 tailwindcss: 4.1.16 - '@tailwindcss/vite@4.1.16(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6))': + '@tailwindcss/vite@4.1.16(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0))': dependencies: '@tailwindcss/node': 4.1.16 '@tailwindcss/oxide': 4.1.16 tailwindcss: 4.1.16 - vite: 7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6) + vite: 7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0) '@tanstack/angular-form@0.42.1(@angular/common@20.3.25(@angular/core@20.3.25(@angular/compiler@20.3.25)(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@20.3.25(@angular/compiler@20.3.25)(rxjs@7.8.2)(zone.js@0.15.1))': dependencies: @@ -15909,7 +15897,7 @@ snapshots: '@tufjs/models@4.1.0': dependencies: '@tufjs/canonical-json': 2.0.0 - minimatch: 10.1.1 + minimatch: 10.2.5 '@tybys/wasm-util@0.10.1': dependencies: @@ -16315,15 +16303,15 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.11.1': optional: true - '@vitejs/plugin-basic-ssl@2.1.0(vite@7.3.2(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6))': + '@vitejs/plugin-basic-ssl@2.1.0(vite@7.3.2(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.9.0))': dependencies: - vite: 7.3.2(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6) + vite: 7.3.2(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.9.0) - '@vitejs/plugin-basic-ssl@2.1.0(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6))': + '@vitejs/plugin-basic-ssl@2.1.0(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.9.0))': dependencies: - vite: 7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6) + vite: 7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.9.0) - '@vitejs/plugin-react@5.1.0(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6))': + '@vitejs/plugin-react@5.1.0(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0))': dependencies: '@babel/core': 7.28.5 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5) @@ -16331,7 +16319,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.43 '@types/babel__core': 7.20.5 react-refresh: 0.18.0 - vite: 7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6) + vite: 7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0) transitivePeerDependencies: - supports-color @@ -16350,7 +16338,7 @@ snapshots: std-env: 3.10.0 test-exclude: 7.0.1 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/node@20.19.24)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@25.0.1)(less@4.4.0)(lightningcss@1.30.2)(msw@2.11.6(@types/node@20.19.24)(typescript@5.9.3))(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6) + vitest: 3.2.4(@types/node@20.19.24)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@25.0.1)(less@4.4.0)(lightningcss@1.30.2)(msw@2.11.6(@types/node@20.19.24)(typescript@5.9.3))(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.9.0) transitivePeerDependencies: - supports-color @@ -16362,23 +16350,23 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.4(msw@2.11.6(@types/node@20.19.24)(typescript@5.9.3))(vite@7.3.2(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6))': + '@vitest/mocker@3.2.4(msw@2.11.6(@types/node@20.19.24)(typescript@5.9.3))(vite@7.3.2(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.9.0))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: msw: 2.11.6(@types/node@20.19.24)(typescript@5.9.3) - vite: 7.3.2(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6) + vite: 7.3.2(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.9.0) - '@vitest/mocker@3.2.4(msw@2.11.6(@types/node@24.9.2)(typescript@5.9.3))(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6))': + '@vitest/mocker@3.2.4(msw@2.11.6(@types/node@24.9.2)(typescript@5.9.3))(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: msw: 2.11.6(@types/node@24.9.2)(typescript@5.9.3) - vite: 7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6) + vite: 7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0) '@vitest/pretty-format@3.2.4': dependencies: @@ -16409,7 +16397,7 @@ snapshots: sirv: 3.0.2 tinyglobby: 0.2.15 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/node@20.19.24)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@25.0.1)(less@4.4.0)(lightningcss@1.30.2)(msw@2.11.6(@types/node@20.19.24)(typescript@5.9.3))(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6) + vitest: 3.2.4(@types/node@20.19.24)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@25.0.1)(less@4.4.0)(lightningcss@1.30.2)(msw@2.11.6(@types/node@20.19.24)(typescript@5.9.3))(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.9.0) '@vitest/utils@3.2.4': dependencies: @@ -16923,7 +16911,7 @@ snapshots: content-type: 1.0.5 debug: 4.4.3 http-errors: 2.0.0 - iconv-lite: 0.7.0 + iconv-lite: 0.7.2 on-finished: 2.4.1 qs: 6.15.1 raw-body: 3.0.1 @@ -17007,7 +16995,7 @@ snapshots: fs-minipass: 3.0.3 glob: 13.0.6 lru-cache: 11.2.2 - minipass: 7.1.2 + minipass: 7.1.3 minipass-collect: 2.0.1 minipass-flush: 1.0.5 minipass-pipeline: 1.2.4 @@ -18109,7 +18097,7 @@ snapshots: once: 1.4.0 parseurl: 1.3.3 proxy-addr: 2.0.7 - qs: 6.14.0 + qs: 6.15.1 range-parser: 1.2.1 router: 2.2.0 send: 1.2.0 @@ -18339,10 +18327,13 @@ snapshots: fs-minipass@3.0.3: dependencies: - minipass: 7.1.2 + minipass: 7.1.3 fs.realpath@1.0.0: {} + fsevents@2.3.2: + optional: true + fsevents@2.3.3: optional: true @@ -18445,7 +18436,7 @@ snapshots: foreground-child: 3.3.1 jackspeak: 3.4.3 minimatch: 9.0.5 - minipass: 7.1.2 + minipass: 7.1.3 package-json-from-dist: 1.0.1 path-scurry: 1.11.1 @@ -18453,10 +18444,10 @@ snapshots: dependencies: foreground-child: 3.3.1 jackspeak: 4.1.1 - minimatch: 10.1.1 - minipass: 7.1.2 + minimatch: 10.2.5 + minipass: 7.1.3 package-json-from-dist: 1.0.1 - path-scurry: 2.0.0 + path-scurry: 2.0.2 glob@13.0.6: dependencies: @@ -18706,7 +18697,6 @@ snapshots: iconv-lite@0.7.2: dependencies: safer-buffer: 2.1.2 - optional: true icss-utils@5.1.0(postcss@8.5.14): dependencies: @@ -18718,7 +18708,7 @@ snapshots: ignore-walk@8.0.0: dependencies: - minimatch: 10.1.1 + minimatch: 10.2.5 ignore@5.3.2: {} @@ -18776,8 +18766,6 @@ snapshots: internmap@2.0.3: {} - ip-address@10.0.1: {} - ip-address@10.2.0: {} ipaddr.js@1.9.1: {} @@ -19042,15 +19030,15 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@30.2.0(@types/node@20.19.24): + jest-cli@30.2.0(@types/node@20.19.24)(ts-node@10.9.2(@types/node@20.19.24)(typescript@5.9.3)): dependencies: - '@jest/core': 30.2.0(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)) + '@jest/core': 30.2.0(ts-node@10.9.2(@types/node@20.19.24)(typescript@5.9.3)) '@jest/test-result': 30.2.0 '@jest/types': 30.2.0 chalk: 4.1.2 exit-x: 0.2.2 import-local: 3.2.0 - jest-config: 30.2.0(@types/node@20.19.24)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)) + jest-config: 30.2.0(@types/node@20.19.24)(ts-node@10.9.2(@types/node@20.19.24)(typescript@5.9.3)) jest-util: 30.2.0 jest-validate: 30.2.0 yargs: 17.7.2 @@ -19081,6 +19069,40 @@ snapshots: - supports-color - ts-node + jest-config@30.2.0(@types/node@20.19.24)(ts-node@10.9.2(@types/node@20.19.24)(typescript@5.9.3)): + dependencies: + '@babel/core': 7.29.0 + '@jest/get-type': 30.1.0 + '@jest/pattern': 30.0.1 + '@jest/test-sequencer': 30.2.0 + '@jest/types': 30.2.0 + babel-jest: 30.2.0(@babel/core@7.29.0) + chalk: 4.1.2 + ci-info: 4.3.1 + deepmerge: 4.3.1 + glob: 10.4.5 + graceful-fs: 4.2.11 + jest-circus: 30.2.0 + jest-docblock: 30.2.0 + jest-environment-node: 30.2.0 + jest-regex-util: 30.0.1 + jest-resolve: 30.2.0 + jest-runner: 30.2.0 + jest-util: 30.2.0 + jest-validate: 30.2.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 30.2.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 20.19.24 + ts-node: 10.9.2(@types/node@20.19.24)(typescript@5.9.3) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + optional: true + jest-config@30.2.0(@types/node@20.19.24)(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)): dependencies: '@babel/core': 7.29.0 @@ -19217,7 +19239,7 @@ snapshots: jest-message-util@30.2.0: dependencies: - '@babel/code-frame': 7.27.1 + '@babel/code-frame': 7.29.7 '@jest/types': 30.2.0 '@types/stack-utils': 2.0.3 chalk: 4.1.2 @@ -19338,10 +19360,10 @@ snapshots: jest-snapshot@30.2.0: dependencies: '@babel/core': 7.29.0 - '@babel/generator': 7.28.5 + '@babel/generator': 7.29.1 '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.29.0) '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.29.0) - '@babel/types': 7.28.5 + '@babel/types': 7.29.0 '@jest/expect-utils': 30.2.0 '@jest/get-type': 30.1.0 '@jest/snapshot-utils': 30.2.0 @@ -19404,12 +19426,12 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@30.2.0(@types/node@20.19.24): + jest@30.2.0(@types/node@20.19.24)(ts-node@10.9.2(@types/node@20.19.24)(typescript@5.9.3)): dependencies: - '@jest/core': 30.2.0(ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3)) + '@jest/core': 30.2.0(ts-node@10.9.2(@types/node@20.19.24)(typescript@5.9.3)) '@jest/types': 30.2.0 import-local: 3.2.0 - jest-cli: 30.2.0(@types/node@20.19.24) + jest-cli: 30.2.0(@types/node@20.19.24)(ts-node@10.9.2(@types/node@20.19.24)(typescript@5.9.3)) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -19867,7 +19889,7 @@ snapshots: '@npmcli/redact': 4.0.0 cacache: 20.0.4 http-cache-semantics: 4.2.0 - minipass: 7.1.2 + minipass: 7.1.3 minipass-fetch: 5.0.2 minipass-flush: 1.0.5 minipass-pipeline: 1.2.4 @@ -19946,10 +19968,6 @@ snapshots: minimalistic-assert@1.0.1: {} - minimatch@10.1.1: - dependencies: - '@isaacs/brace-expansion': 5.0.0 - minimatch@10.2.5: dependencies: brace-expansion: 5.0.6 @@ -19970,11 +19988,11 @@ snapshots: minipass-collect@2.0.1: dependencies: - minipass: 7.1.2 + minipass: 7.1.3 minipass-fetch@5.0.2: dependencies: - minipass: 7.1.2 + minipass: 7.1.3 minipass-sized: 2.0.0 minizlib: 3.1.0 optionalDependencies: @@ -19990,7 +20008,7 @@ snapshots: minipass-sized@2.0.0: dependencies: - minipass: 7.1.2 + minipass: 7.1.3 minipass@3.3.6: dependencies: @@ -20002,7 +20020,7 @@ snapshots: minizlib@3.1.0: dependencies: - minipass: 7.1.2 + minipass: 7.1.3 mkdirp@2.1.6: {} @@ -20038,7 +20056,7 @@ snapshots: msw@2.11.6(@types/node@20.19.24)(typescript@5.9.3): dependencies: - '@inquirer/confirm': 5.1.19(@types/node@20.19.24) + '@inquirer/confirm': 5.1.21(@types/node@20.19.24) '@mswjs/interceptors': 0.40.0 '@open-draft/deferred-promise': 2.2.0 '@types/statuses': 2.0.6 @@ -20064,7 +20082,7 @@ snapshots: msw@2.11.6(@types/node@24.9.2)(typescript@5.9.3): dependencies: - '@inquirer/confirm': 5.1.19(@types/node@24.9.2) + '@inquirer/confirm': 5.1.21(@types/node@24.9.2) '@mswjs/interceptors': 0.40.0 '@open-draft/deferred-promise': 2.2.0 '@types/statuses': 2.0.6 @@ -20129,7 +20147,7 @@ snapshots: react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - next@15.5.18(@opentelemetry/api@1.9.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.97.3): + next@15.5.18(@opentelemetry/api@1.9.0)(@playwright/test@1.61.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(sass@1.97.3): dependencies: '@next/env': 15.5.18 '@swc/helpers': 0.5.15 @@ -20148,6 +20166,7 @@ snapshots: '@next/swc-win32-arm64-msvc': 15.5.18 '@next/swc-win32-x64-msvc': 15.5.18 '@opentelemetry/api': 1.9.0 + '@playwright/test': 1.61.1 sass: 1.97.3 sharp: 0.34.5 transitivePeerDependencies: @@ -20277,7 +20296,7 @@ snapshots: '@npmcli/redact': 4.0.0 jsonparse: 1.3.1 make-fetch-happen: 15.0.5 - minipass: 7.1.2 + minipass: 7.1.3 minipass-fetch: 5.0.2 minizlib: 3.1.0 npm-package-arg: 13.0.0 @@ -20511,12 +20530,7 @@ snapshots: path-scurry@1.11.1: dependencies: lru-cache: 10.4.3 - minipass: 7.1.2 - - path-scurry@2.0.0: - dependencies: - lru-cache: 11.2.2 - minipass: 7.1.2 + minipass: 7.1.3 path-scurry@2.0.2: dependencies: @@ -20568,15 +20582,24 @@ snapshots: mlly: 1.8.0 pathe: 2.0.3 + playwright-core@1.61.1: {} + + playwright@1.61.1: + dependencies: + playwright-core: 1.61.1 + optionalDependencies: + fsevents: 2.3.2 + possible-typed-array-names@1.1.0: {} - postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.14)(tsx@4.20.6): + postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.14)(tsx@4.20.6)(yaml@2.9.0): dependencies: lilconfig: 3.1.3 optionalDependencies: jiti: 2.6.1 postcss: 8.5.14 tsx: 4.20.6 + yaml: 2.9.0 postcss-loader@8.1.1(postcss@8.5.12)(typescript@5.9.3)(webpack@5.105.0(esbuild@0.28.0)): dependencies: @@ -21498,7 +21521,7 @@ snapshots: socks@2.8.7: dependencies: - ip-address: 10.0.1 + ip-address: 10.2.0 smart-buffer: 4.2.0 sonner@2.0.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3): @@ -21566,7 +21589,7 @@ snapshots: ssri@13.0.1: dependencies: - minipass: 7.1.2 + minipass: 7.1.3 stack-utils@2.0.6: dependencies: @@ -21767,7 +21790,7 @@ snapshots: dependencies: '@isaacs/fs-minipass': 4.0.1 chownr: 3.0.0 - minipass: 7.1.2 + minipass: 7.1.3 minizlib: 3.1.0 yallist: 5.0.0 @@ -21775,7 +21798,7 @@ snapshots: dependencies: '@isaacs/fs-minipass': 4.0.1 chownr: 3.0.0 - minipass: 7.1.2 + minipass: 7.1.3 minizlib: 3.1.0 yallist: 5.0.0 @@ -21791,7 +21814,7 @@ snapshots: - supports-color optional: true - terser-webpack-plugin@5.4.0(esbuild@0.28.0)(webpack@5.105.0): + terser-webpack-plugin@5.4.0(esbuild@0.28.0)(webpack@5.105.0(esbuild@0.28.0)): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 @@ -21946,6 +21969,25 @@ snapshots: '@ts-morph/common': 0.19.0 code-block-writer: 12.0.0 + ts-node@10.9.2(@types/node@20.19.24)(typescript@5.9.3): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 20.19.24 + acorn: 8.15.0 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.9.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + optional: true + ts-node@10.9.2(@types/node@24.9.2)(typescript@5.9.3): dependencies: '@cspotcode/source-map-support': 0.8.1 @@ -21972,7 +22014,7 @@ snapshots: tslib@2.8.1: {} - tsup@8.5.0(jiti@2.6.1)(postcss@8.5.14)(tsx@4.20.6)(typescript@5.9.3): + tsup@8.5.0(jiti@2.6.1)(postcss@8.5.14)(tsx@4.20.6)(typescript@5.9.3)(yaml@2.9.0): dependencies: bundle-require: 5.1.0(esbuild@0.25.11) cac: 6.7.14 @@ -21983,7 +22025,7 @@ snapshots: fix-dts-default-cjs-exports: 1.0.1 joycon: 3.1.1 picocolors: 1.1.1 - postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.14)(tsx@4.20.6) + postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.14)(tsx@4.20.6)(yaml@2.9.0) resolve-from: 5.0.0 rollup: 4.52.5 source-map: 0.8.0-beta.0 @@ -22228,13 +22270,13 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - vite-node@3.2.4(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6): + vite-node@3.2.4(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.9.0): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.3.2(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6) + vite: 7.3.2(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.9.0) transitivePeerDependencies: - '@types/node' - jiti @@ -22249,13 +22291,13 @@ snapshots: - tsx - yaml - vite-node@3.2.4(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6): + vite-node@3.2.4(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6) + vite: 7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0) transitivePeerDependencies: - '@types/node' - jiti @@ -22280,18 +22322,18 @@ snapshots: transitivePeerDependencies: - supports-color - vite-plugin-svgr@4.5.0(rollup@4.62.0)(typescript@5.9.3)(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)): + vite-plugin-svgr@4.5.0(rollup@4.62.0)(typescript@5.9.3)(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0)): dependencies: '@rollup/pluginutils': 5.3.0(rollup@4.62.0) '@svgr/core': 8.1.0(typescript@5.9.3) '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3)) - vite: 7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6) + vite: 7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0) transitivePeerDependencies: - rollup - supports-color - typescript - vite@7.3.2(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6): + vite@7.3.2(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.9.0): dependencies: esbuild: 0.27.7 fdir: 6.5.0(picomatch@4.0.4) @@ -22308,8 +22350,9 @@ snapshots: sass: 1.90.0 terser: 5.43.1 tsx: 4.20.6 + yaml: 2.9.0 - vite@7.3.2(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6): + vite@7.3.2(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0): dependencies: esbuild: 0.27.7 fdir: 6.5.0(picomatch@4.0.4) @@ -22326,8 +22369,9 @@ snapshots: sass: 1.97.3 terser: 5.46.0 tsx: 4.20.6 + yaml: 2.9.0 - vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6): + vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.9.0): dependencies: esbuild: 0.27.7 fdir: 6.5.0(picomatch@4.0.4) @@ -22344,8 +22388,9 @@ snapshots: sass: 1.90.0 terser: 5.43.1 tsx: 4.20.6 + yaml: 2.9.0 - vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6): + vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0): dependencies: esbuild: 0.27.7 fdir: 6.5.0(picomatch@4.0.4) @@ -22362,12 +22407,13 @@ snapshots: sass: 1.97.3 terser: 5.46.0 tsx: 4.20.6 + yaml: 2.9.0 - vitest@3.2.4(@types/node@20.19.24)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@25.0.1)(less@4.4.0)(lightningcss@1.30.2)(msw@2.11.6(@types/node@20.19.24)(typescript@5.9.3))(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6): + vitest@3.2.4(@types/node@20.19.24)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@25.0.1)(less@4.4.0)(lightningcss@1.30.2)(msw@2.11.6(@types/node@20.19.24)(typescript@5.9.3))(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.9.0): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(msw@2.11.6(@types/node@20.19.24)(typescript@5.9.3))(vite@7.3.2(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)) + '@vitest/mocker': 3.2.4(msw@2.11.6(@types/node@20.19.24)(typescript@5.9.3))(vite@7.3.2(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.9.0)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -22385,8 +22431,8 @@ snapshots: tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.3.2(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6) - vite-node: 3.2.4(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6) + vite: 7.3.2(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.9.0) + vite-node: 3.2.4(@types/node@20.19.24)(jiti@2.6.1)(less@4.4.0)(lightningcss@1.30.2)(sass@1.90.0)(terser@5.43.1)(tsx@4.20.6)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 20.19.24 @@ -22406,11 +22452,11 @@ snapshots: - tsx - yaml - vitest@3.2.4(@types/node@24.9.2)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@25.0.1)(less@4.4.2)(lightningcss@1.30.2)(msw@2.11.6(@types/node@24.9.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6): + vitest@3.2.4(@types/node@24.9.2)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@25.0.1)(less@4.4.2)(lightningcss@1.30.2)(msw@2.11.6(@types/node@24.9.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(msw@2.11.6(@types/node@24.9.2)(typescript@5.9.3))(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)) + '@vitest/mocker': 3.2.4(msw@2.11.6(@types/node@24.9.2)(typescript@5.9.3))(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -22428,8 +22474,8 @@ snapshots: tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6) - vite-node: 3.2.4(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6) + vite: 7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0) + vite-node: 3.2.4(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 24.9.2 @@ -22450,11 +22496,11 @@ snapshots: - yaml optional: true - vitest@3.2.4(@types/node@24.9.2)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(less@4.4.2)(lightningcss@1.30.2)(msw@2.11.6(@types/node@24.9.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6): + vitest@3.2.4(@types/node@24.9.2)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@26.1.0)(less@4.4.2)(lightningcss@1.30.2)(msw@2.11.6(@types/node@24.9.2)(typescript@5.9.3))(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(msw@2.11.6(@types/node@24.9.2)(typescript@5.9.3))(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)) + '@vitest/mocker': 3.2.4(msw@2.11.6(@types/node@24.9.2)(typescript@5.9.3))(vite@7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -22472,8 +22518,8 @@ snapshots: tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6) - vite-node: 3.2.4(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6) + vite: 7.3.2(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0) + vite-node: 3.2.4(@types/node@24.9.2)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.97.3)(terser@5.46.0)(tsx@4.20.6)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 24.9.2 @@ -22543,7 +22589,7 @@ snapshots: optionalDependencies: webpack: 5.105.0(esbuild@0.28.0) - webpack-dev-middleware@7.4.5(webpack@5.105.0): + webpack-dev-middleware@7.4.5(webpack@5.105.0(esbuild@0.28.0)): dependencies: colorette: 2.0.20 memfs: 4.50.0 @@ -22554,7 +22600,7 @@ snapshots: optionalDependencies: webpack: 5.105.0(esbuild@0.28.0) - webpack-dev-server@5.2.2(webpack@5.105.0): + webpack-dev-server@5.2.2(webpack@5.105.0(esbuild@0.28.0)): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 @@ -22582,7 +22628,7 @@ snapshots: serve-index: 1.9.1 sockjs: 0.3.24 spdy: 4.0.2 - webpack-dev-middleware: 7.4.5(webpack@5.105.0) + webpack-dev-middleware: 7.4.5(webpack@5.105.0(esbuild@0.28.0)) ws: 8.18.3 optionalDependencies: webpack: 5.105.0(esbuild@0.28.0) @@ -22629,7 +22675,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.0 - terser-webpack-plugin: 5.4.0(esbuild@0.28.0)(webpack@5.105.0) + terser-webpack-plugin: 5.4.0(esbuild@0.28.0)(webpack@5.105.0(esbuild@0.28.0)) watchpack: 2.5.1 webpack-sources: 3.3.3 transitivePeerDependencies: @@ -22780,6 +22826,9 @@ snapshots: yallist@5.0.0: {} + yaml@2.9.0: + optional: true + yargs-parser@21.1.1: {} yargs-parser@22.0.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index f5486d2b1..7aaf93135 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,6 +1,7 @@ packages: - packages/* - examples/* + - e2e catalog: "@angular-devkit/architect": ^0.2003.21 @@ -29,6 +30,7 @@ catalog: "@vitest/coverage-v8": ^3.2.4 "@vitest/ui": ^3.2.4 "@nanostores/deepmap": ^0.0.1 + "@playwright/test": 1.61.1 "@vitejs/plugin-react": ^5.0.2 eslint: ^9.35.0 firebase: ^11.10.0 @@ -82,3 +84,11 @@ allowBuilds: unrs-resolver: true gitChecks: false + +# Block @angular/fire optional peer firebase-tools from entering the lockfile (e2e uses npx; CI uses global install). +peerDependencyRules: + ignoreMissing: + - firebase-tools + +overrides: + firebase-tools: "-" diff --git a/scripts/e2e-run.mjs b/scripts/e2e-run.mjs new file mode 100644 index 000000000..3c001da6e --- /dev/null +++ b/scripts/e2e-run.mjs @@ -0,0 +1,96 @@ +/** + * Copyright 2025 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { readFileSync, rmSync } from "node:fs"; +import { spawnSync } from "node:child_process"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { resetCoverageArtifacts } from "../e2e/fixtures/coverage-artifacts.mjs"; + +const REPO_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); +const EMULATOR_STATE_FILE = path.join(REPO_ROOT, "e2e", ".state", "emulator.json"); + +/** UI examples exercised serially by `pnpm test:e2e` (browser smoke S1–S3). */ +const E2E_UI_EXAMPLES = ["react", "shadcn", "nextjs", "nextjs-ssr", "angular-example"]; + +/** Non-browser examples (HTTP boot smoke), run after the UI examples. AD-6. */ +const E2E_HTTP_EXAMPLES = ["custom-auth-server"]; + +const E2E_EXAMPLES = [...E2E_UI_EXAMPLES, ...E2E_HTTP_EXAMPLES]; + +function ensurePackagesBuilt() { + console.log("\n[e2e-run] build:packages (once)…\n"); + const build = spawnSync("pnpm", ["build:packages"], { cwd: REPO_ROOT, stdio: "inherit" }); + if (build.status !== 0) { + process.exit(build.status ?? 1); + } +} + +function runExample(example) { + console.log(`\n[e2e-run] Starting ${example}…\n`); + + const result = spawnSync("pnpm", ["--filter=e2e", "exec", "playwright", "test", `--project=${example}`], { + cwd: REPO_ROOT, + stdio: "inherit", + env: { + ...process.env, + E2E_PROJECT: example, + E2E_SKIP_BUILD_PACKAGES: "1", + E2E_KEEP_EMULATOR: "1", + }, + }); + + if (result.status !== 0) { + process.exitCode = result.status ?? 1; + } +} + +function stopOrchestratedEmulator() { + try { + const state = JSON.parse(readFileSync(EMULATOR_STATE_FILE, "utf8")); + if (state?.startedBySetup && state.pid !== undefined) { + try { + process.kill(-state.pid, "SIGTERM"); + } catch { + // Emulator may already have stopped. + } + } + } catch { + // No state file — nothing to stop. + } + + try { + rmSync(path.dirname(EMULATOR_STATE_FILE), { recursive: true, force: true }); + } catch { + // Best-effort cleanup. + } +} + +ensurePackagesBuilt(); +resetCoverageArtifacts(); + +for (const example of E2E_EXAMPLES) { + runExample(example); + if (process.exitCode) { + break; + } +} + +stopOrchestratedEmulator(); + +if (process.exitCode) { + process.exit(process.exitCode); +}