From b040c62c1fce537dca932165bb3aa23383aa4f72 Mon Sep 17 00:00:00 2001 From: AleCastro Date: Wed, 30 Apr 2025 13:25:23 -0300 Subject: [PATCH] feat: add Music licensing challenge with Nextjs --- .../.gitignore | 40 + .../.husky/pre-commit | 4 + .../.husky/pre-push | 4 + .../README.md | 92 + .../biome.json | 54 + .../env.example | 7 + .../next-env.d.ts | 5 + .../next.config.ts | 17 + .../package.json | 41 + .../pnpm-lock.yaml | 1996 +++++++++++++++++ .../postcss.config.mjs | 5 + .../src/app/(auth)/login/page.tsx | 53 + .../src/app/(auth)/register/page.tsx | 5 + .../(protected)/scenes/[sceneId]/page.tsx | 34 + .../app/(movies)/(protected)/scenes/page.tsx | 36 + .../app/(movies)/movies/[movieId]/page.tsx | 60 + .../src/app/(movies)/movies/page.tsx | 32 + .../src/app/api/auth/[...nextauth]/route.ts | 3 + .../src/app/error.tsx | 11 + .../src/app/layout.tsx | 39 + .../src/app/not-found.tsx | 9 + .../src/app/page.tsx | 17 + .../src/auth/index.ts | 35 + .../src/components/Button/index.tsx | 22 + .../src/components/Dropdown/index.tsx | 56 + .../src/components/LoginForm/index.tsx | 89 + .../src/components/MovieCard/index.tsx | 44 + .../src/components/MovieDetails/index.tsx | 42 + .../src/components/Navbar/actionButtons.tsx | 34 + .../src/components/Navbar/getNavbarLinks.tsx | 43 + .../src/components/Navbar/index.tsx | 88 + .../SceneList/MenuButtonContent.tsx | 13 + .../src/components/SceneList/SceneItem.tsx | 19 + .../src/components/SceneList/SongItem.tsx | 51 + .../src/components/SceneList/TrackItem.tsx | 18 + .../SceneList/getLicensesOptions.tsx | 34 + .../src/components/SceneList/index.tsx | 21 + .../src/hooks/useSongWithLiveStatus.tsx | 20 + .../src/lib/auth/index.ts | 23 + .../src/lib/fetchApi/index.ts | 9 + .../src/lib/graphql/client.ts | 26 + .../src/lib/graphql/mutations/songs.ts | 10 + .../src/lib/graphql/queries/licenses.ts | 10 + .../src/lib/graphql/queries/movies.ts | 67 + .../src/lib/graphql/queries/scenes.ts | 43 + .../src/lib/graphql/queries/songs.ts | 12 + .../graphql/subscriptions/license-status.ts | 11 + .../src/lib/graphql/websocket.ts | 8 + .../src/middleware.ts | 29 + .../src/middleware/auth.ts | 16 + .../src/routes/index.ts | 44 + .../src/styles/globals.css | 1 + .../src/types/index.ts | 35 + .../src/utils/getMoviesData.ts | 64 + .../src/utils/updateSongStatus.ts | 22 + .../tsconfig.json | 27 + 56 files changed, 3650 insertions(+) create mode 100644 examples/music-licensing-challenge-nextjs/.gitignore create mode 100644 examples/music-licensing-challenge-nextjs/.husky/pre-commit create mode 100755 examples/music-licensing-challenge-nextjs/.husky/pre-push create mode 100644 examples/music-licensing-challenge-nextjs/README.md create mode 100644 examples/music-licensing-challenge-nextjs/biome.json create mode 100644 examples/music-licensing-challenge-nextjs/env.example create mode 100644 examples/music-licensing-challenge-nextjs/next-env.d.ts create mode 100644 examples/music-licensing-challenge-nextjs/next.config.ts create mode 100644 examples/music-licensing-challenge-nextjs/package.json create mode 100644 examples/music-licensing-challenge-nextjs/pnpm-lock.yaml create mode 100644 examples/music-licensing-challenge-nextjs/postcss.config.mjs create mode 100644 examples/music-licensing-challenge-nextjs/src/app/(auth)/login/page.tsx create mode 100644 examples/music-licensing-challenge-nextjs/src/app/(auth)/register/page.tsx create mode 100644 examples/music-licensing-challenge-nextjs/src/app/(movies)/(protected)/scenes/[sceneId]/page.tsx create mode 100644 examples/music-licensing-challenge-nextjs/src/app/(movies)/(protected)/scenes/page.tsx create mode 100644 examples/music-licensing-challenge-nextjs/src/app/(movies)/movies/[movieId]/page.tsx create mode 100644 examples/music-licensing-challenge-nextjs/src/app/(movies)/movies/page.tsx create mode 100644 examples/music-licensing-challenge-nextjs/src/app/api/auth/[...nextauth]/route.ts create mode 100644 examples/music-licensing-challenge-nextjs/src/app/error.tsx create mode 100644 examples/music-licensing-challenge-nextjs/src/app/layout.tsx create mode 100644 examples/music-licensing-challenge-nextjs/src/app/not-found.tsx create mode 100644 examples/music-licensing-challenge-nextjs/src/app/page.tsx create mode 100644 examples/music-licensing-challenge-nextjs/src/auth/index.ts create mode 100644 examples/music-licensing-challenge-nextjs/src/components/Button/index.tsx create mode 100644 examples/music-licensing-challenge-nextjs/src/components/Dropdown/index.tsx create mode 100644 examples/music-licensing-challenge-nextjs/src/components/LoginForm/index.tsx create mode 100644 examples/music-licensing-challenge-nextjs/src/components/MovieCard/index.tsx create mode 100644 examples/music-licensing-challenge-nextjs/src/components/MovieDetails/index.tsx create mode 100644 examples/music-licensing-challenge-nextjs/src/components/Navbar/actionButtons.tsx create mode 100644 examples/music-licensing-challenge-nextjs/src/components/Navbar/getNavbarLinks.tsx create mode 100644 examples/music-licensing-challenge-nextjs/src/components/Navbar/index.tsx create mode 100644 examples/music-licensing-challenge-nextjs/src/components/SceneList/MenuButtonContent.tsx create mode 100644 examples/music-licensing-challenge-nextjs/src/components/SceneList/SceneItem.tsx create mode 100644 examples/music-licensing-challenge-nextjs/src/components/SceneList/SongItem.tsx create mode 100644 examples/music-licensing-challenge-nextjs/src/components/SceneList/TrackItem.tsx create mode 100644 examples/music-licensing-challenge-nextjs/src/components/SceneList/getLicensesOptions.tsx create mode 100644 examples/music-licensing-challenge-nextjs/src/components/SceneList/index.tsx create mode 100644 examples/music-licensing-challenge-nextjs/src/hooks/useSongWithLiveStatus.tsx create mode 100644 examples/music-licensing-challenge-nextjs/src/lib/auth/index.ts create mode 100644 examples/music-licensing-challenge-nextjs/src/lib/fetchApi/index.ts create mode 100644 examples/music-licensing-challenge-nextjs/src/lib/graphql/client.ts create mode 100644 examples/music-licensing-challenge-nextjs/src/lib/graphql/mutations/songs.ts create mode 100644 examples/music-licensing-challenge-nextjs/src/lib/graphql/queries/licenses.ts create mode 100644 examples/music-licensing-challenge-nextjs/src/lib/graphql/queries/movies.ts create mode 100644 examples/music-licensing-challenge-nextjs/src/lib/graphql/queries/scenes.ts create mode 100644 examples/music-licensing-challenge-nextjs/src/lib/graphql/queries/songs.ts create mode 100644 examples/music-licensing-challenge-nextjs/src/lib/graphql/subscriptions/license-status.ts create mode 100644 examples/music-licensing-challenge-nextjs/src/lib/graphql/websocket.ts create mode 100644 examples/music-licensing-challenge-nextjs/src/middleware.ts create mode 100644 examples/music-licensing-challenge-nextjs/src/middleware/auth.ts create mode 100644 examples/music-licensing-challenge-nextjs/src/routes/index.ts create mode 100644 examples/music-licensing-challenge-nextjs/src/styles/globals.css create mode 100644 examples/music-licensing-challenge-nextjs/src/types/index.ts create mode 100644 examples/music-licensing-challenge-nextjs/src/utils/getMoviesData.ts create mode 100644 examples/music-licensing-challenge-nextjs/src/utils/updateSongStatus.ts create mode 100644 examples/music-licensing-challenge-nextjs/tsconfig.json diff --git a/examples/music-licensing-challenge-nextjs/.gitignore b/examples/music-licensing-challenge-nextjs/.gitignore new file mode 100644 index 0000000..4e50592 --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/.gitignore @@ -0,0 +1,40 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo diff --git a/examples/music-licensing-challenge-nextjs/.husky/pre-commit b/examples/music-licensing-challenge-nextjs/.husky/pre-commit new file mode 100644 index 0000000..d9046d2 --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +. "$(dirname -- "$0")/_/husky.sh" + +pnpm run lint-staged \ No newline at end of file diff --git a/examples/music-licensing-challenge-nextjs/.husky/pre-push b/examples/music-licensing-challenge-nextjs/.husky/pre-push new file mode 100755 index 0000000..a180137 --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/.husky/pre-push @@ -0,0 +1,4 @@ +#!/usr/bin/sh +. "$(dirname "$0")/_/husky.sh" + +npm run type-check \ No newline at end of file diff --git a/examples/music-licensing-challenge-nextjs/README.md b/examples/music-licensing-challenge-nextjs/README.md new file mode 100644 index 0000000..674333d --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/README.md @@ -0,0 +1,92 @@ +# Music Licensing Challenge Frontend + + +## Features +- Movie, scene, track, and song management UI +- License status management for songs +- Real-time updates for license status via GraphQL subscriptions +- Authentication (login/register) +- TypeScript, TailwindCSS, and Apollo Client integration +- Linting and formatting with BiomeJs + +## Tech Stack +- [Next.js 15 (App Router)](https://nextjs.org/) +- [React 19](https://react.dev/) +- [Apollo Client 3](https://www.apollographql.com/docs/react/) +- [GraphQL](https://graphql.org/) +- [TailwindCSS 4](https://tailwindcss.com/) +- [TypeScript](https://www.typescriptlang.org/) +- [Biome](https://biomejs.dev/) (linting/formatting) + +## Getting Started + +1. **Install dependencies:** + ```bash + pnpm install + # or + npm install + # or + yarn install + ``` + +2. **Set up environment variables:** + - Create a `.env.local` file with: + ```env + NEXT_PUBLIC_GRAPHQL_URL=your-graphql-http-endpoint + NEXT_PUBLIC_WS_URL=your-graphql-ws-endpoint + ``` + +3. **Run the development server:** + ```bash + pnpm dev + # or + npm run dev + # or + yarn dev + ``` + Open [http://localhost:3000](http://localhost:3000) in your browser. + +## Project Structure +- `src/app/` — App Router pages, layouts, and routes (including movies, scenes, auth) +- `src/components/` — UI components (SceneList, MovieCard, Navbar, etc.) +- `src/lib/graphql/` — Apollo Client setup, queries, mutations, subscriptions +- `src/hooks/` — Custom React hooks (e.g., `useSongWithLiveStatus`) +- `src/types/` — TypeScript type definitions +- `src/styles/` — Global and Tailwind styles + +## GraphQL Usage +- **Apollo Client** is set up in `src/lib/graphql/client.ts` with HTTP and WebSocket links for queries/mutations and subscriptions. +- **Queries:** + - Example: `GET_SONG_BY_ID`, `GET_SCENES`, `GET_MOVIES` in `src/lib/graphql/queries/` +- **Mutations:** + - Example: `UPDATE_SONG_LICENSE_STATUS` in `src/lib/graphql/mutations/songs.ts` +- **Subscriptions:** + - Example: `LICENSE_STATUS_UPDATED` in `src/lib/graphql/subscriptions/license-status.ts` +- **Custom Hooks:** + - `useSongWithLiveStatus(song)` — Combines query and subscription for live song status + +## Linting & Formatting +- Run `pnpm lint` or `pnpm format` to lint/format code with Biome. +- Type-check with `pnpm type-check`. + +## TypeScript +- Full TypeScript support with strict settings (`tsconfig.json`) +- Types in `src/types/` + +## Styling +- TailwindCSS is used for all styling. See `src/styles/globals.css`. + +## Contributing +Pull requests are welcome! Please lint, format, and type-check your code before submitting. + +--- + +For more, see the source code and comments throughout the project. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + diff --git a/examples/music-licensing-challenge-nextjs/biome.json b/examples/music-licensing-challenge-nextjs/biome.json new file mode 100644 index 0000000..1613dc6 --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/biome.json @@ -0,0 +1,54 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", + "vcs": { + "enabled": false, + "clientKind": "git", + "useIgnoreFile": false + }, + "files": { + "ignoreUnknown": false, + "ignore": [".next"], + "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx", "**/*.css"] + }, + "formatter": { + "enabled": true, + "indentStyle": "tab" + }, + "organizeImports": { + "enabled": true + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "suspicious": { + "noArrayIndexKey": "warn" + }, + "a11y": { + "useAltText": "warn", + "useValidAnchor": "warn", + "noSvgWithoutTitle": "warn" + }, + "complexity": { + "noExtraBooleanCast": "warn" + }, + "correctness": { + "noUnusedVariables": "error", + "noUnusedImports": "error" + } + } + }, + "javascript": { + "formatter": { + "arrowParentheses": "always", + "bracketSameLine": false, + "bracketSpacing": true, + "semicolons": "always", + "trailingCommas": "all", + "jsxQuoteStyle": "double", + "quoteProperties": "asNeeded", + "lineWidth": 80, + "indentWidth": 2 + } + } +} diff --git a/examples/music-licensing-challenge-nextjs/env.example b/examples/music-licensing-challenge-nextjs/env.example new file mode 100644 index 0000000..ad279a6 --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/env.example @@ -0,0 +1,7 @@ +NEXT_PUBLIC_API_BASE_URL= +NEXT_PUBLIC_AUTH_SECRET= +NEXT_PUBLIC_USER_EXAMPLE= +NEXT_PUBLIC_PASSWORD_EXAMPLE= +NEXT_PUBLIC_WS_URL= +NEXT_PUBLIC_GRAPHQL_URL= +NEXTAUTH_URL= diff --git a/examples/music-licensing-challenge-nextjs/next-env.d.ts b/examples/music-licensing-challenge-nextjs/next-env.d.ts new file mode 100644 index 0000000..1b3be08 --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/examples/music-licensing-challenge-nextjs/next.config.ts b/examples/music-licensing-challenge-nextjs/next.config.ts new file mode 100644 index 0000000..f38d952 --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/next.config.ts @@ -0,0 +1,17 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + images: { + remotePatterns: [ + { + protocol: "https", + hostname: "**", + }, + ], + }, + eslint: { + ignoreDuringBuilds: true, + }, +}; + +export default nextConfig; diff --git a/examples/music-licensing-challenge-nextjs/package.json b/examples/music-licensing-challenge-nextjs/package.json new file mode 100644 index 0000000..561b73b --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/package.json @@ -0,0 +1,41 @@ +{ + "name": "music-licensing-challenge", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev --turbopack", + "build": "next build", + "start": "next start", + "lint": "biome lint --write", + "lint:check": "biome lint --diagnostic-level=error", + "format": "biome format --write", + "format:check": "biome format", + "prepare": "husky || true", + "lint-staged": "lint-staged", + "type-check": "tsc --noEmit" + }, + "dependencies": { + "@apollo/client": "^3.13.8", + "@apollo/client-integration-nextjs": "^0.12.2", + "@headlessui/react": "^2.2.1", + "@heroicons/react": "^2.2.0", + "@tailwindcss/postcss": "^4.1.3", + "clsx": "^2.1.1", + "graphql-ws": "^6.0.4", + "next": "15.2.5", + "next-auth": "5.0.0-beta.25", + "postcss": "^8.5.3", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "tailwindcss": "^4.1.3" + }, + "devDependencies": { + "@biomejs/biome": "^1.9.4", + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "husky": "^9.1.7", + "lint-staged": "^15.5.0", + "typescript": "^5" + } +} diff --git a/examples/music-licensing-challenge-nextjs/pnpm-lock.yaml b/examples/music-licensing-challenge-nextjs/pnpm-lock.yaml new file mode 100644 index 0000000..e8c003e --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/pnpm-lock.yaml @@ -0,0 +1,1996 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@apollo/client': + specifier: ^3.13.8 + version: 3.13.8(@types/react@19.1.2)(graphql-ws@6.0.4(graphql@16.11.0))(graphql@16.11.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@apollo/client-integration-nextjs': + specifier: ^0.12.2 + version: 0.12.2(@apollo/client@3.13.8(@types/react@19.1.2)(graphql-ws@6.0.4(graphql@16.11.0))(graphql@16.11.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@types/react@19.1.2)(graphql@16.11.0)(next@15.2.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@headlessui/react': + specifier: ^2.2.1 + version: 2.2.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@heroicons/react': + specifier: ^2.2.0 + version: 2.2.0(react@19.1.0) + '@tailwindcss/postcss': + specifier: ^4.1.3 + version: 4.1.4 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + graphql-ws: + specifier: ^6.0.4 + version: 6.0.4(graphql@16.11.0) + next: + specifier: 15.2.5 + version: 15.2.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + next-auth: + specifier: 5.0.0-beta.25 + version: 5.0.0-beta.25(next@15.2.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0) + postcss: + specifier: ^8.5.3 + version: 8.5.3 + react: + specifier: ^19.0.0 + version: 19.1.0 + react-dom: + specifier: ^19.0.0 + version: 19.1.0(react@19.1.0) + tailwindcss: + specifier: ^4.1.3 + version: 4.1.4 + devDependencies: + '@biomejs/biome': + specifier: ^1.9.4 + version: 1.9.4 + '@types/node': + specifier: ^20 + version: 20.17.32 + '@types/react': + specifier: ^19 + version: 19.1.2 + '@types/react-dom': + specifier: ^19 + version: 19.1.2(@types/react@19.1.2) + husky: + specifier: ^9.1.7 + version: 9.1.7 + lint-staged: + specifier: ^15.5.0 + version: 15.5.1 + typescript: + specifier: ^5 + version: 5.8.3 + +packages: + + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + '@apollo/client-integration-nextjs@0.12.2': + resolution: {integrity: sha512-Nsoe/onkEqCfIcQfoklnimRGibtaYXmkst6moXJw9Jl0sFqxpEyNMv3xvdPXItN6lZABBeKM8N+u+/7iqyZDig==} + peerDependencies: + '@apollo/client': ^3.13.0 + next: ^15.2.3 + react: ^19 + + '@apollo/client-react-streaming@0.12.2': + resolution: {integrity: sha512-zVc6QmvvR+9DZaLPUES1Rp63MC2VAnvHJC7gNVagH5kI3IZgeJGNgxKX/RMpYJ2+a2EclOG50czFCD7XkXe24w==} + peerDependencies: + '@apollo/client': ^3.13.0 + graphql: ^16 || >=17.0.0-alpha.2 + react: ^19 + react-dom: ^19 + + '@apollo/client@3.13.8': + resolution: {integrity: sha512-YM9lQpm0VfVco4DSyKooHS/fDTiKQcCHfxr7i3iL6a0kP/jNO5+4NFK6vtRDxaYisd5BrwOZHLJpPBnvRVpKPg==} + peerDependencies: + graphql: ^15.0.0 || ^16.0.0 + graphql-ws: ^5.5.5 || ^6.0.3 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc + subscriptions-transport-ws: ^0.9.0 || ^0.11.0 + peerDependenciesMeta: + graphql-ws: + optional: true + react: + optional: true + react-dom: + optional: true + subscriptions-transport-ws: + optional: true + + '@auth/core@0.37.2': + resolution: {integrity: sha512-kUvzyvkcd6h1vpeMAojK2y7+PAV5H+0Cc9+ZlKYDFhDY31AlvsB+GW5vNO4qE3Y07KeQgvNO9U0QUx/fN62kBw==} + peerDependencies: + '@simplewebauthn/browser': ^9.0.1 + '@simplewebauthn/server': ^9.0.2 + nodemailer: ^6.8.0 + peerDependenciesMeta: + '@simplewebauthn/browser': + optional: true + '@simplewebauthn/server': + optional: true + nodemailer: + optional: true + + '@biomejs/biome@1.9.4': + resolution: {integrity: sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==} + engines: {node: '>=14.21.3'} + hasBin: true + + '@biomejs/cli-darwin-arm64@1.9.4': + resolution: {integrity: sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [darwin] + + '@biomejs/cli-darwin-x64@1.9.4': + resolution: {integrity: sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [darwin] + + '@biomejs/cli-linux-arm64-musl@1.9.4': + resolution: {integrity: sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + + '@biomejs/cli-linux-arm64@1.9.4': + resolution: {integrity: sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + + '@biomejs/cli-linux-x64-musl@1.9.4': + resolution: {integrity: sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + + '@biomejs/cli-linux-x64@1.9.4': + resolution: {integrity: sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + + '@biomejs/cli-win32-arm64@1.9.4': + resolution: {integrity: sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [win32] + + '@biomejs/cli-win32-x64@1.9.4': + resolution: {integrity: sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [win32] + + '@emnapi/runtime@1.4.3': + resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==} + + '@floating-ui/core@1.6.9': + resolution: {integrity: sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==} + + '@floating-ui/dom@1.6.13': + resolution: {integrity: sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==} + + '@floating-ui/react-dom@2.1.2': + resolution: {integrity: sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/react@0.26.28': + resolution: {integrity: sha512-yORQuuAtVpiRjpMhdc0wJj06b9JFjrYF4qp96j++v2NBpbi6SEGF7donUJ3TMieerQ6qVkAv1tgr7L4r5roTqw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.9': + resolution: {integrity: sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==} + + '@graphql-typed-document-node/core@3.2.0': + resolution: {integrity: sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==} + peerDependencies: + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + + '@headlessui/react@2.2.2': + resolution: {integrity: sha512-zbniWOYBQ8GHSUIOPY7BbdIn6PzUOq0z41RFrF30HbjsxG6Rrfk+6QulR8Kgf2Vwj2a/rE6i62q5vo+2gI5dJA==} + engines: {node: '>=10'} + peerDependencies: + react: ^18 || ^19 || ^19.0.0-rc + react-dom: ^18 || ^19 || ^19.0.0-rc + + '@heroicons/react@2.2.0': + resolution: {integrity: sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ==} + peerDependencies: + react: '>= 16 || ^19.0.0-rc' + + '@img/sharp-darwin-arm64@0.33.5': + resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.33.5': + resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.0.4': + resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.0.4': + resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.0.4': + resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linux-arm@1.0.5': + resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.0.4': + resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} + cpu: [s390x] + os: [linux] + + '@img/sharp-libvips-linux-x64@1.0.4': + resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.0.4': + resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} + cpu: [x64] + os: [linux] + + '@img/sharp-linux-arm64@0.33.5': + resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linux-arm@0.33.5': + resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + + '@img/sharp-linux-s390x@0.33.5': + resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + + '@img/sharp-linux-x64@0.33.5': + resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-linuxmusl-arm64@0.33.5': + resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linuxmusl-x64@0.33.5': + resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-wasm32@0.33.5': + resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-ia32@0.33.5': + resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.33.5': + resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@next/env@15.2.5': + resolution: {integrity: sha512-uWkCf9C8wKTyQjqrNk+BA7eL3LOQdhL+xlmJUf2O85RM4lbzwBwot3Sqv2QGe/RGnc3zysIf1oJdtq9S00pkmQ==} + + '@next/swc-darwin-arm64@15.2.5': + resolution: {integrity: sha512-4OimvVlFTbgzPdA0kh8A1ih6FN9pQkL4nPXGqemEYgk+e7eQhsst/p35siNNqA49eQA6bvKZ1ASsDtu9gtXuog==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@next/swc-darwin-x64@15.2.5': + resolution: {integrity: sha512-ohzRaE9YbGt1ctE0um+UGYIDkkOxHV44kEcHzLqQigoRLaiMtZzGrA11AJh2Lu0lv51XeiY1ZkUvkThjkVNBMA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@next/swc-linux-arm64-gnu@15.2.5': + resolution: {integrity: sha512-FMSdxSUt5bVXqqOoZCc/Seg4LQep9w/fXTazr/EkpXW2Eu4IFI9FD7zBDlID8TJIybmvKk7mhd9s+2XWxz4flA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@next/swc-linux-arm64-musl@15.2.5': + resolution: {integrity: sha512-4ZNKmuEiW5hRKkGp2HWwZ+JrvK4DQLgf8YDaqtZyn7NYdl0cHfatvlnLFSWUayx9yFAUagIgRGRk8pFxS8Qniw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@next/swc-linux-x64-gnu@15.2.5': + resolution: {integrity: sha512-bE6lHQ9GXIf3gCDE53u2pTl99RPZW5V1GLHSRMJ5l/oB/MT+cohu9uwnCK7QUph2xIOu2a6+27kL0REa/kqwZw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@next/swc-linux-x64-musl@15.2.5': + resolution: {integrity: sha512-y7EeQuSkQbTAkCEQnJXm1asRUuGSWAchGJ3c+Qtxh8LVjXleZast8Mn/rL7tZOm7o35QeIpIcid6ufG7EVTTcA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@next/swc-win32-arm64-msvc@15.2.5': + resolution: {integrity: sha512-gQMz0yA8/dskZM2Xyiq2FRShxSrsJNha40Ob/M2n2+JGRrZ0JwTVjLdvtN6vCxuq4ByhOd4a9qEf60hApNR2gQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@next/swc-win32-x64-msvc@15.2.5': + resolution: {integrity: sha512-tBDNVUcI7U03+3oMvJ11zrtVin5p0NctiuKmTGyaTIEAVj9Q77xukLXGXRnWxKRIIdFG4OTA2rUVGZDYOwgmAA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@panva/hkdf@1.2.1': + resolution: {integrity: sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==} + + '@react-aria/focus@3.20.2': + resolution: {integrity: sha512-Q3rouk/rzoF/3TuH6FzoAIKrl+kzZi9LHmr8S5EqLAOyP9TXIKG34x2j42dZsAhrw7TbF9gA8tBKwnCNH4ZV+Q==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + + '@react-aria/interactions@3.25.0': + resolution: {integrity: sha512-GgIsDLlO8rDU/nFn6DfsbP9rfnzhm8QFjZkB9K9+r+MTSCn7bMntiWQgMM+5O6BiA8d7C7x4zuN4bZtc0RBdXQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + + '@react-aria/ssr@3.9.8': + resolution: {integrity: sha512-lQDE/c9uTfBSDOjaZUJS8xP2jCKVk4zjQeIlCH90xaLhHDgbpCdns3xvFpJJujfj3nI4Ll9K7A+ONUBDCASOuw==} + engines: {node: '>= 12'} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + + '@react-aria/utils@3.28.2': + resolution: {integrity: sha512-J8CcLbvnQgiBn54eeEvQQbIOfBF3A1QizxMw9P4cl9MkeR03ug7RnjTIdJY/n2p7t59kLeAB3tqiczhcj+Oi5w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + + '@react-stately/flags@3.1.1': + resolution: {integrity: sha512-XPR5gi5LfrPdhxZzdIlJDz/B5cBf63l4q6/AzNqVWFKgd0QqY5LvWJftXkklaIUpKSJkIKQb8dphuZXDtkWNqg==} + + '@react-stately/utils@3.10.6': + resolution: {integrity: sha512-O76ip4InfTTzAJrg8OaZxKU4vvjMDOpfA/PGNOytiXwBbkct2ZeZwaimJ8Bt9W1bj5VsZ81/o/tW4BacbdDOMA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + + '@react-types/shared@3.29.0': + resolution: {integrity: sha512-IDQYu/AHgZimObzCFdNl1LpZvQW/xcfLt3v20sorl5qRucDVj4S9os98sVTZ4IRIBjmS+MkjqpR5E70xan7ooA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 + + '@swc/counter@0.1.3': + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + + '@swc/helpers@0.5.17': + resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==} + + '@tailwindcss/node@4.1.4': + resolution: {integrity: sha512-MT5118zaiO6x6hNA04OWInuAiP1YISXql8Z+/Y8iisV5nuhM8VXlyhRuqc2PEviPszcXI66W44bCIk500Oolhw==} + + '@tailwindcss/oxide-android-arm64@4.1.4': + resolution: {integrity: sha512-xMMAe/SaCN/vHfQYui3fqaBDEXMu22BVwQ33veLc8ep+DNy7CWN52L+TTG9y1K397w9nkzv+Mw+mZWISiqhmlA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.1.4': + resolution: {integrity: sha512-JGRj0SYFuDuAGilWFBlshcexev2hOKfNkoX+0QTksKYq2zgF9VY/vVMq9m8IObYnLna0Xlg+ytCi2FN2rOL0Sg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.1.4': + resolution: {integrity: sha512-sdDeLNvs3cYeWsEJ4H1DvjOzaGios4QbBTNLVLVs0XQ0V95bffT3+scptzYGPMjm7xv4+qMhCDrkHwhnUySEzA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.1.4': + resolution: {integrity: sha512-VHxAqxqdghM83HslPhRsNhHo91McsxRJaEnShJOMu8mHmEj9Ig7ToHJtDukkuLWLzLboh2XSjq/0zO6wgvykNA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.4': + resolution: {integrity: sha512-OTU/m/eV4gQKxy9r5acuesqaymyeSCnsx1cFto/I1WhPmi5HDxX1nkzb8KYBiwkHIGg7CTfo/AcGzoXAJBxLfg==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.4': + resolution: {integrity: sha512-hKlLNvbmUC6z5g/J4H+Zx7f7w15whSVImokLPmP6ff1QqTVE+TxUM9PGuNsjHvkvlHUtGTdDnOvGNSEUiXI1Ww==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.1.4': + resolution: {integrity: sha512-X3As2xhtgPTY/m5edUtddmZ8rCruvBvtxYLMw9OsZdH01L2gS2icsHRwxdU0dMItNfVmrBezueXZCHxVeeb7Aw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.1.4': + resolution: {integrity: sha512-2VG4DqhGaDSmYIu6C4ua2vSLXnJsb/C9liej7TuSO04NK+JJJgJucDUgmX6sn7Gw3Cs5ZJ9ZLrnI0QRDOjLfNQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.1.4': + resolution: {integrity: sha512-v+mxVgH2kmur/X5Mdrz9m7TsoVjbdYQT0b4Z+dr+I4RvreCNXyCFELZL/DO0M1RsidZTrm6O1eMnV6zlgEzTMQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.1.4': + resolution: {integrity: sha512-2TLe9ir+9esCf6Wm+lLWTMbgklIjiF0pbmDnwmhR9MksVOq+e8aP3TSsXySnBDDvTTVd/vKu1aNttEGj3P6l8Q==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.4': + resolution: {integrity: sha512-VlnhfilPlO0ltxW9/BgfLI5547PYzqBMPIzRrk4W7uupgCt8z6Trw/tAj6QUtF2om+1MH281Pg+HHUJoLesmng==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.1.4': + resolution: {integrity: sha512-+7S63t5zhYjslUGb8NcgLpFXD+Kq1F/zt5Xv5qTv7HaFTG/DHyHD9GA6ieNAxhgyA4IcKa/zy7Xx4Oad2/wuhw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.1.4': + resolution: {integrity: sha512-p5wOpXyOJx7mKh5MXh5oKk+kqcz8T+bA3z/5VWWeQwFrmuBItGwz8Y2CHk/sJ+dNb9B0nYFfn0rj/cKHZyjahQ==} + engines: {node: '>= 10'} + + '@tailwindcss/postcss@4.1.4': + resolution: {integrity: sha512-bjV6sqycCEa+AQSt2Kr7wpGF1bOZJ5wsqnLEkqSbM/JEHxx/yhMH8wHmdkPyApF9xhHeMSwnnkDUUMMM/hYnXw==} + + '@tanstack/react-virtual@3.13.6': + resolution: {integrity: sha512-WT7nWs8ximoQ0CDx/ngoFP7HbQF9Q2wQe4nh2NB+u2486eX3nZRE40P9g6ccCVq7ZfTSH5gFOuCoVH5DLNS/aA==} + 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 + + '@tanstack/virtual-core@3.13.6': + resolution: {integrity: sha512-cnQUeWnhNP8tJ4WsGcYiX24Gjkc9ALstLbHcBj1t3E7EimN6n6kHH+DPV4PpDnuw00NApQp+ViojMj1GRdwYQg==} + + '@types/cookie@0.6.0': + resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} + + '@types/node@20.17.32': + resolution: {integrity: sha512-zeMXFn8zQ+UkjK4ws0RiOC9EWByyW1CcVmLe+2rQocXRsGEDxUCwPEIVgpsGcLHS/P8JkT0oa3839BRABS0oPw==} + + '@types/react-dom@19.1.2': + resolution: {integrity: sha512-XGJkWF41Qq305SKWEILa1O8vzhb3aOo3ogBlSmiqNko/WmRb6QIaweuZCXjKygVDXpzXb5wyxKTSOsmkuqj+Qw==} + peerDependencies: + '@types/react': ^19.0.0 + + '@types/react@19.1.2': + resolution: {integrity: sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==} + + '@wry/caches@1.0.1': + resolution: {integrity: sha512-bXuaUNLVVkD20wcGBWRyo7j9N3TxePEWFZj2Y+r9OoUzfqmavM84+mFykRicNsBqatba5JLay1t48wxaXaWnlA==} + engines: {node: '>=8'} + + '@wry/context@0.7.4': + resolution: {integrity: sha512-jmT7Sb4ZQWI5iyu3lobQxICu2nC/vbUhP0vIdd6tHC9PTfenmRmuIFqktc6GH9cgi+ZHnsLWPvfSvc4DrYmKiQ==} + engines: {node: '>=8'} + + '@wry/equality@0.5.7': + resolution: {integrity: sha512-BRFORjsTuQv5gxcXsuDXx6oGRhuVsEGwZy6LOzRRfgu+eSfxbhUQ9L9YtSEIuIjY/o7g3iWFjrc5eSY1GXP2Dw==} + engines: {node: '>=8'} + + '@wry/trie@0.5.0': + resolution: {integrity: sha512-FNoYzHawTMk/6KMQoEG5O4PuioX19UbwdQKF44yw0nLfOypfQdjtfZzo/UIJWAJ23sNIFbD1Ug9lbaDGMwbqQA==} + engines: {node: '>=8'} + + ansi-escapes@7.0.0: + resolution: {integrity: sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==} + engines: {node: '>=18'} + + ansi-regex@6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + engines: {node: '>=12'} + + ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + busboy@1.6.0: + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} + engines: {node: '>=10.16.0'} + + caniuse-lite@1.0.30001715: + resolution: {integrity: sha512-7ptkFGMm2OAOgvZpwgA4yjQ5SQbrNVGdRjzH0pBdy1Fasvcr+KAeECmbCAECzTuDuoX0FCY8KzUxjf9+9kfZEw==} + + chalk@5.4.1: + resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} + + cli-truncate@4.0.0: + resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==} + engines: {node: '>=18'} + + client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + color-string@1.9.1: + resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + + color@4.2.3: + resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} + engines: {node: '>=12.5.0'} + + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + + commander@13.1.0: + resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} + engines: {node: '>=18'} + + cookie@0.7.1: + resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} + engines: {node: '>= 0.6'} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + debug@4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + detect-libc@2.0.4: + resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} + engines: {node: '>=8'} + + emoji-regex@10.4.0: + resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} + + enhanced-resolve@5.18.1: + resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==} + engines: {node: '>=10.13.0'} + + environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} + + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + + execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + get-east-asian-width@1.3.0: + resolution: {integrity: sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==} + engines: {node: '>=18'} + + get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + graphql-tag@2.12.6: + resolution: {integrity: sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==} + engines: {node: '>=10'} + peerDependencies: + graphql: ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 + + graphql-ws@6.0.4: + resolution: {integrity: sha512-8b4OZtNOvv8+NZva8HXamrc0y1jluYC0+13gdh7198FKjVzXyTvVc95DCwGzaKEfn3YuWZxUqjJlHe3qKM/F2g==} + engines: {node: '>=20'} + peerDependencies: + '@fastify/websocket': ^10 || ^11 + graphql: ^15.10.1 || ^16 + uWebSockets.js: ^20 + ws: ^8 + peerDependenciesMeta: + '@fastify/websocket': + optional: true + uWebSockets.js: + optional: true + ws: + optional: true + + graphql@16.11.0: + resolution: {integrity: sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + + hoist-non-react-statics@3.3.2: + resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + + human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + + husky@9.1.7: + resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==} + engines: {node: '>=18'} + hasBin: true + + is-arrayish@0.3.2: + resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} + + is-fullwidth-code-point@4.0.0: + resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} + engines: {node: '>=12'} + + is-fullwidth-code-point@5.0.0: + resolution: {integrity: sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==} + engines: {node: '>=18'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jiti@2.4.2: + resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} + hasBin: true + + jose@5.10.0: + resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + lightningcss-darwin-arm64@1.29.2: + resolution: {integrity: sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.29.2: + resolution: {integrity: sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.29.2: + resolution: {integrity: sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.29.2: + resolution: {integrity: sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.29.2: + resolution: {integrity: sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.29.2: + resolution: {integrity: sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.29.2: + resolution: {integrity: sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.29.2: + resolution: {integrity: sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.29.2: + resolution: {integrity: sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.29.2: + resolution: {integrity: sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.29.2: + resolution: {integrity: sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA==} + engines: {node: '>= 12.0.0'} + + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + lint-staged@15.5.1: + resolution: {integrity: sha512-6m7u8mue4Xn6wK6gZvSCQwBvMBR36xfY24nF5bMTf2MHDYG6S3yhJuOgdYVw99hsjyDt2d4z168b3naI8+NWtQ==} + engines: {node: '>=18.12.0'} + hasBin: true + + listr2@8.3.2: + resolution: {integrity: sha512-vsBzcU4oE+v0lj4FhVLzr9dBTv4/fHIa57l+GCwovP8MoFNZJTOhGU8PXd4v2VJCbECAaijBiHntiekFMLvo0g==} + engines: {node: '>=18.0.0'} + + log-update@6.1.0: + resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} + engines: {node: '>=18'} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + + mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + next-auth@5.0.0-beta.25: + resolution: {integrity: sha512-2dJJw1sHQl2qxCrRk+KTQbeH+izFbGFPuJj5eGgBZFYyiYYtvlrBeUw1E/OJJxTRjuxbSYGnCTkUIRsIIW0bog==} + peerDependencies: + '@simplewebauthn/browser': ^9.0.1 + '@simplewebauthn/server': ^9.0.2 + next: ^14.0.0-0 || ^15.0.0-0 + nodemailer: ^6.6.5 + react: ^18.2.0 || ^19.0.0-0 + peerDependenciesMeta: + '@simplewebauthn/browser': + optional: true + '@simplewebauthn/server': + optional: true + nodemailer: + optional: true + + next@15.2.5: + resolution: {integrity: sha512-LlqS8ljc7RWR3riUwxB5+14v7ULAa5EuLUyarD/sFgXPd6Hmmscg8DXcu9hDdh5atybrIDVBrFhjDpRIQo/4pQ==} + engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} + hasBin: true + 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 + + npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + oauth4webapi@3.5.0: + resolution: {integrity: sha512-DF3mLWNuxPkxJkHmWxbSFz4aE5CjWOsm465VBfBdWzmzX4Mg3vF8icxK+iKqfdWrIumBJ2TaoNQWx+SQc2bsPQ==} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + + onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} + + optimism@0.18.1: + resolution: {integrity: sha512-mLXNwWPa9dgFyDqkNi54sjDyNJ9/fTI6WGBLgnXku1vdKY/jovHfZT5r+aiVeFFLOz+foPNOm5YJ4mqgld2GBQ==} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + pidtree@0.6.0: + resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} + engines: {node: '>=0.10'} + hasBin: true + + postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + + postcss@8.5.3: + resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} + engines: {node: ^10 || ^12 || >=14} + + preact-render-to-string@5.2.3: + resolution: {integrity: sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA==} + peerDependencies: + preact: '>=10' + + preact@10.11.3: + resolution: {integrity: sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg==} + + pretty-format@3.8.0: + resolution: {integrity: sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==} + + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + + react-dom@19.1.0: + resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==} + peerDependencies: + react: ^19.1.0 + + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + react@19.1.0: + resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==} + engines: {node: '>=0.10.0'} + + rehackt@0.1.0: + resolution: {integrity: sha512-7kRDOuLHB87D/JESKxQoRwv4DzbIdwkAGQ7p6QKGdVlY1IZheUnVhlk/4UZlNUVxdAXpyxikE3URsG067ybVzw==} + peerDependencies: + '@types/react': '*' + react: '*' + peerDependenciesMeta: + '@types/react': + optional: true + react: + optional: true + + restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} + + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + + scheduler@0.26.0: + resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} + + semver@7.7.1: + resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} + engines: {node: '>=10'} + hasBin: true + + sharp@0.33.5: + resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + simple-swizzle@0.2.2: + resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} + + slice-ansi@5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + + slice-ansi@7.1.0: + resolution: {integrity: sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==} + engines: {node: '>=18'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + + string-argv@0.3.2: + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} + + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + + strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + + strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + + styled-jsx@5.1.6: + resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + 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 + + symbol-observable@4.0.0: + resolution: {integrity: sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==} + engines: {node: '>=0.10'} + + tabbable@6.2.0: + resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} + + tailwindcss@4.1.4: + resolution: {integrity: sha512-1ZIUqtPITFbv/DxRmDr5/agPqJwF69d24m9qmM1939TJehgY539CtzeZRjbLt5G6fSy/7YqqYsfvoTEw9xUI2A==} + + tapable@2.2.1: + resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} + engines: {node: '>=6'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + ts-invariant@0.10.3: + resolution: {integrity: sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ==} + engines: {node: '>=8'} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + typescript@5.8.3: + resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + + use-sync-external-store@1.5.0: + resolution: {integrity: sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + wrap-ansi@9.0.0: + resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==} + engines: {node: '>=18'} + + yaml@2.7.1: + resolution: {integrity: sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==} + engines: {node: '>= 14'} + hasBin: true + + zen-observable-ts@1.2.5: + resolution: {integrity: sha512-QZWQekv6iB72Naeake9hS1KxHlotfRpe+WGNbNx5/ta+R3DNjVO2bswf63gXlWDcs+EMd7XY8HfVQyP1X6T4Zg==} + + zen-observable@0.8.15: + resolution: {integrity: sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==} + +snapshots: + + '@alloc/quick-lru@5.2.0': {} + + '@apollo/client-integration-nextjs@0.12.2(@apollo/client@3.13.8(@types/react@19.1.2)(graphql-ws@6.0.4(graphql@16.11.0))(graphql@16.11.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@types/react@19.1.2)(graphql@16.11.0)(next@15.2.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@apollo/client': 3.13.8(@types/react@19.1.2)(graphql-ws@6.0.4(graphql@16.11.0))(graphql@16.11.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@apollo/client-react-streaming': 0.12.2(@apollo/client@3.13.8(@types/react@19.1.2)(graphql-ws@6.0.4(graphql@16.11.0))(graphql@16.11.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@types/react@19.1.2)(graphql@16.11.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + next: 15.2.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + transitivePeerDependencies: + - '@types/react' + - graphql + - react-dom + + '@apollo/client-react-streaming@0.12.2(@apollo/client@3.13.8(@types/react@19.1.2)(graphql-ws@6.0.4(graphql@16.11.0))(graphql@16.11.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(@types/react@19.1.2)(graphql@16.11.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@apollo/client': 3.13.8(@types/react@19.1.2)(graphql-ws@6.0.4(graphql@16.11.0))(graphql@16.11.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@types/react-dom': 19.1.2(@types/react@19.1.2) + '@wry/equality': 0.5.7 + graphql: 16.11.0 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + ts-invariant: 0.10.3 + transitivePeerDependencies: + - '@types/react' + + '@apollo/client@3.13.8(@types/react@19.1.2)(graphql-ws@6.0.4(graphql@16.11.0))(graphql@16.11.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@graphql-typed-document-node/core': 3.2.0(graphql@16.11.0) + '@wry/caches': 1.0.1 + '@wry/equality': 0.5.7 + '@wry/trie': 0.5.0 + graphql: 16.11.0 + graphql-tag: 2.12.6(graphql@16.11.0) + hoist-non-react-statics: 3.3.2 + optimism: 0.18.1 + prop-types: 15.8.1 + rehackt: 0.1.0(@types/react@19.1.2)(react@19.1.0) + symbol-observable: 4.0.0 + ts-invariant: 0.10.3 + tslib: 2.8.1 + zen-observable-ts: 1.2.5 + optionalDependencies: + graphql-ws: 6.0.4(graphql@16.11.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + transitivePeerDependencies: + - '@types/react' + + '@auth/core@0.37.2': + dependencies: + '@panva/hkdf': 1.2.1 + '@types/cookie': 0.6.0 + cookie: 0.7.1 + jose: 5.10.0 + oauth4webapi: 3.5.0 + preact: 10.11.3 + preact-render-to-string: 5.2.3(preact@10.11.3) + + '@biomejs/biome@1.9.4': + optionalDependencies: + '@biomejs/cli-darwin-arm64': 1.9.4 + '@biomejs/cli-darwin-x64': 1.9.4 + '@biomejs/cli-linux-arm64': 1.9.4 + '@biomejs/cli-linux-arm64-musl': 1.9.4 + '@biomejs/cli-linux-x64': 1.9.4 + '@biomejs/cli-linux-x64-musl': 1.9.4 + '@biomejs/cli-win32-arm64': 1.9.4 + '@biomejs/cli-win32-x64': 1.9.4 + + '@biomejs/cli-darwin-arm64@1.9.4': + optional: true + + '@biomejs/cli-darwin-x64@1.9.4': + optional: true + + '@biomejs/cli-linux-arm64-musl@1.9.4': + optional: true + + '@biomejs/cli-linux-arm64@1.9.4': + optional: true + + '@biomejs/cli-linux-x64-musl@1.9.4': + optional: true + + '@biomejs/cli-linux-x64@1.9.4': + optional: true + + '@biomejs/cli-win32-arm64@1.9.4': + optional: true + + '@biomejs/cli-win32-x64@1.9.4': + optional: true + + '@emnapi/runtime@1.4.3': + dependencies: + tslib: 2.8.1 + optional: true + + '@floating-ui/core@1.6.9': + dependencies: + '@floating-ui/utils': 0.2.9 + + '@floating-ui/dom@1.6.13': + dependencies: + '@floating-ui/core': 1.6.9 + '@floating-ui/utils': 0.2.9 + + '@floating-ui/react-dom@2.1.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@floating-ui/dom': 1.6.13 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + + '@floating-ui/react@0.26.28(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@floating-ui/react-dom': 2.1.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@floating-ui/utils': 0.2.9 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + tabbable: 6.2.0 + + '@floating-ui/utils@0.2.9': {} + + '@graphql-typed-document-node/core@3.2.0(graphql@16.11.0)': + dependencies: + graphql: 16.11.0 + + '@headlessui/react@2.2.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@floating-ui/react': 0.26.28(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@react-aria/focus': 3.20.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@react-aria/interactions': 3.25.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@tanstack/react-virtual': 3.13.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + use-sync-external-store: 1.5.0(react@19.1.0) + + '@heroicons/react@2.2.0(react@19.1.0)': + dependencies: + react: 19.1.0 + + '@img/sharp-darwin-arm64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.0.4 + optional: true + + '@img/sharp-darwin-x64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.0.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.0.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.0.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.0.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.0.5': + optional: true + + '@img/sharp-libvips-linux-s390x@1.0.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.0.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.0.4': + optional: true + + '@img/sharp-linux-arm64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.0.4 + optional: true + + '@img/sharp-linux-arm@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.0.5 + optional: true + + '@img/sharp-linux-s390x@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.0.4 + optional: true + + '@img/sharp-linux-x64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.0.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.33.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + optional: true + + '@img/sharp-wasm32@0.33.5': + dependencies: + '@emnapi/runtime': 1.4.3 + optional: true + + '@img/sharp-win32-ia32@0.33.5': + optional: true + + '@img/sharp-win32-x64@0.33.5': + optional: true + + '@next/env@15.2.5': {} + + '@next/swc-darwin-arm64@15.2.5': + optional: true + + '@next/swc-darwin-x64@15.2.5': + optional: true + + '@next/swc-linux-arm64-gnu@15.2.5': + optional: true + + '@next/swc-linux-arm64-musl@15.2.5': + optional: true + + '@next/swc-linux-x64-gnu@15.2.5': + optional: true + + '@next/swc-linux-x64-musl@15.2.5': + optional: true + + '@next/swc-win32-arm64-msvc@15.2.5': + optional: true + + '@next/swc-win32-x64-msvc@15.2.5': + optional: true + + '@panva/hkdf@1.2.1': {} + + '@react-aria/focus@3.20.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@react-aria/interactions': 3.25.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@react-aria/utils': 3.28.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@react-types/shared': 3.29.0(react@19.1.0) + '@swc/helpers': 0.5.17 + clsx: 2.1.1 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + + '@react-aria/interactions@3.25.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@react-aria/ssr': 3.9.8(react@19.1.0) + '@react-aria/utils': 3.28.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@react-stately/flags': 3.1.1 + '@react-types/shared': 3.29.0(react@19.1.0) + '@swc/helpers': 0.5.17 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + + '@react-aria/ssr@3.9.8(react@19.1.0)': + dependencies: + '@swc/helpers': 0.5.17 + react: 19.1.0 + + '@react-aria/utils@3.28.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@react-aria/ssr': 3.9.8(react@19.1.0) + '@react-stately/flags': 3.1.1 + '@react-stately/utils': 3.10.6(react@19.1.0) + '@react-types/shared': 3.29.0(react@19.1.0) + '@swc/helpers': 0.5.17 + clsx: 2.1.1 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + + '@react-stately/flags@3.1.1': + dependencies: + '@swc/helpers': 0.5.17 + + '@react-stately/utils@3.10.6(react@19.1.0)': + dependencies: + '@swc/helpers': 0.5.17 + react: 19.1.0 + + '@react-types/shared@3.29.0(react@19.1.0)': + dependencies: + react: 19.1.0 + + '@swc/counter@0.1.3': {} + + '@swc/helpers@0.5.15': + dependencies: + tslib: 2.8.1 + + '@swc/helpers@0.5.17': + dependencies: + tslib: 2.8.1 + + '@tailwindcss/node@4.1.4': + dependencies: + enhanced-resolve: 5.18.1 + jiti: 2.4.2 + lightningcss: 1.29.2 + tailwindcss: 4.1.4 + + '@tailwindcss/oxide-android-arm64@4.1.4': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.1.4': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.1.4': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.1.4': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.4': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.4': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.1.4': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.1.4': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.1.4': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.1.4': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.4': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.1.4': + optional: true + + '@tailwindcss/oxide@4.1.4': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.1.4 + '@tailwindcss/oxide-darwin-arm64': 4.1.4 + '@tailwindcss/oxide-darwin-x64': 4.1.4 + '@tailwindcss/oxide-freebsd-x64': 4.1.4 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.4 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.4 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.4 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.4 + '@tailwindcss/oxide-linux-x64-musl': 4.1.4 + '@tailwindcss/oxide-wasm32-wasi': 4.1.4 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.4 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.4 + + '@tailwindcss/postcss@4.1.4': + dependencies: + '@alloc/quick-lru': 5.2.0 + '@tailwindcss/node': 4.1.4 + '@tailwindcss/oxide': 4.1.4 + postcss: 8.5.3 + tailwindcss: 4.1.4 + + '@tanstack/react-virtual@3.13.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + dependencies: + '@tanstack/virtual-core': 3.13.6 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + + '@tanstack/virtual-core@3.13.6': {} + + '@types/cookie@0.6.0': {} + + '@types/node@20.17.32': + dependencies: + undici-types: 6.19.8 + + '@types/react-dom@19.1.2(@types/react@19.1.2)': + dependencies: + '@types/react': 19.1.2 + + '@types/react@19.1.2': + dependencies: + csstype: 3.1.3 + + '@wry/caches@1.0.1': + dependencies: + tslib: 2.8.1 + + '@wry/context@0.7.4': + dependencies: + tslib: 2.8.1 + + '@wry/equality@0.5.7': + dependencies: + tslib: 2.8.1 + + '@wry/trie@0.5.0': + dependencies: + tslib: 2.8.1 + + ansi-escapes@7.0.0: + dependencies: + environment: 1.1.0 + + ansi-regex@6.1.0: {} + + ansi-styles@6.2.1: {} + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + busboy@1.6.0: + dependencies: + streamsearch: 1.1.0 + + caniuse-lite@1.0.30001715: {} + + chalk@5.4.1: {} + + cli-cursor@5.0.0: + dependencies: + restore-cursor: 5.1.0 + + cli-truncate@4.0.0: + dependencies: + slice-ansi: 5.0.0 + string-width: 7.2.0 + + client-only@0.0.1: {} + + clsx@2.1.1: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + optional: true + + color-name@1.1.4: + optional: true + + color-string@1.9.1: + dependencies: + color-name: 1.1.4 + simple-swizzle: 0.2.2 + optional: true + + color@4.2.3: + dependencies: + color-convert: 2.0.1 + color-string: 1.9.1 + optional: true + + colorette@2.0.20: {} + + commander@13.1.0: {} + + cookie@0.7.1: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.1.3: {} + + debug@4.4.0: + dependencies: + ms: 2.1.3 + + detect-libc@2.0.4: {} + + emoji-regex@10.4.0: {} + + enhanced-resolve@5.18.1: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.1 + + environment@1.1.0: {} + + eventemitter3@5.0.1: {} + + execa@8.0.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.3.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + get-east-asian-width@1.3.0: {} + + get-stream@8.0.1: {} + + graceful-fs@4.2.11: {} + + graphql-tag@2.12.6(graphql@16.11.0): + dependencies: + graphql: 16.11.0 + tslib: 2.8.1 + + graphql-ws@6.0.4(graphql@16.11.0): + dependencies: + graphql: 16.11.0 + + graphql@16.11.0: {} + + hoist-non-react-statics@3.3.2: + dependencies: + react-is: 16.13.1 + + human-signals@5.0.0: {} + + husky@9.1.7: {} + + is-arrayish@0.3.2: + optional: true + + is-fullwidth-code-point@4.0.0: {} + + is-fullwidth-code-point@5.0.0: + dependencies: + get-east-asian-width: 1.3.0 + + is-number@7.0.0: {} + + is-stream@3.0.0: {} + + isexe@2.0.0: {} + + jiti@2.4.2: {} + + jose@5.10.0: {} + + js-tokens@4.0.0: {} + + lightningcss-darwin-arm64@1.29.2: + optional: true + + lightningcss-darwin-x64@1.29.2: + optional: true + + lightningcss-freebsd-x64@1.29.2: + optional: true + + lightningcss-linux-arm-gnueabihf@1.29.2: + optional: true + + lightningcss-linux-arm64-gnu@1.29.2: + optional: true + + lightningcss-linux-arm64-musl@1.29.2: + optional: true + + lightningcss-linux-x64-gnu@1.29.2: + optional: true + + lightningcss-linux-x64-musl@1.29.2: + optional: true + + lightningcss-win32-arm64-msvc@1.29.2: + optional: true + + lightningcss-win32-x64-msvc@1.29.2: + optional: true + + lightningcss@1.29.2: + dependencies: + detect-libc: 2.0.4 + optionalDependencies: + lightningcss-darwin-arm64: 1.29.2 + lightningcss-darwin-x64: 1.29.2 + lightningcss-freebsd-x64: 1.29.2 + lightningcss-linux-arm-gnueabihf: 1.29.2 + lightningcss-linux-arm64-gnu: 1.29.2 + lightningcss-linux-arm64-musl: 1.29.2 + lightningcss-linux-x64-gnu: 1.29.2 + lightningcss-linux-x64-musl: 1.29.2 + lightningcss-win32-arm64-msvc: 1.29.2 + lightningcss-win32-x64-msvc: 1.29.2 + + lilconfig@3.1.3: {} + + lint-staged@15.5.1: + dependencies: + chalk: 5.4.1 + commander: 13.1.0 + debug: 4.4.0 + execa: 8.0.1 + lilconfig: 3.1.3 + listr2: 8.3.2 + micromatch: 4.0.8 + pidtree: 0.6.0 + string-argv: 0.3.2 + yaml: 2.7.1 + transitivePeerDependencies: + - supports-color + + listr2@8.3.2: + dependencies: + cli-truncate: 4.0.0 + colorette: 2.0.20 + eventemitter3: 5.0.1 + log-update: 6.1.0 + rfdc: 1.4.1 + wrap-ansi: 9.0.0 + + log-update@6.1.0: + dependencies: + ansi-escapes: 7.0.0 + cli-cursor: 5.0.0 + slice-ansi: 7.1.0 + strip-ansi: 7.1.0 + wrap-ansi: 9.0.0 + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + merge-stream@2.0.0: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mimic-fn@4.0.0: {} + + mimic-function@5.0.1: {} + + ms@2.1.3: {} + + nanoid@3.3.11: {} + + next-auth@5.0.0-beta.25(next@15.2.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0): + dependencies: + '@auth/core': 0.37.2 + next: 15.2.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + react: 19.1.0 + + next@15.2.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + dependencies: + '@next/env': 15.2.5 + '@swc/counter': 0.1.3 + '@swc/helpers': 0.5.15 + busboy: 1.6.0 + caniuse-lite: 1.0.30001715 + postcss: 8.4.31 + react: 19.1.0 + react-dom: 19.1.0(react@19.1.0) + styled-jsx: 5.1.6(react@19.1.0) + optionalDependencies: + '@next/swc-darwin-arm64': 15.2.5 + '@next/swc-darwin-x64': 15.2.5 + '@next/swc-linux-arm64-gnu': 15.2.5 + '@next/swc-linux-arm64-musl': 15.2.5 + '@next/swc-linux-x64-gnu': 15.2.5 + '@next/swc-linux-x64-musl': 15.2.5 + '@next/swc-win32-arm64-msvc': 15.2.5 + '@next/swc-win32-x64-msvc': 15.2.5 + sharp: 0.33.5 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + + npm-run-path@5.3.0: + dependencies: + path-key: 4.0.0 + + oauth4webapi@3.5.0: {} + + object-assign@4.1.1: {} + + onetime@6.0.0: + dependencies: + mimic-fn: 4.0.0 + + onetime@7.0.0: + dependencies: + mimic-function: 5.0.1 + + optimism@0.18.1: + dependencies: + '@wry/caches': 1.0.1 + '@wry/context': 0.7.4 + '@wry/trie': 0.5.0 + tslib: 2.8.1 + + path-key@3.1.1: {} + + path-key@4.0.0: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + pidtree@0.6.0: {} + + postcss@8.4.31: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + postcss@8.5.3: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + preact-render-to-string@5.2.3(preact@10.11.3): + dependencies: + preact: 10.11.3 + pretty-format: 3.8.0 + + preact@10.11.3: {} + + pretty-format@3.8.0: {} + + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + + react-dom@19.1.0(react@19.1.0): + dependencies: + react: 19.1.0 + scheduler: 0.26.0 + + react-is@16.13.1: {} + + react@19.1.0: {} + + rehackt@0.1.0(@types/react@19.1.2)(react@19.1.0): + optionalDependencies: + '@types/react': 19.1.2 + react: 19.1.0 + + restore-cursor@5.1.0: + dependencies: + onetime: 7.0.0 + signal-exit: 4.1.0 + + rfdc@1.4.1: {} + + scheduler@0.26.0: {} + + semver@7.7.1: + optional: true + + sharp@0.33.5: + dependencies: + color: 4.2.3 + detect-libc: 2.0.4 + semver: 7.7.1 + 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 + optional: true + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + signal-exit@4.1.0: {} + + simple-swizzle@0.2.2: + dependencies: + is-arrayish: 0.3.2 + optional: true + + slice-ansi@5.0.0: + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 4.0.0 + + slice-ansi@7.1.0: + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 5.0.0 + + source-map-js@1.2.1: {} + + streamsearch@1.1.0: {} + + string-argv@0.3.2: {} + + string-width@7.2.0: + dependencies: + emoji-regex: 10.4.0 + get-east-asian-width: 1.3.0 + strip-ansi: 7.1.0 + + strip-ansi@7.1.0: + dependencies: + ansi-regex: 6.1.0 + + strip-final-newline@3.0.0: {} + + styled-jsx@5.1.6(react@19.1.0): + dependencies: + client-only: 0.0.1 + react: 19.1.0 + + symbol-observable@4.0.0: {} + + tabbable@6.2.0: {} + + tailwindcss@4.1.4: {} + + tapable@2.2.1: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + ts-invariant@0.10.3: + dependencies: + tslib: 2.8.1 + + tslib@2.8.1: {} + + typescript@5.8.3: {} + + undici-types@6.19.8: {} + + use-sync-external-store@1.5.0(react@19.1.0): + dependencies: + react: 19.1.0 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + wrap-ansi@9.0.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 7.2.0 + strip-ansi: 7.1.0 + + yaml@2.7.1: {} + + zen-observable-ts@1.2.5: + dependencies: + zen-observable: 0.8.15 + + zen-observable@0.8.15: {} diff --git a/examples/music-licensing-challenge-nextjs/postcss.config.mjs b/examples/music-licensing-challenge-nextjs/postcss.config.mjs new file mode 100644 index 0000000..a34a3d5 --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/postcss.config.mjs @@ -0,0 +1,5 @@ +export default { + plugins: { + '@tailwindcss/postcss': {}, + }, +}; diff --git a/examples/music-licensing-challenge-nextjs/src/app/(auth)/login/page.tsx b/examples/music-licensing-challenge-nextjs/src/app/(auth)/login/page.tsx new file mode 100644 index 0000000..ab53f3e --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/src/app/(auth)/login/page.tsx @@ -0,0 +1,53 @@ +"use client"; + +import { useState } from "react"; +import { logIn } from "@/lib/auth"; +import LoginForm from "@/components/LoginForm"; + +const LoginPage = () => { + const [credentials, setCredentials] = useState({ + email: "", + password: "", + }); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(""); + + const handleSubmit = async (event: React.FormEvent) => { + event.preventDefault(); + setLoading(true); + setError(""); + + try { + await logIn({ ...credentials }); + } catch (error) { + console.error(error); + setError("Something went wrong"); + } finally { + setLoading(false); + } + }; + + const handleChange = (event: React.ChangeEvent) => { + setError(""); + setCredentials({ ...credentials, [event.target.name]: event.target.value }); + }; + + const disableLoginButton = + loading || !credentials.email || !credentials.password; + + return ( +
+

