feat(video,chat): native player, ad-break awareness, chat send/delay reliability, and tab redesign (#567)

Squash-merge commit. Covers four areas: native video player, chat reliability, multi-tab, and hardening.

## Native video player
- Direct HLS playback via `better_native_video_player` (forked from `plug-and-pay/flutter-native-video-player`, patched on `frosty-patches` branch)
- Twitch GQL playback token fetching with platform cookie extraction (iOS Swift + Android Kotlin plugins) for authenticated streams
- Quality selection (source, 720p, 480p, 360p, 160p, audio-only) persisted per channel
- Picture-in-picture: iOS automatic inline PiP, Android auto-PiP on API 31+ guarded against older devices
- Latency polling, chat latency sync, stall detection/recovery, startup auto-pause recovery, watchdog timers
- **Twitch stitched-ad break detection** (HLS `EXT-X-DATERANGE`) on both platforms, emitting `adBreakChanged` so the host suspends latency/stall recovery and chat sync during ads (program-date-time is unreliable then). Matches `CLASS="twitch-stitched-ad"` / `ID="stitched-ad-"` **and** the `X-TV-TWITCH-AD-*` attribute prefix (the durable signal streamlink/yt-dlp use)
- Shared `VideoPlayerInterface` so WebView and native paths are interchangeable via settings toggle
- `PlaybackAccessToken` model, `TwitchGqlApi` client

## Chat delay & send reliability
- **Optimistic send-finalize**: Twitch acks a sent message with a per-PRIVMSG USERSTATE (not an echo), which it can intermittently drop — more so under a long chat delay. A missing ack no longer shows a false "message may not have been sent" error; the send is finalized optimistically (local echo rendered), and only genuine rejection NOTICEs surface an error. Ack timeout scaled by the chat delay.
- **Per-line chat-delay bypass**: control/state lines (USERSTATE/ROOMSTATE/GLOBALUSERSTATE), rejection NOTICEs, the reconnect notice, and untagged server lines bypass the delay so send-acks and PONGs aren't stalled; only displayable chat content is delayed, staying in sync with delayed video.
- **Measured chat bottom-bar height**: the message list reflows to the composer's real measured height, fixing the input overlapping messages when a long message expands it (replaces a fixed-constant estimate).
- IRC tag parsing handles valueless and escaped tags per the IRCv3 message-tags spec (fixes a recent-messages RangeError on certain tags).

## Chat / multi-tab
- Redesigned tab chips: unread dot indicator, chips dim until WebSocket connects
- Animated tab options popover replacing `MenuAnchor` (no animation hook in Flutter 3.44)
- Simplified `ChatTabs` from `StatefulWidget` to `StatelessWidget`
- Focus-current-channel fade bump to 0.55; section-header alpha lifted to match the muted-label tier
- `addTab` now calls `setActiveTab` to snapshot outgoing tab's `lastSeenMessageId` — fixes spurious unread dots after adding a tab
- `onActivateSourceTab` threaded into `ChatUserModal` so Reply in merged mode switches to the correct source tab's composer

## Bug fixes and hardening
- **Reverted the experimental iOS low-latency mode** (5s live-edge join + 1.05x catch-up): AVPlayer can't sustain <~18s on Twitch (declared `TARGETDURATION:6` paces playlist refreshes), and the offset starved the buffer into pause-on-launch. Default join distance restored.
- Fork (Android): **cap `BEHIND_LIVE_WINDOW` recovery** so a stream repeatedly falling off the live window can't silently re-prepare forever; emits `error` on exhaustion so the host recovery ladder takes over
- Guard all Android `setAutoPipMode` calls with `_autoPipAvailable` — prevents `PlatformException` on Android 8–11; check `_disposed` after `isAutoPipAvailable` await to prevent post-dispose auto-PiP re-enable
- Remove `_isInPipMode` guard from `_onPaused` so `_paused` tracks actual state, fixing PiP play/pause toggle getting stuck
- Tighten iOS cookie domain check to exact `twitch.tv` / `.twitch.tv` suffix
- Invalidate the stored web session token when Twitch rejects it with a 401 (profile card flips back to unlinked; future loads skip the doomed authenticated request), and re-extract the cookie on launch when logged in without a linked session
- Send `play_session_id` and `player_backend=mediaplayer` to Usher, matching the web client / streamlink
- Fork (iOS): restore program-date-time latency measurement (a prior rev measured distance to the manifest edge, reading ~0s and silently disabling high-latency recovery / chat-delay auto-sync); release platform views on dispose (per-stream view + AVPlayerViewController leak), track the observed AVPlayerItem for KVO removal (sibling-view crash), main-thread seek results, resolve superseded load futures
- Fork (Android): clean up method handlers orphaned by PiP-time view disposal (leaked audio-focus listeners), drop the live-offset re-anchoring seekTo on metadata updates (latency creep), restore pre-duck volume, respect user pause in the stall watchdog, resolve superseded load futures
- Deep review pass: expire the quality-switch flag so stall recovery isn't disabled for the session, cap latency-driven recovery (clock-skew loop), generation-guard the error overlay, two-strike offline confirmation, controller null-safety on quality switch
- Tighten `/me` local-echo match (no longer renders `/meow ...` as an action); clear pending send text on disconnect

## Web / docs
- Remove stale Cloudflare Images binding from `wrangler.jsonc` (covered by `images.unoptimized: true`)
- Correct `web/AGENTS.md` Cache Components claim (feature not enabled)
- Repo and agent config cleanup

## Test plan
- [x] `flutter analyze` — clean (frosty + plugin lib)
- [x] `flutter test` — 319/319 pass (adds `ChatLatencySync`, `StreamInfoPoller`, video timing invariants, `PlaybackAccessToken`, IRC tag parsing)
- [x] Android plugin Kotlin compiles against the bumped fork rev
- [ ] Native player plays live streams on iOS and Android
- [ ] Quality switching works and persists across channel reopens
- [ ] PiP enters/exits correctly; pause/resume toggle in PiP window works
- [ ] Audio-only mode does not crash on Android < API 31
- [ ] Sending under a long synced chat delay no longer shows a false "may not have been sent" error
- [ ] Long composer text reflows the message list (no input/message overlap)
- [ ] Multi-tab: adding a tab does not mark previous tab as unread
- [ ] Merged chat: Reply from user modal targets the correct tab's composer

🤖 Generated with [Claude Code](https://claude.com/claude-code)
This commit is contained in:
Tommy Chow 2026-06-13 17:06:24 -04:00 • committed by GitHub
parent 8883af90f0
commit f2b932bc93
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
72 changed files with 7220 additions and 3816 deletions

1
web/.gitignore vendored
View file

@ -45,3 +45,4 @@ next-env.d.ts
# ai
.claude/settings.local.json
.playwright-mcp

View file

@ -1,5 +1,19 @@
# AGENTS.md
---
# Author Preferences
## Infrastructure Checklist
When creating new infrastructure (routes, API handlers, providers), use exploration findings as a **checklist** — systematically verify each convention is followed before writing code.
---
# Project
Next.js 16 landing page for [Frosty](https://frostyapp.io) using the App Router with React 19. Deployed on **Cloudflare Workers** via `@opennextjs/cloudflare`.
## Commands
```bash
@ -17,25 +31,25 @@ pnpm clean # Delete .next, .open-next, and node_modules
pnpm nuke # Delete .next, .open-next, node_modules, and pnpm-lock.yaml
```
## Architecture
Next.js 16 landing page for [Frosty](https://frostyapp.io) using the App Router with React 19. Deployed on **Cloudflare Workers** via `@opennextjs/cloudflare`.
### Key Configuration
- **React Compiler**: Enabled in `next.config.ts` for automatic memoization
- **Typed Routes**: Enabled for type-safe navigation (use `Route` type from `next/navigation`)
- **Path Alias**: `@/*` maps to `./src/*`
- **Strict TypeScript**: `noUncheckedIndexedAccess`, `noImplicitReturns`, `noFallthroughCasesInSwitch`, `noImplicitOverride`, `verbatimModuleSyntax`
### Source Structure
## Source Structure
- `src/app/` - App Router pages and layouts
- `src/components/` - React components (`ui/` subdirectory for shadcn `base-vega` style — add with `pnpm dlx shadcn@latest add <component>`)
- `src/lib/` - Utilities (`cn()` for className merging, `constants.ts` for external links)
- `src/assets/` - Static images (screenshots)
### Cloudflare Workers
## Key Configuration
- **React Compiler**: Enabled in `next.config.ts` for automatic memoization
- **Typed Routes**: Enabled for type-safe navigation (use `Route` type from `next/navigation`)
- **Path Alias**: `@/*` maps to `./src/*`
- **Strict TypeScript**: `noUncheckedIndexedAccess`, `noImplicitReturns`, `noFallthroughCasesInSwitch`, `noImplicitOverride`, `verbatimModuleSyntax`
## Cache Components
Not yet enabled — `cacheComponents` is not set in `next.config.ts` and no `"use cache"` directives are in use. Everything is dynamic (SSR) by default. To opt in: add `cacheComponents: true` to `next.config.ts`, use `"use cache"` + `cacheLife()` on server components/functions, and wrap async work in `<Suspense>` for PPR. Durable runtime cache requires R2 incremental cache (see `open-next.config.ts`) — without it, cache is in-memory only per Worker instance.
## Cloudflare Workers
- `wrangler.jsonc` - Cloudflare Workers configuration (bindings, R2, KV, etc.)
- `open-next.config.ts` - OpenNext adapter config (ISR requires uncommenting R2 incremental cache)
@ -67,9 +81,12 @@ Notable strict rules enforced:
- `react-you-might-not-need-an-effect` - Avoid unnecessary useEffect
- Unused variables must be prefixed with `_`
## Commits
## Gotchas
Lowercase, no prefixes (e.g., `remove marquee emote background from hero section`). Keep commits tightly scoped.
- **shadcn uses @base-ui/react**: Not Radix UI — component primitives differ from older shadcn examples. `button.tsx` is a `'use client'` module with no `asChild` prop. Check `src/components/ui/` before building custom UI.
- **`useSearchParams()` needs Suspense**: Always wrap components using `useSearchParams()` in a `<Suspense>` boundary — required for production builds.
- **Never remove `tw-animate-css`**: Required by shadcn/ui components for animations. Check shadcn dependencies before removing any package.
- **No `pnpm` prefix inside package.json scripts**: The package manager is already the script runner. Use bare commands (e.g., `next build`, not `pnpm next build`).
## Dev Tooling

View file

@ -36,7 +36,6 @@
"@eslint/js": "^9.39.2",
"@opennextjs/cloudflare": "^1.16.5",
"@tailwindcss/postcss": "^4.1.18",
"@tailwindcss/typography": "^0.5.19",
"@types/node": "^25.2.3",
"@types/react": "^19.2.14",
"@types/react-dom": "^19.2.3",
@ -50,7 +49,6 @@
"prettier": "^3.8.1",
"prettier-plugin-organize-imports": "^4.3.0",
"prettier-plugin-tailwindcss": "^0.7.2",
"react-scan": "^0.5.3",
"shadcn": "^3.8.5",
"tailwindcss": "^4.1.18",
"typescript": "^5.9.3",

420
web/pnpm-lock.yaml generated
View file

@ -60,9 +60,6 @@ importers:
'@tailwindcss/postcss':
specifier: ^4.1.18
version: 4.1.18
'@tailwindcss/typography':
specifier: ^0.5.19
version: 0.5.19(tailwindcss@4.1.18)
'@types/node':
specifier: ^25.2.3
version: 25.2.3
@ -102,9 +99,6 @@ importers:
prettier-plugin-tailwindcss:
specifier: ^0.7.2
version: 0.7.2(prettier-plugin-organize-imports@4.3.0(prettier@3.8.1)(typescript@5.9.3))(prettier@3.8.1)
react-scan:
specifier: ^0.5.3
version: 0.5.3(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
shadcn:
specifier: ^3.8.5
version: 3.8.5(@types/node@25.2.3)(typescript@5.9.3)
@ -612,12 +606,6 @@ packages:
'@emnapi/wasi-threads@1.1.0':
resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==}
'@esbuild/aix-ppc64@0.25.12':
resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [aix]
'@esbuild/aix-ppc64@0.25.4':
resolution: {integrity: sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==}
engines: {node: '>=18'}
@ -630,12 +618,6 @@ packages:
cpu: [ppc64]
os: [aix]
'@esbuild/android-arm64@0.25.12':
resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [android]
'@esbuild/android-arm64@0.25.4':
resolution: {integrity: sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==}
engines: {node: '>=18'}
@ -648,12 +630,6 @@ packages:
cpu: [arm64]
os: [android]
'@esbuild/android-arm@0.25.12':
resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==}
engines: {node: '>=18'}
cpu: [arm]
os: [android]
'@esbuild/android-arm@0.25.4':
resolution: {integrity: sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==}
engines: {node: '>=18'}
@ -666,12 +642,6 @@ packages:
cpu: [arm]
os: [android]
'@esbuild/android-x64@0.25.12':
resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==}
engines: {node: '>=18'}
cpu: [x64]
os: [android]
'@esbuild/android-x64@0.25.4':
resolution: {integrity: sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==}
engines: {node: '>=18'}
@ -684,12 +654,6 @@ packages:
cpu: [x64]
os: [android]
'@esbuild/darwin-arm64@0.25.12':
resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [darwin]
'@esbuild/darwin-arm64@0.25.4':
resolution: {integrity: sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==}
engines: {node: '>=18'}
@ -702,12 +666,6 @@ packages:
cpu: [arm64]
os: [darwin]
'@esbuild/darwin-x64@0.25.12':
resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==}
engines: {node: '>=18'}
cpu: [x64]
os: [darwin]
'@esbuild/darwin-x64@0.25.4':
resolution: {integrity: sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==}
engines: {node: '>=18'}
@ -720,12 +678,6 @@ packages:
cpu: [x64]
os: [darwin]
'@esbuild/freebsd-arm64@0.25.12':
resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [freebsd]
'@esbuild/freebsd-arm64@0.25.4':
resolution: {integrity: sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==}
engines: {node: '>=18'}
@ -738,12 +690,6 @@ packages:
cpu: [arm64]
os: [freebsd]
'@esbuild/freebsd-x64@0.25.12':
resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [freebsd]
'@esbuild/freebsd-x64@0.25.4':
resolution: {integrity: sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==}
engines: {node: '>=18'}
@ -756,12 +702,6 @@ packages:
cpu: [x64]
os: [freebsd]
'@esbuild/linux-arm64@0.25.12':
resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==}
engines: {node: '>=18'}
cpu: [arm64]
os: [linux]
'@esbuild/linux-arm64@0.25.4':
resolution: {integrity: sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==}
engines: {node: '>=18'}
@ -774,12 +714,6 @@ packages:
cpu: [arm64]
os: [linux]
'@esbuild/linux-arm@0.25.12':
resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==}
engines: {node: '>=18'}
cpu: [arm]
os: [linux]
'@esbuild/linux-arm@0.25.4':
resolution: {integrity: sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==}
engines: {node: '>=18'}
@ -792,12 +726,6 @@ packages:
cpu: [arm]
os: [linux]
'@esbuild/linux-ia32@0.25.12':
resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==}
engines: {node: '>=18'}
cpu: [ia32]
os: [linux]
'@esbuild/linux-ia32@0.25.4':
resolution: {integrity: sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==}
engines: {node: '>=18'}
@ -810,12 +738,6 @@ packages:
cpu: [ia32]
os: [linux]
'@esbuild/linux-loong64@0.25.12':
resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==}
engines: {node: '>=18'}
cpu: [loong64]
os: [linux]
'@esbuild/linux-loong64@0.25.4':
resolution: {integrity: sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==}
engines: {node: '>=18'}
@ -828,12 +750,6 @@ packages:
cpu: [loong64]
os: [linux]
'@esbuild/linux-mips64el@0.25.12':
resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==}
engines: {node: '>=18'}
cpu: [mips64el]
os: [linux]
'@esbuild/linux-mips64el@0.25.4':
resolution: {integrity: sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==}
engines: {node: '>=18'}
@ -846,12 +762,6 @@ packages:
cpu: [mips64el]
os: [linux]
'@esbuild/linux-ppc64@0.25.12':
resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==}
engines: {node: '>=18'}
cpu: [ppc64]
os: [linux]
'@esbuild/linux-ppc64@0.25.4':
resolution: {integrity: sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==}
engines: {node: '>=18'}
@ -864,12 +774,6 @@ packages:
cpu: [ppc64]
os: [linux]
'@esbuild/linux-riscv64@0.25.12':
resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==}
engines: {node: '>=18'}
cpu: [riscv64]
os: [linux]
'@esbuild/linux-riscv64@0.25.4':
resolution: {integrity: sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==}
engines: {node: '>=18'}
@ -882,12 +786,6 @@ packages:
cpu: [riscv64]
os: [linux]
'@esbuild/linux-s390x@0.25.12':
resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==}
engines: {node: '>=18'}
cpu: [s390x]
os: [linux]
'@esbuild/linux-s390x@0.25.4':
resolution: {integrity: sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==}
engines: {node: '>=18'}
@ -900,12 +798,6 @@ packages:
cpu: [s390x]
os: [linux]
'@esbuild/linux-x64@0.25.12':
resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==}
engines: {node: '>=18'}
cpu: [x64]
os: [linux]
'@esbuild/linux-x64@0.25.4':
resolution: {integrity: sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==}
engines: {node: '>=18'}
@ -918,12 +810,6 @@ packages:
cpu: [x64]
os: [linux]
'@esbuild/netbsd-arm64@0.25.12':
resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [netbsd]
'@esbuild/netbsd-arm64@0.25.4':
resolution: {integrity: sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==}
engines: {node: '>=18'}
@ -936,12 +822,6 @@ packages:
cpu: [arm64]
os: [netbsd]
'@esbuild/netbsd-x64@0.25.12':
resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==}
engines: {node: '>=18'}
cpu: [x64]
os: [netbsd]
'@esbuild/netbsd-x64@0.25.4':
resolution: {integrity: sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==}
engines: {node: '>=18'}
@ -954,12 +834,6 @@ packages:
cpu: [x64]
os: [netbsd]
'@esbuild/openbsd-arm64@0.25.12':
resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openbsd]
'@esbuild/openbsd-arm64@0.25.4':
resolution: {integrity: sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==}
engines: {node: '>=18'}
@ -972,12 +846,6 @@ packages:
cpu: [arm64]
os: [openbsd]
'@esbuild/openbsd-x64@0.25.12':
resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==}
engines: {node: '>=18'}
cpu: [x64]
os: [openbsd]
'@esbuild/openbsd-x64@0.25.4':
resolution: {integrity: sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==}
engines: {node: '>=18'}
@ -990,24 +858,12 @@ packages:
cpu: [x64]
os: [openbsd]
'@esbuild/openharmony-arm64@0.25.12':
resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openharmony]
'@esbuild/openharmony-arm64@0.27.3':
resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==}
engines: {node: '>=18'}
cpu: [arm64]
os: [openharmony]
'@esbuild/sunos-x64@0.25.12':
resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==}
engines: {node: '>=18'}
cpu: [x64]
os: [sunos]
'@esbuild/sunos-x64@0.25.4':
resolution: {integrity: sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==}
engines: {node: '>=18'}
@ -1020,12 +876,6 @@ packages:
cpu: [x64]
os: [sunos]
'@esbuild/win32-arm64@0.25.12':
resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==}
engines: {node: '>=18'}
cpu: [arm64]
os: [win32]
'@esbuild/win32-arm64@0.25.4':
resolution: {integrity: sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==}
engines: {node: '>=18'}
@ -1038,12 +888,6 @@ packages:
cpu: [arm64]
os: [win32]
'@esbuild/win32-ia32@0.25.12':
resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==}
engines: {node: '>=18'}
cpu: [ia32]
os: [win32]
'@esbuild/win32-ia32@0.25.4':
resolution: {integrity: sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==}
engines: {node: '>=18'}
@ -1056,12 +900,6 @@ packages:
cpu: [ia32]
os: [win32]
'@esbuild/win32-x64@0.25.12':
resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==}
engines: {node: '>=18'}
cpu: [x64]
os: [win32]
'@esbuild/win32-x64@0.25.4':
resolution: {integrity: sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==}
engines: {node: '>=18'}
@ -1546,23 +1384,6 @@ packages:
'@poppinss/exception@1.2.3':
resolution: {integrity: sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==}
'@preact/signals-core@1.13.0':
resolution: {integrity: sha512-slT6XeTCAbdql61GVLlGU4x7XHI7kCZV5Um5uhE4zLX4ApgiiXc0UYFvVOKq06xcovzp7p+61l68oPi563ARKg==}
'@preact/signals@1.3.4':
resolution: {integrity: sha512-TPMkStdT0QpSc8FpB63aOwXoSiZyIrPsP9Uj347KopdS6olZdAYeeird/5FZv/M1Yc1ge5qstub2o8VDbvkT4g==}
peerDependencies:
preact: 10.x
'@rollup/pluginutils@5.3.0':
resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==}
engines: {node: '>=14.0.0'}
peerDependencies:
rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
peerDependenciesMeta:
rollup:
optional: true
'@rtsao/scc@1.1.0':
resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==}
@ -1887,11 +1708,6 @@ packages:
'@tailwindcss/postcss@4.1.18':
resolution: {integrity: sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g==}
'@tailwindcss/typography@0.5.19':
resolution: {integrity: sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==}
peerDependencies:
tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1'
'@ts-morph/common@0.27.0':
resolution: {integrity: sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ==}
@ -1916,9 +1732,6 @@ packages:
'@types/node@18.19.130':
resolution: {integrity: sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==}
'@types/node@20.19.33':
resolution: {integrity: sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw==}
'@types/node@25.2.3':
resolution: {integrity: sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==}
@ -1927,11 +1740,6 @@ packages:
peerDependencies:
'@types/react': ^19.2.0
'@types/react-reconciler@0.28.9':
resolution: {integrity: sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg==}
peerDependencies:
'@types/react': '*'
'@types/react@19.2.14':
resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==}
@ -2288,11 +2096,6 @@ packages:
resolution: {integrity: sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==}
hasBin: true
bippy@0.5.30:
resolution: {integrity: sha512-8CFmJAHD3gmTLDOCDHuWhjm1nxHSFZdlGoWtak9r53Uxn36ynOjxBLyxXHh/7h/XiKLyPvfdXa0gXWcD9o9lLQ==}
peerDependencies:
react: '>=17.0.1'
birecord@0.1.1:
resolution: {integrity: sha512-VUpsf/qykW0heRlC8LooCq28Kxn3mAqKohhDG/49rrsQ1dT1CXyj/pgXS+5BSRzFTR/3DyIBOqQOrGyZOh71Aw==}
@ -2658,11 +2461,6 @@ packages:
resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==}
engines: {node: '>= 0.4'}
esbuild@0.25.12:
resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==}
engines: {node: '>=18'}
hasBin: true
esbuild@0.25.4:
resolution: {integrity: sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==}
engines: {node: '>=18'}
@ -2859,12 +2657,6 @@ packages:
resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
engines: {node: '>=4.0'}
estree-walker@2.0.2:
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
estree-walker@3.0.3:
resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
esutils@2.0.3:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'}
@ -3979,10 +3771,6 @@ packages:
resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==}
engines: {node: '>= 0.4'}
postcss-selector-parser@6.0.10:
resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==}
engines: {node: '>=4'}
postcss-selector-parser@7.1.1:
resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==}
engines: {node: '>=4'}
@ -3999,9 +3787,6 @@ packages:
resolution: {integrity: sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==}
engines: {node: '>=20'}
preact@10.28.3:
resolution: {integrity: sha512-tCmoRkPQLpBeWzpmbhryairGnhW9tKV6c6gr/w+RhoRoKEJwsjzipwp//1oCpGPOchvSLaAPlpcJi9MwMmoPyA==}
prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
@ -4123,13 +3908,6 @@ packages:
react-is@16.13.1:
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
react-scan@0.5.3:
resolution: {integrity: sha512-qde9PupmUf0L3MU1H6bjmoukZNbCXdMyTEwP4Gh8RQ4rZPd2GGNBgEKWszwLm96E8k+sGtMpc0B9P0KyFDP6Bw==}
hasBin: true
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
react@19.2.4:
resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==}
engines: {node: '>=0.10.0'}
@ -4547,9 +4325,6 @@ packages:
undici-types@5.26.5:
resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==}
undici-types@6.21.0:
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
undici-types@7.16.0:
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
@ -4576,10 +4351,6 @@ packages:
resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
engines: {node: '>= 0.8'}
unplugin@2.1.0:
resolution: {integrity: sha512-us4j03/499KhbGP8BU7Hrzrgseo+KdfJYWcbcajCOqsAyb8Gk0Yn2kiUIcZISYCb1JFaZfIuG3b42HmguVOKCQ==}
engines: {node: '>=18.12.0'}
unrs-resolver@1.11.1:
resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==}
@ -4625,9 +4396,6 @@ packages:
webidl-conversions@3.0.1:
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
webpack-virtual-modules@0.6.2:
resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==}
whatwg-url@5.0.0:
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
@ -5816,231 +5584,153 @@ snapshots:
tslib: 2.8.1
optional: true
'@esbuild/aix-ppc64@0.25.12':
optional: true
'@esbuild/aix-ppc64@0.25.4':
optional: true
'@esbuild/aix-ppc64@0.27.3':
optional: true
'@esbuild/android-arm64@0.25.12':
optional: true
'@esbuild/android-arm64@0.25.4':
optional: true
'@esbuild/android-arm64@0.27.3':
optional: true
'@esbuild/android-arm@0.25.12':
optional: true
'@esbuild/android-arm@0.25.4':
optional: true
'@esbuild/android-arm@0.27.3':
optional: true
'@esbuild/android-x64@0.25.12':
optional: true
'@esbuild/android-x64@0.25.4':
optional: true
'@esbuild/android-x64@0.27.3':
optional: true
'@esbuild/darwin-arm64@0.25.12':
optional: true
'@esbuild/darwin-arm64@0.25.4':
optional: true
'@esbuild/darwin-arm64@0.27.3':
optional: true
'@esbuild/darwin-x64@0.25.12':
optional: true
'@esbuild/darwin-x64@0.25.4':
optional: true
'@esbuild/darwin-x64@0.27.3':
optional: true
'@esbuild/freebsd-arm64@0.25.12':
optional: true
'@esbuild/freebsd-arm64@0.25.4':
optional: true
'@esbuild/freebsd-arm64@0.27.3':
optional: true
'@esbuild/freebsd-x64@0.25.12':
optional: true
'@esbuild/freebsd-x64@0.25.4':
optional: true
'@esbuild/freebsd-x64@0.27.3':
optional: true
'@esbuild/linux-arm64@0.25.12':
optional: true
'@esbuild/linux-arm64@0.25.4':
optional: true
'@esbuild/linux-arm64@0.27.3':
optional: true
'@esbuild/linux-arm@0.25.12':
optional: true
'@esbuild/linux-arm@0.25.4':
optional: true
'@esbuild/linux-arm@0.27.3':
optional: true
'@esbuild/linux-ia32@0.25.12':
optional: true
'@esbuild/linux-ia32@0.25.4':
optional: true
'@esbuild/linux-ia32@0.27.3':
optional: true
'@esbuild/linux-loong64@0.25.12':
optional: true
'@esbuild/linux-loong64@0.25.4':
optional: true
'@esbuild/linux-loong64@0.27.3':
optional: true
'@esbuild/linux-mips64el@0.25.12':
optional: true
'@esbuild/linux-mips64el@0.25.4':
optional: true
'@esbuild/linux-mips64el@0.27.3':
optional: true
'@esbuild/linux-ppc64@0.25.12':
optional: true
'@esbuild/linux-ppc64@0.25.4':
optional: true
'@esbuild/linux-ppc64@0.27.3':
optional: true
'@esbuild/linux-riscv64@0.25.12':
optional: true
'@esbuild/linux-riscv64@0.25.4':
optional: true
'@esbuild/linux-riscv64@0.27.3':
optional: true
'@esbuild/linux-s390x@0.25.12':
optional: true
'@esbuild/linux-s390x@0.25.4':
optional: true
'@esbuild/linux-s390x@0.27.3':
optional: true
'@esbuild/linux-x64@0.25.12':
optional: true
'@esbuild/linux-x64@0.25.4':
optional: true
'@esbuild/linux-x64@0.27.3':
optional: true
'@esbuild/netbsd-arm64@0.25.12':
optional: true
'@esbuild/netbsd-arm64@0.25.4':
optional: true
'@esbuild/netbsd-arm64@0.27.3':
optional: true
'@esbuild/netbsd-x64@0.25.12':
optional: true
'@esbuild/netbsd-x64@0.25.4':
optional: true
'@esbuild/netbsd-x64@0.27.3':
optional: true
'@esbuild/openbsd-arm64@0.25.12':
optional: true
'@esbuild/openbsd-arm64@0.25.4':
optional: true
'@esbuild/openbsd-arm64@0.27.3':
optional: true
'@esbuild/openbsd-x64@0.25.12':
optional: true
'@esbuild/openbsd-x64@0.25.4':
optional: true
'@esbuild/openbsd-x64@0.27.3':
optional: true
'@esbuild/openharmony-arm64@0.25.12':
optional: true
'@esbuild/openharmony-arm64@0.27.3':
optional: true
'@esbuild/sunos-x64@0.25.12':
optional: true
'@esbuild/sunos-x64@0.25.4':
optional: true
'@esbuild/sunos-x64@0.27.3':
optional: true
'@esbuild/win32-arm64@0.25.12':
optional: true
'@esbuild/win32-arm64@0.25.4':
optional: true
'@esbuild/win32-arm64@0.27.3':
optional: true
'@esbuild/win32-ia32@0.25.12':
optional: true
'@esbuild/win32-ia32@0.25.4':
optional: true
'@esbuild/win32-ia32@0.27.3':
optional: true
'@esbuild/win32-x64@0.25.12':
optional: true
'@esbuild/win32-x64@0.25.4':
optional: true
@ -6546,19 +6236,6 @@ snapshots:
'@poppinss/exception@1.2.3': {}
'@preact/signals-core@1.13.0': {}
'@preact/signals@1.3.4(preact@10.28.3)':
dependencies:
'@preact/signals-core': 1.13.0
preact: 10.28.3
'@rollup/pluginutils@5.3.0':
dependencies:
'@types/estree': 1.0.8
estree-walker: 2.0.2
picomatch: 4.0.3
'@rtsao/scc@1.1.0': {}
'@sec-ant/readable-stream@0.4.1': {}
@ -6980,11 +6657,6 @@ snapshots:
postcss: 8.5.6
tailwindcss: 4.1.18
'@tailwindcss/typography@0.5.19(tailwindcss@4.1.18)':
dependencies:
postcss-selector-parser: 6.0.10
tailwindcss: 4.1.18
'@ts-morph/common@0.27.0':
dependencies:
fast-glob: 3.3.3
@ -7013,10 +6685,6 @@ snapshots:
dependencies:
undici-types: 5.26.5
'@types/node@20.19.33':
dependencies:
undici-types: 6.21.0
'@types/node@25.2.3':
dependencies:
undici-types: 7.16.0
@ -7025,10 +6693,6 @@ snapshots:
dependencies:
'@types/react': 19.2.14
'@types/react-reconciler@0.28.9(@types/react@19.2.14)':
dependencies:
'@types/react': 19.2.14
'@types/react@19.2.14':
dependencies:
csstype: 3.2.3
@ -7417,13 +7081,6 @@ snapshots:
baseline-browser-mapping@2.9.19: {}
bippy@0.5.30(@types/react@19.2.14)(react@19.2.4):
dependencies:
'@types/react-reconciler': 0.28.9(@types/react@19.2.14)
react: 19.2.4
transitivePeerDependencies:
- '@types/react'
birecord@0.1.1: {}
blake3-wasm@2.1.5: {}
@ -7824,35 +7481,6 @@ snapshots:
is-date-object: 1.1.0
is-symbol: 1.1.1
esbuild@0.25.12:
optionalDependencies:
'@esbuild/aix-ppc64': 0.25.12
'@esbuild/android-arm': 0.25.12
'@esbuild/android-arm64': 0.25.12
'@esbuild/android-x64': 0.25.12
'@esbuild/darwin-arm64': 0.25.12
'@esbuild/darwin-x64': 0.25.12
'@esbuild/freebsd-arm64': 0.25.12
'@esbuild/freebsd-x64': 0.25.12
'@esbuild/linux-arm': 0.25.12
'@esbuild/linux-arm64': 0.25.12
'@esbuild/linux-ia32': 0.25.12
'@esbuild/linux-loong64': 0.25.12
'@esbuild/linux-mips64el': 0.25.12
'@esbuild/linux-ppc64': 0.25.12
'@esbuild/linux-riscv64': 0.25.12
'@esbuild/linux-s390x': 0.25.12
'@esbuild/linux-x64': 0.25.12
'@esbuild/netbsd-arm64': 0.25.12
'@esbuild/netbsd-x64': 0.25.12
'@esbuild/openbsd-arm64': 0.25.12
'@esbuild/openbsd-x64': 0.25.12
'@esbuild/openharmony-arm64': 0.25.12
'@esbuild/sunos-x64': 0.25.12
'@esbuild/win32-arm64': 0.25.12
'@esbuild/win32-ia32': 0.25.12
'@esbuild/win32-x64': 0.25.12
esbuild@0.25.4:
optionalDependencies:
'@esbuild/aix-ppc64': 0.25.4
@ -8233,12 +7861,6 @@ snapshots:
estraverse@5.3.0: {}
estree-walker@2.0.2: {}
estree-walker@3.0.3:
dependencies:
'@types/estree': 1.0.8
esutils@2.0.3: {}
etag@1.8.1: {}
@ -9323,11 +8945,6 @@ snapshots:
possible-typed-array-names@1.1.0: {}
postcss-selector-parser@6.0.10:
dependencies:
cssesc: 3.0.0
util-deprecate: 1.0.2
postcss-selector-parser@7.1.1:
dependencies:
cssesc: 3.0.0
@ -9347,8 +8964,6 @@ snapshots:
powershell-utils@0.1.0: {}
preact@10.28.3: {}
prelude-ls@1.2.1: {}
prettier-plugin-organize-imports@4.3.0(prettier@3.8.1)(typescript@5.9.3):
@ -9412,30 +9027,6 @@ snapshots:
react-is@16.13.1: {}
react-scan@0.5.3(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4):
dependencies:
'@babel/core': 7.29.0
'@babel/generator': 7.29.1
'@babel/types': 7.29.0
'@preact/signals': 1.3.4(preact@10.28.3)
'@rollup/pluginutils': 5.3.0
'@types/node': 20.19.33
bippy: 0.5.30(@types/react@19.2.14)(react@19.2.4)
commander: 14.0.3
esbuild: 0.25.12
estree-walker: 3.0.3
picocolors: 1.1.1
preact: 10.28.3
prompts: 2.4.2
react: 19.2.4
react-dom: 19.2.4(react@19.2.4)
optionalDependencies:
unplugin: 2.1.0
transitivePeerDependencies:
- '@types/react'
- rollup
- supports-color
react@19.2.4: {}
recast@0.23.11:
@ -9982,8 +9573,6 @@ snapshots:
undici-types@5.26.5: {}
undici-types@6.21.0: {}
undici-types@7.16.0: {}
undici@7.16.0: {}
@ -10000,12 +9589,6 @@ snapshots:
unpipe@1.0.0: {}
unplugin@2.1.0:
dependencies:
acorn: 8.15.0
webpack-virtual-modules: 0.6.2
optional: true
unrs-resolver@1.11.1:
dependencies:
napi-postinstall: 0.3.4
@ -10060,9 +9643,6 @@ snapshots:
webidl-conversions@3.0.1: {}
webpack-virtual-modules@0.6.2:
optional: true
whatwg-url@5.0.0:
dependencies:
tr46: 0.0.3

