From 3e35f976df60f7ca0c608baa59d281ed683ea907 Mon Sep 17 00:00:00 2001 From: aXenDeveloper Date: Sat, 17 May 2025 22:23:54 +0200 Subject: [PATCH 1/9] feat: Add watch script to copy pages & layouts to nextjs --- .../(main)/(plugins)/(blog)/blog/layout.tsx | 5 + .../(main)/(plugins)/(blog)/blog/page.tsx | 14 ++ .../[locale]/(main)/(vitnode)/login/page.tsx | 21 ++ .../(vitnode)/login/sso/[providerId]/page.tsx | 15 ++ .../(main)/(vitnode)/register/page.tsx | 21 ++ .../app/[locale]/(main)/[...rest]/page.tsx | 16 +- .../web/src/app/[locale]/(main)/blog/page.tsx | 3 + package.json | 2 +- packages/vitnode/package.json | 4 +- packages/vitnode/scripts/plugin.ts | 226 ++++++++++++++++++ packages/vitnode/scripts/scripts.ts | 6 + packages/vitnode/src/app/login/page.tsx | 21 ++ .../src/app/login/sso/[providerId]/page.tsx | 15 ++ packages/vitnode/src/app/register/page.tsx | 21 ++ packages/vitnode/src/lib/plugin.ts | 11 - .../src/views/auth/sign-in/sign-in-view.tsx | 12 - .../src/views/auth/sign-up/sign-up-view.tsx | 12 - packages/vitnode/src/views/dynamic-view.tsx | 90 ------- plugins/blog/package.json | 2 +- plugins/blog/src/app/blog/layout.tsx | 5 + plugins/blog/src/app/blog/page.tsx | 14 ++ plugins/blog/src/plugin.tsx | 7 - plugins/blog/src/views/test/client.tsx | 10 + plugins/blog/src/views/test/layout.tsx | 21 ++ 24 files changed, 425 insertions(+), 149 deletions(-) create mode 100644 apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/layout.tsx create mode 100644 apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/page.tsx create mode 100644 apps/web/src/app/[locale]/(main)/(vitnode)/login/page.tsx create mode 100644 apps/web/src/app/[locale]/(main)/(vitnode)/login/sso/[providerId]/page.tsx create mode 100644 apps/web/src/app/[locale]/(main)/(vitnode)/register/page.tsx create mode 100644 apps/web/src/app/[locale]/(main)/blog/page.tsx create mode 100644 packages/vitnode/scripts/plugin.ts create mode 100644 packages/vitnode/src/app/login/page.tsx create mode 100644 packages/vitnode/src/app/login/sso/[providerId]/page.tsx create mode 100644 packages/vitnode/src/app/register/page.tsx delete mode 100644 packages/vitnode/src/views/dynamic-view.tsx create mode 100644 plugins/blog/src/app/blog/layout.tsx create mode 100644 plugins/blog/src/app/blog/page.tsx create mode 100644 plugins/blog/src/views/test/client.tsx create mode 100644 plugins/blog/src/views/test/layout.tsx diff --git a/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/layout.tsx b/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/layout.tsx new file mode 100644 index 000000000..8bc961a91 --- /dev/null +++ b/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/layout.tsx @@ -0,0 +1,5 @@ +import { TestLayout } from 'vitnode-blog/views/test/layout'; + +export default function Layout({ children }: { children: React.ReactNode }) { + return {children}; +} diff --git a/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/page.tsx b/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/page.tsx new file mode 100644 index 000000000..27357a980 --- /dev/null +++ b/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/page.tsx @@ -0,0 +1,14 @@ +import { Link } from 'vitnode/lib/navigation'; + +import { Test } from 'vitnode-blog/views/test'; +import { TestClient } from 'vitnode-blog/views/test/client'; + +export default function Page() { + return ( + <> + + + Go to blog - test + + ); +} diff --git a/apps/web/src/app/[locale]/(main)/(vitnode)/login/page.tsx b/apps/web/src/app/[locale]/(main)/(vitnode)/login/page.tsx new file mode 100644 index 000000000..bcc9eed40 --- /dev/null +++ b/apps/web/src/app/[locale]/(main)/(vitnode)/login/page.tsx @@ -0,0 +1,21 @@ +import type { Metadata } from 'next/dist/types'; + +import { getTranslations } from 'next-intl/server'; + +import { SignInView } from 'vitnode/views/auth/sign-in/sign-in-view'; + +export const generateMetadata = async ({ + locale, +}: { + locale: string; +}): Promise => { + const t = await getTranslations({ locale, namespace: 'core.global' }); + + return { + title: t('login'), + }; +}; + +export default function Page() { + return ; +} diff --git a/apps/web/src/app/[locale]/(main)/(vitnode)/login/sso/[providerId]/page.tsx b/apps/web/src/app/[locale]/(main)/(vitnode)/login/sso/[providerId]/page.tsx new file mode 100644 index 000000000..ebcb22918 --- /dev/null +++ b/apps/web/src/app/[locale]/(main)/(vitnode)/login/sso/[providerId]/page.tsx @@ -0,0 +1,15 @@ +import { CallbackSSOView } from 'vitnode/views/auth/sso/callback/callback-sso-view'; + +export default async function Page({ + params, + searchParams, +}: { + params: Promise<{ providerId: string }>; + searchParams: Promise>; +}) { + const { providerId } = await params; + + return ( + + ); +} diff --git a/apps/web/src/app/[locale]/(main)/(vitnode)/register/page.tsx b/apps/web/src/app/[locale]/(main)/(vitnode)/register/page.tsx new file mode 100644 index 000000000..89be25034 --- /dev/null +++ b/apps/web/src/app/[locale]/(main)/(vitnode)/register/page.tsx @@ -0,0 +1,21 @@ +import type { Metadata } from 'next/dist/types'; + +import { getTranslations } from 'next-intl/server'; + +import { SignUpView } from 'vitnode/views/auth/sign-up/sign-up-view'; + +export const generateMetadata = async ({ + locale, +}: { + locale: string; +}): Promise => { + const t = await getTranslations({ locale, namespace: 'core.global' }); + + return { + title: t('register'), + }; +}; + +export default function Page() { + return ; +} diff --git a/apps/web/src/app/[locale]/(main)/[...rest]/page.tsx b/apps/web/src/app/[locale]/(main)/[...rest]/page.tsx index 43e13dad6..560ede6f4 100644 --- a/apps/web/src/app/[locale]/(main)/[...rest]/page.tsx +++ b/apps/web/src/app/[locale]/(main)/[...rest]/page.tsx @@ -1,15 +1,5 @@ -import type { DynamicViewProps } from 'vitnode/views/dynamic-view'; +import { notFound } from 'next/navigation'; -import { vitNodeConfig } from '@/vitnode.config'; -import { - DynamicView, - dynamicViewGenerateStaticParams, - generateMetadataDynamicView, -} from 'vitnode/views/dynamic-view'; - -export const generateMetadata = generateMetadataDynamicView; -export const generateStaticParams = dynamicViewGenerateStaticParams; - -export default function RestPage(props: DynamicViewProps) { - return ; +export default function RestPage() { + notFound(); } diff --git a/apps/web/src/app/[locale]/(main)/blog/page.tsx b/apps/web/src/app/[locale]/(main)/blog/page.tsx new file mode 100644 index 000000000..7abb1c085 --- /dev/null +++ b/apps/web/src/app/[locale]/(main)/blog/page.tsx @@ -0,0 +1,3 @@ +export default function Page() { + return
Register
; +} diff --git a/package.json b/package.json index 8deea055f..0e8725302 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "vitnode-bun", + "name": "vitnode", "private": true, "scripts": { "db:migrate": "turbo db:migrate", diff --git a/packages/vitnode/package.json b/packages/vitnode/package.json index c723a7ed7..75e1f9b7e 100644 --- a/packages/vitnode/package.json +++ b/packages/vitnode/package.json @@ -60,9 +60,9 @@ }, "scripts": { "build:scripts": "tsup", - "start:scripts": "bun ./dist/scripts/scripts.js", + "start:scripts": "node dist/scripts/scripts.cjs plugin --w", "build": "tsc && swc src -d dist --config-file .swcrc && tsc-alias -p tsconfig.json", - "dev": "concurrently \"tsc -w --preserveWatchOutput\" \"swc src -d dist --config-file .swcrc -w\" \"tsc-alias -w\"", + "dev": "concurrently \"tsc -w --preserveWatchOutput\" \"swc src -d dist --config-file .swcrc -w\" \"tsc-alias -w\" \"node dist/scripts/scripts.cjs plugin --w\"", "dev:email": "email dev", "lint": "eslint .", "lint:fix": "eslint . --fix", diff --git a/packages/vitnode/scripts/plugin.ts b/packages/vitnode/scripts/plugin.ts new file mode 100644 index 000000000..d9df86867 --- /dev/null +++ b/packages/vitnode/scripts/plugin.ts @@ -0,0 +1,226 @@ +/* eslint-disable no-console */ +import chokidar from 'chokidar'; +import { + copyFileSync, + existsSync, + mkdirSync, + readdirSync, + readFileSync, + unlinkSync, + writeFileSync, +} from 'fs'; +import { basename, dirname, extname, join, relative } from 'path'; + +// Regex patterns for import statements +const relativeImportRegex = + /import\s+(?:(?:{[^}]*})|(?:[^{}\s,]*))?\s*(?:,\s*(?:{[^}]*}))?\s*from\s+['"]([./]+[^'"]*)['"]/g; +const atImportRegex = + /import\s+(?:(?:{[^}]*})|(?:[^{}\s,]*))?\s*(?:,\s*(?:{[^}]*}))?\s*from\s+['"](@\/[^'"]*)['"]/g; +const jsExtensionRegex = /\.(js|jsx|ts|tsx)$/; + +// Function to transform file content by updating import statements +const transformFileImports = (content: string, pluginName: string): string => { + // First handle relative imports + let transformedContent = content.replace( + relativeImportRegex, + (match, importPath: string) => { + // Only transform relative imports (starting with ./ or ../) + if (importPath.startsWith('.')) { + // Remove any file extensions from the import path + const cleanPath = importPath.replace(jsExtensionRegex, ''); + // Extract the path after removing leading '../' sequences + const normalizedPath = cleanPath.replace(/^(?:\.\.\/)+/, ''); + // Return the package import format + + return match.replace(importPath, `${pluginName}/${normalizedPath}`); + } + + return match; + }, + ); + + // Then handle @/ imports + transformedContent = transformedContent.replace( + atImportRegex, + (match, importPath: string) => { + // Remove '@/' prefix and any file extensions + const cleanPath = importPath + .replace(/^@\//, '') + .replace(jsExtensionRegex, ''); + // Return the package import format + + return match.replace(importPath, `${pluginName}/${cleanPath}`); + }, + ); + + return transformedContent; +}; + +const copyFile = (srcPath: string, destPath: string, pluginName?: string) => { + try { + const destDir = destPath.substring(0, destPath.lastIndexOf('/')); + if (!existsSync(destDir)) { + mkdirSync(destDir, { recursive: true }); + } + + // Check if file should have imports processed (like .js, .jsx, .ts, .tsx files) + const ext = extname(srcPath); + if (pluginName && ['.js', '.jsx', '.ts', '.tsx'].includes(ext)) { + // Read file content + const content = readFileSync(srcPath, 'utf-8'); + // Transform imports + const transformedContent = transformFileImports(content, pluginName); + // Write transformed content + writeFileSync(destPath, transformedContent); + } else { + // Copy file directly without transforming + copyFileSync(srcPath, destPath); + } + + // Show even shorter, project-rooted paths for clarity + const repoRoot = findRepoRoot(process.cwd()); + // Remove everything before '/src/app' in the source path if present + const srcAppIdx = srcPath.indexOf('/src/app'); + const shortSrc = + srcAppIdx !== -1 + ? srcPath.substring(srcAppIdx) + : srcPath.startsWith(repoRoot) + ? srcPath.substring(repoRoot.length + 1) + : srcPath; + const shortDest = destPath.startsWith(repoRoot) + ? destPath.substring(repoRoot.length + 1) + : destPath; + console.log(`\x1b[32mCopied:\x1b[0m ${shortSrc} → ${shortDest}`); + } catch (error) { + console.error(`\x1b[31mError copying file:\x1b[0m ${srcPath}`, error); + } +}; + +const removeFile = (filePath: string) => { + try { + if (existsSync(filePath)) { + unlinkSync(filePath); + console.log(`\x1b[33mRemoved:\x1b[0m ${filePath}`); + } + } catch (error) { + console.error(`\x1b[31mError removing file:\x1b[0m ${filePath}`, error); + } +}; + +function findRepoRoot(start: string): string { + let dir = start; + while (dir !== dirname(dir)) { + if ( + existsSync(join(dir, 'turbo.json')) || + existsSync(join(dir, 'pnpm-workspace.yaml')) || + existsSync(join(dir, '.git')) + ) + return dir; + dir = dirname(dir); + } + throw new Error( + '❌ Could not locate monorepo root – add a marker file or pass it via CLI/env', + ); +} + +const getAllFiles = (dir: string): string[] => { + const files: string[] = []; + const entries = readdirSync(dir, { withFileTypes: true }); + + for (const entry of entries) { + const fullPath = join(dir, entry.name); + if (entry.isDirectory()) { + files.push(...getAllFiles(fullPath)); + } else { + files.push(fullPath); + } + } + + return files; +}; + +const cleanupDeletedFiles = (sourceDir: string, destinationDir: string) => { + if (!existsSync(destinationDir)) return; + + const destFiles = getAllFiles(destinationDir); + for (const destFile of destFiles) { + const relativePath = relative(destinationDir, destFile); + const sourceFile = join(sourceDir, relativePath); + + if (!existsSync(sourceFile)) { + removeFile(destFile); + } + } +}; + +export const processPlugin = ({ initMessage }: { initMessage: string }) => { + const pluginDir = process.cwd(); + const repoRoot = findRepoRoot(pluginDir); + const pluginName = basename(pluginDir); + + // Get the package name from package.json for imports + let packageName = ''; + try { + const packageJsonPath = join(pluginDir, 'package.json'); + if (existsSync(packageJsonPath)) { + const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8')); + packageName = packageJson.name ?? ''; + } + } catch (error) { + console.error(`\x1b[31mError reading package.json:\x1b[0m`, error); + } + + const sourceDir = join(pluginDir, 'src', 'app'); + const destinationDir = join( + repoRoot, + 'apps', + 'web', + 'src', + 'app', + '[locale]', + '(main)', + pluginName === 'vitnode' + ? join('(vitnode)') + : join('(plugins)', `(${pluginName})`), + ); + + // Create destination directory if it doesn't exist + if (!existsSync(destinationDir)) { + mkdirSync(destinationDir, { recursive: true }); + } + + // Clean up any files that were deleted while the script wasn't running + cleanupDeletedFiles(sourceDir, destinationDir); + + console.log( + `${initMessage} \x1b[34mWatching for changes in plugins...\x1b[0m`, + ); + + const watcher = chokidar.watch(sourceDir, { + ignoreInitial: false, + persistent: true, + }); + + const getDestinationPath = (srcPath: string): string => { + const relativePath = srcPath.substring(sourceDir.length); + + return join(destinationDir, relativePath); + }; + + watcher + .on('add', filePath => { + const destPath = getDestinationPath(filePath); + copyFile(filePath, destPath, packageName); + }) + .on('change', filePath => { + const destPath = getDestinationPath(filePath); + copyFile(filePath, destPath, packageName); + }) + .on('unlink', filePath => { + const destPath = getDestinationPath(filePath); + removeFile(destPath); + }) + .on('error', error => { + console.error('\x1b[31mWatcher error:\x1b[0m', error); + }); +}; diff --git a/packages/vitnode/scripts/scripts.ts b/packages/vitnode/scripts/scripts.ts index 4ee18f94b..63a9162fa 100644 --- a/packages/vitnode/scripts/scripts.ts +++ b/packages/vitnode/scripts/scripts.ts @@ -3,6 +3,7 @@ import { existsSync } from 'fs'; import { join } from 'path'; +import { processPlugin } from './plugin.js'; import { prepareDatabase } from './prepare-database.js'; import { prepareFiles } from './prepare-files.js'; @@ -23,6 +24,11 @@ if (process.argv[2] === 'prepare') { void prepareFiles({ pluginsPath: getPluginsPath(), initMessage }); } else if (process.argv[2] === 'init') { void prepareDatabase({ initMessage }); +} else if ( + process.argv[2] === 'plugin' && + (process.argv[3] === '--w' || process.argv[3] === '--watch') +) { + processPlugin({ initMessage }); } else { console.log( `${initMessage} \x1b[31mCommand not found: "${process.argv[2] ?? ''}"\x1b[0m`, diff --git a/packages/vitnode/src/app/login/page.tsx b/packages/vitnode/src/app/login/page.tsx new file mode 100644 index 000000000..1c6496b6b --- /dev/null +++ b/packages/vitnode/src/app/login/page.tsx @@ -0,0 +1,21 @@ +import type { Metadata } from 'next/dist/types'; + +import { getTranslations } from 'next-intl/server'; + +import { SignInView } from '../../views/auth/sign-in/sign-in-view'; + +export const generateMetadata = async ({ + locale, +}: { + locale: string; +}): Promise => { + const t = await getTranslations({ locale, namespace: 'core.global' }); + + return { + title: t('login'), + }; +}; + +export default function Page() { + return ; +} diff --git a/packages/vitnode/src/app/login/sso/[providerId]/page.tsx b/packages/vitnode/src/app/login/sso/[providerId]/page.tsx new file mode 100644 index 000000000..6d086f7c8 --- /dev/null +++ b/packages/vitnode/src/app/login/sso/[providerId]/page.tsx @@ -0,0 +1,15 @@ +import { CallbackSSOView } from '@/views/auth/sso/callback/callback-sso-view'; + +export default async function Page({ + params, + searchParams, +}: { + params: Promise<{ providerId: string }>; + searchParams: Promise>; +}) { + const { providerId } = await params; + + return ( + + ); +} diff --git a/packages/vitnode/src/app/register/page.tsx b/packages/vitnode/src/app/register/page.tsx new file mode 100644 index 000000000..bdff092d7 --- /dev/null +++ b/packages/vitnode/src/app/register/page.tsx @@ -0,0 +1,21 @@ +import type { Metadata } from 'next/dist/types'; + +import { getTranslations } from 'next-intl/server'; + +import { SignUpView } from '../../views/auth/sign-up/sign-up-view'; + +export const generateMetadata = async ({ + locale, +}: { + locale: string; +}): Promise => { + const t = await getTranslations({ locale, namespace: 'core.global' }); + + return { + title: t('register'), + }; +}; + +export default function Page() { + return ; +} diff --git a/packages/vitnode/src/lib/plugin.ts b/packages/vitnode/src/lib/plugin.ts index 2ffbf62f3..7f0d9435e 100644 --- a/packages/vitnode/src/lib/plugin.ts +++ b/packages/vitnode/src/lib/plugin.ts @@ -1,16 +1,5 @@ -interface Pages { - component: (args: { - locale: string; - params: string[]; - searchParams: Promise>; - }) => React.ReactNode | undefined; - staticPaths?: string[]; -} - export interface BuildPluginReturn

{ - adminPages?: Pages; name: P; - pages?: Pages; } export function buildPlugin

( diff --git a/packages/vitnode/src/views/auth/sign-in/sign-in-view.tsx b/packages/vitnode/src/views/auth/sign-in/sign-in-view.tsx index 97dc579d6..00be0bed5 100644 --- a/packages/vitnode/src/views/auth/sign-in/sign-in-view.tsx +++ b/packages/vitnode/src/views/auth/sign-in/sign-in-view.tsx @@ -1,5 +1,3 @@ -import type { Metadata } from 'next/dist/types'; - import { Card, CardDescription } from '@/components/ui/card'; import { Link } from '@/lib/navigation'; import { getTranslations } from 'next-intl/server'; @@ -9,16 +7,6 @@ import { I18nProvider } from '../../../components/i18n-provider'; import { SSOButtons, SSOButtonsSkeleton } from '../sso/buttons/sso-buttons'; import { FormSignIn } from './form/form'; -export const generateMetadataSignInView = async ( - locale: string, -): Promise => { - const t = await getTranslations({ locale, namespace: 'core.global' }); - - return { - title: t('login'), - }; -}; - export const SignInView = async () => { const t = await getTranslations('core.auth.sign_in'); const tGlobal = await getTranslations('core.global'); diff --git a/packages/vitnode/src/views/auth/sign-up/sign-up-view.tsx b/packages/vitnode/src/views/auth/sign-up/sign-up-view.tsx index cf777bbf9..e81ac6178 100644 --- a/packages/vitnode/src/views/auth/sign-up/sign-up-view.tsx +++ b/packages/vitnode/src/views/auth/sign-up/sign-up-view.tsx @@ -1,5 +1,3 @@ -import type { Metadata } from 'next/dist/types'; - import { Card, CardDescription } from '@/components/ui/card'; import { getMiddlewareApi } from '@/lib/api/get-middleware-api'; import { Link } from '@/lib/navigation'; @@ -10,16 +8,6 @@ import { I18nProvider } from '../../../components/i18n-provider'; import { SSOButtons, SSOButtonsSkeleton } from '../sso/buttons/sso-buttons'; import { FormSignUp } from './form/form'; -export const generateMetadataSignUpView = async ( - locale: string, -): Promise => { - const t = await getTranslations({ locale, namespace: 'core.global' }); - - return { - title: t('register'), - }; -}; - export const SignUpView = async () => { const [t, tGlobal, { isEmail }] = await Promise.all([ getTranslations('core.auth.sign_up'), diff --git a/packages/vitnode/src/views/dynamic-view.tsx b/packages/vitnode/src/views/dynamic-view.tsx deleted file mode 100644 index 56bef9509..000000000 --- a/packages/vitnode/src/views/dynamic-view.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import type { Metadata } from 'next/dist/types'; - -import { setRequestLocale } from 'next-intl/server'; -import { notFound } from 'next/navigation'; - -import type { VitNodeConfig } from '../vitnode.config'; - -import { - generateMetadataSignInView, - SignInView, -} from './auth/sign-in/sign-in-view'; -import { - generateMetadataSignUpView, - SignUpView, -} from './auth/sign-up/sign-up-view'; -import { CallbackSSOView } from './auth/sso/callback/callback-sso-view'; - -export interface DynamicViewProps { - params: Promise<{ - locale: string; - rest: string[]; - }>; - searchParams: Promise>; -} - -export const generateMetadataDynamicView = async ({ - params, -}: DynamicViewProps): Promise => { - const { rest, locale } = await params; - const path = rest.join('/'); - - const views: Record> = { - register: generateMetadataSignUpView(locale), - login: generateMetadataSignInView(locale), - }; - - return await views[path]; -}; - -export const DynamicView = async ({ - params, - searchParams, - config, -}: DynamicViewProps & { - config: VitNodeConfig; -}) => { - const { rest, locale } = await params; - setRequestLocale(locale); - const path = rest.join('/'); - - if (rest[0] === 'login' && rest[1] === 'sso' && rest[2] && !rest[3]) { - const providerId = rest[2]; - - return ( - - ); - } - - // Attempt to render a plugin view if available for any route - for (const plugin of config.plugins) { - if (typeof plugin.pages?.component === 'function') { - const page = plugin.pages.component({ - locale, - searchParams, - params: rest, - }); - - if (page) { - return page; - } - } - } - - const views = { - register: SignUpView, - login: SignInView, - }; - - const view = views[path]?.(); - - if (view) { - return view; - } - - notFound(); -}; - -export function dynamicViewGenerateStaticParams() { - return ['login', 'register'].map(item => ({ rest: item.split('/') })); -} diff --git a/plugins/blog/package.json b/plugins/blog/package.json index e418504e9..d6f16cacb 100644 --- a/plugins/blog/package.json +++ b/plugins/blog/package.json @@ -14,7 +14,7 @@ }, "scripts": { "build": "tsc && swc src -d dist --config-file .swcrc && tsc-alias -p tsconfig.json", - "dev": "concurrently \"tsc -w --preserveWatchOutput\" \"swc src -d dist --config-file .swcrc -w\" \"tsc-alias -w\"", + "dev": "concurrently \"tsc -w --preserveWatchOutput\" \"swc src -d dist --config-file .swcrc -w\" \"tsc-alias -w\" \"vitnode plugin --w\"", "lint": "eslint .", "lint:fix": "eslint . --fix" }, diff --git a/plugins/blog/src/app/blog/layout.tsx b/plugins/blog/src/app/blog/layout.tsx new file mode 100644 index 000000000..5677225e3 --- /dev/null +++ b/plugins/blog/src/app/blog/layout.tsx @@ -0,0 +1,5 @@ +import { TestLayout } from '@/views/test/layout'; + +export default function Layout({ children }: { children: React.ReactNode }) { + return {children}; +} diff --git a/plugins/blog/src/app/blog/page.tsx b/plugins/blog/src/app/blog/page.tsx new file mode 100644 index 000000000..0ef15a9c0 --- /dev/null +++ b/plugins/blog/src/app/blog/page.tsx @@ -0,0 +1,14 @@ +import { Link } from 'vitnode/lib/navigation'; + +import { Test } from '../../views/test'; +import { TestClient } from '../../views/test/client'; + +export default function Page() { + return ( + <> + + + Go to blog - test + + ); +} diff --git a/plugins/blog/src/plugin.tsx b/plugins/blog/src/plugin.tsx index 0b1a03b9f..9527c5e0a 100644 --- a/plugins/blog/src/plugin.tsx +++ b/plugins/blog/src/plugin.tsx @@ -5,12 +5,5 @@ import { configPlugin } from './config'; export const blogPlugin = () => { return buildPlugin({ ...configPlugin, - pages: { - component: ({ params }) => { - if (params[0] === 'blog' && !params[1]) { - return

Page Blog plugin
; - } - }, - }, }); }; diff --git a/plugins/blog/src/views/test/client.tsx b/plugins/blog/src/views/test/client.tsx new file mode 100644 index 000000000..ae74464f6 --- /dev/null +++ b/plugins/blog/src/views/test/client.tsx @@ -0,0 +1,10 @@ +'use client'; + +export const TestClient = () => { + return ( +
+

Test Client

+

This is a test client component.

+
+ ); +}; diff --git a/plugins/blog/src/views/test/layout.tsx b/plugins/blog/src/views/test/layout.tsx new file mode 100644 index 000000000..a40d64c52 --- /dev/null +++ b/plugins/blog/src/views/test/layout.tsx @@ -0,0 +1,21 @@ +'use client'; + +import React from 'react'; + +export const TestLayout = ({ children }: { children: React.ReactNode }) => { + const [count, setCount] = React.useState(0); + + return ( +
+

Test Layout

+

This is a test layout component.

+ +
+

Count: {count}

+ + +
+ {children} +
+ ); +}; From dd066952f6db51a683b1a1524c53e5175c0b3c69 Mon Sep 17 00:00:00 2001 From: aXenDeveloper Date: Sun, 18 May 2025 21:21:02 +0200 Subject: [PATCH 2/9] =?UTF-8?q?feat(plugin):=20=E2=9C=A8=20Enhance=20plugi?= =?UTF-8?q?n=20processing=20with=20route=20key=20management=20and=20cleanu?= =?UTF-8?q?p?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 7 +- .../web/src/app/[locale]/(main)/blog/page.tsx | 3 - packages/vitnode/scripts/plugin.ts | 224 ++++++++++++------ 3 files changed, 160 insertions(+), 74 deletions(-) delete mode 100644 apps/web/src/app/[locale]/(main)/blog/page.tsx diff --git a/.vscode/settings.json b/.vscode/settings.json index 0391eb563..4e7edd6bb 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,8 @@ { - "cSpell.words": ["vitnode"] + "cSpell.words": ["vitnode"], + "github.copilot.chat.commitMessageGeneration.instructions": [ + { + "text": "Follow the Conventional Commits format strictly for commit messages. Use the structure below:\n\n```\n[optional scope]: \n```\n\nGuidelines:\n\n1. **Type and Scope**: Choose an appropriate type (e.g., `feat`, `fix`) and optional scope to describe the affected module or feature.\n\n2. **Gitmoji**: Include a relevant `gitmoji` that best represents the nature of the change.\n\n3. **Description**: Write a concise, informative description in the header; use backticks if referencing code or specific terms.\n\nCommit messages should be clear, informative, and professional, aiding readability and project tracking." + } + ] } diff --git a/apps/web/src/app/[locale]/(main)/blog/page.tsx b/apps/web/src/app/[locale]/(main)/blog/page.tsx deleted file mode 100644 index 7abb1c085..000000000 --- a/apps/web/src/app/[locale]/(main)/blog/page.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function Page() { - return
Register
; -} diff --git a/packages/vitnode/scripts/plugin.ts b/packages/vitnode/scripts/plugin.ts index d9df86867..e24f5933b 100644 --- a/packages/vitnode/scripts/plugin.ts +++ b/packages/vitnode/scripts/plugin.ts @@ -9,7 +9,15 @@ import { unlinkSync, writeFileSync, } from 'fs'; -import { basename, dirname, extname, join, relative } from 'path'; +import { + basename, + dirname, + extname, + join, + normalize, + relative, + sep, +} from 'path'; // Regex patterns for import statements const relativeImportRegex = @@ -17,6 +25,45 @@ const relativeImportRegex = const atImportRegex = /import\s+(?:(?:{[^}]*})|(?:[^{}\s,]*))?\s*(?:,\s*(?:{[^}]*}))?\s*from\s+['"](@\/[^'"]*)['"]/g; const jsExtensionRegex = /\.(js|jsx|ts|tsx)$/; +const pageFileRegex = /^page\.(tsx|ts|jsx|js)$/i; + +const routeKey = (filePath: string, localeRoot: string): string => { + const rel = relative(localeRoot, filePath); + const parts = rel.split(sep); + + // remove filename + parts.pop(); + + // drop any group folders + const filtered = parts.filter(p => !p.startsWith('(')); + + // '' represents the root route + return normalize(filtered.join('/')); +}; + +const buildInitialRouteMap = (localeRoot: string): Map => { + const map = new Map(); + + const visit = (dir: string) => { + for (const entry of readdirSync(dir, { withFileTypes: true })) { + const full = join(dir, entry.name); + + if (entry.isDirectory()) { + visit(full); + continue; + } + + if (pageFileRegex.test(entry.name)) { + const key = routeKey(full, localeRoot); + map.set(key, full); + } + } + }; + + visit(localeRoot); + + return map; +}; // Function to transform file content by updating import statements const transformFileImports = (content: string, pluginName: string): string => { @@ -56,57 +103,6 @@ const transformFileImports = (content: string, pluginName: string): string => { return transformedContent; }; -const copyFile = (srcPath: string, destPath: string, pluginName?: string) => { - try { - const destDir = destPath.substring(0, destPath.lastIndexOf('/')); - if (!existsSync(destDir)) { - mkdirSync(destDir, { recursive: true }); - } - - // Check if file should have imports processed (like .js, .jsx, .ts, .tsx files) - const ext = extname(srcPath); - if (pluginName && ['.js', '.jsx', '.ts', '.tsx'].includes(ext)) { - // Read file content - const content = readFileSync(srcPath, 'utf-8'); - // Transform imports - const transformedContent = transformFileImports(content, pluginName); - // Write transformed content - writeFileSync(destPath, transformedContent); - } else { - // Copy file directly without transforming - copyFileSync(srcPath, destPath); - } - - // Show even shorter, project-rooted paths for clarity - const repoRoot = findRepoRoot(process.cwd()); - // Remove everything before '/src/app' in the source path if present - const srcAppIdx = srcPath.indexOf('/src/app'); - const shortSrc = - srcAppIdx !== -1 - ? srcPath.substring(srcAppIdx) - : srcPath.startsWith(repoRoot) - ? srcPath.substring(repoRoot.length + 1) - : srcPath; - const shortDest = destPath.startsWith(repoRoot) - ? destPath.substring(repoRoot.length + 1) - : destPath; - console.log(`\x1b[32mCopied:\x1b[0m ${shortSrc} → ${shortDest}`); - } catch (error) { - console.error(`\x1b[31mError copying file:\x1b[0m ${srcPath}`, error); - } -}; - -const removeFile = (filePath: string) => { - try { - if (existsSync(filePath)) { - unlinkSync(filePath); - console.log(`\x1b[33mRemoved:\x1b[0m ${filePath}`); - } - } catch (error) { - console.error(`\x1b[31mError removing file:\x1b[0m ${filePath}`, error); - } -}; - function findRepoRoot(start: string): string { let dir = start; while (dir !== dirname(dir)) { @@ -139,24 +135,12 @@ const getAllFiles = (dir: string): string[] => { return files; }; -const cleanupDeletedFiles = (sourceDir: string, destinationDir: string) => { - if (!existsSync(destinationDir)) return; - - const destFiles = getAllFiles(destinationDir); - for (const destFile of destFiles) { - const relativePath = relative(destinationDir, destFile); - const sourceFile = join(sourceDir, relativePath); - - if (!existsSync(sourceFile)) { - removeFile(destFile); - } - } -}; - export const processPlugin = ({ initMessage }: { initMessage: string }) => { const pluginDir = process.cwd(); const repoRoot = findRepoRoot(pluginDir); const pluginName = basename(pluginDir); + const localeRoot = join(repoRoot, 'apps', 'web', 'src', 'app', '[locale]'); + const routeMap = buildInitialRouteMap(localeRoot); // Get the package name from package.json for imports let packageName = ''; @@ -171,6 +155,11 @@ export const processPlugin = ({ initMessage }: { initMessage: string }) => { } const sourceDir = join(pluginDir, 'src', 'app'); + const pluginPath = + pluginName === 'vitnode' + ? join('(vitnode)') + : join('(plugins)', `(${pluginName})`); + const destinationDir = join( repoRoot, 'apps', @@ -179,9 +168,7 @@ export const processPlugin = ({ initMessage }: { initMessage: string }) => { 'app', '[locale]', '(main)', - pluginName === 'vitnode' - ? join('(vitnode)') - : join('(plugins)', `(${pluginName})`), + pluginPath, ); // Create destination directory if it doesn't exist @@ -189,6 +176,103 @@ export const processPlugin = ({ initMessage }: { initMessage: string }) => { mkdirSync(destinationDir, { recursive: true }); } + const copyFile = (srcPath: string, destPath: string, pluginName?: string) => { + const fileName = basename(srcPath); + if (pageFileRegex.test(fileName)) { + const key = routeKey(destPath, localeRoot); + + const existing = routeMap.get(key); + // another file (not this exact one) already owns the route + if (existing && existing !== destPath) { + console.log( + `\x1b[31mSkipped duplicate page:\x1b[0m ${relative( + repoRoot, + destPath, + )} (collides with ${relative(repoRoot, existing)})`, + ); + + return; // 🔥 skip the copy + } + } + + try { + const destDir = dirname(destPath); + if (!existsSync(destDir)) { + mkdirSync(destDir, { recursive: true }); + } + + // Check if file should have imports processed (like .js, .jsx, .ts, .tsx files) + const ext = extname(srcPath); + if (pluginName && ['.js', '.jsx', '.ts', '.tsx'].includes(ext)) { + // Read file content + const content = readFileSync(srcPath, 'utf-8'); + // Transform imports + const transformedContent = transformFileImports(content, pluginName); + // Write transformed content + writeFileSync(destPath, transformedContent); + } else { + // Copy file directly without transforming + copyFileSync(srcPath, destPath); + } + + // Show even shorter, project-rooted paths for clarity + const repoRoot = findRepoRoot(process.cwd()); + // Remove everything before '/src/app' in the source path if present + const srcAppIdx = srcPath.indexOf(join('src', 'app')); + const shortSrc = + srcAppIdx !== -1 + ? srcPath.substring(srcAppIdx) + : srcPath.startsWith(repoRoot) + ? relative(repoRoot, srcPath) + : srcPath; + const shortDest = destPath.startsWith(repoRoot) + ? relative(repoRoot, destPath) + : destPath; + console.log(`\x1b[32mCopied:\x1b[0m ${shortSrc} → ${shortDest}`); + + // 📝 update the map now that the copy succeeded + if (pageFileRegex.test(basename(destPath))) { + const key = routeKey(destPath, localeRoot); + routeMap.set(key, destPath); + } + } catch (error) { + console.error(`\x1b[31mError copying file:\x1b[0m ${srcPath}`, error); + } + }; + + const removeFile = (filePath: string) => { + try { + if (existsSync(filePath)) { + unlinkSync(filePath); + console.log(`\x1b[33mRemoved:\x1b[0m ${filePath}`); + + if (pageFileRegex.test(basename(filePath))) { + const key = routeKey(filePath, localeRoot); + // only delete if this exact file is the one in the map + if (routeMap.get(key) === filePath) { + routeMap.delete(key); + } + } + } + } catch (error) { + console.error(`\x1b[31mError removing file:\x1b[0m ${filePath}`, error); + } + }; + + const cleanupDeletedFiles = (sourceDir: string, destinationDir: string) => { + if (!existsSync(destinationDir)) return; + + const destFiles = getAllFiles(destinationDir); + for (const destFile of destFiles) { + const relativePath = relative(destinationDir, destFile); + const sourceFile = join(sourceDir, relativePath); + + if (!existsSync(sourceFile)) { + removeFile(destFile); + } + } + }; + // Clean up any files that were deleted while the script wasn't running cleanupDeletedFiles(sourceDir, destinationDir); @@ -202,7 +286,7 @@ export const processPlugin = ({ initMessage }: { initMessage: string }) => { }); const getDestinationPath = (srcPath: string): string => { - const relativePath = srcPath.substring(sourceDir.length); + const relativePath = relative(sourceDir, srcPath); return join(destinationDir, relativePath); }; From 708303b91675d295ddfb902c66c0c4803e909617 Mon Sep 17 00:00:00 2001 From: aXenDeveloper Date: Sun, 18 May 2025 22:34:31 +0200 Subject: [PATCH 3/9] =?UTF-8?q?feat(plugin):=20=E2=9C=A8=20Add=20support?= =?UTF-8?q?=20for=20app=5Fadmin=20folder=20to=20create=20layouts=20and=20p?= =?UTF-8?q?ages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../docs/plugins/layouts-and-pages.mdx | 202 ++++++------------ .../(main)/(plugins)/(blog)/blog/page.tsx | 2 +- .../(auth)/(plugins)/blog/categories/page.tsx | 3 + .../admin/(auth)/(vitnode)/core/page.tsx | 5 + .../admin/(auth)/(vitnode)/core/test/page.tsx | 5 + .../(auth)/(vitnode)/core/users/page.tsx | 7 + .../[locale]/admin/(auth)/[...rest]/page.tsx | 15 -- packages/vitnode/scripts/plugin.ts | 75 +++++-- packages/vitnode/src/app_admin/page.tsx | 5 + packages/vitnode/src/app_admin/test/page.tsx | 5 + packages/vitnode/src/app_admin/users/page.tsx | 7 + .../src/views/admin/dynamic-admin-view.tsx | 59 ----- plugins/blog/src/app/blog/page.tsx | 2 +- .../blog/src/app_admin/categories/page.tsx | 3 + 14 files changed, 164 insertions(+), 231 deletions(-) create mode 100644 apps/web/src/app/[locale]/admin/(auth)/(plugins)/blog/categories/page.tsx create mode 100644 apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/page.tsx create mode 100644 apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/test/page.tsx create mode 100644 apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/users/page.tsx delete mode 100644 apps/web/src/app/[locale]/admin/(auth)/[...rest]/page.tsx create mode 100644 packages/vitnode/src/app_admin/page.tsx create mode 100644 packages/vitnode/src/app_admin/test/page.tsx create mode 100644 packages/vitnode/src/app_admin/users/page.tsx delete mode 100644 packages/vitnode/src/views/admin/dynamic-admin-view.tsx create mode 100644 plugins/blog/src/app_admin/categories/page.tsx diff --git a/apps/docs/content/docs/plugins/layouts-and-pages.mdx b/apps/docs/content/docs/plugins/layouts-and-pages.mdx index 9909da33c..6bfcb8505 100644 --- a/apps/docs/content/docs/plugins/layouts-and-pages.mdx +++ b/apps/docs/content/docs/plugins/layouts-and-pages.mdx @@ -5,166 +5,86 @@ description: Learn how to create custom layouts and pages for your VitNode plugi Welcome to the magical world of VitNode layouts and pages! Think of these as the digital feng shui for your plugin - they determine how things look and where everything goes. Let's dive in! -## Create a Page - -Pages in VitNode are like unexpected guests - they show up when someone visits a URL matching your plugin's route. Here's how to roll out the welcome mat: - -```tsx title="plugins/blog/src/plugin.tsx" -import { buildPlugin } from 'vitnode/lib/plugin'; - -import { configPlugin } from './config'; - -export const blogPlugin = () => { - return buildPlugin({ - ...configPlugin, - // [!code ++] - pages: { - // [!code ++] - component: ({ params }) => { - // [!code ++] - if (params[0] === 'blog' && !params[1]) { - // [!code ++] - return ( - // [!code ++] -
Page Blog plugin
- // [!code ++] - ); - // [!code ++] - } - // [!code ++] - }, - // [!code ++] - }, - }); -}; -``` +## How Routing Works - - The page component must be a React Server Component (RSC). This means it - should be a function that returns JSX and does not use hooks or state. If you - want to use `use client;` then you need to create a new file and import the - page component. - - -## Page Parameters - -Your pages can access URL parameters like a nosy neighbor reading your mail. The `params` array contains each segment of the URL path: - -```tsx -component: ({ params, locale, searchParams }) => { - // params[0] is the first segment after the base URL - // For example, in "/blog/post/123": - // params[0] would be "blog" - // params[1] would be "post" - // params[2] would be "123" - - if (params[0] === 'blog' && params[1] === 'post' && params[2] && !params[3]) { - return ; - } -}; -``` +VitNode follows Next.js app directory conventions for routing. Each plugin can define its own pages that get integrated into the main application. When developing a plugin: - - Always end your page-matching conditionals with !params[X] to - ensure you only match the intended page and not sub-paths. - +- Files named `page.tsx` define a route +- The route path is determined by the folder structure +- Page files are automatically detected and copied to the appropriate location in the main app -## Static Paths +## Pages -Sometimes you know exactly who's coming to dinner. For those cases, define your static paths: +Pages in VitNode work the same way as in the Next.js framework. You can create a page by creating a `page.tsx` file in the `src/app` directory of your plugin. -```tsx -pages: { - component: ({ params }) => { - if (params[0] === 'about' && !params[1]) { - return ; - } - }, - staticPaths: ['/about', '/terms', '/privacy'], +For example, if you want to create a page at `/dashboard`, you would create: + +```tsx title="plugins/{plugin_name}/src/app/dashboard/page.tsx" +export default function DashboardPage() { + return
Welcome to the dashboard!
; } ``` -These paths will be pre-rendered at build time - like preparing snacks before your guests arrive! +When your plugin is loaded, VitNode will automatically copy this page to the appropriate location in the main application and handle all the routing. ## Layouts -Layouts are like the interior designers of your plugin - they wrap your content in a consistent style. Unlike Next.js layouts that use file-system conventions, VitNode uses a more explicit approach: - -```tsx title="plugins/blog/src/plugin.tsx" -import { BlogLayout } from './components/blog-layout'; -import { BlogListing } from './components/blog-listing'; -import { BlogPost } from './components/blog-post'; -import { AboutPage } from './components/about-page'; - -export const blogPlugin = () => { - return buildPlugin({ - ...configPlugin, - pages: { - component: ({ params }) => { - return ( - - {/* Blog listing page: /blog */} - {params[0] === 'blog' && !params[1] && } - {/* Blog post page: /blog/post/[id] */} - {params[0] === 'blog' && - params[1] === 'post' && - params[2] && - !params[3] && } - {/* About page: /about */} - {params[0] === 'about' && !params[1] && } - {/* You can add more pages here */} - - ); - }, - staticPaths: ['/blog', '/about'], - }, - }); -}; +Layouts allow you to create shared UI for multiple pages. They follow Next.js conventions and should be defined as `layout.tsx` files. + +For example, to create a layout for all pages under `/dashboard`: + +```tsx title="plugins/{plugin_name}/src/app/dashboard/layout.tsx" +export default function DashboardLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( +
+ +
{children}
+
+ ); +} ``` -Think of `searchParams` as that friend who always asks too many questions - sometimes annoying, but often useful! +This layout will wrap any pages within the `dashboard` directory. -## Mixing Client and Server Components +## Admin Pages -Want the best of both worlds? Here's how to dance the client-server tango: +For admin pages, follow the same pattern but create your files in the `src/app_admin` directory of your plugin. This is the only difference - the structure and implementation remain the same. -```tsx title="plugins/blog/src/components/blog-post.client.tsx" -'use client'; +For example, to create an admin page at `/admin/{plugin_name}/settings`: -import { useState } from 'react'; +``` +src/app_admin/settings/page.tsx +``` -export function ClientBlogPost({ initialData }) { - const [likes, setLikes] = useState(initialData.likes); +And for a layout: - return ( -
-

{initialData.title}

-

{initialData.content}

- -
- ); -} ``` +src/app_admin/settings/layout.tsx +``` + +## Route Groups and Special Folders + +VitNode supports Next.js route grouping with parentheses: + +- `(group-name)` - Creates a logical group without affecting the URL path +- `[dynamicParam]` - Creates a dynamic route segment -```tsx title="plugins/blog/src/plugin.tsx" -import { ClientBlogPost } from './components/blog-post.client'; - -export const blogPlugin = () => { - return buildPlugin({ - ...configPlugin, - pages: { - component: async ({ params }) => { - if (params[0] === 'blog' && params[1] && !params[2]) { - const postData = await fetchBlogPost(params[1]); - - return ( -
- -
- ); - } - }, - }, - }); -}; +For example: + +``` +src/app/(user-section)/profile/page.tsx // Route: /profile +src/app/products/[id]/page.tsx // Route: /products/:id ``` + +## Import Considerations + +When developing your plugin pages, you can use: + +- Relative imports (e.g., `import { Button } from '../components/Button'`) +- Imports with `@/` prefix (e.g., `import { utils } from '@/lib/utils'`) + +VitNode will automatically transform these imports when your plugin is integrated into the main application. diff --git a/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/page.tsx b/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/page.tsx index 27357a980..41938f2c2 100644 --- a/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/page.tsx +++ b/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/page.tsx @@ -8,7 +8,7 @@ export default function Page() { <> - Go to blog - test + Go to blog - test 123 ); } diff --git a/apps/web/src/app/[locale]/admin/(auth)/(plugins)/blog/categories/page.tsx b/apps/web/src/app/[locale]/admin/(auth)/(plugins)/blog/categories/page.tsx new file mode 100644 index 000000000..60ba38a0e --- /dev/null +++ b/apps/web/src/app/[locale]/admin/(auth)/(plugins)/blog/categories/page.tsx @@ -0,0 +1,3 @@ +export default function Page() { + return
Categories from admin - blog plugin
; +} diff --git a/apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/page.tsx b/apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/page.tsx new file mode 100644 index 000000000..63745336c --- /dev/null +++ b/apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/page.tsx @@ -0,0 +1,5 @@ +import { DashboardAdminView } from 'vitnode/views/admin/views/core/dashboard/dashboard-admin-view'; + +export default function Page() { + return ; +} diff --git a/apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/test/page.tsx b/apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/test/page.tsx new file mode 100644 index 000000000..92ea2fc30 --- /dev/null +++ b/apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/test/page.tsx @@ -0,0 +1,5 @@ +import { TestView } from 'vitnode/views/admin/views/core/test'; + +export default function Page() { + return ; +} diff --git a/apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/users/page.tsx b/apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/users/page.tsx new file mode 100644 index 000000000..306e0807b --- /dev/null +++ b/apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/users/page.tsx @@ -0,0 +1,7 @@ +import { UsersAdminView } from 'vitnode/views/admin/views/core/users/users-admin-view'; + +export default function Page( + props: React.ComponentProps, +) { + return ; +} diff --git a/apps/web/src/app/[locale]/admin/(auth)/[...rest]/page.tsx b/apps/web/src/app/[locale]/admin/(auth)/[...rest]/page.tsx deleted file mode 100644 index c4a8220b7..000000000 --- a/apps/web/src/app/[locale]/admin/(auth)/[...rest]/page.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import type { DynamicAdminViewProps } from 'vitnode/views/admin/dynamic-admin-view'; - -import { vitNodeConfig } from '@/vitnode.config'; -import { - DynamicAdminView, - dynamicAdminViewGenerateStaticParams, - generateMetadataDynamicAdminView, -} from 'vitnode/views/admin/dynamic-admin-view'; - -export const generateMetadata = generateMetadataDynamicAdminView; -export const generateStaticParams = dynamicAdminViewGenerateStaticParams; - -export default function CatchAllPage(props: DynamicAdminViewProps) { - return ; -} diff --git a/packages/vitnode/scripts/plugin.ts b/packages/vitnode/scripts/plugin.ts index e24f5933b..945b8b210 100644 --- a/packages/vitnode/scripts/plugin.ts +++ b/packages/vitnode/scripts/plugin.ts @@ -135,6 +135,11 @@ const getAllFiles = (dir: string): string[] => { return files; }; +interface SourceConfig { + destinationDir: string; + sourceDir: string; +} + export const processPlugin = ({ initMessage }: { initMessage: string }) => { const pluginDir = process.cwd(); const repoRoot = findRepoRoot(pluginDir); @@ -154,26 +159,46 @@ export const processPlugin = ({ initMessage }: { initMessage: string }) => { console.error(`\x1b[31mError reading package.json:\x1b[0m`, error); } - const sourceDir = join(pluginDir, 'src', 'app'); - const pluginPath = + const mainDest = join( + repoRoot, + 'apps', + 'web', + 'src', + 'app', + '[locale]', + '(main)', pluginName === 'vitnode' ? join('(vitnode)') - : join('(plugins)', `(${pluginName})`); - - const destinationDir = join( + : join('(plugins)', `(${pluginName})`), + ); + const adminDest = join( repoRoot, 'apps', 'web', 'src', 'app', '[locale]', - '(main)', - pluginPath, + 'admin', + '(auth)', + pluginName === 'vitnode' + ? join('(vitnode)', 'core') + : join('(plugins)', pluginName), ); - // Create destination directory if it doesn't exist - if (!existsSync(destinationDir)) { - mkdirSync(destinationDir, { recursive: true }); + // tell the copier about both trees + const sources: SourceConfig[] = [ + { + sourceDir: join(pluginDir, 'src', 'app_admin'), + destinationDir: adminDest, + }, + { sourceDir: join(pluginDir, 'src', 'app'), destinationDir: mainDest }, + ]; + + // Create destination directories if they don't exist + for (const { destinationDir } of sources) { + if (!existsSync(destinationDir)) { + mkdirSync(destinationDir, { recursive: true }); + } } const copyFile = (srcPath: string, destPath: string, pluginName?: string) => { @@ -274,21 +299,43 @@ export const processPlugin = ({ initMessage }: { initMessage: string }) => { }; // Clean up any files that were deleted while the script wasn't running - cleanupDeletedFiles(sourceDir, destinationDir); + // Clean up deleted files for each source directory + for (const { sourceDir, destinationDir } of sources) { + cleanupDeletedFiles(sourceDir, destinationDir); + } console.log( `${initMessage} \x1b[34mWatching for changes in plugins...\x1b[0m`, ); - const watcher = chokidar.watch(sourceDir, { + const sourceDirs = sources + .map(s => s.sourceDir) + .filter(dir => existsSync(dir)); + + const watcher = chokidar.watch(sourceDirs, { ignoreInitial: false, persistent: true, }); const getDestinationPath = (srcPath: string): string => { - const relativePath = relative(sourceDir, srcPath); + // collect all matching sourceConfigs + const candidates = sources.filter(({ sourceDir }) => + srcPath.startsWith(sourceDir), + ); + + if (candidates.length === 0) { + throw new Error(`No matching source directory for: ${srcPath}`); + } + + // pick the one with the longest sourceDir (most specific) + const sourceConfig = candidates.reduce((best, cur) => + cur.sourceDir.length > best.sourceDir.length ? cur : best, + ); + + // now append the relative path + const relativePath = relative(sourceConfig.sourceDir, srcPath); - return join(destinationDir, relativePath); + return join(sourceConfig.destinationDir, relativePath); }; watcher diff --git a/packages/vitnode/src/app_admin/page.tsx b/packages/vitnode/src/app_admin/page.tsx new file mode 100644 index 000000000..0ba052e39 --- /dev/null +++ b/packages/vitnode/src/app_admin/page.tsx @@ -0,0 +1,5 @@ +import { DashboardAdminView } from '../views/admin/views/core/dashboard/dashboard-admin-view'; + +export default function Page() { + return ; +} diff --git a/packages/vitnode/src/app_admin/test/page.tsx b/packages/vitnode/src/app_admin/test/page.tsx new file mode 100644 index 000000000..537c4e896 --- /dev/null +++ b/packages/vitnode/src/app_admin/test/page.tsx @@ -0,0 +1,5 @@ +import { TestView } from '../../views/admin/views/core/test'; + +export default function Page() { + return ; +} diff --git a/packages/vitnode/src/app_admin/users/page.tsx b/packages/vitnode/src/app_admin/users/page.tsx new file mode 100644 index 000000000..f73488f26 --- /dev/null +++ b/packages/vitnode/src/app_admin/users/page.tsx @@ -0,0 +1,7 @@ +import { UsersAdminView } from '../../views/admin/views/core/users/users-admin-view'; + +export default function Page( + props: React.ComponentProps, +) { + return ; +} diff --git a/packages/vitnode/src/views/admin/dynamic-admin-view.tsx b/packages/vitnode/src/views/admin/dynamic-admin-view.tsx deleted file mode 100644 index aaefa6376..000000000 --- a/packages/vitnode/src/views/admin/dynamic-admin-view.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import type { Metadata } from 'next/dist/types'; - -import { setRequestLocale } from 'next-intl/server'; -import { notFound } from 'next/navigation'; - -import type { VitNodeConfig } from '../../vitnode.config'; - -import { DashboardAdminView } from './views/core/dashboard/dashboard-admin-view'; -import { TestView } from './views/core/test'; -import { UsersAdminView } from './views/core/users/users-admin-view'; - -export interface DynamicAdminViewProps { - params: Promise<{ - locale: string; - rest: string[]; - }>; - searchParams: Promise>; -} - -export const generateMetadataDynamicAdminView = async ({ - params, -}: DynamicAdminViewProps): Promise => { - const { rest } = await params; - const path = rest.join('/'); - - const views: Record> = {}; - - return await views[path]; -}; - -export const DynamicAdminView = async ( - props: DynamicAdminViewProps & { - config: VitNodeConfig; - }, -) => { - const { rest, locale } = await props.params; - setRequestLocale(locale); - const path = rest.join('/'); - - const views = { - core: , - 'core/users': , - 'core/test': , - }; - - const view = views[path]; - - if (view) { - return view; - } - - notFound(); -}; - -export const dynamicAdminViewGenerateStaticParams = () => { - return ['core', 'core/users', 'core/test'].map(item => ({ - rest: item.split('/'), - })); -}; diff --git a/plugins/blog/src/app/blog/page.tsx b/plugins/blog/src/app/blog/page.tsx index 0ef15a9c0..085899b19 100644 --- a/plugins/blog/src/app/blog/page.tsx +++ b/plugins/blog/src/app/blog/page.tsx @@ -8,7 +8,7 @@ export default function Page() { <> - Go to blog - test + Go to blog - test 123 ); } diff --git a/plugins/blog/src/app_admin/categories/page.tsx b/plugins/blog/src/app_admin/categories/page.tsx new file mode 100644 index 000000000..60ba38a0e --- /dev/null +++ b/plugins/blog/src/app_admin/categories/page.tsx @@ -0,0 +1,3 @@ +export default function Page() { + return
Categories from admin - blog plugin
; +} From 1e91cf173b24c3e869c3dba9d3fb38f42be8d72b Mon Sep 17 00:00:00 2001 From: aXenDeveloper Date: Tue, 20 May 2025 22:58:00 +0200 Subject: [PATCH 4/9] feat: Add getConfig script and replace commonjs to ESM for scripts --- apps/web/package.json | 1 + .../(main)/(plugins)/(blog)/blog/page.tsx | 3 +- .../[locale]/(main)/(vitnode)/login/page.tsx | 1 - .../(main)/(vitnode)/register/page.tsx | 1 - packages/eslint/tsconfig.json | 3 +- packages/vitnode/package.json | 7 +- packages/vitnode/scripts/get-config.ts | 17 + packages/vitnode/scripts/prepare-database.ts | 2 +- packages/vitnode/scripts/prepare-files.ts | 4 + packages/vitnode/scripts/scripts.ts | 3 + packages/vitnode/tsup.config.ts | 11 + pnpm-lock.yaml | 566 +++++++++--------- 12 files changed, 324 insertions(+), 295 deletions(-) create mode 100644 packages/vitnode/scripts/get-config.ts diff --git a/apps/web/package.json b/apps/web/package.json index 66b5cf072..62140b7d0 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -5,6 +5,7 @@ "type": "module", "scripts": { "init": "vitnode init", + "test": "vitnode test", "drizzle-kit": "drizzle-kit", "db:push": "drizzle-kit push", "db:migrate": "drizzle-kit up && drizzle-kit generate && drizzle-kit migrate", diff --git a/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/page.tsx b/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/page.tsx index 41938f2c2..d89100e90 100644 --- a/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/page.tsx +++ b/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/page.tsx @@ -1,7 +1,6 @@ -import { Link } from 'vitnode/lib/navigation'; - import { Test } from 'vitnode-blog/views/test'; import { TestClient } from 'vitnode-blog/views/test/client'; +import { Link } from 'vitnode/lib/navigation'; export default function Page() { return ( diff --git a/apps/web/src/app/[locale]/(main)/(vitnode)/login/page.tsx b/apps/web/src/app/[locale]/(main)/(vitnode)/login/page.tsx index bcc9eed40..9a04c0d56 100644 --- a/apps/web/src/app/[locale]/(main)/(vitnode)/login/page.tsx +++ b/apps/web/src/app/[locale]/(main)/(vitnode)/login/page.tsx @@ -1,7 +1,6 @@ import type { Metadata } from 'next/dist/types'; import { getTranslations } from 'next-intl/server'; - import { SignInView } from 'vitnode/views/auth/sign-in/sign-in-view'; export const generateMetadata = async ({ diff --git a/apps/web/src/app/[locale]/(main)/(vitnode)/register/page.tsx b/apps/web/src/app/[locale]/(main)/(vitnode)/register/page.tsx index 89be25034..4c9e16800 100644 --- a/apps/web/src/app/[locale]/(main)/(vitnode)/register/page.tsx +++ b/apps/web/src/app/[locale]/(main)/(vitnode)/register/page.tsx @@ -1,7 +1,6 @@ import type { Metadata } from 'next/dist/types'; import { getTranslations } from 'next-intl/server'; - import { SignUpView } from 'vitnode/views/auth/sign-up/sign-up-view'; export const generateMetadata = async ({ diff --git a/packages/eslint/tsconfig.json b/packages/eslint/tsconfig.json index d4b966d55..826f2b958 100644 --- a/packages/eslint/tsconfig.json +++ b/packages/eslint/tsconfig.json @@ -18,6 +18,7 @@ "strictBindCallApply": false, "allowSyntheticDefaultImports": true, "forceConsistentCasingInFileNames": true, - "erasableSyntaxOnly": true + "erasableSyntaxOnly": true, + "verbatimModuleSyntax": true } } diff --git a/packages/vitnode/package.json b/packages/vitnode/package.json index 75e1f9b7e..dd37eba80 100644 --- a/packages/vitnode/package.json +++ b/packages/vitnode/package.json @@ -36,6 +36,7 @@ "tailwindcss": "^4.1.5", "tsc-alias": "^1.8.15", "tsup": "^8.4.0", + "tsx": "^4.19.4", "tw-animate-css": "^1.2.8", "typescript": "^5.8.3", "vite-tsconfig-paths": "^5.1.4", @@ -43,7 +44,7 @@ "zod": "^3.24.3" }, "bin": { - "vitnode": "./dist/scripts/scripts.cjs" + "vitnode": "./dist/scripts/scripts.js" }, "exports": { "./api/config": { @@ -60,9 +61,9 @@ }, "scripts": { "build:scripts": "tsup", - "start:scripts": "node dist/scripts/scripts.cjs plugin --w", + "start:scripts": "node dist/scripts/scripts.js plugin --w", "build": "tsc && swc src -d dist --config-file .swcrc && tsc-alias -p tsconfig.json", - "dev": "concurrently \"tsc -w --preserveWatchOutput\" \"swc src -d dist --config-file .swcrc -w\" \"tsc-alias -w\" \"node dist/scripts/scripts.cjs plugin --w\"", + "dev": "concurrently \"tsc -w --preserveWatchOutput\" \"swc src -d dist --config-file .swcrc -w\" \"tsc-alias -w\" \"node dist/scripts/scripts.js plugin --w\"", "dev:email": "email dev", "lint": "eslint .", "lint:fix": "eslint . --fix", diff --git a/packages/vitnode/scripts/get-config.ts b/packages/vitnode/scripts/get-config.ts new file mode 100644 index 000000000..6f82dccef --- /dev/null +++ b/packages/vitnode/scripts/get-config.ts @@ -0,0 +1,17 @@ +/* eslint-disable no-console */ +import { join } from 'path'; +import { pathToFileURL } from 'url'; + +export const getConfig = async () => { + const configPath = join(process.cwd(), 'src', 'vitnode.config.ts'); + try { + const configUrl = pathToFileURL(configPath).href; + const loaded = await import(configUrl); + + const config = loaded.vitNodeConfig ?? loaded.default; + console.log('Config metadata title:', config.metadata.title); + } catch (error) { + console.error('Failed to load config:', error); + process.exit(1); + } +}; diff --git a/packages/vitnode/scripts/prepare-database.ts b/packages/vitnode/scripts/prepare-database.ts index 151e24db1..765539044 100644 --- a/packages/vitnode/scripts/prepare-database.ts +++ b/packages/vitnode/scripts/prepare-database.ts @@ -146,7 +146,7 @@ export const prepareDatabase = async ({ await generateDatabaseMigrations(); console.log(`${initMessage} [2/3] Run migrations...`); await runMigrations(); - console.log(`${initMessage} [3/3] Insert initial data...`); + console.log(`\n${initMessage} [3/3] Insert initial data...`); await initialDataForDatabase(); console.log(`${initMessage} \x1b[32mDatabase prepared successfully.\x1b[0m`); process.exit(0); diff --git a/packages/vitnode/scripts/prepare-files.ts b/packages/vitnode/scripts/prepare-files.ts index 4049673b5..d1be5dfb8 100644 --- a/packages/vitnode/scripts/prepare-files.ts +++ b/packages/vitnode/scripts/prepare-files.ts @@ -2,6 +2,10 @@ import { existsSync } from 'fs'; import { cp, mkdir } from 'fs/promises'; import { join } from 'path'; +import { dirname } from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); const copyDatabase = async (pluginsPath: string) => { const databasePath = join(__dirname, '..', '..', 'src', 'database'); diff --git a/packages/vitnode/scripts/scripts.ts b/packages/vitnode/scripts/scripts.ts index 63a9162fa..88f9cd98e 100644 --- a/packages/vitnode/scripts/scripts.ts +++ b/packages/vitnode/scripts/scripts.ts @@ -3,6 +3,7 @@ import { existsSync } from 'fs'; import { join } from 'path'; +import { getConfig } from './get-config.js'; import { processPlugin } from './plugin.js'; import { prepareDatabase } from './prepare-database.js'; import { prepareFiles } from './prepare-files.js'; @@ -29,6 +30,8 @@ if (process.argv[2] === 'prepare') { (process.argv[3] === '--w' || process.argv[3] === '--watch') ) { processPlugin({ initMessage }); +} else if (process.argv[2] === 'test') { + void getConfig(); } else { console.log( `${initMessage} \x1b[31mCommand not found: "${process.argv[2] ?? ''}"\x1b[0m`, diff --git a/packages/vitnode/tsup.config.ts b/packages/vitnode/tsup.config.ts index 8aa2bfcb1..666887f35 100644 --- a/packages/vitnode/tsup.config.ts +++ b/packages/vitnode/tsup.config.ts @@ -5,4 +5,15 @@ export default defineConfig({ outDir: 'dist/scripts', clean: false, minify: true, + splitting: true, + format: 'esm', + target: 'esnext', + platform: 'node', + noExternal: ['fs'], + banner: { + js: `import 'tsx/esm'; +import { createRequire } from 'module'; +const require = createRequire(import.meta.url); +`, + }, }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 246fd8411..fc982b2cb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -37,7 +37,7 @@ importers: version: 11.6.3(@fumadocs/mdx-remote@1.3.0(acorn@8.14.1)(fumadocs-core@15.3.0(@types/react@19.1.3)(next@15.3.2(@playwright/test@1.52.0)(babel-plugin-react-compiler@19.1.0-rc.1)(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))(react@19.1.0))(acorn@8.14.1)(fumadocs-core@15.3.0(@types/react@19.1.3)(next@15.3.2(@playwright/test@1.52.0)(babel-plugin-react-compiler@19.1.0-rc.1)(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))(next@15.3.2(@playwright/test@1.52.0)(babel-plugin-react-compiler@19.1.0-rc.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)) fumadocs-ui: specifier: ^15.2.12 - version: 15.3.0(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(next@15.3.2(@playwright/test@1.52.0)(babel-plugin-react-compiler@19.1.0-rc.1)(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)(tailwindcss@4.1.6) + version: 15.3.0(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(next@15.3.2(@playwright/test@1.52.0)(babel-plugin-react-compiler@19.1.0-rc.1)(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)(tailwindcss@4.1.6) lucide-react: specifier: ^0.509.0 version: 0.509.0(react@19.1.0) @@ -71,7 +71,7 @@ importers: version: 19.1.3 '@types/react-dom': specifier: ^19.1.2 - version: 19.1.3(@types/react@19.1.3) + version: 19.1.5(@types/react@19.1.3) postcss: specifier: ^8.5.3 version: 8.5.3 @@ -159,7 +159,7 @@ importers: version: 19.1.3 '@types/react-dom': specifier: ^19.1.2 - version: 19.1.3(@types/react@19.1.3) + version: 19.1.5(@types/react@19.1.3) eslint: specifier: ^9.25.1 version: 9.26.0(jiti@2.4.2) @@ -271,7 +271,7 @@ importers: version: 2.1.1 cmdk: specifier: ^1.1.1 - version: 1.1.1(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + version: 1.1.1(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) input-otp: specifier: ^1.4.2 version: 1.4.2(react-dom@19.1.0(react@19.1.0))(react@19.1.0) @@ -286,7 +286,7 @@ importers: version: 3.4.5 radix-ui: specifier: ^1.3.4 - version: 1.4.1(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + version: 1.4.1(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) react-scan: specifier: ^0.3.3 version: 0.3.3(@types/react@19.1.3)(next@15.3.2(@babel/core@7.27.1)(@playwright/test@1.52.0)(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)(rollup@4.40.1) @@ -298,7 +298,7 @@ importers: version: 3.2.0 vaul: specifier: ^1.1.2 - version: 1.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + version: 1.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) devDependencies: '@hono/swagger-ui': specifier: ^0.5.1 @@ -323,7 +323,7 @@ importers: version: 1.11.24 '@testing-library/react': specifier: ^16.3.0 - version: 16.3.0(@testing-library/dom@9.3.4)(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + version: 16.3.0(@testing-library/dom@9.3.4)(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@types/node': specifier: ^22.15.3 version: 22.15.17 @@ -335,7 +335,7 @@ importers: version: 19.1.3 '@types/react-dom': specifier: ^19.1.3 - version: 19.1.3(@types/react@19.1.3) + version: 19.1.5(@types/react@19.1.3) '@vitejs/plugin-react': specifier: ^4.4.1 version: 4.4.1(vite@5.4.19(@types/node@22.15.17)(lightningcss@1.29.2)) @@ -402,6 +402,9 @@ importers: tsup: specifier: ^8.4.0 version: 8.4.0(@swc/core@1.11.24)(jiti@2.4.2)(postcss@8.5.3)(tsx@4.19.4)(typescript@5.8.3)(yaml@2.7.1) + tsx: + specifier: ^4.19.4 + version: 4.19.4 tw-animate-css: specifier: ^1.2.8 version: 1.2.9 @@ -3410,11 +3413,6 @@ packages: '@types/prompts@2.4.9': resolution: {integrity: sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA==} - '@types/react-dom@19.1.3': - resolution: {integrity: sha512-rJXC08OG0h3W6wDMFxQrZF00Kq6qQvw0djHRdzl3U5DnIERz0MRce3WVc7IS6JYBwtaP/DwYtRRjVlvivNveKg==} - peerDependencies: - '@types/react': ^19.0.0 - '@types/react-dom@19.1.5': resolution: {integrity: sha512-CMCjrWucUBZvohgZxkjd6S9h0nZxXjzus6yDfUb+xLxYM7VvjKNH1tQrE9GWLql1XoOP4/Ds3bwFqShHUYraGg==} peerDependencies: @@ -8595,68 +8593,68 @@ snapshots: '@radix-ui/primitive@1.1.2': {} - '@radix-ui/react-accessible-icon@1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-accessible-icon@1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: - '@radix-ui/react-visually-hidden': 1.2.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-visually-hidden': 1.2.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(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) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-accordion@1.2.10(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-accordion@1.2.10(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-collapsible': 1.1.10(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-collection': 1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-collapsible': 1.1.10(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-collection': 1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-direction': 1.1.1(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-id': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.3)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-alert-dialog@1.1.13(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-alert-dialog@1.1.13(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-dialog': 1.1.13(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-dialog': 1.1.13(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-slot': 1.2.2(@types/react@19.1.3)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-arrow@1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-arrow@1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(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) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-aspect-ratio@1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-aspect-ratio@1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(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) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-avatar@1.1.9(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-avatar@1.1.9(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.3)(react@19.1.0) @@ -8664,15 +8662,15 @@ snapshots: react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-checkbox@1.3.1(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-checkbox@1.3.1(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.3)(react@19.1.0) @@ -8680,35 +8678,35 @@ snapshots: react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-collapsible@1.1.10(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-collapsible@1.1.10(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-id': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.3)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-collection@1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-collection@1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-slot': 1.2.2(@types/react@19.1.3)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) '@radix-ui/react-compose-refs@1.1.2(@types/react@19.1.3)(react@19.1.0)': dependencies: @@ -8716,19 +8714,19 @@ snapshots: optionalDependencies: '@types/react': 19.1.3 - '@radix-ui/react-context-menu@2.2.14(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-context-menu@2.2.14(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-menu': 2.1.14(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-menu': 2.1.14(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.3)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) '@radix-ui/react-context@1.1.2(@types/react@19.1.3)(react@19.1.0)': dependencies: @@ -8736,18 +8734,18 @@ snapshots: optionalDependencies: '@types/react': 19.1.3 - '@radix-ui/react-dialog@1.1.11(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-dialog@1.1.11(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-dismissable-layer': 1.1.7(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.7(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-focus-scope': 1.1.4(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-focus-scope': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-id': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-portal': 1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-primitive': 2.1.0(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-portal': 1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.0(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-slot': 1.2.0(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.3)(react@19.1.0) aria-hidden: 1.2.4 @@ -8756,20 +8754,20 @@ snapshots: react-remove-scroll: 2.6.3(@types/react@19.1.3)(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-dialog@1.1.13(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-dialog@1.1.13(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-dismissable-layer': 1.1.9(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-focus-scope': 1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-focus-scope': 1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-id': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-portal': 1.1.8(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-portal': 1.1.8(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-slot': 1.2.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.3)(react@19.1.0) aria-hidden: 1.2.4 @@ -8778,7 +8776,7 @@ snapshots: react-remove-scroll: 2.6.3(@types/react@19.1.3)(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) '@radix-ui/react-direction@1.1.1(@types/react@19.1.3)(react@19.1.0)': dependencies: @@ -8786,46 +8784,46 @@ snapshots: optionalDependencies: '@types/react': 19.1.3 - '@radix-ui/react-dismissable-layer@1.1.7(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-dismissable-layer@1.1.7(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-primitive': 2.1.0(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.0(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.1.3)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-dismissable-layer@1.1.9(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-dismissable-layer@1.1.9(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.1.3)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-dropdown-menu@2.1.14(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-dropdown-menu@2.1.14(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-id': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-menu': 2.1.14(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-menu': 2.1.14(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.3)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) '@radix-ui/react-focus-guards@1.1.2(@types/react@19.1.3)(react@19.1.0)': dependencies: @@ -8833,58 +8831,58 @@ snapshots: optionalDependencies: '@types/react': 19.1.3 - '@radix-ui/react-focus-scope@1.1.4(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-focus-scope@1.1.4(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-primitive': 2.1.0(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.0(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.3)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-focus-scope@1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-focus-scope@1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.3)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-form@0.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-form@0.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-id': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-label': 2.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-label': 2.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(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) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-hover-card@1.1.13(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-hover-card@1.1.13(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-dismissable-layer': 1.1.9(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-popper': 1.2.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-portal': 1.1.8(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-popper': 1.2.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-portal': 1.1.8(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.3)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) '@radix-ui/react-id@1.1.1(@types/react@19.1.3)(react@19.1.0)': dependencies: @@ -8893,31 +8891,31 @@ snapshots: optionalDependencies: '@types/react': 19.1.3 - '@radix-ui/react-label@2.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-label@2.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(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) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-menu@2.1.14(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-menu@2.1.14(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-collection': 1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-collection': 1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-direction': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-dismissable-layer': 1.1.9(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-focus-scope': 1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-focus-scope': 1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-id': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-popper': 1.2.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-portal': 1.1.8(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-roving-focus': 1.1.9(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-popper': 1.2.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-portal': 1.1.8(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-roving-focus': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-slot': 1.2.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.3)(react@19.1.0) aria-hidden: 1.2.4 @@ -8926,58 +8924,58 @@ snapshots: react-remove-scroll: 2.6.3(@types/react@19.1.3)(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-menubar@1.1.14(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-menubar@1.1.14(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-collection': 1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-collection': 1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-direction': 1.1.1(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-id': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-menu': 2.1.14(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-roving-focus': 1.1.9(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-menu': 2.1.14(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-roving-focus': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.3)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-navigation-menu@1.2.12(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-navigation-menu@1.2.12(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-collection': 1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-collection': 1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-direction': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-dismissable-layer': 1.1.9(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-id': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-visually-hidden': 1.2.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-visually-hidden': 1.2.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(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) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-one-time-password-field@0.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-one-time-password-field@0.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/number': 1.1.1 '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-collection': 1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-collection': 1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-direction': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-roving-focus': 1.1.9(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-roving-focus': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.1.3)(react@19.1.0) @@ -8986,15 +8984,15 @@ snapshots: react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-password-toggle-field@0.1.1(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-password-toggle-field@0.1.1(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-id': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.1.3)(react@19.1.0) @@ -9002,21 +9000,21 @@ snapshots: react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-popover@1.1.13(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-popover@1.1.13(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-dismissable-layer': 1.1.9(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-focus-scope': 1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-focus-scope': 1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-id': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-popper': 1.2.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-portal': 1.1.8(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-popper': 1.2.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-portal': 1.1.8(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-slot': 1.2.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.3)(react@19.1.0) aria-hidden: 1.2.4 @@ -9025,15 +9023,15 @@ snapshots: react-remove-scroll: 2.6.3(@types/react@19.1.3)(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-popper@1.2.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-popper@1.2.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(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) - '@radix-ui/react-arrow': 1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-arrow': 1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-rect': 1.1.1(@types/react@19.1.3)(react@19.1.0) @@ -9043,29 +9041,29 @@ snapshots: react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-portal@1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-portal@1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: - '@radix-ui/react-primitive': 2.1.0(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.0(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.3)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-portal@1.1.8(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-portal@1.1.8(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.3)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-presence@1.1.4(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-presence@1.1.4(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.3)(react@19.1.0) @@ -9073,45 +9071,45 @@ snapshots: react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-primitive@2.1.0(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-primitive@2.1.0(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/react-slot': 1.2.0(@types/react@19.1.3)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-primitive@2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-primitive@2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/react-slot': 1.2.2(@types/react@19.1.3)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-progress@1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-progress@1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(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) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-radio-group@1.3.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-radio-group@1.3.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-direction': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-roving-focus': 1.1.9(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-roving-focus': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.3)(react@19.1.0) @@ -9119,89 +9117,89 @@ snapshots: react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-roving-focus@1.1.9(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-roving-focus@1.1.9(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-collection': 1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-collection': 1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-direction': 1.1.1(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-id': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.3)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-scroll-area@1.2.8(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-scroll-area@1.2.8(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/number': 1.1.1 '@radix-ui/primitive': 1.1.2 '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-direction': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.3)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-select@2.2.4(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-select@2.2.4(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/number': 1.1.1 '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-collection': 1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-collection': 1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-direction': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-dismissable-layer': 1.1.9(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-focus-scope': 1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-focus-scope': 1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-id': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-popper': 1.2.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-portal': 1.1.8(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-popper': 1.2.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-portal': 1.1.8(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-slot': 1.2.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-visually-hidden': 1.2.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-visually-hidden': 1.2.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) aria-hidden: 1.2.4 react: 19.1.0 react-dom: 19.1.0(react@19.1.0) react-remove-scroll: 2.6.3(@types/react@19.1.3)(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-separator@1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-separator@1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(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) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-slider@1.3.4(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-slider@1.3.4(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/number': 1.1.1 '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-collection': 1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-collection': 1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-direction': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.3)(react@19.1.0) @@ -9210,7 +9208,7 @@ snapshots: react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) '@radix-ui/react-slot@1.2.0(@types/react@19.1.3)(react@19.1.0)': dependencies: @@ -9226,12 +9224,12 @@ snapshots: optionalDependencies: '@types/react': 19.1.3 - '@radix-ui/react-switch@1.2.4(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-switch@1.2.4(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.3)(react@19.1.0) @@ -9239,104 +9237,104 @@ snapshots: react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-tabs@1.1.11(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-tabs@1.1.11(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-direction': 1.1.1(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-id': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-roving-focus': 1.1.9(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-roving-focus': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.3)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-toast@1.2.13(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-toast@1.2.13(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-collection': 1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-collection': 1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-dismissable-layer': 1.1.9(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-portal': 1.1.8(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-portal': 1.1.8(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-visually-hidden': 1.2.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-visually-hidden': 1.2.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(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) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-toggle-group@1.1.9(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-toggle-group@1.1.9(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-direction': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-roving-focus': 1.1.9(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-toggle': 1.1.8(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-roving-focus': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-toggle': 1.1.8(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.3)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-toggle@1.1.8(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-toggle@1.1.8(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.3)(react@19.1.0) react: 19.1.0 react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-toolbar@1.1.9(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-toolbar@1.1.9(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-direction': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-roving-focus': 1.1.9(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-separator': 1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-toggle-group': 1.1.9(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-roving-focus': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-separator': 1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-toggle-group': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(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) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) - '@radix-ui/react-tooltip@1.2.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-tooltip@1.2.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@radix-ui/primitive': 1.1.2 '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-dismissable-layer': 1.1.9(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-id': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-popper': 1.2.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-portal': 1.1.8(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-popper': 1.2.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-portal': 1.1.8(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-slot': 1.2.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-visually-hidden': 1.2.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-visually-hidden': 1.2.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(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) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.1.3)(react@19.1.0)': dependencies: @@ -9399,14 +9397,14 @@ snapshots: optionalDependencies: '@types/react': 19.1.3 - '@radix-ui/react-visually-hidden@1.2.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@radix-ui/react-visually-hidden@1.2.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(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) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) '@radix-ui/rect@1.1.1': {} @@ -9827,7 +9825,7 @@ snapshots: lz-string: 1.5.0 pretty-format: 27.5.1 - '@testing-library/react@16.3.0(@testing-library/dom@9.3.4)(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': + '@testing-library/react@16.3.0(@testing-library/dom@9.3.4)(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)': dependencies: '@babel/runtime': 7.27.1 '@testing-library/dom': 9.3.4 @@ -9835,7 +9833,7 @@ snapshots: react-dom: 19.1.0(react@19.1.0) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) '@tokenizer/token@0.3.0': {} @@ -9929,10 +9927,6 @@ snapshots: '@types/node': 22.15.17 kleur: 3.0.3 - '@types/react-dom@19.1.3(@types/react@19.1.3)': - dependencies: - '@types/react': 19.1.3 - '@types/react-dom@19.1.5(@types/react@19.1.3)': dependencies: '@types/react': 19.1.3 @@ -10547,12 +10541,12 @@ snapshots: clsx@2.1.1: {} - cmdk@1.1.1(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + cmdk@1.1.1(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-dialog': 1.1.11(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-dialog': 1.1.11(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-id': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-primitive': 2.1.0(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.0(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(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) transitivePeerDependencies: @@ -11550,18 +11544,18 @@ snapshots: - acorn - supports-color - fumadocs-ui@15.3.0(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(next@15.3.2(@playwright/test@1.52.0)(babel-plugin-react-compiler@19.1.0-rc.1)(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)(tailwindcss@4.1.6): + fumadocs-ui@15.3.0(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(next@15.3.2(@playwright/test@1.52.0)(babel-plugin-react-compiler@19.1.0-rc.1)(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)(tailwindcss@4.1.6): dependencies: - '@radix-ui/react-accordion': 1.2.10(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-collapsible': 1.1.10(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-dialog': 1.1.13(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-accordion': 1.2.10(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-collapsible': 1.1.10(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-dialog': 1.1.13(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-direction': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-navigation-menu': 1.2.12(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-popover': 1.1.13(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-scroll-area': 1.2.8(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-navigation-menu': 1.2.12(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-popover': 1.1.13(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-scroll-area': 1.2.8(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-slot': 1.2.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-tabs': 1.1.11(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-tabs': 1.1.11(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) class-variance-authority: 0.7.1 fumadocs-core: 15.3.0(@types/react@19.1.3)(next@15.3.2(@playwright/test@1.52.0)(babel-plugin-react-compiler@19.1.0-rc.1)(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) lodash.merge: 4.6.2 @@ -13309,55 +13303,55 @@ snapshots: quick-lru@5.1.1: {} - radix-ui@1.4.1(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + radix-ui@1.4.1(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): dependencies: '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-accessible-icon': 1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-accordion': 1.2.10(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-alert-dialog': 1.1.13(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-arrow': 1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-aspect-ratio': 1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-avatar': 1.1.9(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-checkbox': 1.3.1(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-collapsible': 1.1.10(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-collection': 1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-accessible-icon': 1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-accordion': 1.2.10(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-alert-dialog': 1.1.13(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-arrow': 1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-aspect-ratio': 1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-avatar': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-checkbox': 1.3.1(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-collapsible': 1.1.10(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-collection': 1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-context': 1.1.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-context-menu': 2.2.14(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-dialog': 1.1.13(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-context-menu': 2.2.14(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-dialog': 1.1.13(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-direction': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-dismissable-layer': 1.1.9(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-dropdown-menu': 2.1.14(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-dismissable-layer': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-dropdown-menu': 2.1.14(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-focus-scope': 1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-form': 0.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-hover-card': 1.1.13(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-label': 2.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-menu': 2.1.14(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-menubar': 1.1.14(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-navigation-menu': 1.2.12(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-one-time-password-field': 0.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-password-toggle-field': 0.1.1(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-popover': 1.1.13(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-popper': 1.2.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-portal': 1.1.8(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-progress': 1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-radio-group': 1.3.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-roving-focus': 1.1.9(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-scroll-area': 1.2.8(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-select': 2.2.4(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-separator': 1.1.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-slider': 1.3.4(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-focus-scope': 1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-form': 0.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-hover-card': 1.1.13(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-label': 2.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-menu': 2.1.14(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-menubar': 1.1.14(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-navigation-menu': 1.2.12(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-one-time-password-field': 0.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-password-toggle-field': 0.1.1(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-popover': 1.1.13(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-popper': 1.2.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-portal': 1.1.8(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-primitive': 2.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-progress': 1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-radio-group': 1.3.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-roving-focus': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-scroll-area': 1.2.8(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-select': 2.2.4(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-separator': 1.1.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-slider': 1.3.4(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-slot': 1.2.2(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-switch': 1.2.4(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-tabs': 1.1.11(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-toast': 1.2.13(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-toggle': 1.1.8(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-toggle-group': 1.1.9(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-toolbar': 1.1.9(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) - '@radix-ui/react-tooltip': 1.2.6(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-switch': 1.2.4(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-tabs': 1.1.11(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-toast': 1.2.13(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-toggle': 1.1.8(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-toggle-group': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-toolbar': 1.1.9(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-tooltip': 1.2.6(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.3)(react@19.1.0) @@ -13365,12 +13359,12 @@ snapshots: '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.3)(react@19.1.0) '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.3)(react@19.1.0) - '@radix-ui/react-visually-hidden': 1.2.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-visually-hidden': 1.2.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(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) optionalDependencies: '@types/react': 19.1.3 - '@types/react-dom': 19.1.3(@types/react@19.1.3) + '@types/react-dom': 19.1.5(@types/react@19.1.3) range-parser@1.2.1: {} @@ -14312,7 +14306,7 @@ snapshots: tsx@4.19.4: dependencies: - esbuild: 0.25.3 + esbuild: 0.25.4 get-tsconfig: 4.10.0 optionalDependencies: fsevents: 2.3.3 @@ -14508,9 +14502,9 @@ snapshots: vary@1.1.2: {} - vaul@1.1.2(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): + vaul@1.1.2(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0): dependencies: - '@radix-ui/react-dialog': 1.1.11(@types/react-dom@19.1.3(@types/react@19.1.3))(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@radix-ui/react-dialog': 1.1.11(@types/react-dom@19.1.5(@types/react@19.1.3))(@types/react@19.1.3)(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) transitivePeerDependencies: From a3033469e8332afa278192ef3d423b0586954c7c Mon Sep 17 00:00:00 2001 From: aXenDeveloper Date: Sun, 25 May 2025 12:13:26 +0200 Subject: [PATCH 5/9] feat: Add checking package.json for plugins --- .cursor/rules/backend/backend.mdc | 8 ---- .cursor/rules/docs.mdc | 13 ------ .cursor/rules/frontend/frontend.mdc | 10 ---- .cursor/rules/frontend/i18n.mdc | 9 ---- .cursor/rules/global.mdc | 15 ------ .github/copilot-instructions.md | 46 +++++++++++++++++++ .../(main)/(plugins)/(blog)/blog/page.tsx | 3 +- .../(plugins)/(blog)/blog/test/page.tsx | 9 ++++ .../[locale]/(main)/(vitnode)/login/page.tsx | 1 + .../(main)/(vitnode)/register/page.tsx | 1 + apps/web/src/vitnode.api.config.ts | 2 +- .../src/helpers/get-package-json.ts | 4 +- packages/eslint/eslint.config.mjs | 1 + packages/vitnode/src/api/lib/plugin.ts | 10 +++- packages/vitnode/src/api/lib/route.ts | 11 +++-- .../src/api/modules/admin/admin.module.ts | 2 +- .../api/modules/admin/routes/session.route.ts | 2 +- .../modules/admin/users/routes/list.route.ts | 2 +- .../modules/admin/users/routes/users.route.ts | 2 +- .../modules/admin/users/users.admin.module.ts | 2 +- .../modules/middleware/middleware.module.ts | 2 +- .../src/api/modules/middleware/route.ts | 2 +- .../src/api/modules/middleware/test.ts | 2 +- .../api/modules/users/routes/session.route.ts | 2 +- .../api/modules/users/routes/sign-in.route.ts | 2 +- .../modules/users/routes/sign-out.route.ts | 2 +- .../api/modules/users/routes/sign-up.route.ts | 2 +- .../api/modules/users/routes/test.route.ts | 2 +- .../users/sso/routes/callback.route.ts | 2 +- .../users/sso/routes/create-url.route.ts | 2 +- .../src/api/modules/users/sso/sso.module.ts | 2 +- .../src/api/modules/users/users.module.ts | 2 +- packages/vitnode/src/api/plugin.ts | 2 +- .../src/lib/get-plugin-package-json.ts | 30 ++++++++++++ .../modules/categories/categories.module.ts | 2 +- .../blog/src/api/modules/categories/route.ts | 2 +- plugins/blog/src/app/blog/test/page.tsx | 9 ++++ plugins/blog/src/{api.ts => config.api.ts} | 0 plugins/blog/src/config.ts | 2 +- 39 files changed, 139 insertions(+), 85 deletions(-) delete mode 100644 .cursor/rules/backend/backend.mdc delete mode 100644 .cursor/rules/docs.mdc delete mode 100644 .cursor/rules/frontend/frontend.mdc delete mode 100644 .cursor/rules/frontend/i18n.mdc delete mode 100644 .cursor/rules/global.mdc create mode 100644 .github/copilot-instructions.md create mode 100644 apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/test/page.tsx create mode 100644 packages/vitnode/src/lib/get-plugin-package-json.ts create mode 100644 plugins/blog/src/app/blog/test/page.tsx rename plugins/blog/src/{api.ts => config.api.ts} (100%) diff --git a/.cursor/rules/backend/backend.mdc b/.cursor/rules/backend/backend.mdc deleted file mode 100644 index 2c2eaf440..000000000 --- a/.cursor/rules/backend/backend.mdc +++ /dev/null @@ -1,8 +0,0 @@ ---- -description: Rule is for generate backend code with Hono.js -globs: -alwaysApply: false ---- -- Use @hono/zod-openapi or zod 3 for schema validation -- Use PostgreSQL with Drizzle ORM -- Use `t.serial().primaryKey()` for all database IDs \ No newline at end of file diff --git a/.cursor/rules/docs.mdc b/.cursor/rules/docs.mdc deleted file mode 100644 index 81a3ef75c..000000000 --- a/.cursor/rules/docs.mdc +++ /dev/null @@ -1,13 +0,0 @@ ---- -description: -globs: *.mdx,*.md -alwaysApply: false ---- -- Use Fumadocs framework -- Write docs in `.mdx` file -- [index.mdx](mdc:apps/docs/content/docs/dev/index.mdx) are the main docs -- Use easy, clear and funny language for documentation to make it accessible to a wide audience (exclude title and deescription) -- Use clear and concise examples to illustrate concepts -- Use `// [!code ++]` to highlight code snippets and `// [!code --]` to hide code snippets -- Don't add h1 tag in markdown -- Don't use emoji on heading \ No newline at end of file diff --git a/.cursor/rules/frontend/frontend.mdc b/.cursor/rules/frontend/frontend.mdc deleted file mode 100644 index 6d326d68a..000000000 --- a/.cursor/rules/frontend/frontend.mdc +++ /dev/null @@ -1,10 +0,0 @@ ---- -description: Rule is for generate frontend code along with Next.js & React -globs: -alwaysApply: false ---- -- Use Next.js 15 -- Use App Router and Server Components -- Use server actions for form handling and data mutations from Server Components -- Leverage Next.js Image component with proper sizing for core web vitals optimization -- Navigation api is in `vitnode/lib/navigation` file. Avoid using `next/navigation` directly \ No newline at end of file diff --git a/.cursor/rules/frontend/i18n.mdc b/.cursor/rules/frontend/i18n.mdc deleted file mode 100644 index 0c975ce1c..000000000 --- a/.cursor/rules/frontend/i18n.mdc +++ /dev/null @@ -1,9 +0,0 @@ ---- -description: Use while write text on frontend -globs: -alwaysApply: false ---- -- Use `next-intl` for internationalization -- Use `t('key')` for translation keys -- Use `getTranslation` function for server component but `useTranslation` for client -- Languages keys should be added in [en.json](mdc:apps/web/src/plugins/core/langs/en.json) file \ No newline at end of file diff --git a/.cursor/rules/global.mdc b/.cursor/rules/global.mdc deleted file mode 100644 index 26fd9e9f1..000000000 --- a/.cursor/rules/global.mdc +++ /dev/null @@ -1,15 +0,0 @@ ---- -description: -globs: -alwaysApply: true ---- - VitNode is a comprehensive framework designed to simplify and accelerate application development with Next.js and Hono.js. Built as a monorepo solution managed by Turborepo, VitNode provides a structured environment that makes development faster and less complex. The framework includes an integrated AdminCP and plugin system to extend its core functionality. - - - Write ESModule only - - Always use snake_case for file name - - Use pnpm as pacakge manager - - Use zod 3 for schema validation - - Use react-hook-form 7 for forms - - Use Shadcn UI & Tailwind CSS 4 for UI - - Respect Prettier [prettierrc.mjs](mdc:packages/eslint/prettierrc.mjs) and ESLint [eslint.config.mjs](mdc:packages/eslint/eslint.config.mjs) - - Use TypeScript 5, React 19 & Hono.js 4 \ No newline at end of file diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 000000000..00fd51080 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,46 @@ +# VitNode Development Guidelines + +VitNode is a comprehensive framework designed to simplify and accelerate application development with Next.js and Hono.js. Built as a monorepo solution managed by Turborepo, VitNode provides a structured environment that makes development faster and less complex. The framework includes an integrated AdminCP and plugin system to extend its core functionality. + +## Global Rules + +- Write ESModule only +- Always use snake_case for file names +- Use pnpm as package manager +- Use Zod 3 for schema validation +- Use react-hook-form 7 for forms +- Use Shadcn UI & Tailwind CSS 4 for UI +- Respect Prettier configuration in `packages/eslint/prettierrc.mjs` and ESLint configuration in `packages/eslint/eslint.config.mjs` +- Use TypeScript 5, React 19 & Hono.js 4 + +## Frontend Development (Next.js & React) + +- Use Next.js 15 +- Use App Router and Server Components +- Use server actions for form handling and data mutations from Server Components +- Leverage Next.js Image component with proper sizing for core web vitals optimization +- Navigation API is in `vitnode/lib/navigation` file. Avoid using `next/navigation` directly + +### Internationalization (i18n) + +- Use `next-intl` for internationalization +- Use `t('key')` for translation keys +- Use `getTranslation` function for server components but `useTranslation` for client components +- Language keys should be added in `apps/web/src/plugins/core/langs/en.json` file + +## Backend Development (Hono.js) + +- Use @hono/zod-openapi or Zod 3 for schema validation +- Use PostgreSQL with Drizzle ORM +- Use `t.serial().primaryKey()` for all database IDs + +## Documentation (\*.mdx files) + +- Use Fumadocs framework +- Write docs in `.mdx` files +- `apps/docs/content/docs/dev/index.mdx` contains the main documentation +- Use easy, clear and funny language for documentation to make it accessible to a wide audience (exclude title and description) +- Use clear and concise examples to illustrate concepts +- Use `// [!code ++]` to highlight code snippets and `// [!code --]` to hide code snippets +- Don't add h1 tag in markdown +- Don't use emoji on headings diff --git a/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/page.tsx b/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/page.tsx index d89100e90..41938f2c2 100644 --- a/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/page.tsx +++ b/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/page.tsx @@ -1,6 +1,7 @@ +import { Link } from 'vitnode/lib/navigation'; + import { Test } from 'vitnode-blog/views/test'; import { TestClient } from 'vitnode-blog/views/test/client'; -import { Link } from 'vitnode/lib/navigation'; export default function Page() { return ( diff --git a/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/test/page.tsx b/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/test/page.tsx new file mode 100644 index 000000000..c34490860 --- /dev/null +++ b/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/test/page.tsx @@ -0,0 +1,9 @@ +import { Link } from 'vitnode/lib/navigation'; + +export default function Page() { + return ( + <> + Go to blog + + ); +} diff --git a/apps/web/src/app/[locale]/(main)/(vitnode)/login/page.tsx b/apps/web/src/app/[locale]/(main)/(vitnode)/login/page.tsx index 9a04c0d56..bcc9eed40 100644 --- a/apps/web/src/app/[locale]/(main)/(vitnode)/login/page.tsx +++ b/apps/web/src/app/[locale]/(main)/(vitnode)/login/page.tsx @@ -1,6 +1,7 @@ import type { Metadata } from 'next/dist/types'; import { getTranslations } from 'next-intl/server'; + import { SignInView } from 'vitnode/views/auth/sign-in/sign-in-view'; export const generateMetadata = async ({ diff --git a/apps/web/src/app/[locale]/(main)/(vitnode)/register/page.tsx b/apps/web/src/app/[locale]/(main)/(vitnode)/register/page.tsx index 4c9e16800..89be25034 100644 --- a/apps/web/src/app/[locale]/(main)/(vitnode)/register/page.tsx +++ b/apps/web/src/app/[locale]/(main)/(vitnode)/register/page.tsx @@ -1,6 +1,7 @@ import type { Metadata } from 'next/dist/types'; import { getTranslations } from 'next-intl/server'; + import { SignUpView } from 'vitnode/views/auth/sign-up/sign-up-view'; export const generateMetadata = async ({ diff --git a/apps/web/src/vitnode.api.config.ts b/apps/web/src/vitnode.api.config.ts index 28bb607e8..06b3cc7bb 100644 --- a/apps/web/src/vitnode.api.config.ts +++ b/apps/web/src/vitnode.api.config.ts @@ -1,4 +1,4 @@ -import { blogApiPlugin } from 'vitnode-blog/api'; +import { blogApiPlugin } from 'vitnode-blog/config.api'; import { NodemailerEmailPlugin } from 'vitnode/api/plugins/email/nodemailer'; import { DiscordSSOApiPlugin } from 'vitnode/api/plugins/sso/discord'; import { FacebookSSOApiPlugin } from 'vitnode/api/plugins/sso/facebook'; diff --git a/packages/create-vitnode-app/src/helpers/get-package-json.ts b/packages/create-vitnode-app/src/helpers/get-package-json.ts index e37a86560..ead3ff3ba 100644 --- a/packages/create-vitnode-app/src/helpers/get-package-json.ts +++ b/packages/create-vitnode-app/src/helpers/get-package-json.ts @@ -1,7 +1,7 @@ -import { readFile } from 'fs/promises'; +import { readFileSync } from 'fs'; import type { PackageJSON } from './packages-json.js'; export const packageJson: PackageJSON = JSON.parse( - await readFile(new URL('../../../package.json', import.meta.url), 'utf-8'), + readFileSync(new URL('../../../package.json', import.meta.url), 'utf-8'), ); diff --git a/packages/eslint/eslint.config.mjs b/packages/eslint/eslint.config.mjs index 9414dd183..fa6849fe3 100644 --- a/packages/eslint/eslint.config.mjs +++ b/packages/eslint/eslint.config.mjs @@ -73,6 +73,7 @@ export default [ }, { rules: { + 'perfectionist/sort-array-includes': 'warn', '@typescript-eslint/consistent-type-imports': 'error', '@typescript-eslint/no-confusing-void-expression': 'off', '@typescript-eslint/no-unnecessary-type-parameters': 'off', diff --git a/packages/vitnode/src/api/lib/plugin.ts b/packages/vitnode/src/api/lib/plugin.ts index 2bd77db6c..3d68e18b4 100644 --- a/packages/vitnode/src/api/lib/plugin.ts +++ b/packages/vitnode/src/api/lib/plugin.ts @@ -2,6 +2,8 @@ import { OpenAPIHono } from '@hono/zod-openapi'; import type { BuildModuleReturn } from './module'; +import { getPluginPackageJson } from '../../lib/get-plugin-package-json'; + export interface BuildPluginApiReturn { hono: OpenAPIHono; name: string; @@ -14,10 +16,16 @@ export function buildApiPlugin

({ modules?: BuildModuleReturn[]; name: P; }): BuildPluginApiReturn { + // Run for checking if the plugin is valid + getPluginPackageJson(name); + const hono = new OpenAPIHono(); modules.forEach(handler => { hono.route(`/${handler.name}`, handler.hono); }); - return { name, hono }; + return { + name: name, + hono, + }; } diff --git a/packages/vitnode/src/api/lib/route.ts b/packages/vitnode/src/api/lib/route.ts index 22f917372..8b069003c 100644 --- a/packages/vitnode/src/api/lib/route.ts +++ b/packages/vitnode/src/api/lib/route.ts @@ -33,10 +33,13 @@ export const buildRoute = < getRoutingPath: () => RoutingPath; }; } => { - const pluginTag = plugin - .split(/[-_]/) - .map(word => word.charAt(0).toUpperCase() + word.slice(1)) - .join(' '); + const pluginTag = + plugin === 'vitnode' + ? 'Core' + : plugin + .split(/[-_]/) + .map(word => word.charAt(0).toUpperCase() + word.slice(1)) + .join(' '); const tags = [pluginTag, ...(route.tags ?? [])]; diff --git a/packages/vitnode/src/api/modules/admin/admin.module.ts b/packages/vitnode/src/api/modules/admin/admin.module.ts index 61beec33b..70b3935b5 100644 --- a/packages/vitnode/src/api/modules/admin/admin.module.ts +++ b/packages/vitnode/src/api/modules/admin/admin.module.ts @@ -5,7 +5,7 @@ import { usersAdminModule } from './users/users.admin.module'; export const adminModule = buildModule({ name: 'admin', - plugin: 'core', + plugin: 'vitnode', routes: [sessionAdminRoute], modules: [usersAdminModule], }); diff --git a/packages/vitnode/src/api/modules/admin/routes/session.route.ts b/packages/vitnode/src/api/modules/admin/routes/session.route.ts index 8c3df327e..b8d907e6c 100644 --- a/packages/vitnode/src/api/modules/admin/routes/session.route.ts +++ b/packages/vitnode/src/api/modules/admin/routes/session.route.ts @@ -4,7 +4,7 @@ import { HTTPException } from 'hono/http-exception'; import { z } from 'zod'; export const sessionAdminRoute = buildRoute({ - plugin: 'core', + plugin: 'vitnode', route: { method: 'get', description: 'Verify admin session', diff --git a/packages/vitnode/src/api/modules/admin/users/routes/list.route.ts b/packages/vitnode/src/api/modules/admin/users/routes/list.route.ts index d9a52c9be..37d02485e 100644 --- a/packages/vitnode/src/api/modules/admin/users/routes/list.route.ts +++ b/packages/vitnode/src/api/modules/admin/users/routes/list.route.ts @@ -9,7 +9,7 @@ import { core_users } from '@/database/schema/users'; import { z } from '@hono/zod-openapi'; export const listUsersAdminRoute = buildRoute({ - plugin: 'core', + plugin: 'vitnode', route: { method: 'get', description: 'Get list of all users', diff --git a/packages/vitnode/src/api/modules/admin/users/routes/users.route.ts b/packages/vitnode/src/api/modules/admin/users/routes/users.route.ts index 9189734d7..14132f645 100644 --- a/packages/vitnode/src/api/modules/admin/users/routes/users.route.ts +++ b/packages/vitnode/src/api/modules/admin/users/routes/users.route.ts @@ -9,7 +9,7 @@ import { core_users } from '@/database/schema/users'; import { z } from '@hono/zod-openapi'; export const usersAdminRoute = buildRoute({ - plugin: 'core', + plugin: 'vitnode', route: { method: 'get', description: 'Get list of all users (Admin only)', diff --git a/packages/vitnode/src/api/modules/admin/users/users.admin.module.ts b/packages/vitnode/src/api/modules/admin/users/users.admin.module.ts index 00defefa1..1ea5193b5 100644 --- a/packages/vitnode/src/api/modules/admin/users/users.admin.module.ts +++ b/packages/vitnode/src/api/modules/admin/users/users.admin.module.ts @@ -4,6 +4,6 @@ import { listUsersAdminRoute } from './routes/list.route'; export const usersAdminModule = buildModule({ name: 'users', - plugin: 'core', + plugin: 'vitnode', routes: [listUsersAdminRoute], }); diff --git a/packages/vitnode/src/api/modules/middleware/middleware.module.ts b/packages/vitnode/src/api/modules/middleware/middleware.module.ts index 923fe69bc..7669ea521 100644 --- a/packages/vitnode/src/api/modules/middleware/middleware.module.ts +++ b/packages/vitnode/src/api/modules/middleware/middleware.module.ts @@ -4,7 +4,7 @@ import { routeMiddleware } from './route'; import { routeTestMiddleware } from './test'; export const middlewareModule = buildModule({ - plugin: 'core', + plugin: 'vitnode', name: 'middleware', routes: [routeMiddleware, routeTestMiddleware], }); diff --git a/packages/vitnode/src/api/modules/middleware/route.ts b/packages/vitnode/src/api/modules/middleware/route.ts index 968fdc03f..7e6e8045b 100644 --- a/packages/vitnode/src/api/modules/middleware/route.ts +++ b/packages/vitnode/src/api/modules/middleware/route.ts @@ -3,7 +3,7 @@ import { EmailModel } from '@/api/models/email'; import { z } from 'zod'; export const routeMiddleware = buildRoute({ - plugin: 'core', + plugin: 'vitnode', route: { path: '/', method: 'get', diff --git a/packages/vitnode/src/api/modules/middleware/test.ts b/packages/vitnode/src/api/modules/middleware/test.ts index 13b3c0707..a6d5bd054 100644 --- a/packages/vitnode/src/api/modules/middleware/test.ts +++ b/packages/vitnode/src/api/modules/middleware/test.ts @@ -10,7 +10,7 @@ import { } from '../../lib/with-pagination'; export const routeTestMiddleware = buildRoute({ - plugin: 'core', + plugin: 'vitnode', route: { path: '/test', method: 'get', diff --git a/packages/vitnode/src/api/modules/users/routes/session.route.ts b/packages/vitnode/src/api/modules/users/routes/session.route.ts index 6910df5a5..e7942c3eb 100644 --- a/packages/vitnode/src/api/modules/users/routes/session.route.ts +++ b/packages/vitnode/src/api/modules/users/routes/session.route.ts @@ -3,7 +3,7 @@ import { SessionAdminModel } from '@/api/models/session-admin'; import { z } from 'zod'; export const sessionRoute = buildRoute({ - plugin: 'core', + plugin: 'vitnode', route: { method: 'get', description: 'Verify session', diff --git a/packages/vitnode/src/api/modules/users/routes/sign-in.route.ts b/packages/vitnode/src/api/modules/users/routes/sign-in.route.ts index bc6a948ac..4ee8f87e7 100644 --- a/packages/vitnode/src/api/modules/users/routes/sign-in.route.ts +++ b/packages/vitnode/src/api/modules/users/routes/sign-in.route.ts @@ -5,7 +5,7 @@ import { UserModel } from '@/api/models/user'; import { z } from 'zod'; export const signInRoute = buildRoute({ - plugin: 'core', + plugin: 'vitnode', route: { method: 'post', description: 'Sign in with email and password', diff --git a/packages/vitnode/src/api/modules/users/routes/sign-out.route.ts b/packages/vitnode/src/api/modules/users/routes/sign-out.route.ts index 973ae5ec1..32c260ed4 100644 --- a/packages/vitnode/src/api/modules/users/routes/sign-out.route.ts +++ b/packages/vitnode/src/api/modules/users/routes/sign-out.route.ts @@ -4,7 +4,7 @@ import { SessionAdminModel } from '@/api/models/session-admin'; import { z } from '@hono/zod-openapi'; export const signOutRoute = buildRoute({ - plugin: 'core', + plugin: 'vitnode', route: { method: 'delete', description: 'Sign out the current admin', diff --git a/packages/vitnode/src/api/modules/users/routes/sign-up.route.ts b/packages/vitnode/src/api/modules/users/routes/sign-up.route.ts index 6013397e2..b048b56e7 100644 --- a/packages/vitnode/src/api/modules/users/routes/sign-up.route.ts +++ b/packages/vitnode/src/api/modules/users/routes/sign-up.route.ts @@ -6,7 +6,7 @@ import { z } from 'zod'; const nameRegex = /^(?!.* {2})[\p{L}\p{N}._@ -]*$/u; export const signUpRoute = buildRoute({ - plugin: 'core', + plugin: 'vitnode', route: { method: 'post', description: 'Create a new user', diff --git a/packages/vitnode/src/api/modules/users/routes/test.route.ts b/packages/vitnode/src/api/modules/users/routes/test.route.ts index efad0701e..47b7128e7 100644 --- a/packages/vitnode/src/api/modules/users/routes/test.route.ts +++ b/packages/vitnode/src/api/modules/users/routes/test.route.ts @@ -2,7 +2,7 @@ import { buildRoute } from '@/api/lib/route'; import { z } from 'zod'; export const testRoute = buildRoute({ - plugin: 'core', + plugin: 'vitnode', route: { method: 'get', description: 'Test route', diff --git a/packages/vitnode/src/api/modules/users/sso/routes/callback.route.ts b/packages/vitnode/src/api/modules/users/sso/routes/callback.route.ts index ea0598e0e..8bef71c4c 100644 --- a/packages/vitnode/src/api/modules/users/sso/routes/callback.route.ts +++ b/packages/vitnode/src/api/modules/users/sso/routes/callback.route.ts @@ -4,7 +4,7 @@ import { SSOModel } from '@/api/models/sso'; import { z } from 'zod'; export const callbackRoute = buildRoute({ - plugin: 'core', + plugin: 'vitnode', route: { method: 'get', description: 'SSO Callback', diff --git a/packages/vitnode/src/api/modules/users/sso/routes/create-url.route.ts b/packages/vitnode/src/api/modules/users/sso/routes/create-url.route.ts index c976850b9..818b6eb3c 100644 --- a/packages/vitnode/src/api/modules/users/sso/routes/create-url.route.ts +++ b/packages/vitnode/src/api/modules/users/sso/routes/create-url.route.ts @@ -3,7 +3,7 @@ import { SSOModel } from '@/api/models/sso'; import { z } from 'zod'; export const createUrlRoute = buildRoute({ - plugin: 'core', + plugin: 'vitnode', route: { method: 'post', description: 'Generate SSO URL', diff --git a/packages/vitnode/src/api/modules/users/sso/sso.module.ts b/packages/vitnode/src/api/modules/users/sso/sso.module.ts index f80c2f59a..51f8a2e89 100644 --- a/packages/vitnode/src/api/modules/users/sso/sso.module.ts +++ b/packages/vitnode/src/api/modules/users/sso/sso.module.ts @@ -5,6 +5,6 @@ import { createUrlRoute } from './routes/create-url.route'; export const ssoUserModule = buildModule({ name: 'sso', - plugin: 'core', + plugin: 'vitnode', routes: [callbackRoute, createUrlRoute], }); diff --git a/packages/vitnode/src/api/modules/users/users.module.ts b/packages/vitnode/src/api/modules/users/users.module.ts index f4a718915..76126e18a 100644 --- a/packages/vitnode/src/api/modules/users/users.module.ts +++ b/packages/vitnode/src/api/modules/users/users.module.ts @@ -8,7 +8,7 @@ import { testRoute } from './routes/test.route'; import { ssoUserModule } from './sso/sso.module'; export const usersModule = buildModule({ - plugin: 'core', + plugin: 'vitnode', name: 'users', routes: [sessionRoute, signInRoute, signOutRoute, signUpRoute, testRoute], modules: [ssoUserModule], diff --git a/packages/vitnode/src/api/plugin.ts b/packages/vitnode/src/api/plugin.ts index b582d2bb9..307e5556d 100644 --- a/packages/vitnode/src/api/plugin.ts +++ b/packages/vitnode/src/api/plugin.ts @@ -4,6 +4,6 @@ import { middlewareModule } from './modules/middleware/middleware.module'; import { usersModule } from './modules/users/users.module'; export const newBuildPluginApiCore = buildApiPlugin({ - name: 'core', + name: 'vitnode', modules: [middlewareModule, usersModule, adminModule], }); diff --git a/packages/vitnode/src/lib/get-plugin-package-json.ts b/packages/vitnode/src/lib/get-plugin-package-json.ts new file mode 100644 index 000000000..d231fbe31 --- /dev/null +++ b/packages/vitnode/src/lib/get-plugin-package-json.ts @@ -0,0 +1,30 @@ +import { existsSync, readFileSync } from 'fs'; +import { join } from 'path'; + +export interface PackageJSON { + dependencies?: Record; + devDependencies?: Record; + exports?: Record>; + name: string; + overrides?: Record; + packageManager?: string; + pnpm?: Record>; + private: boolean; + scripts?: Record; + version: string; + workspaces?: string[]; +} + +export const getPluginPackageJson = (pluginName: string): PackageJSON => { + const path = join(process.cwd(), 'node_modules', pluginName, 'package.json'); + + if (!existsSync(path) && pluginName !== 'vitnode') { + throw new Error( + `package.json file not found at ${path}. If you are the developer of this plugin, please ensure you are using the correct plugin name as specified in its package.json. If you are not the author, please contact the plugin author for support.`, + ); + } + + const content: PackageJSON = JSON.parse(readFileSync(path, 'utf-8')); + + return content; +}; diff --git a/plugins/blog/src/api/modules/categories/categories.module.ts b/plugins/blog/src/api/modules/categories/categories.module.ts index b086fff55..438103d9a 100644 --- a/plugins/blog/src/api/modules/categories/categories.module.ts +++ b/plugins/blog/src/api/modules/categories/categories.module.ts @@ -3,7 +3,7 @@ import { buildModule } from 'vitnode/api/lib/module'; import { categoriesRoute } from './route'; export const categoriesModule = buildModule({ - plugin: 'blog', + plugin: 'vitnode-blog', name: 'categories', routes: [categoriesRoute], }); diff --git a/plugins/blog/src/api/modules/categories/route.ts b/plugins/blog/src/api/modules/categories/route.ts index f5978354b..d4a2dd6b9 100644 --- a/plugins/blog/src/api/modules/categories/route.ts +++ b/plugins/blog/src/api/modules/categories/route.ts @@ -2,7 +2,7 @@ import { z } from '@hono/zod-openapi'; import { buildRoute } from 'vitnode/api/lib/route'; export const categoriesRoute = buildRoute({ - plugin: 'blog', + plugin: 'vitnode-blog', route: { method: 'get', path: '/', diff --git a/plugins/blog/src/app/blog/test/page.tsx b/plugins/blog/src/app/blog/test/page.tsx new file mode 100644 index 000000000..c34490860 --- /dev/null +++ b/plugins/blog/src/app/blog/test/page.tsx @@ -0,0 +1,9 @@ +import { Link } from 'vitnode/lib/navigation'; + +export default function Page() { + return ( + <> + Go to blog + + ); +} diff --git a/plugins/blog/src/api.ts b/plugins/blog/src/config.api.ts similarity index 100% rename from plugins/blog/src/api.ts rename to plugins/blog/src/config.api.ts diff --git a/plugins/blog/src/config.ts b/plugins/blog/src/config.ts index ca730fc84..6afc7e884 100644 --- a/plugins/blog/src/config.ts +++ b/plugins/blog/src/config.ts @@ -1,3 +1,3 @@ export const configPlugin = { - name: 'blog', + name: 'vitnode-blog' as const, }; From 80ffce9858f526c0d0a72980358ce0ba008c10b4 Mon Sep 17 00:00:00 2001 From: aXenDeveloper Date: Sun, 25 May 2025 17:28:20 +0200 Subject: [PATCH 6/9] =?UTF-8?q?feat(plugin):=20=E2=9C=A8=20Refactor=20blog?= =?UTF-8?q?=20plugin=20structure=20and=20enhance=20file=20handling?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/.gitignore | 2 + apps/web/package.json | 2 +- .../(main)/(plugins)/(blog)/blog/layout.tsx | 5 - .../(main)/(plugins)/(blog)/blog/page.tsx | 14 - .../(plugins)/(blog)/blog/test/page.tsx | 9 - .../[locale]/(main)/(vitnode)/login/page.tsx | 21 -- .../(vitnode)/login/sso/[providerId]/page.tsx | 15 -- .../(main)/(vitnode)/register/page.tsx | 21 -- .../admin/(auth)/(vitnode)/core/page.tsx | 5 - .../admin/(auth)/(vitnode)/core/test/page.tsx | 5 - .../(auth)/(vitnode)/core/users/page.tsx | 7 - packages/vitnode/scripts/get-config.ts | 8 +- packages/vitnode/scripts/plugin.ts | 228 ++-------------- .../scripts/{ => prepare}/prepare-files.ts | 5 +- .../scripts/prepare/prepare-plugins.ts | 104 ++++++++ packages/vitnode/scripts/scripts.ts | 42 +-- packages/vitnode/scripts/shared/file-utils.ts | 252 ++++++++++++++++++ .../src/app_admin}/blog/categories/page.tsx | 0 .../blog/src/app_admin/categories/page.tsx | 3 - 19 files changed, 413 insertions(+), 335 deletions(-) delete mode 100644 apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/layout.tsx delete mode 100644 apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/page.tsx delete mode 100644 apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/test/page.tsx delete mode 100644 apps/web/src/app/[locale]/(main)/(vitnode)/login/page.tsx delete mode 100644 apps/web/src/app/[locale]/(main)/(vitnode)/login/sso/[providerId]/page.tsx delete mode 100644 apps/web/src/app/[locale]/(main)/(vitnode)/register/page.tsx delete mode 100644 apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/page.tsx delete mode 100644 apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/test/page.tsx delete mode 100644 apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/users/page.tsx rename packages/vitnode/scripts/{ => prepare}/prepare-files.ts (90%) create mode 100644 packages/vitnode/scripts/prepare/prepare-plugins.ts create mode 100644 packages/vitnode/scripts/shared/file-utils.ts rename {apps/web/src/app/[locale]/admin/(auth)/(plugins) => plugins/blog/src/app_admin}/blog/categories/page.tsx (100%) delete mode 100644 plugins/blog/src/app_admin/categories/page.tsx diff --git a/apps/web/.gitignore b/apps/web/.gitignore index 62121fb82..b2777578b 100644 --- a/apps/web/.gitignore +++ b/apps/web/.gitignore @@ -41,3 +41,5 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts + +# VitNode diff --git a/apps/web/package.json b/apps/web/package.json index 62140b7d0..9fa7daa0b 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -5,7 +5,7 @@ "type": "module", "scripts": { "init": "vitnode init", - "test": "vitnode test", + "prepare": "vitnode prepare", "drizzle-kit": "drizzle-kit", "db:push": "drizzle-kit push", "db:migrate": "drizzle-kit up && drizzle-kit generate && drizzle-kit migrate", diff --git a/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/layout.tsx b/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/layout.tsx deleted file mode 100644 index 8bc961a91..000000000 --- a/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/layout.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { TestLayout } from 'vitnode-blog/views/test/layout'; - -export default function Layout({ children }: { children: React.ReactNode }) { - return {children}; -} diff --git a/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/page.tsx b/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/page.tsx deleted file mode 100644 index 41938f2c2..000000000 --- a/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/page.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { Link } from 'vitnode/lib/navigation'; - -import { Test } from 'vitnode-blog/views/test'; -import { TestClient } from 'vitnode-blog/views/test/client'; - -export default function Page() { - return ( - <> - - - Go to blog - test 123 - - ); -} diff --git a/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/test/page.tsx b/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/test/page.tsx deleted file mode 100644 index c34490860..000000000 --- a/apps/web/src/app/[locale]/(main)/(plugins)/(blog)/blog/test/page.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { Link } from 'vitnode/lib/navigation'; - -export default function Page() { - return ( - <> - Go to blog - - ); -} diff --git a/apps/web/src/app/[locale]/(main)/(vitnode)/login/page.tsx b/apps/web/src/app/[locale]/(main)/(vitnode)/login/page.tsx deleted file mode 100644 index bcc9eed40..000000000 --- a/apps/web/src/app/[locale]/(main)/(vitnode)/login/page.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import type { Metadata } from 'next/dist/types'; - -import { getTranslations } from 'next-intl/server'; - -import { SignInView } from 'vitnode/views/auth/sign-in/sign-in-view'; - -export const generateMetadata = async ({ - locale, -}: { - locale: string; -}): Promise => { - const t = await getTranslations({ locale, namespace: 'core.global' }); - - return { - title: t('login'), - }; -}; - -export default function Page() { - return ; -} diff --git a/apps/web/src/app/[locale]/(main)/(vitnode)/login/sso/[providerId]/page.tsx b/apps/web/src/app/[locale]/(main)/(vitnode)/login/sso/[providerId]/page.tsx deleted file mode 100644 index ebcb22918..000000000 --- a/apps/web/src/app/[locale]/(main)/(vitnode)/login/sso/[providerId]/page.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { CallbackSSOView } from 'vitnode/views/auth/sso/callback/callback-sso-view'; - -export default async function Page({ - params, - searchParams, -}: { - params: Promise<{ providerId: string }>; - searchParams: Promise>; -}) { - const { providerId } = await params; - - return ( - - ); -} diff --git a/apps/web/src/app/[locale]/(main)/(vitnode)/register/page.tsx b/apps/web/src/app/[locale]/(main)/(vitnode)/register/page.tsx deleted file mode 100644 index 89be25034..000000000 --- a/apps/web/src/app/[locale]/(main)/(vitnode)/register/page.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import type { Metadata } from 'next/dist/types'; - -import { getTranslations } from 'next-intl/server'; - -import { SignUpView } from 'vitnode/views/auth/sign-up/sign-up-view'; - -export const generateMetadata = async ({ - locale, -}: { - locale: string; -}): Promise => { - const t = await getTranslations({ locale, namespace: 'core.global' }); - - return { - title: t('register'), - }; -}; - -export default function Page() { - return ; -} diff --git a/apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/page.tsx b/apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/page.tsx deleted file mode 100644 index 63745336c..000000000 --- a/apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { DashboardAdminView } from 'vitnode/views/admin/views/core/dashboard/dashboard-admin-view'; - -export default function Page() { - return ; -} diff --git a/apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/test/page.tsx b/apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/test/page.tsx deleted file mode 100644 index 92ea2fc30..000000000 --- a/apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/test/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import { TestView } from 'vitnode/views/admin/views/core/test'; - -export default function Page() { - return ; -} diff --git a/apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/users/page.tsx b/apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/users/page.tsx deleted file mode 100644 index 306e0807b..000000000 --- a/apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/users/page.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { UsersAdminView } from 'vitnode/views/admin/views/core/users/users-admin-view'; - -export default function Page( - props: React.ComponentProps, -) { - return ; -} diff --git a/packages/vitnode/scripts/get-config.ts b/packages/vitnode/scripts/get-config.ts index 6f82dccef..79c9c1257 100644 --- a/packages/vitnode/scripts/get-config.ts +++ b/packages/vitnode/scripts/get-config.ts @@ -2,14 +2,16 @@ import { join } from 'path'; import { pathToFileURL } from 'url'; -export const getConfig = async () => { +import type { VitNodeConfig } from '../src/vitnode.config'; + +export const getConfig = async (): Promise => { const configPath = join(process.cwd(), 'src', 'vitnode.config.ts'); try { const configUrl = pathToFileURL(configPath).href; const loaded = await import(configUrl); + const config = loaded.vitNodeConfig; - const config = loaded.vitNodeConfig ?? loaded.default; - console.log('Config metadata title:', config.metadata.title); + return config; } catch (error) { console.error('Failed to load config:', error); process.exit(1); diff --git a/packages/vitnode/scripts/plugin.ts b/packages/vitnode/scripts/plugin.ts index 945b8b210..83d785505 100644 --- a/packages/vitnode/scripts/plugin.ts +++ b/packages/vitnode/scripts/plugin.ts @@ -1,162 +1,36 @@ /* eslint-disable no-console */ import chokidar from 'chokidar'; -import { - copyFileSync, - existsSync, - mkdirSync, - readdirSync, - readFileSync, - unlinkSync, - writeFileSync, -} from 'fs'; -import { - basename, - dirname, - extname, - join, - normalize, - relative, - sep, -} from 'path'; - -// Regex patterns for import statements -const relativeImportRegex = - /import\s+(?:(?:{[^}]*})|(?:[^{}\s,]*))?\s*(?:,\s*(?:{[^}]*}))?\s*from\s+['"]([./]+[^'"]*)['"]/g; -const atImportRegex = - /import\s+(?:(?:{[^}]*})|(?:[^{}\s,]*))?\s*(?:,\s*(?:{[^}]*}))?\s*from\s+['"](@\/[^'"]*)['"]/g; -const jsExtensionRegex = /\.(js|jsx|ts|tsx)$/; -const pageFileRegex = /^page\.(tsx|ts|jsx|js)$/i; - -const routeKey = (filePath: string, localeRoot: string): string => { - const rel = relative(localeRoot, filePath); - const parts = rel.split(sep); - - // remove filename - parts.pop(); - - // drop any group folders - const filtered = parts.filter(p => !p.startsWith('(')); - - // '' represents the root route - return normalize(filtered.join('/')); -}; - -const buildInitialRouteMap = (localeRoot: string): Map => { - const map = new Map(); - - const visit = (dir: string) => { - for (const entry of readdirSync(dir, { withFileTypes: true })) { - const full = join(dir, entry.name); - - if (entry.isDirectory()) { - visit(full); - continue; - } - - if (pageFileRegex.test(entry.name)) { - const key = routeKey(full, localeRoot); - map.set(key, full); - } - } - }; - - visit(localeRoot); - - return map; -}; - -// Function to transform file content by updating import statements -const transformFileImports = (content: string, pluginName: string): string => { - // First handle relative imports - let transformedContent = content.replace( - relativeImportRegex, - (match, importPath: string) => { - // Only transform relative imports (starting with ./ or ../) - if (importPath.startsWith('.')) { - // Remove any file extensions from the import path - const cleanPath = importPath.replace(jsExtensionRegex, ''); - // Extract the path after removing leading '../' sequences - const normalizedPath = cleanPath.replace(/^(?:\.\.\/)+/, ''); - // Return the package import format - - return match.replace(importPath, `${pluginName}/${normalizedPath}`); - } - - return match; - }, - ); - - // Then handle @/ imports - transformedContent = transformedContent.replace( - atImportRegex, - (match, importPath: string) => { - // Remove '@/' prefix and any file extensions - const cleanPath = importPath - .replace(/^@\//, '') - .replace(jsExtensionRegex, ''); - // Return the package import format - - return match.replace(importPath, `${pluginName}/${cleanPath}`); - }, - ); +import { existsSync, mkdirSync, readFileSync, unlinkSync } from 'fs'; +import { basename, join, relative } from 'path'; - return transformedContent; -}; - -function findRepoRoot(start: string): string { - let dir = start; - while (dir !== dirname(dir)) { - if ( - existsSync(join(dir, 'turbo.json')) || - existsSync(join(dir, 'pnpm-workspace.yaml')) || - existsSync(join(dir, '.git')) - ) - return dir; - dir = dirname(dir); - } - throw new Error( - '❌ Could not locate monorepo root – add a marker file or pass it via CLI/env', - ); -} - -const getAllFiles = (dir: string): string[] => { - const files: string[] = []; - const entries = readdirSync(dir, { withFileTypes: true }); - - for (const entry of entries) { - const fullPath = join(dir, entry.name); - if (entry.isDirectory()) { - files.push(...getAllFiles(fullPath)); - } else { - files.push(fullPath); - } - } - - return files; -}; - -interface SourceConfig { - destinationDir: string; - sourceDir: string; -} +import { + buildInitialRouteMap, + copyFile, + findRepoRoot, + getAllFiles, + routeKey, + type SourceConfig, +} from './shared/file-utils'; export const processPlugin = ({ initMessage }: { initMessage: string }) => { const pluginDir = process.cwd(); const repoRoot = findRepoRoot(pluginDir); - const pluginName = basename(pluginDir); const localeRoot = join(repoRoot, 'apps', 'web', 'src', 'app', '[locale]'); const routeMap = buildInitialRouteMap(localeRoot); // Get the package name from package.json for imports - let packageName = ''; + let pluginName = basename(pluginDir); try { const packageJsonPath = join(pluginDir, 'package.json'); + if (existsSync(packageJsonPath)) { const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8')); - packageName = packageJson.name ?? ''; + pluginName = packageJson.name ?? ''; } } catch (error) { console.error(`\x1b[31mError reading package.json:\x1b[0m`, error); + + return; } const mainDest = join( @@ -182,7 +56,7 @@ export const processPlugin = ({ initMessage }: { initMessage: string }) => { '(auth)', pluginName === 'vitnode' ? join('(vitnode)', 'core') - : join('(plugins)', pluginName), + : join('(plugins)', `(${pluginName})`), ); // tell the copier about both trees @@ -201,68 +75,8 @@ export const processPlugin = ({ initMessage }: { initMessage: string }) => { } } - const copyFile = (srcPath: string, destPath: string, pluginName?: string) => { - const fileName = basename(srcPath); - if (pageFileRegex.test(fileName)) { - const key = routeKey(destPath, localeRoot); - - const existing = routeMap.get(key); - // another file (not this exact one) already owns the route - if (existing && existing !== destPath) { - console.log( - `\x1b[31mSkipped duplicate page:\x1b[0m ${relative( - repoRoot, - destPath, - )} (collides with ${relative(repoRoot, existing)})`, - ); - - return; // 🔥 skip the copy - } - } - - try { - const destDir = dirname(destPath); - if (!existsSync(destDir)) { - mkdirSync(destDir, { recursive: true }); - } - - // Check if file should have imports processed (like .js, .jsx, .ts, .tsx files) - const ext = extname(srcPath); - if (pluginName && ['.js', '.jsx', '.ts', '.tsx'].includes(ext)) { - // Read file content - const content = readFileSync(srcPath, 'utf-8'); - // Transform imports - const transformedContent = transformFileImports(content, pluginName); - // Write transformed content - writeFileSync(destPath, transformedContent); - } else { - // Copy file directly without transforming - copyFileSync(srcPath, destPath); - } - - // Show even shorter, project-rooted paths for clarity - const repoRoot = findRepoRoot(process.cwd()); - // Remove everything before '/src/app' in the source path if present - const srcAppIdx = srcPath.indexOf(join('src', 'app')); - const shortSrc = - srcAppIdx !== -1 - ? srcPath.substring(srcAppIdx) - : srcPath.startsWith(repoRoot) - ? relative(repoRoot, srcPath) - : srcPath; - const shortDest = destPath.startsWith(repoRoot) - ? relative(repoRoot, destPath) - : destPath; - console.log(`\x1b[32mCopied:\x1b[0m ${shortSrc} → ${shortDest}`); - - // 📝 update the map now that the copy succeeded - if (pageFileRegex.test(basename(destPath))) { - const key = routeKey(destPath, localeRoot); - routeMap.set(key, destPath); - } - } catch (error) { - console.error(`\x1b[31mError copying file:\x1b[0m ${srcPath}`, error); - } + const copyFileWrapper = (srcPath: string, destPath: string) => { + copyFile(srcPath, destPath, pluginName, routeMap, localeRoot, repoRoot); }; const removeFile = (filePath: string) => { @@ -271,7 +85,7 @@ export const processPlugin = ({ initMessage }: { initMessage: string }) => { unlinkSync(filePath); console.log(`\x1b[33mRemoved:\x1b[0m ${filePath}`); - if (pageFileRegex.test(basename(filePath))) { + if (/^page\.(tsx|ts|jsx|js)$/i.test(basename(filePath))) { const key = routeKey(filePath, localeRoot); // only delete if this exact file is the one in the map if (routeMap.get(key) === filePath) { @@ -341,11 +155,11 @@ export const processPlugin = ({ initMessage }: { initMessage: string }) => { watcher .on('add', filePath => { const destPath = getDestinationPath(filePath); - copyFile(filePath, destPath, packageName); + copyFileWrapper(filePath, destPath); }) .on('change', filePath => { const destPath = getDestinationPath(filePath); - copyFile(filePath, destPath, packageName); + copyFileWrapper(filePath, destPath); }) .on('unlink', filePath => { const destPath = getDestinationPath(filePath); diff --git a/packages/vitnode/scripts/prepare-files.ts b/packages/vitnode/scripts/prepare/prepare-files.ts similarity index 90% rename from packages/vitnode/scripts/prepare-files.ts rename to packages/vitnode/scripts/prepare/prepare-files.ts index d1be5dfb8..c4ef96fdb 100644 --- a/packages/vitnode/scripts/prepare-files.ts +++ b/packages/vitnode/scripts/prepare/prepare-files.ts @@ -5,6 +5,8 @@ import { join } from 'path'; import { dirname } from 'path'; import { fileURLToPath } from 'url'; +import { preparePlugins } from './prepare-plugins'; + const __dirname = dirname(fileURLToPath(import.meta.url)); const copyDatabase = async (pluginsPath: string) => { @@ -42,8 +44,9 @@ export const prepareFiles = async ({ initMessage: string; pluginsPath: string; }) => { - console.log(`${initMessage} [1/1] Preparing files...`); + console.log(`${initMessage} Preparing files...`); await copyDatabase(pluginsPath); + await preparePlugins(); console.log(`${initMessage} \x1b[32mFiles prepared successfully.\x1b[0m`); process.exit(0); }; diff --git a/packages/vitnode/scripts/prepare/prepare-plugins.ts b/packages/vitnode/scripts/prepare/prepare-plugins.ts new file mode 100644 index 000000000..1752cad63 --- /dev/null +++ b/packages/vitnode/scripts/prepare/prepare-plugins.ts @@ -0,0 +1,104 @@ +/* eslint-disable no-console */ +import { existsSync, readFileSync } from 'fs'; +import { join, relative } from 'path'; + +import { getConfig } from '../get-config'; +import { + buildInitialRouteMap, + copyDirectoryRecursive, + findRepoRoot, + type SourceConfig, +} from '../shared/file-utils'; + +export const preparePlugins = async () => { + const config = await getConfig(); + const plugins: string[] = [ + ...config.plugins.map(plugin => plugin.name), + 'vitnode', + ]; + + const repoRoot = findRepoRoot(process.cwd()); + const localeRoot = join(repoRoot, 'apps', 'web', 'src', 'app', '[locale]'); + const routeMap = buildInitialRouteMap(localeRoot); + + await Promise.all( + plugins.map(pluginName => { + const pluginPath = join(process.cwd(), 'node_modules', pluginName); + + // Get the package name from package.json for imports + let packageName = ''; + try { + const packageJsonPath = join(pluginPath, 'package.json'); + if (existsSync(packageJsonPath)) { + const packageJson = JSON.parse( + readFileSync(packageJsonPath, 'utf-8'), + ); + packageName = packageJson.name ?? ''; + } + } catch (error) { + console.error( + `\x1b[31mError reading package.json for ${pluginName}:\x1b[0m`, + error, + ); + + return; + } + + const mainDest = join( + repoRoot, + 'apps', + 'web', + 'src', + 'app', + '[locale]', + '(main)', + pluginName === 'vitnode' + ? join('(vitnode)') + : join('(plugins)', `(${pluginName})`), + ); + const adminDest = join( + repoRoot, + 'apps', + 'web', + 'src', + 'app', + '[locale]', + 'admin', + '(auth)', + pluginName === 'vitnode' + ? join('(vitnode)', 'core') + : join('(plugins)', `(${pluginName})`), + ); + + // Define source configurations for this plugin + const sources: SourceConfig[] = [ + { + sourceDir: join(pluginPath, 'src', 'app_admin'), + destinationDir: adminDest, + }, + { + sourceDir: join(pluginPath, 'src', 'app'), + destinationDir: mainDest, + }, + ]; + + // Copy files for each source directory + for (const { sourceDir, destinationDir } of sources) { + if (existsSync(sourceDir)) { + console.log( + `\x1b[36mCopying ${pluginName}:\x1b[0m ${relative(repoRoot, sourceDir)} → ${relative(repoRoot, destinationDir)}`, + ); + copyDirectoryRecursive( + sourceDir, + destinationDir, + packageName, + routeMap, + localeRoot, + repoRoot, + false, // verbose = false for prepare mode + ); + } + } + }), + ); +}; diff --git a/packages/vitnode/scripts/scripts.ts b/packages/vitnode/scripts/scripts.ts index 88f9cd98e..f7ea7230f 100644 --- a/packages/vitnode/scripts/scripts.ts +++ b/packages/vitnode/scripts/scripts.ts @@ -3,10 +3,9 @@ import { existsSync } from 'fs'; import { join } from 'path'; -import { getConfig } from './get-config.js'; import { processPlugin } from './plugin.js'; import { prepareDatabase } from './prepare-database.js'; -import { prepareFiles } from './prepare-files.js'; +import { prepareFiles } from './prepare/prepare-files.js'; const initMessage = '\x1b[34m[VitNode]\x1b[0m'; const getPluginsPath = () => { @@ -21,20 +20,27 @@ const getPluginsPath = () => { return pluginsPath; }; -if (process.argv[2] === 'prepare') { - void prepareFiles({ pluginsPath: getPluginsPath(), initMessage }); -} else if (process.argv[2] === 'init') { - void prepareDatabase({ initMessage }); -} else if ( - process.argv[2] === 'plugin' && - (process.argv[3] === '--w' || process.argv[3] === '--watch') -) { - processPlugin({ initMessage }); -} else if (process.argv[2] === 'test') { - void getConfig(); -} else { - console.log( - `${initMessage} \x1b[31mCommand not found: "${process.argv[2] ?? ''}"\x1b[0m`, - ); - process.exit(1); +const command = process.argv[2]; +const flag = process.argv[3]; + +switch (command) { + case 'init': + void prepareDatabase({ initMessage }); + break; + + case 'plugin': + if (flag === '--w' || flag === '--watch') { + processPlugin({ initMessage }); + } + break; + + case 'prepare': + void prepareFiles({ pluginsPath: getPluginsPath(), initMessage }); + break; + + default: + console.log( + `${initMessage} \x1b[31mCommand not found: "${command ?? ''}"\x1b[0m`, + ); + process.exit(1); } diff --git a/packages/vitnode/scripts/shared/file-utils.ts b/packages/vitnode/scripts/shared/file-utils.ts new file mode 100644 index 000000000..27c47ef04 --- /dev/null +++ b/packages/vitnode/scripts/shared/file-utils.ts @@ -0,0 +1,252 @@ +/* eslint-disable no-console */ +import { + copyFileSync, + existsSync, + mkdirSync, + readdirSync, + readFileSync, + writeFileSync, +} from 'fs'; +import { + basename, + dirname, + extname, + join, + normalize, + relative, + sep, +} from 'path'; + +// Regex patterns for import statements +const relativeImportRegex = + /import\s+(?:(?:{[^}]*})|(?:[^{}\s,]*))?\s*(?:,\s*(?:{[^}]*}))?\s*from\s+['"]([./]+[^'"]*)['"]/g; +const atImportRegex = + /import\s+(?:(?:{[^}]*})|(?:[^{}\s,]*))?\s*(?:,\s*(?:{[^}]*}))?\s*from\s+['"](@\/[^'"]*)['"]/g; +const jsExtensionRegex = /\.(js|jsx|ts|tsx)$/; +const pageFileRegex = /^page\.(tsx|ts|jsx|js)$/i; + +export const routeKey = (filePath: string, localeRoot: string): string => { + const rel = relative(localeRoot, filePath); + const parts = rel.split(sep); + + // remove filename + parts.pop(); + + // drop any group folders + const filtered = parts.filter(p => !p.startsWith('(')); + + // '' represents the root route + return normalize(filtered.join('/')); +}; + +export const buildInitialRouteMap = ( + localeRoot: string, +): Map => { + const map = new Map(); + + const visit = (dir: string) => { + if (!existsSync(dir)) return; + + for (const entry of readdirSync(dir, { withFileTypes: true })) { + const full = join(dir, entry.name); + + if (entry.isDirectory()) { + visit(full); + continue; + } + + if (pageFileRegex.test(entry.name)) { + const key = routeKey(full, localeRoot); + map.set(key, full); + } + } + }; + + visit(localeRoot); + + return map; +}; + +// Function to transform file content by updating import statements +export const transformFileImports = ( + content: string, + pluginName: string, +): string => { + // First handle relative imports + let transformedContent = content.replace( + relativeImportRegex, + (match, importPath: string) => { + // Only transform relative imports (starting with ./ or ../) + if (importPath.startsWith('.')) { + // Remove any file extensions from the import path + const cleanPath = importPath.replace(jsExtensionRegex, ''); + // Extract the path after removing leading '../' sequences + const normalizedPath = cleanPath.replace(/^(?:\.\.\/)+/, ''); + // Return the package import format + + return match.replace(importPath, `${pluginName}/${normalizedPath}`); + } + + return match; + }, + ); + + // Then handle @/ imports + transformedContent = transformedContent.replace( + atImportRegex, + (match, importPath: string) => { + // Remove '@/' prefix and any file extensions + const cleanPath = importPath + .replace(/^@\//, '') + .replace(jsExtensionRegex, ''); + // Return the package import format + + return match.replace(importPath, `${pluginName}/${cleanPath}`); + }, + ); + + return transformedContent; +}; + +export function findRepoRoot(start: string): string { + let dir = start; + while (dir !== dirname(dir)) { + if ( + existsSync(join(dir, 'turbo.json')) || + existsSync(join(dir, 'pnpm-workspace.yaml')) || + existsSync(join(dir, '.git')) + ) + return dir; + dir = dirname(dir); + } + throw new Error( + '❌ Could not locate monorepo root – add a marker file or pass it via CLI/env', + ); +} + +export const getAllFiles = (dir: string): string[] => { + const files: string[] = []; + if (!existsSync(dir)) return files; + + const entries = readdirSync(dir, { withFileTypes: true }); + + for (const entry of entries) { + const fullPath = join(dir, entry.name); + if (entry.isDirectory()) { + files.push(...getAllFiles(fullPath)); + } else { + files.push(fullPath); + } + } + + return files; +}; + +export interface SourceConfig { + destinationDir: string; + sourceDir: string; +} + +export const copyFile = ( + srcPath: string, + destPath: string, + pluginName: string, + routeMap: Map, + localeRoot: string, + repoRoot: string, + verbose = true, +) => { + const fileName = basename(srcPath); + if (pageFileRegex.test(fileName)) { + const key = routeKey(destPath, localeRoot); + + const existing = routeMap.get(key); + // another file (not this exact one) already owns the route + if (existing && existing !== destPath) { + if (verbose) { + console.log( + `\x1b[31mSkipped duplicate page:\x1b[0m ${relative( + repoRoot, + destPath, + )} (collides with ${relative(repoRoot, existing)})`, + ); + } + + return; // 🔥 skip the copy + } + } + + try { + const destDir = dirname(destPath); + if (!existsSync(destDir)) { + mkdirSync(destDir, { recursive: true }); + } + + // Check if file should have imports processed (like .js, .jsx, .ts, .tsx files) + const ext = extname(srcPath); + if (pluginName && ['.js', '.jsx', '.ts', '.tsx'].includes(ext)) { + // Read file content + const content = readFileSync(srcPath, 'utf-8'); + // Transform imports + const transformedContent = transformFileImports(content, pluginName); + // Write transformed content + writeFileSync(destPath, transformedContent); + } else { + // Copy file directly without transforming + copyFileSync(srcPath, destPath); + } + + if (verbose) { + // Show even shorter, project-rooted paths for clarity + // Remove everything before '/src/app' in the source path if present + const srcAppIdx = srcPath.indexOf(join('src', 'app')); + const shortSrc = + srcAppIdx !== -1 + ? srcPath.substring(srcAppIdx) + : srcPath.startsWith(repoRoot) + ? relative(repoRoot, srcPath) + : srcPath; + const shortDest = destPath.startsWith(repoRoot) + ? relative(repoRoot, destPath) + : destPath; + console.log(`\x1b[32mCopied:\x1b[0m ${shortSrc} → ${shortDest}`); + } + + // 📝 update the map now that the copy succeeded + if (pageFileRegex.test(basename(destPath))) { + const key = routeKey(destPath, localeRoot); + routeMap.set(key, destPath); + } + } catch (error) { + console.error(`\x1b[31mError copying file:\x1b[0m ${srcPath}`, error); + } +}; + +export const copyDirectoryRecursive = ( + sourceDir: string, + destinationDir: string, + pluginName: string, + routeMap: Map, + localeRoot: string, + repoRoot: string, + verbose = true, +) => { + if (!existsSync(sourceDir)) return; + + const files = getAllFiles(sourceDir); + + for (const srcFile of files) { + const relativePath = relative(sourceDir, srcFile); + const destFile = join(destinationDir, relativePath); + + copyFile( + srcFile, + destFile, + pluginName, + routeMap, + localeRoot, + repoRoot, + verbose, + ); + } +}; diff --git a/apps/web/src/app/[locale]/admin/(auth)/(plugins)/blog/categories/page.tsx b/plugins/blog/src/app_admin/blog/categories/page.tsx similarity index 100% rename from apps/web/src/app/[locale]/admin/(auth)/(plugins)/blog/categories/page.tsx rename to plugins/blog/src/app_admin/blog/categories/page.tsx diff --git a/plugins/blog/src/app_admin/categories/page.tsx b/plugins/blog/src/app_admin/categories/page.tsx deleted file mode 100644 index 60ba38a0e..000000000 --- a/plugins/blog/src/app_admin/categories/page.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export default function Page() { - return

Categories from admin - blog plugin
; -} From f6f3e77bde8959ecd058e0aa4104de6b7e7d251a Mon Sep 17 00:00:00 2001 From: aXenDeveloper Date: Sun, 25 May 2025 17:36:52 +0200 Subject: [PATCH 7/9] chore: Clean up --- .vscode/settings.json | 2 +- apps/web/.gitignore | 2 -- .../(plugins)/(vitnode-blog)/blog/layout.tsx | 5 +++++ .../(plugins)/(vitnode-blog)/blog/page.tsx | 14 +++++++++++++ .../(vitnode-blog)/blog/test/page.tsx | 9 ++++++++ .../[locale]/(main)/(vitnode)/login/page.tsx | 21 +++++++++++++++++++ .../(vitnode)/login/sso/[providerId]/page.tsx | 15 +++++++++++++ .../(main)/(vitnode)/register/page.tsx | 21 +++++++++++++++++++ .../(vitnode-blog)/blog/categories/page.tsx | 3 +++ .../admin/(auth)/(vitnode)/core/page.tsx | 5 +++++ .../admin/(auth)/(vitnode)/core/test/page.tsx | 5 +++++ .../(auth)/(vitnode)/core/users/page.tsx | 7 +++++++ 12 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 apps/web/src/app/[locale]/(main)/(plugins)/(vitnode-blog)/blog/layout.tsx create mode 100644 apps/web/src/app/[locale]/(main)/(plugins)/(vitnode-blog)/blog/page.tsx create mode 100644 apps/web/src/app/[locale]/(main)/(plugins)/(vitnode-blog)/blog/test/page.tsx create mode 100644 apps/web/src/app/[locale]/(main)/(vitnode)/login/page.tsx create mode 100644 apps/web/src/app/[locale]/(main)/(vitnode)/login/sso/[providerId]/page.tsx create mode 100644 apps/web/src/app/[locale]/(main)/(vitnode)/register/page.tsx create mode 100644 apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-blog)/blog/categories/page.tsx create mode 100644 apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/page.tsx create mode 100644 apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/test/page.tsx create mode 100644 apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/users/page.tsx diff --git a/.vscode/settings.json b/.vscode/settings.json index 4e7edd6bb..df70e6afe 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,7 +2,7 @@ "cSpell.words": ["vitnode"], "github.copilot.chat.commitMessageGeneration.instructions": [ { - "text": "Follow the Conventional Commits format strictly for commit messages. Use the structure below:\n\n```\n[optional scope]: \n```\n\nGuidelines:\n\n1. **Type and Scope**: Choose an appropriate type (e.g., `feat`, `fix`) and optional scope to describe the affected module or feature.\n\n2. **Gitmoji**: Include a relevant `gitmoji` that best represents the nature of the change.\n\n3. **Description**: Write a concise, informative description in the header; use backticks if referencing code or specific terms.\n\nCommit messages should be clear, informative, and professional, aiding readability and project tracking." + "text": "Follow the Conventional Commits format strictly for commit messages. Use the structure below:\n\n```\n[optional scope]: \n```\n\nGuidelines:\n\n1. **Type and Scope**: Choose an appropriate type (e.g., `feat`, `fix`, `refactor`, `docs`) and optional scope to describe the affected module or feature.\n\n2. **Gitmoji**: Include a relevant `gitmoji` that best represents the nature of the change.\n\n3. **Description**: Write a concise, informative description in the header; use backticks if referencing code or specific terms.\n\nCommit messages should be clear, informative, and professional, aiding readability and project tracking." } ] } diff --git a/apps/web/.gitignore b/apps/web/.gitignore index b2777578b..62121fb82 100644 --- a/apps/web/.gitignore +++ b/apps/web/.gitignore @@ -41,5 +41,3 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts - -# VitNode diff --git a/apps/web/src/app/[locale]/(main)/(plugins)/(vitnode-blog)/blog/layout.tsx b/apps/web/src/app/[locale]/(main)/(plugins)/(vitnode-blog)/blog/layout.tsx new file mode 100644 index 000000000..8bc961a91 --- /dev/null +++ b/apps/web/src/app/[locale]/(main)/(plugins)/(vitnode-blog)/blog/layout.tsx @@ -0,0 +1,5 @@ +import { TestLayout } from 'vitnode-blog/views/test/layout'; + +export default function Layout({ children }: { children: React.ReactNode }) { + return {children}; +} diff --git a/apps/web/src/app/[locale]/(main)/(plugins)/(vitnode-blog)/blog/page.tsx b/apps/web/src/app/[locale]/(main)/(plugins)/(vitnode-blog)/blog/page.tsx new file mode 100644 index 000000000..41938f2c2 --- /dev/null +++ b/apps/web/src/app/[locale]/(main)/(plugins)/(vitnode-blog)/blog/page.tsx @@ -0,0 +1,14 @@ +import { Link } from 'vitnode/lib/navigation'; + +import { Test } from 'vitnode-blog/views/test'; +import { TestClient } from 'vitnode-blog/views/test/client'; + +export default function Page() { + return ( + <> + + + Go to blog - test 123 + + ); +} diff --git a/apps/web/src/app/[locale]/(main)/(plugins)/(vitnode-blog)/blog/test/page.tsx b/apps/web/src/app/[locale]/(main)/(plugins)/(vitnode-blog)/blog/test/page.tsx new file mode 100644 index 000000000..c34490860 --- /dev/null +++ b/apps/web/src/app/[locale]/(main)/(plugins)/(vitnode-blog)/blog/test/page.tsx @@ -0,0 +1,9 @@ +import { Link } from 'vitnode/lib/navigation'; + +export default function Page() { + return ( + <> + Go to blog + + ); +} diff --git a/apps/web/src/app/[locale]/(main)/(vitnode)/login/page.tsx b/apps/web/src/app/[locale]/(main)/(vitnode)/login/page.tsx new file mode 100644 index 000000000..bcc9eed40 --- /dev/null +++ b/apps/web/src/app/[locale]/(main)/(vitnode)/login/page.tsx @@ -0,0 +1,21 @@ +import type { Metadata } from 'next/dist/types'; + +import { getTranslations } from 'next-intl/server'; + +import { SignInView } from 'vitnode/views/auth/sign-in/sign-in-view'; + +export const generateMetadata = async ({ + locale, +}: { + locale: string; +}): Promise => { + const t = await getTranslations({ locale, namespace: 'core.global' }); + + return { + title: t('login'), + }; +}; + +export default function Page() { + return ; +} diff --git a/apps/web/src/app/[locale]/(main)/(vitnode)/login/sso/[providerId]/page.tsx b/apps/web/src/app/[locale]/(main)/(vitnode)/login/sso/[providerId]/page.tsx new file mode 100644 index 000000000..ebcb22918 --- /dev/null +++ b/apps/web/src/app/[locale]/(main)/(vitnode)/login/sso/[providerId]/page.tsx @@ -0,0 +1,15 @@ +import { CallbackSSOView } from 'vitnode/views/auth/sso/callback/callback-sso-view'; + +export default async function Page({ + params, + searchParams, +}: { + params: Promise<{ providerId: string }>; + searchParams: Promise>; +}) { + const { providerId } = await params; + + return ( + + ); +} diff --git a/apps/web/src/app/[locale]/(main)/(vitnode)/register/page.tsx b/apps/web/src/app/[locale]/(main)/(vitnode)/register/page.tsx new file mode 100644 index 000000000..89be25034 --- /dev/null +++ b/apps/web/src/app/[locale]/(main)/(vitnode)/register/page.tsx @@ -0,0 +1,21 @@ +import type { Metadata } from 'next/dist/types'; + +import { getTranslations } from 'next-intl/server'; + +import { SignUpView } from 'vitnode/views/auth/sign-up/sign-up-view'; + +export const generateMetadata = async ({ + locale, +}: { + locale: string; +}): Promise => { + const t = await getTranslations({ locale, namespace: 'core.global' }); + + return { + title: t('register'), + }; +}; + +export default function Page() { + return ; +} diff --git a/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-blog)/blog/categories/page.tsx b/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-blog)/blog/categories/page.tsx new file mode 100644 index 000000000..60ba38a0e --- /dev/null +++ b/apps/web/src/app/[locale]/admin/(auth)/(plugins)/(vitnode-blog)/blog/categories/page.tsx @@ -0,0 +1,3 @@ +export default function Page() { + return
Categories from admin - blog plugin
; +} diff --git a/apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/page.tsx b/apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/page.tsx new file mode 100644 index 000000000..63745336c --- /dev/null +++ b/apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/page.tsx @@ -0,0 +1,5 @@ +import { DashboardAdminView } from 'vitnode/views/admin/views/core/dashboard/dashboard-admin-view'; + +export default function Page() { + return ; +} diff --git a/apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/test/page.tsx b/apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/test/page.tsx new file mode 100644 index 000000000..92ea2fc30 --- /dev/null +++ b/apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/test/page.tsx @@ -0,0 +1,5 @@ +import { TestView } from 'vitnode/views/admin/views/core/test'; + +export default function Page() { + return ; +} diff --git a/apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/users/page.tsx b/apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/users/page.tsx new file mode 100644 index 000000000..306e0807b --- /dev/null +++ b/apps/web/src/app/[locale]/admin/(auth)/(vitnode)/core/users/page.tsx @@ -0,0 +1,7 @@ +import { UsersAdminView } from 'vitnode/views/admin/views/core/users/users-admin-view'; + +export default function Page( + props: React.ComponentProps, +) { + return ; +} From 08f8c40104fb68524a8b5bf288dbaaeb0c01631c Mon Sep 17 00:00:00 2001 From: aXenDeveloper Date: Sun, 25 May 2025 17:37:56 +0200 Subject: [PATCH 8/9] =?UTF-8?q?chore:=20=F0=9F=A7=B9=20Remove=20unused=20"?= =?UTF-8?q?prepare"=20script=20from=20package.json?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/web/package.json b/apps/web/package.json index 9fa7daa0b..66b5cf072 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -5,7 +5,6 @@ "type": "module", "scripts": { "init": "vitnode init", - "prepare": "vitnode prepare", "drizzle-kit": "drizzle-kit", "db:push": "drizzle-kit push", "db:migrate": "drizzle-kit up && drizzle-kit generate && drizzle-kit migrate", From d28d8725c9fcd81bf1a39646e8bb015f3d811d66 Mon Sep 17 00:00:00 2001 From: aXenDeveloper Date: Sun, 25 May 2025 17:44:12 +0200 Subject: [PATCH 9/9] =?UTF-8?q?refactor(auth):=20=E2=9C=A8=20Simplify=20se?= =?UTF-8?q?archParams=20handling=20in=20CallbackSSOView?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../(main)/(plugins)/(vitnode-blog)/blog/page.tsx | 3 +-- .../web/src/app/[locale]/(main)/(vitnode)/login/page.tsx | 1 - .../(main)/(vitnode)/login/sso/[providerId]/page.tsx | 6 +++++- .../src/app/[locale]/(main)/(vitnode)/register/page.tsx | 1 - packages/vitnode/src/app/login/sso/[providerId]/page.tsx | 6 +++++- .../src/views/auth/sso/callback/callback-sso-view.tsx | 9 +++------ 6 files changed, 14 insertions(+), 12 deletions(-) diff --git a/apps/web/src/app/[locale]/(main)/(plugins)/(vitnode-blog)/blog/page.tsx b/apps/web/src/app/[locale]/(main)/(plugins)/(vitnode-blog)/blog/page.tsx index 41938f2c2..d89100e90 100644 --- a/apps/web/src/app/[locale]/(main)/(plugins)/(vitnode-blog)/blog/page.tsx +++ b/apps/web/src/app/[locale]/(main)/(plugins)/(vitnode-blog)/blog/page.tsx @@ -1,7 +1,6 @@ -import { Link } from 'vitnode/lib/navigation'; - import { Test } from 'vitnode-blog/views/test'; import { TestClient } from 'vitnode-blog/views/test/client'; +import { Link } from 'vitnode/lib/navigation'; export default function Page() { return ( diff --git a/apps/web/src/app/[locale]/(main)/(vitnode)/login/page.tsx b/apps/web/src/app/[locale]/(main)/(vitnode)/login/page.tsx index bcc9eed40..9a04c0d56 100644 --- a/apps/web/src/app/[locale]/(main)/(vitnode)/login/page.tsx +++ b/apps/web/src/app/[locale]/(main)/(vitnode)/login/page.tsx @@ -1,7 +1,6 @@ import type { Metadata } from 'next/dist/types'; import { getTranslations } from 'next-intl/server'; - import { SignInView } from 'vitnode/views/auth/sign-in/sign-in-view'; export const generateMetadata = async ({ diff --git a/apps/web/src/app/[locale]/(main)/(vitnode)/login/sso/[providerId]/page.tsx b/apps/web/src/app/[locale]/(main)/(vitnode)/login/sso/[providerId]/page.tsx index ebcb22918..bf0d48947 100644 --- a/apps/web/src/app/[locale]/(main)/(vitnode)/login/sso/[providerId]/page.tsx +++ b/apps/web/src/app/[locale]/(main)/(vitnode)/login/sso/[providerId]/page.tsx @@ -8,8 +8,12 @@ export default async function Page({ searchParams: Promise>; }) { const { providerId } = await params; + const currentSearchParams = await searchParams; return ( - + ); } diff --git a/apps/web/src/app/[locale]/(main)/(vitnode)/register/page.tsx b/apps/web/src/app/[locale]/(main)/(vitnode)/register/page.tsx index 89be25034..4c9e16800 100644 --- a/apps/web/src/app/[locale]/(main)/(vitnode)/register/page.tsx +++ b/apps/web/src/app/[locale]/(main)/(vitnode)/register/page.tsx @@ -1,7 +1,6 @@ import type { Metadata } from 'next/dist/types'; import { getTranslations } from 'next-intl/server'; - import { SignUpView } from 'vitnode/views/auth/sign-up/sign-up-view'; export const generateMetadata = async ({ diff --git a/packages/vitnode/src/app/login/sso/[providerId]/page.tsx b/packages/vitnode/src/app/login/sso/[providerId]/page.tsx index 6d086f7c8..9e8b6aa07 100644 --- a/packages/vitnode/src/app/login/sso/[providerId]/page.tsx +++ b/packages/vitnode/src/app/login/sso/[providerId]/page.tsx @@ -8,8 +8,12 @@ export default async function Page({ searchParams: Promise>; }) { const { providerId } = await params; + const currentSearchParams = await searchParams; return ( - + ); } diff --git a/packages/vitnode/src/views/auth/sso/callback/callback-sso-view.tsx b/packages/vitnode/src/views/auth/sso/callback/callback-sso-view.tsx index c3c49576d..0a1b51fdf 100644 --- a/packages/vitnode/src/views/auth/sso/callback/callback-sso-view.tsx +++ b/packages/vitnode/src/views/auth/sso/callback/callback-sso-view.tsx @@ -5,15 +5,12 @@ import { ClientCallbackSSO } from './client/client'; export const CallbackSSOView = async ({ providerId, - searchParams, + searchParams: { code, error, state }, }: { providerId: string; - searchParams: Promise>; + searchParams: Record; }) => { - const [{ code, error, state }, t] = await Promise.all([ - searchParams, - getTranslations('core.auth.sso'), - ]); + const t = await getTranslations('core.auth.sso'); if (error === 'access_denied') { return ;