Login Page

+ +
+ ); +}; + +export default LoginPage; diff --git a/examples/music-licensing-challenge-nextjs/src/app/(auth)/register/page.tsx b/examples/music-licensing-challenge-nextjs/src/app/(auth)/register/page.tsx new file mode 100644 index 0000000..add1ee4 --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/src/app/(auth)/register/page.tsx @@ -0,0 +1,5 @@ +const RegisterPage: React.FC = () => { + return

Register Page

; +}; + +export default RegisterPage; diff --git a/examples/music-licensing-challenge-nextjs/src/app/(movies)/(protected)/scenes/[sceneId]/page.tsx b/examples/music-licensing-challenge-nextjs/src/app/(movies)/(protected)/scenes/[sceneId]/page.tsx new file mode 100644 index 0000000..b6b23a9 --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/src/app/(movies)/(protected)/scenes/[sceneId]/page.tsx @@ -0,0 +1,34 @@ +import { SceneItem } from "@/components/SceneList/SceneItem"; +import { client } from "@/lib/graphql/client"; +import { GET_SCENE_BY_ID } from "@/lib/graphql/queries/scenes"; +import type { Scene } from "@/types"; + +interface ScenePageProps { + params: { + sceneId: string; + }; +} + +type SceneData = { + scene: Scene; +}; + +export default async function ScenePage({ params }: ScenePageProps) { + const { sceneId } = await params; + const { + data: { scene }, + } = await client.query({ + query: GET_SCENE_BY_ID, + variables: { id: sceneId }, + }); + + if (!scene) { + return
Scene not found
; + } + + return ( + <> + + + ); +} diff --git a/examples/music-licensing-challenge-nextjs/src/app/(movies)/(protected)/scenes/page.tsx b/examples/music-licensing-challenge-nextjs/src/app/(movies)/(protected)/scenes/page.tsx new file mode 100644 index 0000000..62450e4 --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/src/app/(movies)/(protected)/scenes/page.tsx @@ -0,0 +1,36 @@ +import { Input } from "@headlessui/react"; +import { Button } from "@/components/Button"; +import ScenesList from "@/components/SceneList"; +import { client } from "@/lib/graphql/client"; +import { GET_SCENES } from "@/lib/graphql/queries/scenes"; +import type { Scene } from "@/types"; + +type Scenes = { + allScenes: Scene[]; +}; + +const ScenePage = async () => { + const { + data: { allScenes }, + } = await client.query({ + query: GET_SCENES, + }); + return ( + <> +

Scenes

+ <> +
+ + +
+ + + + ); +}; + +export default ScenePage; diff --git a/examples/music-licensing-challenge-nextjs/src/app/(movies)/movies/[movieId]/page.tsx b/examples/music-licensing-challenge-nextjs/src/app/(movies)/movies/[movieId]/page.tsx new file mode 100644 index 0000000..546f573 --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/src/app/(movies)/movies/[movieId]/page.tsx @@ -0,0 +1,60 @@ +import { Input } from "@headlessui/react"; +import { Button } from "@/components/Button"; +import MovieCard from "@/components/MovieCard"; +import ScenesList from "@/components/SceneList"; +import MovieDetails from "@/components/MovieDetails"; +import { GET_MOVIE_BY_ID } from "@/lib/graphql/queries/movies"; +import { client } from "@/lib/graphql/client"; +import type { MoviesData } from "@/types"; + +interface Params { + movieId: string; +} + +type Movie = { + movie: MoviesData; +}; + +const MovieDetailsPage = async ({ params }: { params: Params }) => { + const { movieId } = await params; + const { + data: { movie }, + } = await client.query({ + query: GET_MOVIE_BY_ID, + variables: { id: movieId }, + }); + if (!movie) { + return

Movie not found

; + } + return ( + <> +

Movie Details

+
+
+
+ +
+
+ +
+
+
+
+ + +
+ +
+
+
+
+
+ + ); +}; + +export default MovieDetailsPage; diff --git a/examples/music-licensing-challenge-nextjs/src/app/(movies)/movies/page.tsx b/examples/music-licensing-challenge-nextjs/src/app/(movies)/movies/page.tsx new file mode 100644 index 0000000..021ea8c --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/src/app/(movies)/movies/page.tsx @@ -0,0 +1,32 @@ +import MovieCard from "@/components/MovieCard"; +import { client } from "@/lib/graphql/client"; +import { GET_MOVIES } from "@/lib/graphql/queries/movies"; +import type { MoviesData } from "@/types"; + +type Movies = { + allMovies: MoviesData[]; +}; + +const MoviesPage = async () => { + const { + data: { allMovies }, + } = await client.query({ + query: GET_MOVIES, + }); + return ( +
+

Movies Dashboard

+
+ {allMovies?.length === 0 ? ( +

No movies available.

+ ) : ( + allMovies?.map((movie) => ( + + )) + )} +
+
+ ); +}; + +export default MoviesPage; diff --git a/examples/music-licensing-challenge-nextjs/src/app/api/auth/[...nextauth]/route.ts b/examples/music-licensing-challenge-nextjs/src/app/api/auth/[...nextauth]/route.ts new file mode 100644 index 0000000..86c9f3d --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/src/app/api/auth/[...nextauth]/route.ts @@ -0,0 +1,3 @@ +import { handlers } from "@/auth"; + +export const { GET, POST } = handlers; diff --git a/examples/music-licensing-challenge-nextjs/src/app/error.tsx b/examples/music-licensing-challenge-nextjs/src/app/error.tsx new file mode 100644 index 0000000..25fc90e --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/src/app/error.tsx @@ -0,0 +1,11 @@ +"use client"; + +const ErrorPage = () => { + return ( + <> +

Error

+ + ); +}; + +export default ErrorPage; diff --git a/examples/music-licensing-challenge-nextjs/src/app/layout.tsx b/examples/music-licensing-challenge-nextjs/src/app/layout.tsx new file mode 100644 index 0000000..515f07b --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/src/app/layout.tsx @@ -0,0 +1,39 @@ +import type { Metadata } from "next"; +import { Geist, Geist_Mono } from "next/font/google"; +import Navbar from "@/components/Navbar"; +import "@/styles/globals.css"; + +const geistSans = Geist({ + variable: "--font-geist-sans", + subsets: ["latin"], +}); + +const geistMono = Geist_Mono({ + variable: "--font-geist-mono", + subsets: ["latin"], +}); + +export const metadata: Metadata = { + title: "Music Licensing App", + description: "manage music licensing", +}; + +export default async function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + +
+ +
{children}
+
+