View file

@ -1,8 +1,2 @@
/_next/static/*
Cache-Control: public, max-age=31536000, immutable
/video.webm
Cache-Control: public, max-age=2592000
/logo.svg
Cache-Control: public, max-age=2592000

View file

@ -2,8 +2,6 @@
@import 'tw-animate-css';
@import 'shadcn/tailwind.css';
@plugin '@tailwindcss/typography';
@custom-variant dark (&:where(.dark, .dark *));
@theme inline {

View file

@ -3,21 +3,12 @@
import { Toaster } from '@/components/ui/sonner'
import { MotionConfig } from 'motion/react'
import { ThemeProvider } from 'next-themes'
import { useEffect } from 'react'
interface ProvidersProps {
children: React.ReactNode
}
export function Providers({ children }: ProvidersProps) {
useEffect(() => {
if (process.env.NODE_ENV === 'development') {
void import('react-scan').then(({ scan }) => {
scan({ enabled: true })
})
}
}, [])
return (
<MotionConfig reducedMotion='user'>
<ThemeProvider attribute='class' disableTransitionOnChange>

View file

@ -29,11 +29,6 @@
// "bucket_name": "<BUCKET_NAME>",
// },
// ],
"images": {
// Enable image optimization
// see https://opennext.js.org/cloudflare/howtos/image
"binding": "IMAGES",
},
"minify": true,
"keep_names": false,
"upload_source_maps": true,