diff --git a/.github/workflows/showcase-smoke.yml b/.github/workflows/showcase-smoke.yml new file mode 100644 index 0000000000..b9752841ee --- /dev/null +++ b/.github/workflows/showcase-smoke.yml @@ -0,0 +1,42 @@ +# Showcase Smoke — NON-BLOCKING. Drives the console (served by the backend at +# /_console) across every showcase nav surface, asserting render health +# (no crash / no leaked dev placeholder / charts draw). Manual + nightly only; +# it never gates PRs. Promote to a PR gate once it has proven stable here. +name: Showcase Smoke + +on: + workflow_dispatch: + schedule: + - cron: '0 7 * * *' # 07:00 UTC nightly + +permissions: + contents: read + +jobs: + smoke: + name: Showcase nav-surface smoke + runs-on: ubuntu-latest + timeout-minutes: 25 + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + - run: pnpm install --frozen-lockfile + # The smoke's webServer runs the CLI (`os serve --dev`); build it first. + - run: pnpm turbo run build --filter=@objectstack/cli + - name: Install Playwright Chromium + working-directory: examples/app-showcase + run: pnpm exec playwright install --with-deps chromium + - name: Run showcase smoke + working-directory: examples/app-showcase + run: pnpm test:smoke + - name: Upload report on failure + if: failure() + uses: actions/upload-artifact@v4 + with: + name: showcase-smoke-report + path: examples/app-showcase/playwright-report/ + retention-days: 7 diff --git a/examples/app-showcase/.gitignore b/examples/app-showcase/.gitignore new file mode 100644 index 0000000000..651e893854 --- /dev/null +++ b/examples/app-showcase/.gitignore @@ -0,0 +1,4 @@ + +# Playwright smoke artifacts +test-results/ +playwright-report/ diff --git a/examples/app-showcase/e2e/.gitignore b/examples/app-showcase/e2e/.gitignore new file mode 100644 index 0000000000..0dcbb783f9 --- /dev/null +++ b/examples/app-showcase/e2e/.gitignore @@ -0,0 +1 @@ +.auth/ diff --git a/examples/app-showcase/e2e/global-setup.ts b/examples/app-showcase/e2e/global-setup.ts new file mode 100644 index 0000000000..6209c9ddd1 --- /dev/null +++ b/examples/app-showcase/e2e/global-setup.ts @@ -0,0 +1,33 @@ +import { request } from '@playwright/test'; +import { mkdirSync, writeFileSync } from 'node:fs'; +import { dirname } from 'node:path'; + +/** + * Auth for the showcase smoke: sign in against the backend (better-auth) and + * persist a Playwright storageState. The console (served at :3000/_console) + * reads a Bearer token from localStorage `auth-session-token` on the :3000 + * origin, so we inject that there; the session cookie covers the API. + */ +const API = process.env.SMOKE_API_URL || 'http://localhost:3000'; +const EMAIL = process.env.SMOKE_EMAIL || 'admin@objectos.ai'; +const PASSWORD = process.env.SMOKE_PASSWORD || 'admin123'; +const STATE_PATH = 'e2e/.auth/state.json'; + +export default async function globalSetup() { + const ctx = await request.newContext(); + const res = await ctx.post(`${API}/api/v1/auth/sign-in/email`, { + data: { email: EMAIL, password: PASSWORD }, + headers: { 'Content-Type': 'application/json' }, + }); + if (!res.ok()) throw new Error(`sign-in failed (${res.status()}): ${await res.text()}`); + const token = res.headers()['set-auth-token']; + if (!token) throw new Error('no set-auth-token header from sign-in'); + const apiState = await ctx.storageState(); + await ctx.dispose(); + const state = { + cookies: apiState.cookies, + origins: [{ origin: API, localStorage: [{ name: 'auth-session-token', value: token }] }], + }; + mkdirSync(dirname(STATE_PATH), { recursive: true }); + writeFileSync(STATE_PATH, JSON.stringify(state, null, 2)); +} diff --git a/examples/app-showcase/e2e/showcase-smoke.spec.ts b/examples/app-showcase/e2e/showcase-smoke.spec.ts new file mode 100644 index 0000000000..837853a7d5 --- /dev/null +++ b/examples/app-showcase/e2e/showcase-smoke.spec.ts @@ -0,0 +1,70 @@ +import { test, expect } from '@playwright/test'; + +/** + * Showcase workspace smoke — sweeps every nav surface and asserts the health + * invariants manual QA otherwise eyeballs (render crash / leaked dev placeholder + * / collapsed chart). Runs against the console the backend serves at /_console + * (baseURL set in playwright.config.ts). Non-blocking nightly + manual. + */ +const APP = process.env.SHOWCASE_APP || 'com.example.showcase'; +const base = (seg: string) => `/_console/apps/${APP}/${seg}`; + +const SURFACES: { name: string; path: string; chart?: boolean }[] = [ + { name: 'My Work', path: base('page/showcase_my_work') }, + { name: 'Approvals', path: base('page/showcase_review_queue') }, + { name: 'New Project Wizard', path: base('page/showcase_new_project_wizard') }, + { name: 'Settings', path: base('showcase_preference') }, + { name: 'Projects', path: base('showcase_project') }, + { name: 'Tasks', path: base('showcase_task') }, + { name: 'Accounts', path: base('showcase_account') }, + { name: 'Invoices', path: base('showcase_invoice') }, + { name: 'Products', path: base('showcase_product') }, + { name: 'Teams', path: base('showcase_team') }, + { name: 'Categories', path: base('showcase_category') }, + { name: 'Field Zoo', path: base('showcase_field_zoo') }, + { name: 'Delivery Operations', path: base('dashboard/showcase_ops_dashboard'), chart: true }, + { name: 'Chart Gallery', path: base('dashboard/showcase_chart_gallery'), chart: true }, + { name: 'Hours by Status', path: base('report/showcase_hours_by_status') }, + { name: 'Status × Priority', path: base('report/showcase_status_priority_matrix') }, + { name: 'Task Overview', path: base('report/showcase_task_overview') }, + { name: 'Component Gallery', path: base('page/showcase_component_gallery') }, + { name: 'Project Workspace', path: base('page/showcase_project_workspace') }, + { name: 'Task Workbench', path: base('page/showcase_task_workbench') }, + { name: 'Task Triage', path: base('page/showcase_task_triage') }, + { name: 'Active Projects', path: base('page/showcase_active_projects') }, + { name: 'All Views', path: base('page/showcase_task_all_views') }, + { name: 'Task Board', path: base('page/showcase_task_board') }, + { name: 'Task Calendar', path: base('page/showcase_task_calendar') }, + { name: 'Task Gallery', path: base('page/showcase_task_gallery') }, + { name: 'Team Schedule', path: base('page/showcase_task_schedule') }, + { name: 'Activity Timeline', path: base('page/showcase_task_timeline') }, + { name: 'Work Map', path: base('page/showcase_task_map') }, +]; + +for (const surface of SURFACES) { + test(`surface renders cleanly: ${surface.name}`, async ({ page }) => { + const pageErrors: string[] = []; + page.on('pageerror', (e) => pageErrors.push(e.message)); + + await page.goto(surface.path, { waitUntil: 'domcontentloaded' }); + await page.locator('main').first().waitFor({ state: 'visible', timeout: 25_000 }); + await page.waitForTimeout(1500); + + expect(pageErrors, `uncaught errors on ${surface.name}`).toEqual([]); + await expect( + page.getByText(/no actions configured/i), + `leaked placeholder on ${surface.name}`, + ).toHaveCount(0); + const mainText = (await page.locator('main').first().innerText().catch(() => '')) || ''; + expect(mainText.trim().length, `${surface.name} rendered no main content`).toBeGreaterThan(0); + + if (surface.chart) { + const svg = page.locator('.recharts-wrapper svg, .recharts-surface').first(); + await svg.waitFor({ state: 'visible', timeout: 25_000 }); + const box = await svg.boundingBox(); + expect(box, `${surface.name}: no chart SVG`).not.toBeNull(); + expect(box!.width, `${surface.name}: chart width`).toBeGreaterThan(0); + expect(box!.height, `${surface.name}: chart height`).toBeGreaterThan(0); + } + }); +} diff --git a/examples/app-showcase/package.json b/examples/app-showcase/package.json index 6bf0595a03..f3a0fe7ffa 100644 --- a/examples/app-showcase/package.json +++ b/examples/app-showcase/package.json @@ -17,7 +17,8 @@ "build": "objectstack build", "typecheck": "tsc --noEmit", "test": "vitest run", - "verify": "pnpm typecheck && pnpm test" + "verify": "pnpm typecheck && pnpm test", + "test:smoke": "playwright test --config=playwright.config.ts" }, "dependencies": { "@objectstack/cloud-connection": "workspace:*", @@ -29,6 +30,7 @@ "devDependencies": { "@objectstack/cli": "workspace:*", "@objectstack/objectql": "workspace:*", + "@playwright/test": "^1.61.0", "typescript": "^6.0.3", "vitest": "^4.1.9" } diff --git a/examples/app-showcase/playwright.config.ts b/examples/app-showcase/playwright.config.ts new file mode 100644 index 0000000000..d15ebcfec8 --- /dev/null +++ b/examples/app-showcase/playwright.config.ts @@ -0,0 +1,35 @@ +import { defineConfig, devices } from '@playwright/test'; + +/** + * Showcase smoke — drives the console (served by the backend at /_console) + * across every nav surface. `webServer` boots the real backend so CI only needs + * to run `playwright test`; locally it reuses an already-running :3000. + * + * Run: pnpm --filter @objectstack/example-showcase exec playwright test + * (or via the ci/showcase-smoke workflow). Non-blocking by design. + */ +const PORT = 3000; +export default defineConfig({ + testDir: './e2e', + fullyParallel: false, + workers: 1, + retries: process.env.CI ? 1 : 0, + reporter: process.env.CI ? [['github'], ['list']] : [['list']], + globalSetup: './e2e/global-setup.ts', + timeout: 45_000, + use: { + baseURL: `http://localhost:${PORT}`, + storageState: 'e2e/.auth/state.json', + trace: 'on-first-retry', + screenshot: 'only-on-failure', + }, + projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }], + webServer: { + command: 'node node_modules/@objectstack/cli/bin/run.js serve --dev', + url: `http://localhost:${PORT}/api/v1/runtime/config`, + timeout: 180_000, + reuseExistingServer: !process.env.CI, + stdout: 'pipe', + stderr: 'pipe', + }, +}); diff --git a/examples/app-showcase/vitest.config.ts b/examples/app-showcase/vitest.config.ts new file mode 100644 index 0000000000..b38a6ee111 --- /dev/null +++ b/examples/app-showcase/vitest.config.ts @@ -0,0 +1,12 @@ +import { defineConfig, configDefaults } from 'vitest/config'; + +/** + * Unit tests only. The Playwright browser smoke under `e2e/` also uses + * `*.spec.ts`, so exclude it here — otherwise vitest tries to run it and chokes + * on the `@playwright/test` import. Run the smoke with `pnpm test:smoke`. + */ +export default defineConfig({ + test: { + exclude: [...configDefaults.exclude, '**/e2e/**'], + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 40a496ed9f..ea81997553 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,19 +44,19 @@ importers: dependencies: fumadocs-core: specifier: 16.10.2 - version: 16.10.2(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.15(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.18.0(react@19.2.7))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react-router@7.15.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7)(zod@4.4.3) + version: 16.10.2(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.15(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.18.0(react@19.2.7))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.61.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react-router@7.15.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7)(zod@4.4.3) fumadocs-mdx: specifier: 15.0.12 - version: 15.0.12(@types/mdast@4.0.4)(@types/mdx@2.0.14)(@types/react@19.2.17)(fumadocs-core@16.10.2(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.15(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.18.0(react@19.2.7))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react-router@7.15.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7)(zod@4.4.3))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7)(rolldown@1.0.3)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)) + version: 15.0.12(@types/mdast@4.0.4)(@types/mdx@2.0.14)(@types/react@19.2.17)(fumadocs-core@16.10.2(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.15(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.18.0(react@19.2.7))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.61.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react-router@7.15.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7)(zod@4.4.3))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.61.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7)(rolldown@1.0.3)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)) fumadocs-ui: specifier: 16.10.2 - version: 16.10.2(@tailwindcss/oxide@4.3.1)(@types/mdx@2.0.14)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(fumadocs-core@16.10.2(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.15(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.18.0(react@19.2.7))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react-router@7.15.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7)(zod@4.4.3))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(tailwindcss@4.3.1) + version: 16.10.2(@tailwindcss/oxide@4.3.1)(@types/mdx@2.0.14)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(fumadocs-core@16.10.2(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.15(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.18.0(react@19.2.7))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.61.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react-router@7.15.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7)(zod@4.4.3))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.61.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(tailwindcss@4.3.1) lucide-react: specifier: ^1.18.0 version: 1.18.0(react@19.2.7) next: specifier: 16.2.9 - version: 16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.61.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: specifier: ^19.2.7 version: 19.2.7 @@ -147,6 +147,9 @@ importers: '@objectstack/objectql': specifier: workspace:* version: link:../../packages/objectql + '@playwright/test': + specifier: ^1.61.0 + version: 1.61.0 typescript: specifier: ^6.0.3 version: 6.0.3 @@ -287,7 +290,7 @@ importers: devDependencies: next: specifier: ^16.2.9 - version: 16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + version: 16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.61.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: specifier: ^19.2.7 version: 19.2.7 @@ -1307,7 +1310,7 @@ importers: version: 1.6.18(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.3.0)(@cloudflare/workers-types@4.20260520.1)(@opentelemetry/api@1.9.1)(better-call@1.3.6(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0) '@better-auth/oauth-provider': specifier: ^1.6.18 - version: 1.6.18(ace7a0f283e33e98a94053209cb42e56) + version: 1.6.18(eae6780b8343fa2684a4fc6cbb52e92d) '@noble/hashes': specifier: ^2.2.0 version: 2.2.0 @@ -1325,7 +1328,7 @@ importers: version: link:../../types better-auth: specifier: ^1.6.18 - version: 1.6.18(@cloudflare/workers-types@4.20260520.1)(@opentelemetry/api@1.9.1)(@sveltejs/kit@2.65.1(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.3(@typescript-eslint/types@8.61.1))(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(svelte@5.55.3(@typescript-eslint/types@8.61.1))(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(better-sqlite3@12.10.1)(mongodb@7.3.0(socks@2.8.9))(mysql2@3.22.4(@types/node@25.9.3))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(svelte@5.55.3(@typescript-eslint/types@8.61.1))(vitest@4.1.9) + version: 1.6.18(@cloudflare/workers-types@4.20260520.1)(@opentelemetry/api@1.9.1)(@sveltejs/kit@2.65.1(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.3(@typescript-eslint/types@8.61.1))(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(svelte@5.55.3(@typescript-eslint/types@8.61.1))(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(better-sqlite3@12.10.1)(mongodb@7.3.0(socks@2.8.9))(mysql2@3.22.4(@types/node@25.9.3))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.61.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(svelte@5.55.3(@typescript-eslint/types@8.61.1))(vitest@4.1.9) devDependencies: '@types/node': specifier: ^25.9.3 @@ -3427,8 +3430,8 @@ packages: '@pinojs/redact@0.4.0': resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} - '@playwright/test@1.60.0': - resolution: {integrity: sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag==} + '@playwright/test@1.61.0': + resolution: {integrity: sha512-cKA5B6lpFEMyMGjxF54QihfYpB4FkEGH+qZhtArDEG+wezQAJY8Pq6C7T1SjWz+FFzt3TbyoXBQYk/0292TdJA==} engines: {node: '>=18'} hasBin: true @@ -7381,13 +7384,13 @@ packages: pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} - playwright-core@1.60.0: - resolution: {integrity: sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==} + playwright-core@1.61.0: + resolution: {integrity: sha512-caX7TrY3Ml6egyDX0WUcTHDxodl/b51y5wJOdCEA36QviK/s2g081hvmGs8eaE3DWb6NYZQ6BjO/QkNRPenoPA==} engines: {node: '>=18'} hasBin: true - playwright@1.60.0: - resolution: {integrity: sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==} + playwright@1.61.0: + resolution: {integrity: sha512-Z+7BeeqQPRRzklHsVFP4KTGIyMxKUmfeRA4WisM6G3/XW6nwGeX6fX9qYaDa+CiUqpOkb2f6X3nar05R3kSuJQ==} engines: {node: '>=18'} hasBin: true @@ -9244,12 +9247,12 @@ snapshots: optionalDependencies: mongodb: 7.3.0(socks@2.8.9) - '@better-auth/oauth-provider@1.6.18(ace7a0f283e33e98a94053209cb42e56)': + '@better-auth/oauth-provider@1.6.18(eae6780b8343fa2684a4fc6cbb52e92d)': dependencies: '@better-auth/core': 1.6.18(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.3.0)(@cloudflare/workers-types@4.20260520.1)(@opentelemetry/api@1.9.1)(better-call@1.3.6(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0) '@better-auth/utils': 0.4.1 '@better-fetch/fetch': 1.3.0 - better-auth: 1.6.18(@cloudflare/workers-types@4.20260520.1)(@opentelemetry/api@1.9.1)(@sveltejs/kit@2.65.1(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.3(@typescript-eslint/types@8.61.1))(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(svelte@5.55.3(@typescript-eslint/types@8.61.1))(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(better-sqlite3@12.10.1)(mongodb@7.3.0(socks@2.8.9))(mysql2@3.22.4(@types/node@25.9.3))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(svelte@5.55.3(@typescript-eslint/types@8.61.1))(vitest@4.1.9) + better-auth: 1.6.18(@cloudflare/workers-types@4.20260520.1)(@opentelemetry/api@1.9.1)(@sveltejs/kit@2.65.1(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.3(@typescript-eslint/types@8.61.1))(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(svelte@5.55.3(@typescript-eslint/types@8.61.1))(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(better-sqlite3@12.10.1)(mongodb@7.3.0(socks@2.8.9))(mysql2@3.22.4(@types/node@25.9.3))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.61.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(svelte@5.55.3(@typescript-eslint/types@8.61.1))(vitest@4.1.9) better-call: 1.3.6(zod@4.4.3) jose: 6.2.3 zod: 4.4.3 @@ -10038,10 +10041,9 @@ snapshots: '@pinojs/redact@0.4.0': {} - '@playwright/test@1.60.0': + '@playwright/test@1.61.0': dependencies: - playwright: 1.60.0 - optional: true + playwright: 1.61.0 '@polka/url@1.0.0-next.29': {} @@ -11429,7 +11431,7 @@ snapshots: baseline-browser-mapping@2.10.37: {} - better-auth@1.6.18(@cloudflare/workers-types@4.20260520.1)(@opentelemetry/api@1.9.1)(@sveltejs/kit@2.65.1(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.3(@typescript-eslint/types@8.61.1))(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(svelte@5.55.3(@typescript-eslint/types@8.61.1))(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(better-sqlite3@12.10.1)(mongodb@7.3.0(socks@2.8.9))(mysql2@3.22.4(@types/node@25.9.3))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(svelte@5.55.3(@typescript-eslint/types@8.61.1))(vitest@4.1.9): + better-auth@1.6.18(@cloudflare/workers-types@4.20260520.1)(@opentelemetry/api@1.9.1)(@sveltejs/kit@2.65.1(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.3(@typescript-eslint/types@8.61.1))(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(svelte@5.55.3(@typescript-eslint/types@8.61.1))(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(better-sqlite3@12.10.1)(mongodb@7.3.0(socks@2.8.9))(mysql2@3.22.4(@types/node@25.9.3))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.61.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.21.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(svelte@5.55.3(@typescript-eslint/types@8.61.1))(vitest@4.1.9): dependencies: '@better-auth/core': 1.6.18(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.3.0)(@cloudflare/workers-types@4.20260520.1)(@opentelemetry/api@1.9.1)(better-call@1.3.6(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0) '@better-auth/drizzle-adapter': 1.6.18(@better-auth/core@1.6.18(@better-auth/utils@0.4.1)(@better-fetch/fetch@1.3.0)(@cloudflare/workers-types@4.20260520.1)(@opentelemetry/api@1.9.1)(better-call@1.3.6(zod@4.4.3))(jose@6.2.3)(kysely@0.29.2)(nanostores@1.3.0))(@better-auth/utils@0.4.1) @@ -11453,7 +11455,7 @@ snapshots: better-sqlite3: 12.10.1 mongodb: 7.3.0(socks@2.8.9) mysql2: 3.22.4(@types/node@25.9.3) - next: 16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + next: 16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.61.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) pg: 8.21.0 react: 19.2.7 react-dom: 19.2.7(react@19.2.7) @@ -12403,7 +12405,7 @@ snapshots: fsevents@2.3.3: optional: true - fumadocs-core@16.10.2(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.15(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.18.0(react@19.2.7))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react-router@7.15.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7)(zod@4.4.3): + fumadocs-core@16.10.2(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.15(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.18.0(react@19.2.7))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.61.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react-router@7.15.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7)(zod@4.4.3): dependencies: '@fuma-translate/react': 1.0.2(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@orama/orama': 3.1.18 @@ -12431,7 +12433,7 @@ snapshots: '@types/mdast': 4.0.4 '@types/react': 19.2.17 lucide-react: 1.18.0(react@19.2.7) - next: 16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + next: 16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.61.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 react-dom: 19.2.7(react@19.2.7) react-router: 7.15.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -12439,14 +12441,14 @@ snapshots: transitivePeerDependencies: - supports-color - fumadocs-mdx@15.0.12(@types/mdast@4.0.4)(@types/mdx@2.0.14)(@types/react@19.2.17)(fumadocs-core@16.10.2(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.15(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.18.0(react@19.2.7))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react-router@7.15.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7)(zod@4.4.3))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7)(rolldown@1.0.3)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)): + fumadocs-mdx@15.0.12(@types/mdast@4.0.4)(@types/mdx@2.0.14)(@types/react@19.2.17)(fumadocs-core@16.10.2(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.15(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.18.0(react@19.2.7))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.61.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react-router@7.15.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7)(zod@4.4.3))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.61.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7)(rolldown@1.0.3)(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)): dependencies: '@mdx-js/mdx': 3.1.1 '@standard-schema/spec': 1.1.0 chokidar: 5.0.0 esbuild: 0.28.1 estree-util-value-to-estree: 3.5.0 - fumadocs-core: 16.10.2(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.15(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.18.0(react@19.2.7))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react-router@7.15.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7)(zod@4.4.3) + fumadocs-core: 16.10.2(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.15(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.18.0(react@19.2.7))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.61.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react-router@7.15.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7)(zod@4.4.3) js-yaml: 4.2.0 mdast-util-mdx: 3.0.0 picocolors: 1.1.1 @@ -12462,14 +12464,14 @@ snapshots: '@types/mdast': 4.0.4 '@types/mdx': 2.0.14 '@types/react': 19.2.17 - next: 16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + next: 16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.61.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) react: 19.2.7 rolldown: 1.0.3 vite: 8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0) transitivePeerDependencies: - supports-color - fumadocs-ui@16.10.2(@tailwindcss/oxide@4.3.1)(@types/mdx@2.0.14)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(fumadocs-core@16.10.2(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.15(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.18.0(react@19.2.7))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react-router@7.15.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7)(zod@4.4.3))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(tailwindcss@4.3.1): + fumadocs-ui@16.10.2(@tailwindcss/oxide@4.3.1)(@types/mdx@2.0.14)(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(fumadocs-core@16.10.2(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.15(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.18.0(react@19.2.7))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.61.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react-router@7.15.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7)(zod@4.4.3))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.61.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(tailwindcss@4.3.1): dependencies: '@fuma-translate/react': 1.0.2(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) '@fumadocs/tailwind': 0.0.5(@tailwindcss/oxide@4.3.1)(tailwindcss@4.3.1) @@ -12484,7 +12486,7 @@ snapshots: '@radix-ui/react-slot': 1.2.5(@types/react@19.2.17)(react@19.2.7) '@radix-ui/react-tabs': 1.1.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) class-variance-authority: 0.7.1 - fumadocs-core: 16.10.2(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.15(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.18.0(react@19.2.7))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react-router@7.15.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7)(zod@4.4.3) + fumadocs-core: 16.10.2(@mdx-js/mdx@3.1.1)(@tanstack/react-router@1.170.15(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(@types/estree-jsx@1.0.5)(@types/hast@3.0.4)(@types/mdast@4.0.4)(@types/react@19.2.17)(lucide-react@1.18.0(react@19.2.7))(next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.61.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react-router@7.15.1(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react@19.2.7)(zod@4.4.3) lucide-react: 1.18.0(react@19.2.7) motion: 12.40.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7) next-themes: 0.4.6(react-dom@19.2.7(react@19.2.7))(react@19.2.7) @@ -12499,7 +12501,7 @@ snapshots: optionalDependencies: '@types/mdx': 2.0.14 '@types/react': 19.2.17 - next: 16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + next: 16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.61.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) transitivePeerDependencies: - '@emotion/is-prop-valid' - '@tailwindcss/oxide' @@ -13967,7 +13969,7 @@ snapshots: react: 19.2.7 react-dom: 19.2.7(react@19.2.7) - next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + next@16.2.9(@opentelemetry/api@1.9.1)(@playwright/test@1.61.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7): dependencies: '@next/env': 16.2.9 '@swc/helpers': 0.5.15 @@ -13987,7 +13989,7 @@ snapshots: '@next/swc-win32-arm64-msvc': 16.2.9 '@next/swc-win32-x64-msvc': 16.2.9 '@opentelemetry/api': 1.9.1 - '@playwright/test': 1.60.0 + '@playwright/test': 1.61.0 sharp: 0.34.5 transitivePeerDependencies: - '@babel/core' @@ -14289,15 +14291,13 @@ snapshots: mlly: 1.8.2 pathe: 2.0.3 - playwright-core@1.60.0: - optional: true + playwright-core@1.61.0: {} - playwright@1.60.0: + playwright@1.61.0: dependencies: - playwright-core: 1.60.0 + playwright-core: 1.61.0 optionalDependencies: fsevents: 2.3.2 - optional: true pluralize@2.0.0: {}