© {new Date().getFullYear()} ACME BROS PICTURES

+
+
+ + + ); +} diff --git a/examples/music-licensing-challenge-nextjs/src/app/not-found.tsx b/examples/music-licensing-challenge-nextjs/src/app/not-found.tsx new file mode 100644 index 0000000..140e3a8 --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/src/app/not-found.tsx @@ -0,0 +1,9 @@ +const NotFoundPage = () => { + return ( + <> +

Page Not Found

+ + ); +}; + +export default NotFoundPage; diff --git a/examples/music-licensing-challenge-nextjs/src/app/page.tsx b/examples/music-licensing-challenge-nextjs/src/app/page.tsx new file mode 100644 index 0000000..f9a800b --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/src/app/page.tsx @@ -0,0 +1,17 @@ +import { APP_ROUTES } from "@/routes"; +import { Button } from "@/components/Button"; +import Link from "next/link"; + +const Home = () => { + return ( +
+

+ Welcome to our Music Licensing App! +

+ +
+ ); +}; +export default Home; diff --git a/examples/music-licensing-challenge-nextjs/src/auth/index.ts b/examples/music-licensing-challenge-nextjs/src/auth/index.ts new file mode 100644 index 0000000..80cb241 --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/src/auth/index.ts @@ -0,0 +1,35 @@ +import NextAuth from "next-auth"; +import CredentialsProvider from "next-auth/providers/credentials"; + +const userExample = process.env.NEXT_PUBLIC_USER_EXAMPLE; +const passwordExample = process.env.NEXT_PUBLIC_PASSWORD_EXAMPLE; + +export const { auth, handlers, signIn, signOut } = NextAuth({ + providers: [ + CredentialsProvider({ + name: "Credentials", + credentials: { + email: { + label: "Email", + type: "email", + placeholder: "example@example.com", + }, + password: { + label: "Password", + type: "password", + placeholder: "password", + }, + }, + authorize: async (credentials) => { + if ( + credentials?.email === userExample && + credentials?.password === passwordExample + ) { + return { email: userExample }; + } + throw new Error("Invalid credentials"); + }, + }), + ], + secret: process.env.NEXT_PUBLIC_AUTH_SECRET, +}); diff --git a/examples/music-licensing-challenge-nextjs/src/components/Button/index.tsx b/examples/music-licensing-challenge-nextjs/src/components/Button/index.tsx new file mode 100644 index 0000000..2d0eaf9 --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/src/components/Button/index.tsx @@ -0,0 +1,22 @@ +import type { ButtonHTMLAttributes, ReactNode } from "react"; +import { Button as BaseButton } from "@headlessui/react"; +import clsx from "clsx"; + +interface ButtonProps extends ButtonHTMLAttributes { + children: ReactNode; + className?: string; +} + +export const Button = ({ children, className, ...props }: ButtonProps) => { + return ( + + {children} + + ); +}; diff --git a/examples/music-licensing-challenge-nextjs/src/components/Dropdown/index.tsx b/examples/music-licensing-challenge-nextjs/src/components/Dropdown/index.tsx new file mode 100644 index 0000000..4591e34 --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/src/components/Dropdown/index.tsx @@ -0,0 +1,56 @@ +"use client"; + +import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react"; +import { ChevronDownIcon } from "@heroicons/react/20/solid"; + +interface DropdownOption { + label: string; + component: React.ReactNode; +} + +interface DropdownProps { + options: DropdownOption[]; + menuButtonContent?: React.ReactNode; + className?: string; +} + +const Dropdown = ({ + options = [], + menuButtonContent, + className, +}: DropdownProps) => { + return ( + +
+ + {menuButtonContent ? ( + menuButtonContent + ) : ( + <> + Options + +
+ + +
+ {options?.map((option) => ( + + {option.component} + + ))} +
+
+
+ ); +}; + +export default Dropdown; diff --git a/examples/music-licensing-challenge-nextjs/src/components/LoginForm/index.tsx b/examples/music-licensing-challenge-nextjs/src/components/LoginForm/index.tsx new file mode 100644 index 0000000..3535cbf --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/src/components/LoginForm/index.tsx @@ -0,0 +1,89 @@ +import Link from "next/link"; +import { Button } from "@/components/Button"; +import { APP_ROUTES } from "@/routes"; + +interface LoginFormProps { + credentials: { + email: string; + password: string; + }; + error: string; + handleSubmit: (event: React.FormEvent) => void; + handleChange: (event: React.ChangeEvent) => void; + loading: boolean; + disableLoginButton: boolean; +} + +const LoginForm: React.FC = ({ + credentials, + error, + handleSubmit, + handleChange, + loading, + disableLoginButton, +}) => { + return ( +
+ {error && ( +
+ {error} +
+ )} +
+ + +
+
+ + +
+
+ + + + Sign Up + +
+
+ ); +}; + +export default LoginForm; diff --git a/examples/music-licensing-challenge-nextjs/src/components/MovieCard/index.tsx b/examples/music-licensing-challenge-nextjs/src/components/MovieCard/index.tsx new file mode 100644 index 0000000..0e942f7 --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/src/components/MovieCard/index.tsx @@ -0,0 +1,44 @@ +import Link from "next/link"; +import Image from "next/image"; +import { Button } from "@/components/Button"; +import type { MoviesData } from "@/types"; +import { APP_ROUTES } from "@/routes"; + +const MovieCard = ({ + movie, + showActionButton = false, +}: { movie: MoviesData; showActionButton?: boolean }) => { + return ( +
+
+ {movie.title} +
+
+
+ {movie.title} +
+

+ {movie.description} +

+
+ {showActionButton && ( +
+ +
+ )} +
+ ); +}; + +export default MovieCard; diff --git a/examples/music-licensing-challenge-nextjs/src/components/MovieDetails/index.tsx b/examples/music-licensing-challenge-nextjs/src/components/MovieDetails/index.tsx new file mode 100644 index 0000000..46a7c25 --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/src/components/MovieDetails/index.tsx @@ -0,0 +1,42 @@ +import type { MoviesData } from "@/types"; + +interface MovieDetailsProps { + movie: MoviesData; +} + +type MovieDetailField = { + label: string; + value: string | number | string[]; +}; + +const MovieDetails: React.FC = ({ movie }) => { + const movieDetailsFields: MovieDetailField[] = [ + { label: "Year", value: movie.year }, + { label: "Genre", value: movie.genre }, + { label: "Director", value: movie.director }, + { label: "Total Scenes", value: movie.scenes.length }, + { + label: "Total Tracks", + value: movie.scenes.reduce( + (total, scene) => total + scene.tracks.length, + 0, + ), + }, + { label: "Description", value: movie.description }, + ]; + + return ( +
+ {movieDetailsFields.map((field) => ( +

+ {field.label}: + + {Array.isArray(field.value) ? field.value.join(", ") : field.value} + +

+ ))} +
+ ); +}; + +export default MovieDetails; diff --git a/examples/music-licensing-challenge-nextjs/src/components/Navbar/actionButtons.tsx b/examples/music-licensing-challenge-nextjs/src/components/Navbar/actionButtons.tsx new file mode 100644 index 0000000..7038f96 --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/src/components/Navbar/actionButtons.tsx @@ -0,0 +1,34 @@ +"use client"; + +import Link from "next/link"; +import { logOut } from "@/lib/auth"; +import { APP_ROUTES } from "@/routes"; + +const buttonStyles = + "hover:bg-gray-100 block w-full px-4 py-2 text-left text-sm text-gray-700"; + +export const SignOutButton = () => { + return ( + + ); +}; +export const YourMoviesButton = () => { + return ( + + Your movies + + ); +}; +export const SignInButton = () => { + return ( + + Sign in + + ); +}; diff --git a/examples/music-licensing-challenge-nextjs/src/components/Navbar/getNavbarLinks.tsx b/examples/music-licensing-challenge-nextjs/src/components/Navbar/getNavbarLinks.tsx new file mode 100644 index 0000000..54c2397 --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/src/components/Navbar/getNavbarLinks.tsx @@ -0,0 +1,43 @@ +import { APP_ROUTES } from "@/routes"; +import { getSession } from "@/lib/auth"; +import { SignOutButton, SignInButton, YourMoviesButton } from "./actionButtons"; + +export const getNavbarLinks = () => { + return Object.values(APP_ROUTES) + .map( + (route) => + route.isNavbarItem && { + name: route.name, + href: route.path, + isProtected: route.isProtected, + }, + ) + .filter(Boolean) as Array<{ + name: string; + href: string; + isProtected: boolean; + }>; +}; + +export const getMenuOptions = async () => { + const session = await getSession(); + if (session) { + return [ + { + label: "Your movies", + component: , + }, + { + label: "Sign out", + component: , + }, + ]; + } + + return [ + { + label: "Sign in", + component: , + }, + ]; +}; diff --git a/examples/music-licensing-challenge-nextjs/src/components/Navbar/index.tsx b/examples/music-licensing-challenge-nextjs/src/components/Navbar/index.tsx new file mode 100644 index 0000000..ac52d97 --- /dev/null +++ b/examples/music-licensing-challenge-nextjs/src/components/Navbar/index.tsx @@ -0,0 +1,88 @@ +import Link from "next/link"; +import Image from "next/image"; +import { + Disclosure, + DisclosureButton, + DisclosurePanel, +} from "@headlessui/react"; +import { + Bars3Icon, + UserCircleIcon, + XMarkIcon, +} from "@heroicons/react/24/outline"; +import Dropdown from "@/components/Dropdown"; +import { getMenuOptions, getNavbarLinks } from "./getNavbarLinks"; + +const MenuUserButton = () => ( +