Merge branch 'main' of github.com:makerkit/next-supabase-saas-kit-turbo
This commit is contained in:
571
AGENTS.md
571
AGENTS.md
@@ -4,17 +4,15 @@ This Agents.md file provides comprehensive guidance for OpenAI Codex and other A
|
|||||||
|
|
||||||
## Project Overview
|
## Project Overview
|
||||||
|
|
||||||
Makerkit - Supabase SaaS Starter Kit (Turbo Edition) is a multi-tenant SaaS application built with Next.js, Supabase, and Tailwind CSS. The project uses a Turborepo monorepo structure with distinct apps for the main web application, development tools, and e2e testing.
|
Makerkit is a multi-tenant SaaS application using a Turborepo monorepo structure with distinct apps for the main web application, development tools, and e2e testing.
|
||||||
|
|
||||||
## Architecture
|
|
||||||
|
|
||||||
### Monorepo Structure
|
### Monorepo Structure
|
||||||
|
|
||||||
- `/apps/web` - Main Next.js SaaS application
|
- `/apps/web` - Main Next.js SaaS application
|
||||||
- `/apps/dev-tool` - Development utilities (runs on port 3010)
|
- `/apps/dev-tool` - Development utilities (port 3010)
|
||||||
- `/apps/e2e` - Playwright end-to-end tests
|
- `/apps/e2e` - Playwright end-to-end tests
|
||||||
- `/packages/` - Shared packages and utilities
|
- `/packages/` - Shared packages and utilities
|
||||||
- `/tooling/` - Build tools, linting, and development scripts
|
- `/tooling/` - Build tools and development scripts
|
||||||
|
|
||||||
### Core Technologies
|
### Core Technologies
|
||||||
|
|
||||||
@@ -27,89 +25,101 @@ Makerkit - Supabase SaaS Starter Kit (Turbo Edition) is a multi-tenant SaaS appl
|
|||||||
|
|
||||||
### Multi-Tenant Architecture
|
### Multi-Tenant Architecture
|
||||||
|
|
||||||
The application uses a dual account model:
|
Uses a dual account model:
|
||||||
|
|
||||||
- **Personal Accounts**: Individual user accounts (auth.users.id = accounts.id)
|
- **Personal Accounts**: Individual user accounts (`auth.users.id = accounts.id`)
|
||||||
- **Team Accounts**: Shared workspaces with members, roles, and permissions
|
- **Team Accounts**: Shared workspaces with members, roles, and permissions
|
||||||
- Data is associated with accounts via foreign keys for proper access control
|
- Data associates with accounts via foreign keys for proper access control
|
||||||
|
|
||||||
## Common Commands
|
## Essential Commands
|
||||||
|
|
||||||
### Development
|
### Development
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Start all apps in development
|
pnpm dev # Start all apps
|
||||||
pnpm dev
|
|
||||||
|
|
||||||
# Start specific app
|
|
||||||
pnpm --filter web dev # Main app (port 3000)
|
pnpm --filter web dev # Main app (port 3000)
|
||||||
pnpm --filter dev-tool dev # Dev tools (port 3010)
|
pnpm --filter dev-tool dev # Dev tools (port 3010)
|
||||||
|
pnpm build # Build all apps
|
||||||
# Build all apps
|
|
||||||
pnpm build
|
|
||||||
|
|
||||||
# Run tests
|
|
||||||
pnpm test # All tests
|
|
||||||
pnpm --filter e2e test # E2E tests only
|
|
||||||
```
|
|
||||||
|
|
||||||
### Code Quality
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Lint all code
|
|
||||||
pnpm lint
|
|
||||||
pnpm lint:fix # Auto-fix issues
|
|
||||||
|
|
||||||
# Format code
|
|
||||||
pnpm format
|
|
||||||
pnpm format:fix # Auto-fix formatting
|
|
||||||
|
|
||||||
# Type checking
|
|
||||||
pnpm typecheck
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Database Operations
|
### Database Operations
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Start Supabase locally
|
pnpm supabase:web:start # Start Supabase locally
|
||||||
pnpm supabase:web:start
|
pnpm supabase:web:reset # Reset with latest schema
|
||||||
|
pnpm supabase:web:typegen # Generate TypeScript types
|
||||||
# Reset database with latest schema
|
pnpm --filter web supabase:db:diff # Create migration
|
||||||
pnpm supabase:web:reset
|
|
||||||
|
|
||||||
# Generate TypeScript types from database
|
|
||||||
pnpm supabase:web:typegen
|
|
||||||
|
|
||||||
# Run database tests
|
|
||||||
pnpm supabase:web:test
|
|
||||||
|
|
||||||
# Create migration from schema changes
|
|
||||||
pnpm --filter web supabase:db:diff
|
|
||||||
|
|
||||||
# Stop Supabase
|
|
||||||
pnpm supabase:web:stop
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Code Quality
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm lint && pnpm format # Lint and format
|
||||||
|
pnpm typecheck # Type checking
|
||||||
|
pnpm test # Run tests
|
||||||
|
```
|
||||||
|
|
||||||
|
## Application Structure
|
||||||
|
|
||||||
|
### Route Organization
|
||||||
|
|
||||||
|
```
|
||||||
|
app/
|
||||||
|
├── (marketing)/ # Public pages (landing, blog, docs)
|
||||||
|
├── (auth)/ # Authentication pages
|
||||||
|
├── home/
|
||||||
|
│ ├── (user)/ # Personal account context
|
||||||
|
│ └── [account]/ # Team account context ([account] = team slug)
|
||||||
|
├── admin/ # Super admin section
|
||||||
|
└── api/ # API routes
|
||||||
|
```
|
||||||
|
|
||||||
|
See complete structure in @apps/web/app/ with examples like:
|
||||||
|
|
||||||
|
- Marketing layout: @apps/web/app/(marketing)/layout.tsx
|
||||||
|
- Personal dashboard: @apps/web/app/home/(user)/page.tsx
|
||||||
|
- Team workspace: @apps/web/app/home/[account]/page.tsx
|
||||||
|
- Admin section: @apps/web/app/admin/page.tsx
|
||||||
|
|
||||||
|
### Component Organization
|
||||||
|
|
||||||
|
- **Route-specific**: Use `_components/` directories
|
||||||
|
- **Route utilities**: Use `_lib/` for client, `_lib/server/` for server-side
|
||||||
|
- **Global components**: Root-level directories
|
||||||
|
|
||||||
|
Example organization:
|
||||||
|
|
||||||
|
- Team components: @apps/web/app/home/[account]/\_components/
|
||||||
|
- Team server utils: @apps/web/app/home/[account]/\_lib/server/
|
||||||
|
- Marketing components: @apps/web/app/(marketing)/\_components/
|
||||||
|
|
||||||
## Database Guidelines
|
## Database Guidelines
|
||||||
|
|
||||||
### Schema Management
|
|
||||||
|
|
||||||
- Database schemas are in `apps/web/supabase/schemas/`
|
|
||||||
- Create new schemas as `<number>-<name>.sql`
|
|
||||||
- After schema changes: run `pnpm --filter web supabase:db:diff` then `pnpm supabase:web:reset`
|
|
||||||
|
|
||||||
### Security & RLS
|
### Security & RLS
|
||||||
|
|
||||||
- **Always enable RLS** on new tables unless explicitly instructed otherwise
|
- **Always enable RLS** on new tables unless explicitly instructed otherwise
|
||||||
- Use helper functions for access control:
|
- Use helper functions for access control:
|
||||||
- `public.has_role_on_account(account_id, role?)` - Check team membership
|
- `public.has_role_on_account(account_id, role?)` - Check team membership
|
||||||
- `public.has_permission(user_id, account_id, permission)` - Check specific permissions
|
- `public.has_permission(user_id, account_id, permission)` - Check permissions
|
||||||
- `public.is_account_owner(account_id)` - Verify account ownership
|
- `public.is_account_owner(account_id)` - Verify ownership
|
||||||
- Associate data with accounts using foreign keys for proper access control
|
|
||||||
|
See RLS examples in database schemas: @apps/web/supabase/schemas/
|
||||||
|
|
||||||
|
### Schema Management
|
||||||
|
|
||||||
|
- Schemas in `apps/web/supabase/schemas/`
|
||||||
|
- Create as `<number>-<name>.sql`
|
||||||
|
- After changes: `pnpm --filter web supabase:db:diff` then `pnpm supabase:web:reset`
|
||||||
|
|
||||||
|
Key schema files:
|
||||||
|
|
||||||
|
- Accounts: `apps/web/supabase/schemas/03-accounts.sql`
|
||||||
|
- Memberships: `apps/web/supabase/schemas/05-memberships.sql`
|
||||||
|
- Permissions: `apps/web/supabase/schemas/06-roles-permissions.sql`
|
||||||
|
|
||||||
### Type Generation
|
### Type Generation
|
||||||
|
|
||||||
Import auto-generated types from `@kit/supabase/database`:
|
Import auto-generated types from @packages/supabase/src/types/database.ts:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { Tables } from '@kit/supabase/database';
|
import { Tables } from '@kit/supabase/database';
|
||||||
@@ -121,50 +131,427 @@ type Account = Tables<'accounts'>;
|
|||||||
|
|
||||||
### Data Fetching
|
### Data Fetching
|
||||||
|
|
||||||
- **Server Components**: Use `getSupabaseServerClient()` directly
|
- **Server Components**: Use `getSupabaseServerClient()` from @packages/supabase/src/clients/server-client.ts
|
||||||
- **Client Components**: Use `useSupabase()` hook + React Query's `useQuery`
|
- **Client Components**: Use `useSupabase()` hook + React Query's `useQuery`
|
||||||
- Prefer Server Components and pass data down to Client Components when needed
|
- **Admin Operations**: Use `getSupabaseServerAdminClient()` from @packages/supabase/src/clients/server-admin-client.ts (rare cases only - bypasses RLS, use with caution!)
|
||||||
|
- Prefer Server Components and pass data down when needed
|
||||||
|
|
||||||
|
Use the Container/Presenter pattern for complex data components:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Container: handles data fetching
|
||||||
|
function UserProfileContainer() {
|
||||||
|
const userData = useUserData();
|
||||||
|
return <UserProfilePresenter data={userData.data} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Presenter: handles UI rendering
|
||||||
|
function UserProfilePresenter({ data }: { data: UserData }) {
|
||||||
|
return <div>{data.name}</div>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Example server-side data loading:
|
||||||
|
|
||||||
|
- User workspace loader: @apps/web/app/home/(user)/\_lib/server/load-user-workspace.ts
|
||||||
|
- Team workspace loader: @apps/web/app/home/[account]/\_lib/server/team-account-workspace.loader.ts
|
||||||
|
- Data provider pattern: @packages/features/team-accounts/src/components/members/roles-data-provider.tsx
|
||||||
|
|
||||||
### Server Actions
|
### Server Actions
|
||||||
|
|
||||||
- Always use `enhanceAction` from `@kit/next/actions`
|
Always use `enhanceAction` from @packages/next/src/actions/index.ts:
|
||||||
- Name files as `server-actions.ts` and functions with `Action` suffix
|
|
||||||
- Place Zod schemas in separate files for reuse with forms
|
|
||||||
- Use `'use server'` directive at top of file
|
|
||||||
|
|
||||||
### Error Handling & Logging
|
```typescript
|
||||||
|
'use server';
|
||||||
|
|
||||||
- Use `@kit/shared/logger` for logging
|
import { enhanceAction } from '@kit/next/actions';
|
||||||
- Don't swallow errors - handle them appropriately
|
|
||||||
- Provide context without sensitive data
|
|
||||||
|
|
||||||
### Component Organization
|
export const createNoteAction = enhanceAction(
|
||||||
|
async function (data, user) {
|
||||||
|
// data is validated, user is authenticated
|
||||||
|
return { success: true };
|
||||||
|
},
|
||||||
|
{
|
||||||
|
auth: true,
|
||||||
|
schema: CreateNoteSchema,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
- Route-specific components in `_components/` directories
|
Example server actions:
|
||||||
- Route-specific utilities in `_lib/` directories
|
|
||||||
- Server-side utilities in `_lib/server/`
|
- Team billing: @apps/web/app/home/[account]/billing/\_lib/server/server-actions.ts
|
||||||
- Global components and utilities in root-level directories
|
- Personal settings: @apps/web/app/home/(user)/settings/\_lib/server/server-actions.ts
|
||||||
|
|
||||||
|
### Forms with React Hook Form & Zod
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 1. Define schema in separate file
|
||||||
|
export const CreateNoteSchema = z.object({
|
||||||
|
title: z.string().min(1),
|
||||||
|
content: z.string().min(1),
|
||||||
|
});
|
||||||
|
|
||||||
|
// 2. Client component with form
|
||||||
|
('use client');
|
||||||
|
const form = useForm({
|
||||||
|
resolver: zodResolver(CreateNoteSchema),
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSubmit = (data) => {
|
||||||
|
startTransition(async () => {
|
||||||
|
await toast.promise(createNoteAction(data), {
|
||||||
|
loading: 'Creating...',
|
||||||
|
success: 'Created!',
|
||||||
|
error: 'Failed!',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
See form examples:
|
||||||
|
|
||||||
|
- Contact form: @apps/web/app/(marketing)/contact/\_components/contact-form.tsx
|
||||||
|
- Verify OTP form: @packages/otp/src/components/verify-otp-form.tsx
|
||||||
|
|
||||||
|
### Route Handlers (API Routes)
|
||||||
|
|
||||||
|
Use `enhanceRouteHandler` from @packages/next/src/routes/index.ts:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { enhanceRouteHandler } from '@kit/next/routes';
|
||||||
|
|
||||||
|
export const POST = enhanceRouteHandler(
|
||||||
|
async function ({ body, user, request }) {
|
||||||
|
// body is validated, user available if auth: true
|
||||||
|
return NextResponse.json({ success: true });
|
||||||
|
},
|
||||||
|
{
|
||||||
|
auth: true,
|
||||||
|
schema: ZodSchema,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Example API routes:
|
||||||
|
|
||||||
|
- Billing webhook: @apps/web/app/api/billing/webhook/route.ts
|
||||||
|
- Database webhook: @apps/web/app/api/db/webhook/route.ts
|
||||||
|
|
||||||
|
## React & TypeScript Best Practices
|
||||||
|
|
||||||
|
### Components
|
||||||
|
|
||||||
|
- Use functional components with TypeScript
|
||||||
|
- Always use `'use client'` directive for client components
|
||||||
|
- Destructure props with proper TypeScript interfaces
|
||||||
|
|
||||||
|
### Conditional Rendering
|
||||||
|
|
||||||
|
Use the `If` component from @packages/ui/src/makerkit/if.tsx:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { If } from '@kit/ui/if';
|
||||||
|
import { Spinner } '@kit/ui/spinner';
|
||||||
|
|
||||||
|
<If condition={isLoading} fallback={<Content />}>
|
||||||
|
<Spinner />
|
||||||
|
</If>
|
||||||
|
|
||||||
|
// With type inference
|
||||||
|
<If condition={error}>
|
||||||
|
{(err) => <ErrorMessage error={err} />}
|
||||||
|
</If>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Testing Attributes
|
||||||
|
|
||||||
|
Add data attributes for testing:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
<button data-test="submit-button">Submit</button>
|
||||||
|
<div data-test="user-profile" data-user-id={user.id}>Profile</div>
|
||||||
|
<form data-test="signup-form">Form content</form>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Internationalization
|
||||||
|
|
||||||
|
Always use `Trans` component from @packages/ui/src/makerkit/trans.tsx:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { Trans } from '@kit/ui/trans';
|
||||||
|
|
||||||
|
// Basic usage
|
||||||
|
<Trans
|
||||||
|
i18nKey="user:welcomeMessage"
|
||||||
|
values={{ name: user.name }}
|
||||||
|
defaults="Welcome, {name}!"
|
||||||
|
/>
|
||||||
|
|
||||||
|
// With HTML elements
|
||||||
|
<Trans
|
||||||
|
i18nKey="terms:agreement"
|
||||||
|
components={{
|
||||||
|
TermsLink: <a href="/terms" className="underline" />,
|
||||||
|
}}
|
||||||
|
defaults="I agree to the <TermsLink>Terms</TermsLink>."
|
||||||
|
/>
|
||||||
|
|
||||||
|
// Pluralization
|
||||||
|
<Trans
|
||||||
|
i18nKey="notifications:count"
|
||||||
|
count={notifications.length}
|
||||||
|
defaults="{count, plural, =0 {No notifications} one {# notification} other {# notifications}}"
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `LanguageSelector` component from @packages/ui/src/makerkit/language-selector.tsx:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { LanguageSelector } from '@kit/ui/language-selector';
|
||||||
|
|
||||||
|
<LanguageSelector />;
|
||||||
|
```
|
||||||
|
|
||||||
|
Adding new languages:
|
||||||
|
|
||||||
|
1. Add language code to @apps/web/lib/i18n/i18n.settings.ts
|
||||||
|
2. Create translation files in @apps/web/public/locales/[new-language]/
|
||||||
|
3. Copy structure from English files as template
|
||||||
|
|
||||||
|
Adding new namespaces:
|
||||||
|
|
||||||
|
1. Add namespace to `defaultI18nNamespaces` in @apps/web/lib/i18n/i18n.settings.ts
|
||||||
|
2. Create corresponding translation files for all supported languages
|
||||||
|
|
||||||
|
Translation files located in @apps/web/public/locales/<locale>/<namespace>.json:
|
||||||
|
|
||||||
|
- Common translations: @apps/web/public/locales/en/common.json
|
||||||
|
- Auth translations: @apps/web/public/locales/en/auth.json
|
||||||
|
- Team translations: @apps/web/public/locales/en/teams.json
|
||||||
|
|
||||||
|
## Security Guidelines
|
||||||
|
|
||||||
|
### Authentication & Authorization
|
||||||
|
|
||||||
|
- Authentication enforced by middleware
|
||||||
|
- Authorization typically handled by RLS at database level, unless using the admin client
|
||||||
|
- For rare admin client usage, enforce both manually
|
||||||
|
- User authentication helper: @apps/web/lib/server/require-user-in-server-component.ts if required or to obtain the authed user
|
||||||
|
|
||||||
|
### Data Passing
|
||||||
|
|
||||||
|
- **Never pass sensitive data** to Client Components
|
||||||
|
- **Never expose server environment variables** to client (unless `NEXT_PUBLIC_`)
|
||||||
|
- Always validate user input before processing
|
||||||
|
|
||||||
|
### OTP for Sensitive Operations
|
||||||
|
|
||||||
|
Use one-time tokens from @packages/otp/src/api/index.ts for destructive operations:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { VerifyOtpForm } from '@kit/otp/components';
|
||||||
|
|
||||||
|
<VerifyOtpForm
|
||||||
|
purpose="account-deletion"
|
||||||
|
email={user.email}
|
||||||
|
onSuccess={(otp) => {
|
||||||
|
// Proceed with verified operation
|
||||||
|
}}
|
||||||
|
/>;
|
||||||
|
```
|
||||||
|
|
||||||
|
OTP schema and functions: @apps/web/supabase/schemas/12-one-time-tokens.sql
|
||||||
|
|
||||||
|
### Super Admin Protection
|
||||||
|
|
||||||
|
For admin routes, use `AdminGuard` from @packages/features/admin/src/components/admin-guard.tsx:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { AdminGuard } from '@kit/admin/components/admin-guard';
|
||||||
|
|
||||||
|
export default AdminGuard(AdminPageComponent);
|
||||||
|
```
|
||||||
|
|
||||||
|
For admin server actions, use `adminAction` wrapper:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { adminAction } from '@kit/admin';
|
||||||
|
|
||||||
|
export const yourAdminAction = adminAction(
|
||||||
|
enhanceAction(
|
||||||
|
async (data) => {
|
||||||
|
// Action implementation
|
||||||
|
},
|
||||||
|
{ schema: YourActionSchema },
|
||||||
|
),
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Admin service security pattern:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
private async assertUserIsNotCurrentSuperAdmin(targetId: string) {
|
||||||
|
const { data } = await this.client.auth.getUser();
|
||||||
|
const currentUserId = data.user?.id;
|
||||||
|
|
||||||
|
if (currentUserId === targetId) {
|
||||||
|
throw new Error('Cannot perform destructive action on your own account');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## UI Components
|
||||||
|
|
||||||
|
### Core UI Library
|
||||||
|
|
||||||
|
Import from @packages/ui/src/:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
// Shadcn components
|
||||||
|
import { Button } from '@kit/ui/button';
|
||||||
|
// @packages/ui/src/shadcn/button.tsx
|
||||||
|
import { Card } from '@kit/ui/card';
|
||||||
|
// @packages/ui/src/shadcn/sonner.tsx
|
||||||
|
|
||||||
|
// Makerkit components
|
||||||
|
import { If } from '@kit/ui/if';
|
||||||
|
// @packages/ui/src/makerkit/trans.tsx
|
||||||
|
import { ProfileAvatar } from '@kit/ui/profile-avatar';
|
||||||
|
// @packages/ui/src/shadcn/card.tsx
|
||||||
|
import { toast } from '@kit/ui/sonner';
|
||||||
|
// @packages/ui/src/makerkit/if.tsx
|
||||||
|
import { Trans } from '@kit/ui/trans';
|
||||||
|
|
||||||
|
// @packages/ui/src/makerkit/profile-avatar.tsx
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key Component Categories
|
||||||
|
|
||||||
|
- **Forms**: Form components in @packages/ui/src/shadcn/form.tsx
|
||||||
|
- **Navigation**: Navigation menu in @packages/ui/src/shadcn/navigation-menu.tsx
|
||||||
|
- **Data Display**: Data table in @packages/ui/src/makerkit/data-table.tsx
|
||||||
|
- **Marketing**: Marketing components in @packages/ui/src/makerkit/marketing/
|
||||||
|
|
||||||
|
### Styling
|
||||||
|
|
||||||
|
- Use Tailwind CSS with semantic classes
|
||||||
|
- Prefer `bg-background`, `text-muted-foreground` over fixed colors
|
||||||
|
- Use `cn()` utility from @packages/ui/src/lib/utils.ts for class merging
|
||||||
|
|
||||||
|
## Workspace Contexts
|
||||||
|
|
||||||
|
### Personal Account Context (`/home/(user)`)
|
||||||
|
|
||||||
|
Use hook from `packages/features/accounts/src/hooks/use-user-workspace.ts`:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { useUserWorkspace } from '@kit/accounts/hooks/use-user-workspace';
|
||||||
|
|
||||||
|
function PersonalComponent() {
|
||||||
|
const { user, account } = useUserWorkspace();
|
||||||
|
// Personal account data
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Context provider: `packages/features/accounts/src/components/user-workspace-context-provider.tsx`
|
||||||
|
|
||||||
|
### Team Account Context (`/home/[account]`)
|
||||||
|
|
||||||
|
Use hook from `packages/features/team-accounts/src/hooks/use-team-account-workspace.ts`:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { useTeamAccountWorkspace } from '@kit/team-accounts/hooks/use-team-account-workspace';
|
||||||
|
|
||||||
|
function TeamComponent() {
|
||||||
|
const { account, user, accounts } = useTeamAccountWorkspace();
|
||||||
|
// Team account data with permissions
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Context provider: `packages/features/team-accounts/src/components/team-account-workspace-context-provider.tsx`
|
||||||
|
|
||||||
|
## Error Handling & Logging
|
||||||
|
|
||||||
|
### Structured Logging
|
||||||
|
|
||||||
|
Use logger from `packages/shared/src/logger/logger.ts`:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { getLogger } from '@kit/shared/logger';
|
||||||
|
|
||||||
|
const logger = await getLogger();
|
||||||
|
const ctx = { name: 'myOperation', userId: user.id };
|
||||||
|
|
||||||
|
logger.info(ctx, 'Operation started');
|
||||||
|
// ... operation
|
||||||
|
logger.error({ ...ctx, error }, 'Operation failed');
|
||||||
|
```
|
||||||
|
|
||||||
|
### Error Boundaries
|
||||||
|
|
||||||
|
Use proper error handling with meaningful user messages:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
try {
|
||||||
|
await operation();
|
||||||
|
} catch (error) {
|
||||||
|
logger.error({ error, context }, 'Operation failed');
|
||||||
|
return { error: 'Unable to complete operation' }; // Generic message
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Feature Development Workflow
|
||||||
|
|
||||||
|
### Creating New Pages
|
||||||
|
|
||||||
|
1. Create page component in appropriate route group
|
||||||
|
2. Add `withI18n()` HOC from `apps/web/lib/i18n/with-i18n.tsx`
|
||||||
|
3. Implement `generateMetadata()` for SEO
|
||||||
|
4. Add loading state with `loading.tsx`
|
||||||
|
5. Create components in `_components/` directory
|
||||||
|
6. Add server utilities in `_lib/server/`
|
||||||
|
|
||||||
|
Example page structure:
|
||||||
|
|
||||||
|
- Marketing page: `apps/web/app/(marketing)/pricing/page.tsx`
|
||||||
|
- Dashboard page: `apps/web/app/home/(user)/page.tsx`
|
||||||
|
- Team page: `apps/web/app/home/[account]/members/page.tsx`
|
||||||
|
|
||||||
### Permission Patterns
|
### Permission Patterns
|
||||||
|
|
||||||
- Check permissions before data operations using helper functions
|
- Check permissions before data operations
|
||||||
- Guard premium features with subscription checks (`public.has_active_subscription`)
|
- Guard premium features with `public.has_active_subscription`
|
||||||
- Use role hierarchy to control member management actions
|
- Use role hierarchy for member management
|
||||||
- Primary account owners have special privileges that cannot be revoked
|
- Primary account owners have special privileges
|
||||||
|
|
||||||
## Testing
|
Permission helpers in database: `apps/web/supabase/schemas/06-roles-permissions.sql`
|
||||||
|
|
||||||
### E2E Tests
|
### Database Development
|
||||||
|
|
||||||
```bash
|
1. Create schema file: `apps/web/supabase/schemas/<number>-<name>.sql`
|
||||||
pnpm --filter e2e test # Run all E2E tests
|
2. Enable RLS and create policies
|
||||||
```
|
3. Generate migration: `pnpm --filter web supabase:db:diff`
|
||||||
|
4. Reset database: `pnpm supabase:web:reset`
|
||||||
|
5. Generate types: `pnpm supabase:web:typegen`
|
||||||
|
|
||||||
Test files are in `apps/e2e/tests/` organized by feature area.
|
## API Services
|
||||||
|
|
||||||
## Important Notes
|
### Account Services
|
||||||
|
|
||||||
- Uses pnpm as package manager
|
- Personal accounts API: `packages/features/accounts/src/server/api.ts`
|
||||||
- Database types are auto-generated - don't write manually if shape matches DB
|
- Team accounts API: `packages/features/team-accounts/src/server/api.ts`
|
||||||
- Always use explicit schema references in SQL (`public.table_name`)
|
- Admin service: `packages/features/admin/src/lib/server/services/admin.service.ts`
|
||||||
- Documentation available at: https://makerkit.dev/docs/next-supabase-turbo/introduction
|
|
||||||
|
### Billing Services
|
||||||
|
|
||||||
|
- Personal billing: `apps/web/app/home/(user)/billing/_lib/server/user-billing.service.ts`
|
||||||
|
- Team billing: `apps/web/app/home/[account]/billing/_lib/server/team-billing.service.ts`
|
||||||
|
- Per-seat billing: `packages/features/team-accounts/src/server/services/account-per-seat-billing.service.ts`
|
||||||
|
|
||||||
|
## Key Configuration Files
|
||||||
|
|
||||||
|
- **Feature flags**: @apps/web/config/feature-flags.config.ts
|
||||||
|
- **i18n settings**: @apps/web/lib/i18n/i18n.settings.ts
|
||||||
|
- **Supabase local config**: @apps/web/supabase/config.toml@
|
||||||
|
- **Middleware**: @apps/web/middleware.ts`
|
||||||
|
|||||||
571
CLAUDE.md
571
CLAUDE.md
@@ -4,17 +4,15 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||||||
|
|
||||||
## Project Overview
|
## Project Overview
|
||||||
|
|
||||||
Makerkit - Supabase SaaS Starter Kit (Turbo Edition) is a multi-tenant SaaS application built with Next.js, Supabase, and Tailwind CSS. The project uses a Turborepo monorepo structure with distinct apps for the main web application, development tools, and e2e testing.
|
Makerkit is a multi-tenant SaaS application using a Turborepo monorepo structure with distinct apps for the main web application, development tools, and e2e testing.
|
||||||
|
|
||||||
## Architecture
|
|
||||||
|
|
||||||
### Monorepo Structure
|
### Monorepo Structure
|
||||||
|
|
||||||
- `/apps/web` - Main Next.js SaaS application
|
- `/apps/web` - Main Next.js SaaS application
|
||||||
- `/apps/dev-tool` - Development utilities (runs on port 3010)
|
- `/apps/dev-tool` - Development utilities (port 3010)
|
||||||
- `/apps/e2e` - Playwright end-to-end tests
|
- `/apps/e2e` - Playwright end-to-end tests
|
||||||
- `/packages/` - Shared packages and utilities
|
- `/packages/` - Shared packages and utilities
|
||||||
- `/tooling/` - Build tools, linting, and development scripts
|
- `/tooling/` - Build tools and development scripts
|
||||||
|
|
||||||
### Core Technologies
|
### Core Technologies
|
||||||
|
|
||||||
@@ -27,89 +25,101 @@ Makerkit - Supabase SaaS Starter Kit (Turbo Edition) is a multi-tenant SaaS appl
|
|||||||
|
|
||||||
### Multi-Tenant Architecture
|
### Multi-Tenant Architecture
|
||||||
|
|
||||||
The application uses a dual account model:
|
Uses a dual account model:
|
||||||
|
|
||||||
- **Personal Accounts**: Individual user accounts (auth.users.id = accounts.id)
|
- **Personal Accounts**: Individual user accounts (`auth.users.id = accounts.id`)
|
||||||
- **Team Accounts**: Shared workspaces with members, roles, and permissions
|
- **Team Accounts**: Shared workspaces with members, roles, and permissions
|
||||||
- Data is associated with accounts via foreign keys for proper access control
|
- Data associates with accounts via foreign keys for proper access control
|
||||||
|
|
||||||
## Common Commands
|
## Essential Commands
|
||||||
|
|
||||||
### Development
|
### Development
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Start all apps in development
|
pnpm dev # Start all apps
|
||||||
pnpm dev
|
|
||||||
|
|
||||||
# Start specific app
|
|
||||||
pnpm --filter web dev # Main app (port 3000)
|
pnpm --filter web dev # Main app (port 3000)
|
||||||
pnpm --filter dev-tool dev # Dev tools (port 3010)
|
pnpm --filter dev-tool dev # Dev tools (port 3010)
|
||||||
|
pnpm build # Build all apps
|
||||||
# Build all apps
|
|
||||||
pnpm build
|
|
||||||
|
|
||||||
# Run tests
|
|
||||||
pnpm test # All tests
|
|
||||||
pnpm --filter e2e test # E2E tests only
|
|
||||||
```
|
|
||||||
|
|
||||||
### Code Quality
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Lint all code
|
|
||||||
pnpm lint
|
|
||||||
pnpm lint:fix # Auto-fix issues
|
|
||||||
|
|
||||||
# Format code
|
|
||||||
pnpm format
|
|
||||||
pnpm format:fix # Auto-fix formatting
|
|
||||||
|
|
||||||
# Type checking
|
|
||||||
pnpm typecheck
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Database Operations
|
### Database Operations
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Start Supabase locally
|
pnpm supabase:web:start # Start Supabase locally
|
||||||
pnpm supabase:web:start
|
pnpm supabase:web:reset # Reset with latest schema
|
||||||
|
pnpm supabase:web:typegen # Generate TypeScript types
|
||||||
# Reset database with latest schema
|
pnpm --filter web supabase:db:diff # Create migration
|
||||||
pnpm supabase:web:reset
|
|
||||||
|
|
||||||
# Generate TypeScript types from database
|
|
||||||
pnpm supabase:web:typegen
|
|
||||||
|
|
||||||
# Run database tests
|
|
||||||
pnpm supabase:web:test
|
|
||||||
|
|
||||||
# Create migration from schema changes
|
|
||||||
pnpm --filter web supabase:db:diff
|
|
||||||
|
|
||||||
# Stop Supabase
|
|
||||||
pnpm supabase:web:stop
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Code Quality
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm lint && pnpm format # Lint and format
|
||||||
|
pnpm typecheck # Type checking
|
||||||
|
pnpm test # Run tests
|
||||||
|
```
|
||||||
|
|
||||||
|
## Application Structure
|
||||||
|
|
||||||
|
### Route Organization
|
||||||
|
|
||||||
|
```
|
||||||
|
app/
|
||||||
|
├── (marketing)/ # Public pages (landing, blog, docs)
|
||||||
|
├── (auth)/ # Authentication pages
|
||||||
|
├── home/
|
||||||
|
│ ├── (user)/ # Personal account context
|
||||||
|
│ └── [account]/ # Team account context ([account] = team slug)
|
||||||
|
├── admin/ # Super admin section
|
||||||
|
└── api/ # API routes
|
||||||
|
```
|
||||||
|
|
||||||
|
See complete structure in @apps/web/app/ with examples like:
|
||||||
|
|
||||||
|
- Marketing layout: @apps/web/app/(marketing)/layout.tsx
|
||||||
|
- Personal dashboard: @apps/web/app/home/(user)/page.tsx
|
||||||
|
- Team workspace: @apps/web/app/home/[account]/page.tsx
|
||||||
|
- Admin section: @apps/web/app/admin/page.tsx
|
||||||
|
|
||||||
|
### Component Organization
|
||||||
|
|
||||||
|
- **Route-specific**: Use `_components/` directories
|
||||||
|
- **Route utilities**: Use `_lib/` for client, `_lib/server/` for server-side
|
||||||
|
- **Global components**: Root-level directories
|
||||||
|
|
||||||
|
Example organization:
|
||||||
|
|
||||||
|
- Team components: @apps/web/app/home/[account]/\_components/
|
||||||
|
- Team server utils: @apps/web/app/home/[account]/\_lib/server/
|
||||||
|
- Marketing components: @apps/web/app/(marketing)/\_components/
|
||||||
|
|
||||||
## Database Guidelines
|
## Database Guidelines
|
||||||
|
|
||||||
### Schema Management
|
|
||||||
|
|
||||||
- Database schemas are in `apps/web/supabase/schemas/`
|
|
||||||
- Create new schemas as `<number>-<name>.sql`
|
|
||||||
- After schema changes: run `pnpm --filter web supabase:db:diff` then `pnpm supabase:web:reset`
|
|
||||||
|
|
||||||
### Security & RLS
|
### Security & RLS
|
||||||
|
|
||||||
- **Always enable RLS** on new tables unless explicitly instructed otherwise
|
- **Always enable RLS** on new tables unless explicitly instructed otherwise
|
||||||
- Use helper functions for access control:
|
- Use helper functions for access control:
|
||||||
- `public.has_role_on_account(account_id, role?)` - Check team membership
|
- `public.has_role_on_account(account_id, role?)` - Check team membership
|
||||||
- `public.has_permission(user_id, account_id, permission)` - Check specific permissions
|
- `public.has_permission(user_id, account_id, permission)` - Check permissions
|
||||||
- `public.is_account_owner(account_id)` - Verify account ownership
|
- `public.is_account_owner(account_id)` - Verify ownership
|
||||||
- Associate data with accounts using foreign keys for proper access control
|
|
||||||
|
See RLS examples in database schemas: @apps/web/supabase/schemas/
|
||||||
|
|
||||||
|
### Schema Management
|
||||||
|
|
||||||
|
- Schemas in `apps/web/supabase/schemas/`
|
||||||
|
- Create as `<number>-<name>.sql`
|
||||||
|
- After changes: `pnpm --filter web supabase:db:diff` then `pnpm supabase:web:reset`
|
||||||
|
|
||||||
|
Key schema files:
|
||||||
|
|
||||||
|
- Accounts: `apps/web/supabase/schemas/03-accounts.sql`
|
||||||
|
- Memberships: `apps/web/supabase/schemas/05-memberships.sql`
|
||||||
|
- Permissions: `apps/web/supabase/schemas/06-roles-permissions.sql`
|
||||||
|
|
||||||
### Type Generation
|
### Type Generation
|
||||||
|
|
||||||
Import auto-generated types from `@kit/supabase/database`:
|
Import auto-generated types from @packages/supabase/src/types/database.ts:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { Tables } from '@kit/supabase/database';
|
import { Tables } from '@kit/supabase/database';
|
||||||
@@ -121,50 +131,427 @@ type Account = Tables<'accounts'>;
|
|||||||
|
|
||||||
### Data Fetching
|
### Data Fetching
|
||||||
|
|
||||||
- **Server Components**: Use `getSupabaseServerClient()` directly
|
- **Server Components**: Use `getSupabaseServerClient()` from @packages/supabase/src/clients/server-client.ts
|
||||||
- **Client Components**: Use `useSupabase()` hook + React Query's `useQuery`
|
- **Client Components**: Use `useSupabase()` hook + React Query's `useQuery`
|
||||||
- Prefer Server Components and pass data down to Client Components when needed
|
- **Admin Operations**: Use `getSupabaseServerAdminClient()` from @packages/supabase/src/clients/server-admin-client.ts (rare cases only - bypasses RLS, use with caution!)
|
||||||
|
- Prefer Server Components and pass data down when needed
|
||||||
|
|
||||||
|
Use the Container/Presenter pattern for complex data components:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Container: handles data fetching
|
||||||
|
function UserProfileContainer() {
|
||||||
|
const userData = useUserData();
|
||||||
|
return <UserProfilePresenter data={userData.data} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Presenter: handles UI rendering
|
||||||
|
function UserProfilePresenter({ data }: { data: UserData }) {
|
||||||
|
return <div>{data.name}</div>;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Example server-side data loading:
|
||||||
|
|
||||||
|
- User workspace loader: @apps/web/app/home/(user)/\_lib/server/load-user-workspace.ts
|
||||||
|
- Team workspace loader: @apps/web/app/home/[account]/\_lib/server/team-account-workspace.loader.ts
|
||||||
|
- Data provider pattern: @packages/features/team-accounts/src/components/members/roles-data-provider.tsx
|
||||||
|
|
||||||
### Server Actions
|
### Server Actions
|
||||||
|
|
||||||
- Always use `enhanceAction` from `@kit/next/actions`
|
Always use `enhanceAction` from @packages/next/src/actions/index.ts:
|
||||||
- Name files as `server-actions.ts` and functions with `Action` suffix
|
|
||||||
- Place Zod schemas in separate files for reuse with forms
|
|
||||||
- Use `'use server'` directive at top of file
|
|
||||||
|
|
||||||
### Error Handling & Logging
|
```typescript
|
||||||
|
'use server';
|
||||||
|
|
||||||
- Use `@kit/shared/logger` for logging
|
import { enhanceAction } from '@kit/next/actions';
|
||||||
- Don't swallow errors - handle them appropriately
|
|
||||||
- Provide context without sensitive data
|
|
||||||
|
|
||||||
### Component Organization
|
export const createNoteAction = enhanceAction(
|
||||||
|
async function (data, user) {
|
||||||
|
// data is validated, user is authenticated
|
||||||
|
return { success: true };
|
||||||
|
},
|
||||||
|
{
|
||||||
|
auth: true,
|
||||||
|
schema: CreateNoteSchema,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
- Route-specific components in `_components/` directories
|
Example server actions:
|
||||||
- Route-specific utilities in `_lib/` directories
|
|
||||||
- Server-side utilities in `_lib/server/`
|
- Team billing: @apps/web/app/home/[account]/billing/\_lib/server/server-actions.ts
|
||||||
- Global components and utilities in root-level directories
|
- Personal settings: @apps/web/app/home/(user)/settings/\_lib/server/server-actions.ts
|
||||||
|
|
||||||
|
### Forms with React Hook Form & Zod
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 1. Define schema in separate file
|
||||||
|
export const CreateNoteSchema = z.object({
|
||||||
|
title: z.string().min(1),
|
||||||
|
content: z.string().min(1),
|
||||||
|
});
|
||||||
|
|
||||||
|
// 2. Client component with form
|
||||||
|
('use client');
|
||||||
|
const form = useForm({
|
||||||
|
resolver: zodResolver(CreateNoteSchema),
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSubmit = (data) => {
|
||||||
|
startTransition(async () => {
|
||||||
|
await toast.promise(createNoteAction(data), {
|
||||||
|
loading: 'Creating...',
|
||||||
|
success: 'Created!',
|
||||||
|
error: 'Failed!',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
See form examples:
|
||||||
|
|
||||||
|
- Contact form: @apps/web/app/(marketing)/contact/\_components/contact-form.tsx
|
||||||
|
- Verify OTP form: @packages/otp/src/components/verify-otp-form.tsx
|
||||||
|
|
||||||
|
### Route Handlers (API Routes)
|
||||||
|
|
||||||
|
Use `enhanceRouteHandler` from @packages/next/src/routes/index.ts:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { enhanceRouteHandler } from '@kit/next/routes';
|
||||||
|
|
||||||
|
export const POST = enhanceRouteHandler(
|
||||||
|
async function ({ body, user, request }) {
|
||||||
|
// body is validated, user available if auth: true
|
||||||
|
return NextResponse.json({ success: true });
|
||||||
|
},
|
||||||
|
{
|
||||||
|
auth: true,
|
||||||
|
schema: ZodSchema,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Example API routes:
|
||||||
|
|
||||||
|
- Billing webhook: @apps/web/app/api/billing/webhook/route.ts
|
||||||
|
- Database webhook: @apps/web/app/api/db/webhook/route.ts
|
||||||
|
|
||||||
|
## React & TypeScript Best Practices
|
||||||
|
|
||||||
|
### Components
|
||||||
|
|
||||||
|
- Use functional components with TypeScript
|
||||||
|
- Always use `'use client'` directive for client components
|
||||||
|
- Destructure props with proper TypeScript interfaces
|
||||||
|
|
||||||
|
### Conditional Rendering
|
||||||
|
|
||||||
|
Use the `If` component from @packages/ui/src/makerkit/if.tsx:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { If } from '@kit/ui/if';
|
||||||
|
import { Spinner } '@kit/ui/spinner';
|
||||||
|
|
||||||
|
<If condition={isLoading} fallback={<Content />}>
|
||||||
|
<Spinner />
|
||||||
|
</If>
|
||||||
|
|
||||||
|
// With type inference
|
||||||
|
<If condition={error}>
|
||||||
|
{(err) => <ErrorMessage error={err} />}
|
||||||
|
</If>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Testing Attributes
|
||||||
|
|
||||||
|
Add data attributes for testing:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
<button data-test="submit-button">Submit</button>
|
||||||
|
<div data-test="user-profile" data-user-id={user.id}>Profile</div>
|
||||||
|
<form data-test="signup-form">Form content</form>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Internationalization
|
||||||
|
|
||||||
|
Always use `Trans` component from @packages/ui/src/makerkit/trans.tsx:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { Trans } from '@kit/ui/trans';
|
||||||
|
|
||||||
|
// Basic usage
|
||||||
|
<Trans
|
||||||
|
i18nKey="user:welcomeMessage"
|
||||||
|
values={{ name: user.name }}
|
||||||
|
defaults="Welcome, {name}!"
|
||||||
|
/>
|
||||||
|
|
||||||
|
// With HTML elements
|
||||||
|
<Trans
|
||||||
|
i18nKey="terms:agreement"
|
||||||
|
components={{
|
||||||
|
TermsLink: <a href="/terms" className="underline" />,
|
||||||
|
}}
|
||||||
|
defaults="I agree to the <TermsLink>Terms</TermsLink>."
|
||||||
|
/>
|
||||||
|
|
||||||
|
// Pluralization
|
||||||
|
<Trans
|
||||||
|
i18nKey="notifications:count"
|
||||||
|
count={notifications.length}
|
||||||
|
defaults="{count, plural, =0 {No notifications} one {# notification} other {# notifications}}"
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `LanguageSelector` component from @packages/ui/src/makerkit/language-selector.tsx:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { LanguageSelector } from '@kit/ui/language-selector';
|
||||||
|
|
||||||
|
<LanguageSelector />;
|
||||||
|
```
|
||||||
|
|
||||||
|
Adding new languages:
|
||||||
|
|
||||||
|
1. Add language code to @apps/web/lib/i18n/i18n.settings.ts
|
||||||
|
2. Create translation files in @apps/web/public/locales/[new-language]/
|
||||||
|
3. Copy structure from English files as template
|
||||||
|
|
||||||
|
Adding new namespaces:
|
||||||
|
|
||||||
|
1. Add namespace to `defaultI18nNamespaces` in @apps/web/lib/i18n/i18n.settings.ts
|
||||||
|
2. Create corresponding translation files for all supported languages
|
||||||
|
|
||||||
|
Translation files located in @apps/web/public/locales/<locale>/<namespace>.json:
|
||||||
|
|
||||||
|
- Common translations: @apps/web/public/locales/en/common.json
|
||||||
|
- Auth translations: @apps/web/public/locales/en/auth.json
|
||||||
|
- Team translations: @apps/web/public/locales/en/teams.json
|
||||||
|
|
||||||
|
## Security Guidelines
|
||||||
|
|
||||||
|
### Authentication & Authorization
|
||||||
|
|
||||||
|
- Authentication enforced by middleware
|
||||||
|
- Authorization typically handled by RLS at database level, unless using the admin client
|
||||||
|
- For rare admin client usage, enforce both manually
|
||||||
|
- User authentication helper: @apps/web/lib/server/require-user-in-server-component.ts if required or to obtain the authed user
|
||||||
|
|
||||||
|
### Data Passing
|
||||||
|
|
||||||
|
- **Never pass sensitive data** to Client Components
|
||||||
|
- **Never expose server environment variables** to client (unless `NEXT_PUBLIC_`)
|
||||||
|
- Always validate user input before processing
|
||||||
|
|
||||||
|
### OTP for Sensitive Operations
|
||||||
|
|
||||||
|
Use one-time tokens from @packages/otp/src/api/index.ts for destructive operations:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { VerifyOtpForm } from '@kit/otp/components';
|
||||||
|
|
||||||
|
<VerifyOtpForm
|
||||||
|
purpose="account-deletion"
|
||||||
|
email={user.email}
|
||||||
|
onSuccess={(otp) => {
|
||||||
|
// Proceed with verified operation
|
||||||
|
}}
|
||||||
|
/>;
|
||||||
|
```
|
||||||
|
|
||||||
|
OTP schema and functions: @apps/web/supabase/schemas/12-one-time-tokens.sql
|
||||||
|
|
||||||
|
### Super Admin Protection
|
||||||
|
|
||||||
|
For admin routes, use `AdminGuard` from @packages/features/admin/src/components/admin-guard.tsx:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { AdminGuard } from '@kit/admin/components/admin-guard';
|
||||||
|
|
||||||
|
export default AdminGuard(AdminPageComponent);
|
||||||
|
```
|
||||||
|
|
||||||
|
For admin server actions, use `adminAction` wrapper:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { adminAction } from '@kit/admin';
|
||||||
|
|
||||||
|
export const yourAdminAction = adminAction(
|
||||||
|
enhanceAction(
|
||||||
|
async (data) => {
|
||||||
|
// Action implementation
|
||||||
|
},
|
||||||
|
{ schema: YourActionSchema },
|
||||||
|
),
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
Admin service security pattern:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
private async assertUserIsNotCurrentSuperAdmin(targetId: string) {
|
||||||
|
const { data } = await this.client.auth.getUser();
|
||||||
|
const currentUserId = data.user?.id;
|
||||||
|
|
||||||
|
if (currentUserId === targetId) {
|
||||||
|
throw new Error('Cannot perform destructive action on your own account');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## UI Components
|
||||||
|
|
||||||
|
### Core UI Library
|
||||||
|
|
||||||
|
Import from @packages/ui/src/:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
// Shadcn components
|
||||||
|
import { Button } from '@kit/ui/button';
|
||||||
|
// @packages/ui/src/shadcn/button.tsx
|
||||||
|
import { Card } from '@kit/ui/card';
|
||||||
|
// @packages/ui/src/shadcn/sonner.tsx
|
||||||
|
|
||||||
|
// Makerkit components
|
||||||
|
import { If } from '@kit/ui/if';
|
||||||
|
// @packages/ui/src/makerkit/trans.tsx
|
||||||
|
import { ProfileAvatar } from '@kit/ui/profile-avatar';
|
||||||
|
// @packages/ui/src/shadcn/card.tsx
|
||||||
|
import { toast } from '@kit/ui/sonner';
|
||||||
|
// @packages/ui/src/makerkit/if.tsx
|
||||||
|
import { Trans } from '@kit/ui/trans';
|
||||||
|
|
||||||
|
// @packages/ui/src/makerkit/profile-avatar.tsx
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key Component Categories
|
||||||
|
|
||||||
|
- **Forms**: Form components in @packages/ui/src/shadcn/form.tsx
|
||||||
|
- **Navigation**: Navigation menu in @packages/ui/src/shadcn/navigation-menu.tsx
|
||||||
|
- **Data Display**: Data table in @packages/ui/src/makerkit/data-table.tsx
|
||||||
|
- **Marketing**: Marketing components in @packages/ui/src/makerkit/marketing/
|
||||||
|
|
||||||
|
### Styling
|
||||||
|
|
||||||
|
- Use Tailwind CSS with semantic classes
|
||||||
|
- Prefer `bg-background`, `text-muted-foreground` over fixed colors
|
||||||
|
- Use `cn()` utility from @packages/ui/src/lib/utils.ts for class merging
|
||||||
|
|
||||||
|
## Workspace Contexts
|
||||||
|
|
||||||
|
### Personal Account Context (`/home/(user)`)
|
||||||
|
|
||||||
|
Use hook from `packages/features/accounts/src/hooks/use-user-workspace.ts`:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { useUserWorkspace } from '@kit/accounts/hooks/use-user-workspace';
|
||||||
|
|
||||||
|
function PersonalComponent() {
|
||||||
|
const { user, account } = useUserWorkspace();
|
||||||
|
// Personal account data
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Context provider: `packages/features/accounts/src/components/user-workspace-context-provider.tsx`
|
||||||
|
|
||||||
|
### Team Account Context (`/home/[account]`)
|
||||||
|
|
||||||
|
Use hook from `packages/features/team-accounts/src/hooks/use-team-account-workspace.ts`:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
import { useTeamAccountWorkspace } from '@kit/team-accounts/hooks/use-team-account-workspace';
|
||||||
|
|
||||||
|
function TeamComponent() {
|
||||||
|
const { account, user, accounts } = useTeamAccountWorkspace();
|
||||||
|
// Team account data with permissions
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Context provider: `packages/features/team-accounts/src/components/team-account-workspace-context-provider.tsx`
|
||||||
|
|
||||||
|
## Error Handling & Logging
|
||||||
|
|
||||||
|
### Structured Logging
|
||||||
|
|
||||||
|
Use logger from `packages/shared/src/logger/logger.ts`:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { getLogger } from '@kit/shared/logger';
|
||||||
|
|
||||||
|
const logger = await getLogger();
|
||||||
|
const ctx = { name: 'myOperation', userId: user.id };
|
||||||
|
|
||||||
|
logger.info(ctx, 'Operation started');
|
||||||
|
// ... operation
|
||||||
|
logger.error({ ...ctx, error }, 'Operation failed');
|
||||||
|
```
|
||||||
|
|
||||||
|
### Error Boundaries
|
||||||
|
|
||||||
|
Use proper error handling with meaningful user messages:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
try {
|
||||||
|
await operation();
|
||||||
|
} catch (error) {
|
||||||
|
logger.error({ error, context }, 'Operation failed');
|
||||||
|
return { error: 'Unable to complete operation' }; // Generic message
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Feature Development Workflow
|
||||||
|
|
||||||
|
### Creating New Pages
|
||||||
|
|
||||||
|
1. Create page component in appropriate route group
|
||||||
|
2. Add `withI18n()` HOC from `apps/web/lib/i18n/with-i18n.tsx`
|
||||||
|
3. Implement `generateMetadata()` for SEO
|
||||||
|
4. Add loading state with `loading.tsx`
|
||||||
|
5. Create components in `_components/` directory
|
||||||
|
6. Add server utilities in `_lib/server/`
|
||||||
|
|
||||||
|
Example page structure:
|
||||||
|
|
||||||
|
- Marketing page: `apps/web/app/(marketing)/pricing/page.tsx`
|
||||||
|
- Dashboard page: `apps/web/app/home/(user)/page.tsx`
|
||||||
|
- Team page: `apps/web/app/home/[account]/members/page.tsx`
|
||||||
|
|
||||||
### Permission Patterns
|
### Permission Patterns
|
||||||
|
|
||||||
- Check permissions before data operations using helper functions
|
- Check permissions before data operations
|
||||||
- Guard premium features with subscription checks (`public.has_active_subscription`)
|
- Guard premium features with `public.has_active_subscription`
|
||||||
- Use role hierarchy to control member management actions
|
- Use role hierarchy for member management
|
||||||
- Primary account owners have special privileges that cannot be revoked
|
- Primary account owners have special privileges
|
||||||
|
|
||||||
## Testing
|
Permission helpers in database: `apps/web/supabase/schemas/06-roles-permissions.sql`
|
||||||
|
|
||||||
### E2E Tests
|
### Database Development
|
||||||
|
|
||||||
```bash
|
1. Create schema file: `apps/web/supabase/schemas/<number>-<name>.sql`
|
||||||
pnpm --filter e2e test # Run all E2E tests
|
2. Enable RLS and create policies
|
||||||
```
|
3. Generate migration: `pnpm --filter web supabase:db:diff`
|
||||||
|
4. Reset database: `pnpm supabase:web:reset`
|
||||||
|
5. Generate types: `pnpm supabase:web:typegen`
|
||||||
|
|
||||||
Test files are in `apps/e2e/tests/` organized by feature area.
|
## API Services
|
||||||
|
|
||||||
## Important Notes
|
### Account Services
|
||||||
|
|
||||||
- Uses pnpm as package manager
|
- Personal accounts API: `packages/features/accounts/src/server/api.ts`
|
||||||
- Database types are auto-generated - don't write manually if shape matches DB
|
- Team accounts API: `packages/features/team-accounts/src/server/api.ts`
|
||||||
- Always use explicit schema references in SQL (`public.table_name`)
|
- Admin service: `packages/features/admin/src/lib/server/services/admin.service.ts`
|
||||||
- Documentation available at: https://makerkit.dev/docs/next-supabase-turbo/introduction
|
|
||||||
|
### Billing Services
|
||||||
|
|
||||||
|
- Personal billing: `apps/web/app/home/(user)/billing/_lib/server/user-billing.service.ts`
|
||||||
|
- Team billing: `apps/web/app/home/[account]/billing/_lib/server/team-billing.service.ts`
|
||||||
|
- Per-seat billing: `packages/features/team-accounts/src/server/services/account-per-seat-billing.service.ts`
|
||||||
|
|
||||||
|
## Key Configuration Files
|
||||||
|
|
||||||
|
- **Feature flags**: @apps/web/config/feature-flags.config.ts
|
||||||
|
- **i18n settings**: @apps/web/lib/i18n/i18n.settings.ts
|
||||||
|
- **Supabase local config**: @apps/web/supabase/config.toml@
|
||||||
|
- **Middleware**: @apps/web/middleware.ts`
|
||||||
@@ -883,7 +883,8 @@ export const envVariables: EnvVariableModel[] = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'EMAIL_TLS',
|
name: 'EMAIL_TLS',
|
||||||
description: 'Whether to use TLS for SMTP connection. Please check this in your SMTP provider settings.',
|
description:
|
||||||
|
'Whether to use TLS for SMTP connection. Please check this in your SMTP provider settings.',
|
||||||
category: 'Email',
|
category: 'Email',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
contextualValidation: {
|
contextualValidation: {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ai-sdk/openai": "^1.3.22",
|
"@ai-sdk/openai": "^1.3.22",
|
||||||
"@hookform/resolvers": "^5.0.1",
|
"@hookform/resolvers": "^5.1.0",
|
||||||
"@tanstack/react-query": "5.80.6",
|
"@tanstack/react-query": "5.80.6",
|
||||||
"ai": "4.3.16",
|
"ai": "4.3.16",
|
||||||
"lucide-react": "^0.513.0",
|
"lucide-react": "^0.513.0",
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
"tailwindcss": "4.1.8",
|
"tailwindcss": "4.1.8",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"zod": "^3.25.53"
|
"zod": "^3.25.56"
|
||||||
},
|
},
|
||||||
"prettier": "@kit/prettier-config",
|
"prettier": "@kit/prettier-config",
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@edge-csrf/nextjs": "2.5.3-cloudflare-rc1",
|
"@edge-csrf/nextjs": "2.5.3-cloudflare-rc1",
|
||||||
"@hookform/resolvers": "^5.0.1",
|
"@hookform/resolvers": "^5.1.0",
|
||||||
"@kit/accounts": "workspace:*",
|
"@kit/accounts": "workspace:*",
|
||||||
"@kit/admin": "workspace:*",
|
"@kit/admin": "workspace:*",
|
||||||
"@kit/analytics": "workspace:*",
|
"@kit/analytics": "workspace:*",
|
||||||
@@ -56,7 +56,7 @@
|
|||||||
"@marsidev/react-turnstile": "^1.1.0",
|
"@marsidev/react-turnstile": "^1.1.0",
|
||||||
"@nosecone/next": "1.0.0-beta.8",
|
"@nosecone/next": "1.0.0-beta.8",
|
||||||
"@radix-ui/react-icons": "^1.3.2",
|
"@radix-ui/react-icons": "^1.3.2",
|
||||||
"@supabase/supabase-js": "2.49.10",
|
"@supabase/supabase-js": "2.50.0",
|
||||||
"@tanstack/react-query": "5.80.6",
|
"@tanstack/react-query": "5.80.6",
|
||||||
"@tanstack/react-table": "^8.21.3",
|
"@tanstack/react-table": "^8.21.3",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
"recharts": "2.15.3",
|
"recharts": "2.15.3",
|
||||||
"sonner": "^2.0.5",
|
"sonner": "^2.0.5",
|
||||||
"tailwind-merge": "^3.3.0",
|
"tailwind-merge": "^3.3.0",
|
||||||
"zod": "^3.25.53"
|
"zod": "^3.25.56"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@kit/eslint-config": "workspace:*",
|
"@kit/eslint-config": "workspace:*",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "next-supabase-saas-kit-turbo",
|
"name": "next-supabase-saas-kit-turbo",
|
||||||
"version": "2.9.0",
|
"version": "2.10.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
"@kit/supabase": "workspace:*",
|
"@kit/supabase": "workspace:*",
|
||||||
"@kit/tsconfig": "workspace:*",
|
"@kit/tsconfig": "workspace:*",
|
||||||
"@kit/ui": "workspace:*",
|
"@kit/ui": "workspace:*",
|
||||||
"zod": "^3.25.53"
|
"zod": "^3.25.56"
|
||||||
},
|
},
|
||||||
"typesVersions": {
|
"typesVersions": {
|
||||||
"*": {
|
"*": {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
"./marketing": "./src/components/marketing.tsx"
|
"./marketing": "./src/components/marketing.tsx"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@hookform/resolvers": "^5.0.1",
|
"@hookform/resolvers": "^5.1.0",
|
||||||
"@kit/billing": "workspace:*",
|
"@kit/billing": "workspace:*",
|
||||||
"@kit/eslint-config": "workspace:*",
|
"@kit/eslint-config": "workspace:*",
|
||||||
"@kit/lemon-squeezy": "workspace:*",
|
"@kit/lemon-squeezy": "workspace:*",
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
"@kit/supabase": "workspace:*",
|
"@kit/supabase": "workspace:*",
|
||||||
"@kit/tsconfig": "workspace:*",
|
"@kit/tsconfig": "workspace:*",
|
||||||
"@kit/ui": "workspace:*",
|
"@kit/ui": "workspace:*",
|
||||||
"@supabase/supabase-js": "2.49.10",
|
"@supabase/supabase-js": "2.50.0",
|
||||||
"@types/react": "19.1.6",
|
"@types/react": "19.1.6",
|
||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"lucide-react": "^0.513.0",
|
"lucide-react": "^0.513.0",
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
"react-hook-form": "^7.57.0",
|
"react-hook-form": "^7.57.0",
|
||||||
"react-i18next": "^15.5.2",
|
"react-i18next": "^15.5.2",
|
||||||
"zod": "^3.25.53"
|
"zod": "^3.25.56"
|
||||||
},
|
},
|
||||||
"typesVersions": {
|
"typesVersions": {
|
||||||
"*": {
|
"*": {
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ import { Enums } from '@kit/supabase/database';
|
|||||||
import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert';
|
import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert';
|
||||||
import { Trans } from '@kit/ui/trans';
|
import { Trans } from '@kit/ui/trans';
|
||||||
|
|
||||||
const statusBadgeMap: Record<Enums<'subscription_status'>, `success` | `destructive` | `warning`> = {
|
const statusBadgeMap: Record<
|
||||||
|
Enums<'subscription_status'>,
|
||||||
|
`success` | `destructive` | `warning`
|
||||||
|
> = {
|
||||||
active: 'success',
|
active: 'success',
|
||||||
trialing: 'success',
|
trialing: 'success',
|
||||||
past_due: 'destructive',
|
past_due: 'destructive',
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ const statusBadgeMap: Record<Status, `success` | `destructive` | `warning`> = {
|
|||||||
pending: 'warning',
|
pending: 'warning',
|
||||||
incomplete_expired: 'destructive',
|
incomplete_expired: 'destructive',
|
||||||
paused: 'warning',
|
paused: 'warning',
|
||||||
}
|
};
|
||||||
|
|
||||||
export function CurrentPlanBadge(
|
export function CurrentPlanBadge(
|
||||||
props: React.PropsWithoutRef<{
|
props: React.PropsWithoutRef<{
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
"@types/react": "19.1.6",
|
"@types/react": "19.1.6",
|
||||||
"next": "15.3.3",
|
"next": "15.3.3",
|
||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
"zod": "^3.25.53"
|
"zod": "^3.25.56"
|
||||||
},
|
},
|
||||||
"typesVersions": {
|
"typesVersions": {
|
||||||
"*": {
|
"*": {
|
||||||
|
|||||||
@@ -454,7 +454,7 @@ export class LemonSqueezyWebhookHandlerService
|
|||||||
pending: 'pending',
|
pending: 'pending',
|
||||||
failed: 'failed',
|
failed: 'failed',
|
||||||
refunded: 'failed',
|
refunded: 'failed',
|
||||||
} satisfies Record<OrderStatus, UpsertOrderParams['status']>
|
} satisfies Record<OrderStatus, UpsertOrderParams['status']>;
|
||||||
|
|
||||||
return statusMap[status] ?? 'pending';
|
return statusMap[status] ?? 'pending';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
"date-fns": "^4.1.0",
|
"date-fns": "^4.1.0",
|
||||||
"next": "15.3.3",
|
"next": "15.3.3",
|
||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
"zod": "^3.25.53"
|
"zod": "^3.25.56"
|
||||||
},
|
},
|
||||||
"typesVersions": {
|
"typesVersions": {
|
||||||
"*": {
|
"*": {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
"@types/node": "^22.15.30",
|
"@types/node": "^22.15.30",
|
||||||
"@types/react": "19.1.6",
|
"@types/react": "19.1.6",
|
||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
"zod": "^3.25.53"
|
"zod": "^3.25.56"
|
||||||
},
|
},
|
||||||
"typesVersions": {
|
"typesVersions": {
|
||||||
"*": {
|
"*": {
|
||||||
|
|||||||
@@ -22,8 +22,8 @@
|
|||||||
"@kit/supabase": "workspace:*",
|
"@kit/supabase": "workspace:*",
|
||||||
"@kit/team-accounts": "workspace:*",
|
"@kit/team-accounts": "workspace:*",
|
||||||
"@kit/tsconfig": "workspace:*",
|
"@kit/tsconfig": "workspace:*",
|
||||||
"@supabase/supabase-js": "2.49.10",
|
"@supabase/supabase-js": "2.50.0",
|
||||||
"zod": "^3.25.53"
|
"zod": "^3.25.56"
|
||||||
},
|
},
|
||||||
"typesVersions": {
|
"typesVersions": {
|
||||||
"*": {
|
"*": {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
"nanoid": "^5.1.5"
|
"nanoid": "^5.1.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@hookform/resolvers": "^5.0.1",
|
"@hookform/resolvers": "^5.1.0",
|
||||||
"@kit/billing-gateway": "workspace:*",
|
"@kit/billing-gateway": "workspace:*",
|
||||||
"@kit/email-templates": "workspace:*",
|
"@kit/email-templates": "workspace:*",
|
||||||
"@kit/eslint-config": "workspace:*",
|
"@kit/eslint-config": "workspace:*",
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
"@kit/tsconfig": "workspace:*",
|
"@kit/tsconfig": "workspace:*",
|
||||||
"@kit/ui": "workspace:*",
|
"@kit/ui": "workspace:*",
|
||||||
"@radix-ui/react-icons": "^1.3.2",
|
"@radix-ui/react-icons": "^1.3.2",
|
||||||
"@supabase/supabase-js": "2.49.10",
|
"@supabase/supabase-js": "2.50.0",
|
||||||
"@tanstack/react-query": "5.80.6",
|
"@tanstack/react-query": "5.80.6",
|
||||||
"@types/react": "19.1.6",
|
"@types/react": "19.1.6",
|
||||||
"@types/react-dom": "19.1.6",
|
"@types/react-dom": "19.1.6",
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
"react-hook-form": "^7.57.0",
|
"react-hook-form": "^7.57.0",
|
||||||
"react-i18next": "^15.5.2",
|
"react-i18next": "^15.5.2",
|
||||||
"sonner": "^2.0.5",
|
"sonner": "^2.0.5",
|
||||||
"zod": "^3.25.53"
|
"zod": "^3.25.56"
|
||||||
},
|
},
|
||||||
"prettier": "@kit/prettier-config",
|
"prettier": "@kit/prettier-config",
|
||||||
"typesVersions": {
|
"typesVersions": {
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ export function AccountSelector({
|
|||||||
role="combobox"
|
role="combobox"
|
||||||
aria-expanded={open}
|
aria-expanded={open}
|
||||||
className={cn(
|
className={cn(
|
||||||
'dark:shadow-primary/10 group w-full min-w-0 px-2 lg:w-auto lg:max-w-fit mr-1',
|
'dark:shadow-primary/10 group mr-1 w-full min-w-0 px-2 lg:w-auto lg:max-w-fit',
|
||||||
{
|
{
|
||||||
'justify-start': !collapsed,
|
'justify-start': !collapsed,
|
||||||
'm-auto justify-center px-2 lg:w-full': collapsed,
|
'm-auto justify-center px-2 lg:w-full': collapsed,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
},
|
},
|
||||||
"prettier": "@kit/prettier-config",
|
"prettier": "@kit/prettier-config",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@hookform/resolvers": "^5.0.1",
|
"@hookform/resolvers": "^5.1.0",
|
||||||
"@kit/eslint-config": "workspace:*",
|
"@kit/eslint-config": "workspace:*",
|
||||||
"@kit/next": "workspace:*",
|
"@kit/next": "workspace:*",
|
||||||
"@kit/prettier-config": "workspace:*",
|
"@kit/prettier-config": "workspace:*",
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
"@kit/ui": "workspace:*",
|
"@kit/ui": "workspace:*",
|
||||||
"@makerkit/data-loader-supabase-core": "^0.0.10",
|
"@makerkit/data-loader-supabase-core": "^0.0.10",
|
||||||
"@makerkit/data-loader-supabase-nextjs": "^1.2.5",
|
"@makerkit/data-loader-supabase-nextjs": "^1.2.5",
|
||||||
"@supabase/supabase-js": "2.49.10",
|
"@supabase/supabase-js": "2.50.0",
|
||||||
"@tanstack/react-query": "5.80.6",
|
"@tanstack/react-query": "5.80.6",
|
||||||
"@tanstack/react-table": "^8.21.3",
|
"@tanstack/react-table": "^8.21.3",
|
||||||
"@types/react": "19.1.6",
|
"@types/react": "19.1.6",
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
"react-dom": "19.1.0",
|
"react-dom": "19.1.0",
|
||||||
"react-hook-form": "^7.57.0",
|
"react-hook-form": "^7.57.0",
|
||||||
"zod": "^3.25.53"
|
"zod": "^3.25.56"
|
||||||
},
|
},
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./src/index.ts",
|
".": "./src/index.ts",
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
"./resend-email-link": "./src/components/resend-auth-link-form.tsx"
|
"./resend-email-link": "./src/components/resend-auth-link-form.tsx"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@hookform/resolvers": "^5.0.1",
|
"@hookform/resolvers": "^5.1.0",
|
||||||
"@kit/eslint-config": "workspace:*",
|
"@kit/eslint-config": "workspace:*",
|
||||||
"@kit/prettier-config": "workspace:*",
|
"@kit/prettier-config": "workspace:*",
|
||||||
"@kit/shared": "workspace:*",
|
"@kit/shared": "workspace:*",
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
"@kit/ui": "workspace:*",
|
"@kit/ui": "workspace:*",
|
||||||
"@marsidev/react-turnstile": "^1.1.0",
|
"@marsidev/react-turnstile": "^1.1.0",
|
||||||
"@radix-ui/react-icons": "^1.3.2",
|
"@radix-ui/react-icons": "^1.3.2",
|
||||||
"@supabase/supabase-js": "2.49.10",
|
"@supabase/supabase-js": "2.50.0",
|
||||||
"@tanstack/react-query": "5.80.6",
|
"@tanstack/react-query": "5.80.6",
|
||||||
"@types/react": "19.1.6",
|
"@types/react": "19.1.6",
|
||||||
"lucide-react": "^0.513.0",
|
"lucide-react": "^0.513.0",
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
"react-hook-form": "^7.57.0",
|
"react-hook-form": "^7.57.0",
|
||||||
"react-i18next": "^15.5.2",
|
"react-i18next": "^15.5.2",
|
||||||
"sonner": "^2.0.5",
|
"sonner": "^2.0.5",
|
||||||
"zod": "^3.25.53"
|
"zod": "^3.25.56"
|
||||||
},
|
},
|
||||||
"prettier": "@kit/prettier-config",
|
"prettier": "@kit/prettier-config",
|
||||||
"typesVersions": {
|
"typesVersions": {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
"@kit/supabase": "workspace:*",
|
"@kit/supabase": "workspace:*",
|
||||||
"@kit/tsconfig": "workspace:*",
|
"@kit/tsconfig": "workspace:*",
|
||||||
"@kit/ui": "workspace:*",
|
"@kit/ui": "workspace:*",
|
||||||
"@supabase/supabase-js": "2.49.10",
|
"@supabase/supabase-js": "2.50.0",
|
||||||
"@tanstack/react-query": "5.80.6",
|
"@tanstack/react-query": "5.80.6",
|
||||||
"@types/react": "19.1.6",
|
"@types/react": "19.1.6",
|
||||||
"lucide-react": "^0.513.0",
|
"lucide-react": "^0.513.0",
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
"nanoid": "^5.1.5"
|
"nanoid": "^5.1.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@hookform/resolvers": "^5.0.1",
|
"@hookform/resolvers": "^5.1.0",
|
||||||
"@kit/accounts": "workspace:*",
|
"@kit/accounts": "workspace:*",
|
||||||
"@kit/billing-gateway": "workspace:*",
|
"@kit/billing-gateway": "workspace:*",
|
||||||
"@kit/email-templates": "workspace:*",
|
"@kit/email-templates": "workspace:*",
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
"@kit/supabase": "workspace:*",
|
"@kit/supabase": "workspace:*",
|
||||||
"@kit/tsconfig": "workspace:*",
|
"@kit/tsconfig": "workspace:*",
|
||||||
"@kit/ui": "workspace:*",
|
"@kit/ui": "workspace:*",
|
||||||
"@supabase/supabase-js": "2.49.10",
|
"@supabase/supabase-js": "2.50.0",
|
||||||
"@tanstack/react-query": "5.80.6",
|
"@tanstack/react-query": "5.80.6",
|
||||||
"@tanstack/react-table": "^8.21.3",
|
"@tanstack/react-table": "^8.21.3",
|
||||||
"@types/react": "19.1.6",
|
"@types/react": "19.1.6",
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
"react-hook-form": "^7.57.0",
|
"react-hook-form": "^7.57.0",
|
||||||
"react-i18next": "^15.5.2",
|
"react-i18next": "^15.5.2",
|
||||||
"sonner": "^2.0.5",
|
"sonner": "^2.0.5",
|
||||||
"zod": "^3.25.53"
|
"zod": "^3.25.56"
|
||||||
},
|
},
|
||||||
"prettier": "@kit/prettier-config",
|
"prettier": "@kit/prettier-config",
|
||||||
"typesVersions": {
|
"typesVersions": {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
"@kit/shared": "workspace:*",
|
"@kit/shared": "workspace:*",
|
||||||
"@kit/tsconfig": "workspace:*",
|
"@kit/tsconfig": "workspace:*",
|
||||||
"@types/node": "^22.15.30",
|
"@types/node": "^22.15.30",
|
||||||
"zod": "^3.25.53"
|
"zod": "^3.25.56"
|
||||||
},
|
},
|
||||||
"typesVersions": {
|
"typesVersions": {
|
||||||
"*": {
|
"*": {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
"@kit/prettier-config": "workspace:*",
|
"@kit/prettier-config": "workspace:*",
|
||||||
"@kit/tsconfig": "workspace:*",
|
"@kit/tsconfig": "workspace:*",
|
||||||
"@types/nodemailer": "6.4.17",
|
"@types/nodemailer": "6.4.17",
|
||||||
"zod": "^3.25.53"
|
"zod": "^3.25.56"
|
||||||
},
|
},
|
||||||
"typesVersions": {
|
"typesVersions": {
|
||||||
"*": {
|
"*": {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
"@kit/prettier-config": "workspace:*",
|
"@kit/prettier-config": "workspace:*",
|
||||||
"@kit/tsconfig": "workspace:*",
|
"@kit/tsconfig": "workspace:*",
|
||||||
"@types/node": "^22.15.30",
|
"@types/node": "^22.15.30",
|
||||||
"zod": "^3.25.53"
|
"zod": "^3.25.56"
|
||||||
},
|
},
|
||||||
"typesVersions": {
|
"typesVersions": {
|
||||||
"*": {
|
"*": {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
"@kit/eslint-config": "workspace:*",
|
"@kit/eslint-config": "workspace:*",
|
||||||
"@kit/prettier-config": "workspace:*",
|
"@kit/prettier-config": "workspace:*",
|
||||||
"@kit/tsconfig": "workspace:*",
|
"@kit/tsconfig": "workspace:*",
|
||||||
"zod": "^3.25.53"
|
"zod": "^3.25.56"
|
||||||
},
|
},
|
||||||
"typesVersions": {
|
"typesVersions": {
|
||||||
"*": {
|
"*": {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
"@kit/tsconfig": "workspace:*",
|
"@kit/tsconfig": "workspace:*",
|
||||||
"@types/react": "19.1.6",
|
"@types/react": "19.1.6",
|
||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
"zod": "^3.25.53"
|
"zod": "^3.25.56"
|
||||||
},
|
},
|
||||||
"typesVersions": {
|
"typesVersions": {
|
||||||
"*": {
|
"*": {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
"@kit/tsconfig": "workspace:*",
|
"@kit/tsconfig": "workspace:*",
|
||||||
"@types/react": "19.1.6",
|
"@types/react": "19.1.6",
|
||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
"zod": "^3.25.53"
|
"zod": "^3.25.56"
|
||||||
},
|
},
|
||||||
"typesVersions": {
|
"typesVersions": {
|
||||||
"*": {
|
"*": {
|
||||||
|
|||||||
@@ -20,9 +20,9 @@
|
|||||||
"@kit/prettier-config": "workspace:*",
|
"@kit/prettier-config": "workspace:*",
|
||||||
"@kit/supabase": "workspace:*",
|
"@kit/supabase": "workspace:*",
|
||||||
"@kit/tsconfig": "workspace:*",
|
"@kit/tsconfig": "workspace:*",
|
||||||
"@supabase/supabase-js": "2.49.10",
|
"@supabase/supabase-js": "2.50.0",
|
||||||
"next": "15.3.3",
|
"next": "15.3.3",
|
||||||
"zod": "^3.25.53"
|
"zod": "^3.25.56"
|
||||||
},
|
},
|
||||||
"typesVersions": {
|
"typesVersions": {
|
||||||
"*": {
|
"*": {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
"./components": "./src/components/index.ts"
|
"./components": "./src/components/index.ts"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@hookform/resolvers": "^5.0.1",
|
"@hookform/resolvers": "^5.1.0",
|
||||||
"@kit/email-templates": "workspace:*",
|
"@kit/email-templates": "workspace:*",
|
||||||
"@kit/eslint-config": "workspace:*",
|
"@kit/eslint-config": "workspace:*",
|
||||||
"@kit/mailers": "workspace:*",
|
"@kit/mailers": "workspace:*",
|
||||||
@@ -25,13 +25,13 @@
|
|||||||
"@kit/tsconfig": "workspace:*",
|
"@kit/tsconfig": "workspace:*",
|
||||||
"@kit/ui": "workspace:*",
|
"@kit/ui": "workspace:*",
|
||||||
"@radix-ui/react-icons": "^1.3.2",
|
"@radix-ui/react-icons": "^1.3.2",
|
||||||
"@supabase/supabase-js": "2.49.10",
|
"@supabase/supabase-js": "2.50.0",
|
||||||
"@types/react": "19.1.6",
|
"@types/react": "19.1.6",
|
||||||
"@types/react-dom": "19.1.6",
|
"@types/react-dom": "19.1.6",
|
||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
"react-dom": "19.1.0",
|
"react-dom": "19.1.0",
|
||||||
"react-hook-form": "^7.57.0",
|
"react-hook-form": "^7.57.0",
|
||||||
"zod": "^3.25.53"
|
"zod": "^3.25.56"
|
||||||
},
|
},
|
||||||
"typesVersions": {
|
"typesVersions": {
|
||||||
"*": {
|
"*": {
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ const Logger = {
|
|||||||
warn: console.warn,
|
warn: console.warn,
|
||||||
debug: console.debug,
|
debug: console.debug,
|
||||||
fatal: console.error,
|
fatal: console.error,
|
||||||
}
|
};
|
||||||
|
|
||||||
export { Logger };
|
export { Logger };
|
||||||
@@ -25,13 +25,13 @@
|
|||||||
"@kit/prettier-config": "workspace:*",
|
"@kit/prettier-config": "workspace:*",
|
||||||
"@kit/tsconfig": "workspace:*",
|
"@kit/tsconfig": "workspace:*",
|
||||||
"@supabase/ssr": "^0.6.1",
|
"@supabase/ssr": "^0.6.1",
|
||||||
"@supabase/supabase-js": "2.49.10",
|
"@supabase/supabase-js": "2.50.0",
|
||||||
"@tanstack/react-query": "5.80.6",
|
"@tanstack/react-query": "5.80.6",
|
||||||
"@types/react": "19.1.6",
|
"@types/react": "19.1.6",
|
||||||
"next": "15.3.3",
|
"next": "15.3.3",
|
||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
"server-only": "^0.0.1",
|
"server-only": "^0.0.1",
|
||||||
"zod": "^3.25.53"
|
"zod": "^3.25.56"
|
||||||
},
|
},
|
||||||
"typesVersions": {
|
"typesVersions": {
|
||||||
"*": {
|
"*": {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
"typecheck": "tsc --noEmit"
|
"typecheck": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hookform/resolvers": "^5.0.1",
|
"@hookform/resolvers": "^5.1.0",
|
||||||
"@radix-ui/react-accordion": "1.2.11",
|
"@radix-ui/react-accordion": "1.2.11",
|
||||||
"@radix-ui/react-alert-dialog": "^1.1.14",
|
"@radix-ui/react-alert-dialog": "^1.1.14",
|
||||||
"@radix-ui/react-avatar": "^1.1.10",
|
"@radix-ui/react-avatar": "^1.1.10",
|
||||||
@@ -53,16 +53,21 @@
|
|||||||
"next": "15.3.3",
|
"next": "15.3.3",
|
||||||
"next-themes": "0.4.6",
|
"next-themes": "0.4.6",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
"react-day-picker": "^8.10.1",
|
"react-day-picker": "^9.7.0",
|
||||||
"react-hook-form": "^7.57.0",
|
"react-hook-form": "^7.57.0",
|
||||||
"react-i18next": "^15.5.2",
|
"react-i18next": "^15.5.2",
|
||||||
"sonner": "^2.0.5",
|
"sonner": "^2.0.5",
|
||||||
"tailwindcss": "4.1.8",
|
"tailwindcss": "4.1.8",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"zod": "^3.25.53"
|
"zod": "^3.25.56"
|
||||||
},
|
},
|
||||||
"prettier": "@kit/prettier-config",
|
"prettier": "@kit/prettier-config",
|
||||||
|
"imports": {
|
||||||
|
"#utils": [
|
||||||
|
"./src/lib/utils/index.ts"
|
||||||
|
]
|
||||||
|
},
|
||||||
"exports": {
|
"exports": {
|
||||||
"./accordion": "./src/shadcn/accordion.tsx",
|
"./accordion": "./src/shadcn/accordion.tsx",
|
||||||
"./alert-dialog": "./src/shadcn/alert-dialog.tsx",
|
"./alert-dialog": "./src/shadcn/alert-dialog.tsx",
|
||||||
|
|||||||
@@ -2,69 +2,210 @@
|
|||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
import {
|
||||||
import { DayPicker } from 'react-day-picker';
|
ChevronDownIcon,
|
||||||
|
ChevronLeftIcon,
|
||||||
|
ChevronRightIcon,
|
||||||
|
} from 'lucide-react';
|
||||||
|
import { DayButton, DayPicker, getDefaultClassNames } from 'react-day-picker';
|
||||||
|
|
||||||
import { cn } from '../lib/utils';
|
import { cn } from '../lib/utils';
|
||||||
import { buttonVariants } from './button';
|
import { Button, buttonVariants } from './button';
|
||||||
|
|
||||||
export type { DateRange } from 'react-day-picker';
|
|
||||||
export type CalendarProps = React.ComponentProps<typeof DayPicker>;
|
|
||||||
|
|
||||||
function Calendar({
|
function Calendar({
|
||||||
className,
|
className,
|
||||||
classNames,
|
classNames,
|
||||||
showOutsideDays = true,
|
showOutsideDays = true,
|
||||||
|
captionLayout = 'label',
|
||||||
|
buttonVariant = 'ghost',
|
||||||
|
formatters,
|
||||||
|
components,
|
||||||
...props
|
...props
|
||||||
}: CalendarProps) {
|
}: React.ComponentProps<typeof DayPicker> & {
|
||||||
|
buttonVariant?: React.ComponentProps<typeof Button>['variant'];
|
||||||
|
}) {
|
||||||
|
const defaultClassNames = getDefaultClassNames();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DayPicker
|
<DayPicker
|
||||||
showOutsideDays={showOutsideDays}
|
showOutsideDays={showOutsideDays}
|
||||||
className={cn('p-3', className)}
|
className={cn(
|
||||||
|
'bg-background group/calendar p-3 [--cell-size:--spacing(8)] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent',
|
||||||
|
String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
|
||||||
|
String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
captionLayout={captionLayout}
|
||||||
|
formatters={{
|
||||||
|
formatMonthDropdown: (date) =>
|
||||||
|
date.toLocaleString('default', { month: 'short' }),
|
||||||
|
...formatters,
|
||||||
|
}}
|
||||||
classNames={{
|
classNames={{
|
||||||
months: 'flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0',
|
root: cn('w-fit', defaultClassNames.root),
|
||||||
month: 'space-y-4',
|
months: cn(
|
||||||
caption: 'flex justify-center pt-1 relative items-center',
|
'relative flex flex-col gap-4 md:flex-row',
|
||||||
caption_label: 'text-sm font-medium',
|
defaultClassNames.months,
|
||||||
nav: 'gap-x-2 flex items-center',
|
),
|
||||||
nav_button: cn(
|
month: cn('flex w-full flex-col gap-4', defaultClassNames.month),
|
||||||
buttonVariants({ variant: 'outline' }),
|
nav: cn(
|
||||||
'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',
|
'absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1',
|
||||||
|
defaultClassNames.nav,
|
||||||
|
),
|
||||||
|
button_previous: cn(
|
||||||
|
buttonVariants({ variant: buttonVariant }),
|
||||||
|
'size-(--cell-size) p-0 select-none aria-disabled:opacity-50',
|
||||||
|
defaultClassNames.button_previous,
|
||||||
|
),
|
||||||
|
button_next: cn(
|
||||||
|
buttonVariants({ variant: buttonVariant }),
|
||||||
|
'size-(--cell-size) p-0 select-none aria-disabled:opacity-50',
|
||||||
|
defaultClassNames.button_next,
|
||||||
|
),
|
||||||
|
month_caption: cn(
|
||||||
|
'flex h-(--cell-size) w-full items-center justify-center px-(--cell-size)',
|
||||||
|
defaultClassNames.month_caption,
|
||||||
|
),
|
||||||
|
dropdowns: cn(
|
||||||
|
'flex h-(--cell-size) w-full items-center justify-center gap-1.5 text-sm font-medium',
|
||||||
|
defaultClassNames.dropdowns,
|
||||||
|
),
|
||||||
|
dropdown_root: cn(
|
||||||
|
'has-focus:border-ring border-input has-focus:ring-ring/50 relative rounded-md border shadow-xs has-focus:ring-[3px]',
|
||||||
|
defaultClassNames.dropdown_root,
|
||||||
|
),
|
||||||
|
dropdown: cn('absolute inset-0 opacity-0', defaultClassNames.dropdown),
|
||||||
|
caption_label: cn(
|
||||||
|
'font-medium select-none',
|
||||||
|
captionLayout === 'label'
|
||||||
|
? 'text-sm'
|
||||||
|
: '[&>svg]:text-muted-foreground flex h-8 items-center gap-1 rounded-md pr-1 pl-2 text-sm [&>svg]:size-3.5',
|
||||||
|
defaultClassNames.caption_label,
|
||||||
|
),
|
||||||
|
table: 'w-full border-collapse',
|
||||||
|
weekdays: cn('flex', defaultClassNames.weekdays),
|
||||||
|
weekday: cn(
|
||||||
|
'text-muted-foreground flex-1 rounded-md text-[0.8rem] font-normal select-none',
|
||||||
|
defaultClassNames.weekday,
|
||||||
|
),
|
||||||
|
week: cn('mt-2 flex w-full', defaultClassNames.week),
|
||||||
|
week_number_header: cn(
|
||||||
|
'w-(--cell-size) select-none',
|
||||||
|
defaultClassNames.week_number_header,
|
||||||
|
),
|
||||||
|
week_number: cn(
|
||||||
|
'text-muted-foreground text-[0.8rem] select-none',
|
||||||
|
defaultClassNames.week_number,
|
||||||
),
|
),
|
||||||
nav_button_previous: 'absolute left-1',
|
|
||||||
nav_button_next: 'absolute right-1',
|
|
||||||
table: 'w-full border-collapse space-y-1',
|
|
||||||
head_row: 'flex',
|
|
||||||
head_cell:
|
|
||||||
'text-muted-foreground rounded-md w-9 font-normal text-[0.8rem]',
|
|
||||||
row: 'flex w-full mt-2',
|
|
||||||
cell: 'text-center text-sm p-0 relative [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20',
|
|
||||||
day: cn(
|
day: cn(
|
||||||
buttonVariants({ variant: 'ghost' }),
|
'group/day relative aspect-square h-full w-full p-0 text-center select-none [&:first-child[data-selected=true]_button]:rounded-l-md [&:last-child[data-selected=true]_button]:rounded-r-md',
|
||||||
'h-9 w-9 p-0 font-normal aria-selected:opacity-100',
|
defaultClassNames.day,
|
||||||
),
|
),
|
||||||
day_selected:
|
range_start: cn(
|
||||||
'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground',
|
'bg-accent rounded-l-md',
|
||||||
day_today: 'bg-accent text-accent-foreground',
|
defaultClassNames.range_start,
|
||||||
day_outside: 'text-muted-foreground opacity-50',
|
),
|
||||||
day_disabled: 'text-muted-foreground opacity-50',
|
range_middle: cn('rounded-none', defaultClassNames.range_middle),
|
||||||
day_range_middle:
|
range_end: cn('bg-accent rounded-r-md', defaultClassNames.range_end),
|
||||||
'aria-selected:bg-accent aria-selected:text-accent-foreground',
|
today: cn(
|
||||||
day_hidden: 'invisible',
|
'bg-accent text-accent-foreground rounded-md data-[selected=true]:rounded-none',
|
||||||
|
defaultClassNames.today,
|
||||||
|
),
|
||||||
|
outside: cn(
|
||||||
|
'text-muted-foreground aria-selected:text-muted-foreground',
|
||||||
|
defaultClassNames.outside,
|
||||||
|
),
|
||||||
|
disabled: cn(
|
||||||
|
'text-muted-foreground opacity-50',
|
||||||
|
defaultClassNames.disabled,
|
||||||
|
),
|
||||||
|
hidden: cn('invisible', defaultClassNames.hidden),
|
||||||
...classNames,
|
...classNames,
|
||||||
}}
|
}}
|
||||||
components={{
|
components={{
|
||||||
IconLeft: ({ ...props }) => (
|
Root: ({ className, rootRef, ...props }) => {
|
||||||
<ChevronLeft className="h-4 w-4" {...props} />
|
return (
|
||||||
),
|
<div
|
||||||
IconRight: ({ ...props }) => (
|
data-slot="calendar"
|
||||||
<ChevronRight className="h-4 w-4" {...props} />
|
ref={rootRef}
|
||||||
),
|
className={cn(className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Chevron: ({ className, orientation, ...props }) => {
|
||||||
|
if (orientation === 'left') {
|
||||||
|
return (
|
||||||
|
<ChevronLeftIcon className={cn('size-4', className)} {...props} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (orientation === 'right') {
|
||||||
|
return (
|
||||||
|
<ChevronRightIcon
|
||||||
|
className={cn('size-4', className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ChevronDownIcon className={cn('size-4', className)} {...props} />
|
||||||
|
);
|
||||||
|
},
|
||||||
|
DayButton: CalendarDayButton,
|
||||||
|
WeekNumber: ({ children, ...props }) => {
|
||||||
|
return (
|
||||||
|
<td {...props}>
|
||||||
|
<div className="flex size-(--cell-size) items-center justify-center text-center">
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
...components,
|
||||||
}}
|
}}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Calendar.displayName = 'Calendar';
|
|
||||||
|
|
||||||
export { Calendar };
|
function CalendarDayButton({
|
||||||
|
className,
|
||||||
|
day,
|
||||||
|
modifiers,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof DayButton>) {
|
||||||
|
const defaultClassNames = getDefaultClassNames();
|
||||||
|
|
||||||
|
const ref = React.useRef<HTMLButtonElement>(null);
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (modifiers.focused) ref.current?.focus();
|
||||||
|
}, [modifiers.focused]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
ref={ref}
|
||||||
|
variant="ghost"
|
||||||
|
size="icon"
|
||||||
|
data-day={day.date.toLocaleDateString()}
|
||||||
|
data-selected-single={
|
||||||
|
modifiers.selected &&
|
||||||
|
!modifiers.range_start &&
|
||||||
|
!modifiers.range_end &&
|
||||||
|
!modifiers.range_middle
|
||||||
|
}
|
||||||
|
data-range-start={modifiers.range_start}
|
||||||
|
data-range-end={modifiers.range_end}
|
||||||
|
data-range-middle={modifiers.range_middle}
|
||||||
|
className={cn(
|
||||||
|
'data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-ring/50 dark:hover:text-accent-foreground flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[3px] data-[range-end=true]:rounded-md data-[range-end=true]:rounded-r-md data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-md data-[range-start=true]:rounded-l-md [&>span]:text-xs [&>span]:opacity-70',
|
||||||
|
defaultClassNames.day,
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Calendar, CalendarDayButton };
|
||||||
|
|||||||
@@ -392,7 +392,10 @@ const SidebarHeader: React.FC<React.ComponentPropsWithRef<'div'>> = ({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-sidebar="header"
|
data-sidebar="header"
|
||||||
className={cn('flex flex-col gap-2 p-2 group-data-[state=collapsed]:group-data-[collapsible=offcanvas]:hidden', className)}
|
className={cn(
|
||||||
|
'flex flex-col gap-2 p-2 group-data-[state=collapsed]:group-data-[collapsible=offcanvas]:hidden',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
306
pnpm-lock.yaml
generated
306
pnpm-lock.yaml
generated
@@ -35,16 +35,16 @@ importers:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@ai-sdk/openai':
|
'@ai-sdk/openai':
|
||||||
specifier: ^1.3.22
|
specifier: ^1.3.22
|
||||||
version: 1.3.22(zod@3.25.53)
|
version: 1.3.22(zod@3.25.56)
|
||||||
'@hookform/resolvers':
|
'@hookform/resolvers':
|
||||||
specifier: ^5.0.1
|
specifier: ^5.1.0
|
||||||
version: 5.0.1(react-hook-form@7.57.0(react@19.1.0))
|
version: 5.1.0(react-hook-form@7.57.0(react@19.1.0))
|
||||||
'@tanstack/react-query':
|
'@tanstack/react-query':
|
||||||
specifier: 5.80.6
|
specifier: 5.80.6
|
||||||
version: 5.80.6(react@19.1.0)
|
version: 5.80.6(react@19.1.0)
|
||||||
ai:
|
ai:
|
||||||
specifier: 4.3.16
|
specifier: 4.3.16
|
||||||
version: 4.3.16(react@19.1.0)(zod@3.25.53)
|
version: 4.3.16(react@19.1.0)(zod@3.25.56)
|
||||||
lucide-react:
|
lucide-react:
|
||||||
specifier: ^0.513.0
|
specifier: ^0.513.0
|
||||||
version: 0.513.0(react@19.1.0)
|
version: 0.513.0(react@19.1.0)
|
||||||
@@ -113,8 +113,8 @@ importers:
|
|||||||
specifier: ^5.8.3
|
specifier: ^5.8.3
|
||||||
version: 5.8.3
|
version: 5.8.3
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.25.53
|
specifier: ^3.25.56
|
||||||
version: 3.25.53
|
version: 3.25.56
|
||||||
|
|
||||||
apps/e2e:
|
apps/e2e:
|
||||||
devDependencies:
|
devDependencies:
|
||||||
@@ -140,8 +140,8 @@ importers:
|
|||||||
specifier: 2.5.3-cloudflare-rc1
|
specifier: 2.5.3-cloudflare-rc1
|
||||||
version: 2.5.3-cloudflare-rc1(next@15.3.3(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))
|
version: 2.5.3-cloudflare-rc1(next@15.3.3(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))
|
||||||
'@hookform/resolvers':
|
'@hookform/resolvers':
|
||||||
specifier: ^5.0.1
|
specifier: ^5.1.0
|
||||||
version: 5.0.1(react-hook-form@7.57.0(react@19.1.0))
|
version: 5.1.0(react-hook-form@7.57.0(react@19.1.0))
|
||||||
'@kit/accounts':
|
'@kit/accounts':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../packages/features/accounts
|
version: link:../../packages/features/accounts
|
||||||
@@ -198,10 +198,10 @@ importers:
|
|||||||
version: link:../../packages/ui
|
version: link:../../packages/ui
|
||||||
'@makerkit/data-loader-supabase-core':
|
'@makerkit/data-loader-supabase-core':
|
||||||
specifier: ^0.0.10
|
specifier: ^0.0.10
|
||||||
version: 0.0.10(@supabase/postgrest-js@1.19.4)(@supabase/supabase-js@2.49.10)
|
version: 0.0.10(@supabase/postgrest-js@1.19.4)(@supabase/supabase-js@2.50.0)
|
||||||
'@makerkit/data-loader-supabase-nextjs':
|
'@makerkit/data-loader-supabase-nextjs':
|
||||||
specifier: ^1.2.5
|
specifier: ^1.2.5
|
||||||
version: 1.2.5(@supabase/postgrest-js@1.19.4)(@supabase/supabase-js@2.49.10)(@tanstack/react-query@5.80.6(react@19.1.0))(next@15.3.3(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)
|
version: 1.2.5(@supabase/postgrest-js@1.19.4)(@supabase/supabase-js@2.50.0)(@tanstack/react-query@5.80.6(react@19.1.0))(next@15.3.3(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)
|
||||||
'@marsidev/react-turnstile':
|
'@marsidev/react-turnstile':
|
||||||
specifier: ^1.1.0
|
specifier: ^1.1.0
|
||||||
version: 1.1.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
version: 1.1.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
@@ -212,8 +212,8 @@ importers:
|
|||||||
specifier: ^1.3.2
|
specifier: ^1.3.2
|
||||||
version: 1.3.2(react@19.1.0)
|
version: 1.3.2(react@19.1.0)
|
||||||
'@supabase/supabase-js':
|
'@supabase/supabase-js':
|
||||||
specifier: 2.49.10
|
specifier: 2.50.0
|
||||||
version: 2.49.10
|
version: 2.50.0
|
||||||
'@tanstack/react-query':
|
'@tanstack/react-query':
|
||||||
specifier: 5.80.6
|
specifier: 5.80.6
|
||||||
version: 5.80.6(react@19.1.0)
|
version: 5.80.6(react@19.1.0)
|
||||||
@@ -257,8 +257,8 @@ importers:
|
|||||||
specifier: ^3.3.0
|
specifier: ^3.3.0
|
||||||
version: 3.3.0
|
version: 3.3.0
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.25.53
|
specifier: ^3.25.56
|
||||||
version: 3.25.53
|
version: 3.25.56
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@kit/eslint-config':
|
'@kit/eslint-config':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
@@ -342,14 +342,14 @@ importers:
|
|||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../ui
|
version: link:../../ui
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.25.53
|
specifier: ^3.25.56
|
||||||
version: 3.25.53
|
version: 3.25.56
|
||||||
|
|
||||||
packages/billing/gateway:
|
packages/billing/gateway:
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@hookform/resolvers':
|
'@hookform/resolvers':
|
||||||
specifier: ^5.0.1
|
specifier: ^5.1.0
|
||||||
version: 5.0.1(react-hook-form@7.57.0(react@19.1.0))
|
version: 5.1.0(react-hook-form@7.57.0(react@19.1.0))
|
||||||
'@kit/billing':
|
'@kit/billing':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../core
|
version: link:../core
|
||||||
@@ -378,8 +378,8 @@ importers:
|
|||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../ui
|
version: link:../../ui
|
||||||
'@supabase/supabase-js':
|
'@supabase/supabase-js':
|
||||||
specifier: 2.49.10
|
specifier: 2.50.0
|
||||||
version: 2.49.10
|
version: 2.50.0
|
||||||
'@types/react':
|
'@types/react':
|
||||||
specifier: 19.1.6
|
specifier: 19.1.6
|
||||||
version: 19.1.6
|
version: 19.1.6
|
||||||
@@ -402,8 +402,8 @@ importers:
|
|||||||
specifier: ^15.5.2
|
specifier: ^15.5.2
|
||||||
version: 15.5.2(i18next@25.2.1(typescript@5.8.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.3)
|
version: 15.5.2(i18next@25.2.1(typescript@5.8.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.3)
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.25.53
|
specifier: ^3.25.56
|
||||||
version: 3.25.53
|
version: 3.25.56
|
||||||
|
|
||||||
packages/billing/lemon-squeezy:
|
packages/billing/lemon-squeezy:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -442,8 +442,8 @@ importers:
|
|||||||
specifier: 19.1.0
|
specifier: 19.1.0
|
||||||
version: 19.1.0
|
version: 19.1.0
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.25.53
|
specifier: ^3.25.56
|
||||||
version: 3.25.53
|
version: 3.25.56
|
||||||
|
|
||||||
packages/billing/stripe:
|
packages/billing/stripe:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -491,8 +491,8 @@ importers:
|
|||||||
specifier: 19.1.0
|
specifier: 19.1.0
|
||||||
version: 19.1.0
|
version: 19.1.0
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.25.53
|
specifier: ^3.25.56
|
||||||
version: 3.25.53
|
version: 3.25.56
|
||||||
|
|
||||||
packages/cms/core:
|
packages/cms/core:
|
||||||
devDependencies:
|
devDependencies:
|
||||||
@@ -558,8 +558,8 @@ importers:
|
|||||||
specifier: 19.1.0
|
specifier: 19.1.0
|
||||||
version: 19.1.0
|
version: 19.1.0
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.25.53
|
specifier: ^3.25.56
|
||||||
version: 3.25.53
|
version: 3.25.56
|
||||||
|
|
||||||
packages/cms/types:
|
packages/cms/types:
|
||||||
devDependencies:
|
devDependencies:
|
||||||
@@ -630,11 +630,11 @@ importers:
|
|||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../tooling/typescript
|
version: link:../../tooling/typescript
|
||||||
'@supabase/supabase-js':
|
'@supabase/supabase-js':
|
||||||
specifier: 2.49.10
|
specifier: 2.50.0
|
||||||
version: 2.49.10
|
version: 2.50.0
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.25.53
|
specifier: ^3.25.56
|
||||||
version: 3.25.53
|
version: 3.25.56
|
||||||
|
|
||||||
packages/email-templates:
|
packages/email-templates:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -662,8 +662,8 @@ importers:
|
|||||||
version: 5.1.5
|
version: 5.1.5
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@hookform/resolvers':
|
'@hookform/resolvers':
|
||||||
specifier: ^5.0.1
|
specifier: ^5.1.0
|
||||||
version: 5.0.1(react-hook-form@7.57.0(react@19.1.0))
|
version: 5.1.0(react-hook-form@7.57.0(react@19.1.0))
|
||||||
'@kit/billing-gateway':
|
'@kit/billing-gateway':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../billing/gateway
|
version: link:../../billing/gateway
|
||||||
@@ -704,8 +704,8 @@ importers:
|
|||||||
specifier: ^1.3.2
|
specifier: ^1.3.2
|
||||||
version: 1.3.2(react@19.1.0)
|
version: 1.3.2(react@19.1.0)
|
||||||
'@supabase/supabase-js':
|
'@supabase/supabase-js':
|
||||||
specifier: 2.49.10
|
specifier: 2.50.0
|
||||||
version: 2.49.10
|
version: 2.50.0
|
||||||
'@tanstack/react-query':
|
'@tanstack/react-query':
|
||||||
specifier: 5.80.6
|
specifier: 5.80.6
|
||||||
version: 5.80.6(react@19.1.0)
|
version: 5.80.6(react@19.1.0)
|
||||||
@@ -740,14 +740,14 @@ importers:
|
|||||||
specifier: ^2.0.5
|
specifier: ^2.0.5
|
||||||
version: 2.0.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
version: 2.0.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.25.53
|
specifier: ^3.25.56
|
||||||
version: 3.25.53
|
version: 3.25.56
|
||||||
|
|
||||||
packages/features/admin:
|
packages/features/admin:
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@hookform/resolvers':
|
'@hookform/resolvers':
|
||||||
specifier: ^5.0.1
|
specifier: ^5.1.0
|
||||||
version: 5.0.1(react-hook-form@7.57.0(react@19.1.0))
|
version: 5.1.0(react-hook-form@7.57.0(react@19.1.0))
|
||||||
'@kit/eslint-config':
|
'@kit/eslint-config':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../../tooling/eslint
|
version: link:../../../tooling/eslint
|
||||||
@@ -771,13 +771,13 @@ importers:
|
|||||||
version: link:../../ui
|
version: link:../../ui
|
||||||
'@makerkit/data-loader-supabase-core':
|
'@makerkit/data-loader-supabase-core':
|
||||||
specifier: ^0.0.10
|
specifier: ^0.0.10
|
||||||
version: 0.0.10(@supabase/postgrest-js@1.19.4)(@supabase/supabase-js@2.49.10)
|
version: 0.0.10(@supabase/postgrest-js@1.19.4)(@supabase/supabase-js@2.50.0)
|
||||||
'@makerkit/data-loader-supabase-nextjs':
|
'@makerkit/data-loader-supabase-nextjs':
|
||||||
specifier: ^1.2.5
|
specifier: ^1.2.5
|
||||||
version: 1.2.5(@supabase/postgrest-js@1.19.4)(@supabase/supabase-js@2.49.10)(@tanstack/react-query@5.80.6(react@19.1.0))(next@15.3.3(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)
|
version: 1.2.5(@supabase/postgrest-js@1.19.4)(@supabase/supabase-js@2.50.0)(@tanstack/react-query@5.80.6(react@19.1.0))(next@15.3.3(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)
|
||||||
'@supabase/supabase-js':
|
'@supabase/supabase-js':
|
||||||
specifier: 2.49.10
|
specifier: 2.50.0
|
||||||
version: 2.49.10
|
version: 2.50.0
|
||||||
'@tanstack/react-query':
|
'@tanstack/react-query':
|
||||||
specifier: 5.80.6
|
specifier: 5.80.6
|
||||||
version: 5.80.6(react@19.1.0)
|
version: 5.80.6(react@19.1.0)
|
||||||
@@ -803,14 +803,14 @@ importers:
|
|||||||
specifier: ^7.57.0
|
specifier: ^7.57.0
|
||||||
version: 7.57.0(react@19.1.0)
|
version: 7.57.0(react@19.1.0)
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.25.53
|
specifier: ^3.25.56
|
||||||
version: 3.25.53
|
version: 3.25.56
|
||||||
|
|
||||||
packages/features/auth:
|
packages/features/auth:
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@hookform/resolvers':
|
'@hookform/resolvers':
|
||||||
specifier: ^5.0.1
|
specifier: ^5.1.0
|
||||||
version: 5.0.1(react-hook-form@7.57.0(react@19.1.0))
|
version: 5.1.0(react-hook-form@7.57.0(react@19.1.0))
|
||||||
'@kit/eslint-config':
|
'@kit/eslint-config':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../../tooling/eslint
|
version: link:../../../tooling/eslint
|
||||||
@@ -836,8 +836,8 @@ importers:
|
|||||||
specifier: ^1.3.2
|
specifier: ^1.3.2
|
||||||
version: 1.3.2(react@19.1.0)
|
version: 1.3.2(react@19.1.0)
|
||||||
'@supabase/supabase-js':
|
'@supabase/supabase-js':
|
||||||
specifier: 2.49.10
|
specifier: 2.50.0
|
||||||
version: 2.49.10
|
version: 2.50.0
|
||||||
'@tanstack/react-query':
|
'@tanstack/react-query':
|
||||||
specifier: 5.80.6
|
specifier: 5.80.6
|
||||||
version: 5.80.6(react@19.1.0)
|
version: 5.80.6(react@19.1.0)
|
||||||
@@ -860,8 +860,8 @@ importers:
|
|||||||
specifier: ^2.0.5
|
specifier: ^2.0.5
|
||||||
version: 2.0.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
version: 2.0.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.25.53
|
specifier: ^3.25.56
|
||||||
version: 3.25.53
|
version: 3.25.56
|
||||||
|
|
||||||
packages/features/notifications:
|
packages/features/notifications:
|
||||||
devDependencies:
|
devDependencies:
|
||||||
@@ -881,8 +881,8 @@ importers:
|
|||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../ui
|
version: link:../../ui
|
||||||
'@supabase/supabase-js':
|
'@supabase/supabase-js':
|
||||||
specifier: 2.49.10
|
specifier: 2.50.0
|
||||||
version: 2.49.10
|
version: 2.50.0
|
||||||
'@tanstack/react-query':
|
'@tanstack/react-query':
|
||||||
specifier: 5.80.6
|
specifier: 5.80.6
|
||||||
version: 5.80.6(react@19.1.0)
|
version: 5.80.6(react@19.1.0)
|
||||||
@@ -909,8 +909,8 @@ importers:
|
|||||||
version: 5.1.5
|
version: 5.1.5
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@hookform/resolvers':
|
'@hookform/resolvers':
|
||||||
specifier: ^5.0.1
|
specifier: ^5.1.0
|
||||||
version: 5.0.1(react-hook-form@7.57.0(react@19.1.0))
|
version: 5.1.0(react-hook-form@7.57.0(react@19.1.0))
|
||||||
'@kit/accounts':
|
'@kit/accounts':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../accounts
|
version: link:../accounts
|
||||||
@@ -951,8 +951,8 @@ importers:
|
|||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../ui
|
version: link:../../ui
|
||||||
'@supabase/supabase-js':
|
'@supabase/supabase-js':
|
||||||
specifier: 2.49.10
|
specifier: 2.50.0
|
||||||
version: 2.49.10
|
version: 2.50.0
|
||||||
'@tanstack/react-query':
|
'@tanstack/react-query':
|
||||||
specifier: 5.80.6
|
specifier: 5.80.6
|
||||||
version: 5.80.6(react@19.1.0)
|
version: 5.80.6(react@19.1.0)
|
||||||
@@ -993,8 +993,8 @@ importers:
|
|||||||
specifier: ^2.0.5
|
specifier: ^2.0.5
|
||||||
version: 2.0.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
version: 2.0.5(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.25.53
|
specifier: ^3.25.56
|
||||||
version: 3.25.53
|
version: 3.25.56
|
||||||
|
|
||||||
packages/i18n:
|
packages/i18n:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -1063,8 +1063,8 @@ importers:
|
|||||||
specifier: ^22.15.30
|
specifier: ^22.15.30
|
||||||
version: 22.15.30
|
version: 22.15.30
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.25.53
|
specifier: ^3.25.56
|
||||||
version: 3.25.53
|
version: 3.25.56
|
||||||
|
|
||||||
packages/mailers/nodemailer:
|
packages/mailers/nodemailer:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -1088,8 +1088,8 @@ importers:
|
|||||||
specifier: 6.4.17
|
specifier: 6.4.17
|
||||||
version: 6.4.17
|
version: 6.4.17
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.25.53
|
specifier: ^3.25.56
|
||||||
version: 3.25.53
|
version: 3.25.56
|
||||||
|
|
||||||
packages/mailers/resend:
|
packages/mailers/resend:
|
||||||
devDependencies:
|
devDependencies:
|
||||||
@@ -1109,8 +1109,8 @@ importers:
|
|||||||
specifier: ^22.15.30
|
specifier: ^22.15.30
|
||||||
version: 22.15.30
|
version: 22.15.30
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.25.53
|
specifier: ^3.25.56
|
||||||
version: 3.25.53
|
version: 3.25.56
|
||||||
|
|
||||||
packages/mailers/shared:
|
packages/mailers/shared:
|
||||||
devDependencies:
|
devDependencies:
|
||||||
@@ -1124,8 +1124,8 @@ importers:
|
|||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../../tooling/typescript
|
version: link:../../../tooling/typescript
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.25.53
|
specifier: ^3.25.56
|
||||||
version: 3.25.53
|
version: 3.25.56
|
||||||
|
|
||||||
packages/monitoring/api:
|
packages/monitoring/api:
|
||||||
devDependencies:
|
devDependencies:
|
||||||
@@ -1157,8 +1157,8 @@ importers:
|
|||||||
specifier: 19.1.0
|
specifier: 19.1.0
|
||||||
version: 19.1.0
|
version: 19.1.0
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.25.53
|
specifier: ^3.25.56
|
||||||
version: 3.25.53
|
version: 3.25.56
|
||||||
|
|
||||||
packages/monitoring/baselime:
|
packages/monitoring/baselime:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -1188,8 +1188,8 @@ importers:
|
|||||||
specifier: 19.1.0
|
specifier: 19.1.0
|
||||||
version: 19.1.0
|
version: 19.1.0
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.25.53
|
specifier: ^3.25.56
|
||||||
version: 3.25.53
|
version: 3.25.56
|
||||||
|
|
||||||
packages/monitoring/core:
|
packages/monitoring/core:
|
||||||
devDependencies:
|
devDependencies:
|
||||||
@@ -1258,20 +1258,20 @@ importers:
|
|||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../tooling/typescript
|
version: link:../../tooling/typescript
|
||||||
'@supabase/supabase-js':
|
'@supabase/supabase-js':
|
||||||
specifier: 2.49.10
|
specifier: 2.50.0
|
||||||
version: 2.49.10
|
version: 2.50.0
|
||||||
next:
|
next:
|
||||||
specifier: 15.3.3
|
specifier: 15.3.3
|
||||||
version: 15.3.3(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
version: 15.3.3(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.25.53
|
specifier: ^3.25.56
|
||||||
version: 3.25.53
|
version: 3.25.56
|
||||||
|
|
||||||
packages/otp:
|
packages/otp:
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@hookform/resolvers':
|
'@hookform/resolvers':
|
||||||
specifier: ^5.0.1
|
specifier: ^5.1.0
|
||||||
version: 5.0.1(react-hook-form@7.57.0(react@19.1.0))
|
version: 5.1.0(react-hook-form@7.57.0(react@19.1.0))
|
||||||
'@kit/email-templates':
|
'@kit/email-templates':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../email-templates
|
version: link:../email-templates
|
||||||
@@ -1303,8 +1303,8 @@ importers:
|
|||||||
specifier: ^1.3.2
|
specifier: ^1.3.2
|
||||||
version: 1.3.2(react@19.1.0)
|
version: 1.3.2(react@19.1.0)
|
||||||
'@supabase/supabase-js':
|
'@supabase/supabase-js':
|
||||||
specifier: 2.49.10
|
specifier: 2.50.0
|
||||||
version: 2.49.10
|
version: 2.50.0
|
||||||
'@types/react':
|
'@types/react':
|
||||||
specifier: 19.1.6
|
specifier: 19.1.6
|
||||||
version: 19.1.6
|
version: 19.1.6
|
||||||
@@ -1321,8 +1321,8 @@ importers:
|
|||||||
specifier: ^7.57.0
|
specifier: ^7.57.0
|
||||||
version: 7.57.0(react@19.1.0)
|
version: 7.57.0(react@19.1.0)
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.25.53
|
specifier: ^3.25.56
|
||||||
version: 3.25.53
|
version: 3.25.56
|
||||||
|
|
||||||
packages/shared:
|
packages/shared:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -1356,10 +1356,10 @@ importers:
|
|||||||
version: link:../../tooling/typescript
|
version: link:../../tooling/typescript
|
||||||
'@supabase/ssr':
|
'@supabase/ssr':
|
||||||
specifier: ^0.6.1
|
specifier: ^0.6.1
|
||||||
version: 0.6.1(@supabase/supabase-js@2.49.10)
|
version: 0.6.1(@supabase/supabase-js@2.50.0)
|
||||||
'@supabase/supabase-js':
|
'@supabase/supabase-js':
|
||||||
specifier: 2.49.10
|
specifier: 2.50.0
|
||||||
version: 2.49.10
|
version: 2.50.0
|
||||||
'@tanstack/react-query':
|
'@tanstack/react-query':
|
||||||
specifier: 5.80.6
|
specifier: 5.80.6
|
||||||
version: 5.80.6(react@19.1.0)
|
version: 5.80.6(react@19.1.0)
|
||||||
@@ -1376,14 +1376,14 @@ importers:
|
|||||||
specifier: ^0.0.1
|
specifier: ^0.0.1
|
||||||
version: 0.0.1
|
version: 0.0.1
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.25.53
|
specifier: ^3.25.56
|
||||||
version: 3.25.53
|
version: 3.25.56
|
||||||
|
|
||||||
packages/ui:
|
packages/ui:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@hookform/resolvers':
|
'@hookform/resolvers':
|
||||||
specifier: ^5.0.1
|
specifier: ^5.1.0
|
||||||
version: 5.0.1(react-hook-form@7.57.0(react@19.1.0))
|
version: 5.1.0(react-hook-form@7.57.0(react@19.1.0))
|
||||||
'@radix-ui/react-accordion':
|
'@radix-ui/react-accordion':
|
||||||
specifier: 1.2.11
|
specifier: 1.2.11
|
||||||
version: 1.2.11(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
version: 1.2.11(@types/react-dom@19.1.6(@types/react@19.1.6))(@types/react@19.1.6)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
@@ -1509,8 +1509,8 @@ importers:
|
|||||||
specifier: ^3.5.3
|
specifier: ^3.5.3
|
||||||
version: 3.5.3
|
version: 3.5.3
|
||||||
react-day-picker:
|
react-day-picker:
|
||||||
specifier: ^8.10.1
|
specifier: ^9.7.0
|
||||||
version: 8.10.1(date-fns@4.1.0)(react@19.1.0)
|
version: 9.7.0(react@19.1.0)
|
||||||
react-hook-form:
|
react-hook-form:
|
||||||
specifier: ^7.57.0
|
specifier: ^7.57.0
|
||||||
version: 7.57.0(react@19.1.0)
|
version: 7.57.0(react@19.1.0)
|
||||||
@@ -1530,8 +1530,8 @@ importers:
|
|||||||
specifier: ^5.8.3
|
specifier: ^5.8.3
|
||||||
version: 5.8.3
|
version: 5.8.3
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.25.53
|
specifier: ^3.25.56
|
||||||
version: 3.25.53
|
version: 3.25.56
|
||||||
|
|
||||||
tooling/eslint:
|
tooling/eslint:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -1568,13 +1568,13 @@ importers:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@trivago/prettier-plugin-sort-imports':
|
'@trivago/prettier-plugin-sort-imports':
|
||||||
specifier: 5.2.2
|
specifier: 5.2.2
|
||||||
version: 5.2.2(@vue/compiler-sfc@3.5.16)(prettier@3.5.3)(svelte@5.33.14)
|
version: 5.2.2(@vue/compiler-sfc@3.5.16)(prettier@3.5.3)(svelte@5.33.17)
|
||||||
prettier:
|
prettier:
|
||||||
specifier: ^3.5.3
|
specifier: ^3.5.3
|
||||||
version: 3.5.3
|
version: 3.5.3
|
||||||
prettier-plugin-tailwindcss:
|
prettier-plugin-tailwindcss:
|
||||||
specifier: ^0.6.12
|
specifier: ^0.6.12
|
||||||
version: 0.6.12(@trivago/prettier-plugin-sort-imports@5.2.2(@vue/compiler-sfc@3.5.16)(prettier@3.5.3)(svelte@5.33.14))(prettier@3.5.3)
|
version: 0.6.12(@trivago/prettier-plugin-sort-imports@5.2.2(@vue/compiler-sfc@3.5.16)(prettier@3.5.3)(svelte@5.33.17))(prettier@3.5.3)
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@kit/tsconfig':
|
'@kit/tsconfig':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
@@ -1777,6 +1777,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
|
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
|
'@date-fns/tz@1.2.0':
|
||||||
|
resolution: {integrity: sha512-LBrd7MiJZ9McsOgxqWX7AaxrDjcFVjWH/tIKJd7pnR7McaslGYOP1QmmiBXdJH/H/yLCT+rcQ7FaPBUxRGUtrg==}
|
||||||
|
|
||||||
'@discoveryjs/json-ext@0.5.7':
|
'@discoveryjs/json-ext@0.5.7':
|
||||||
resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==}
|
resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==}
|
||||||
engines: {node: '>=10.0.0'}
|
engines: {node: '>=10.0.0'}
|
||||||
@@ -1916,8 +1919,8 @@ packages:
|
|||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
'@hookform/resolvers@5.0.1':
|
'@hookform/resolvers@5.1.0':
|
||||||
resolution: {integrity: sha512-u/+Jp83luQNx9AdyW2fIPGY6Y7NG68eN2ZW8FOJYL+M0i4s49+refdJdOp/A9n9HFQtQs3HIDHQvX3ZET2o7YA==}
|
resolution: {integrity: sha512-A5tY8gxqvvR0lFfropqpy/gUDOxjwT7LZCxJ8lNA9puK7nFNRl/O0egGKxzdF4JSz/pnnT1O8g76P/YMyTBEFw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
react-hook-form: ^7.55.0
|
react-hook-form: ^7.55.0
|
||||||
|
|
||||||
@@ -4175,8 +4178,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-pTzb864TQWDRQBPLgSPFRoyjSDUqpCkbEgTzpsjiTjGz1Z5SxZNXJek28w1s6Dyry4CyW4/Izj5jHE/J9hCJYQ==}
|
resolution: {integrity: sha512-pTzb864TQWDRQBPLgSPFRoyjSDUqpCkbEgTzpsjiTjGz1Z5SxZNXJek28w1s6Dyry4CyW4/Izj5jHE/J9hCJYQ==}
|
||||||
engines: {node: '>=12.16'}
|
engines: {node: '>=12.16'}
|
||||||
|
|
||||||
'@supabase/auth-js@2.69.1':
|
'@supabase/auth-js@2.70.0':
|
||||||
resolution: {integrity: sha512-FILtt5WjCNzmReeRLq5wRs3iShwmnWgBvxHfqapC/VoljJl+W8hDAyFmf1NVw3zH+ZjZ05AKxiKxVeb0HNWRMQ==}
|
resolution: {integrity: sha512-BaAK/tOAZFJtzF1sE3gJ2FwTjLf4ky3PSvcvLGEgEmO4BSBkwWKu8l67rLLIBZPDnCyV7Owk2uPyKHa0kj5QGg==}
|
||||||
|
|
||||||
'@supabase/functions-js@2.4.4':
|
'@supabase/functions-js@2.4.4':
|
||||||
resolution: {integrity: sha512-WL2p6r4AXNGwop7iwvul2BvOtuJ1YQy8EbOd0dhG1oN1q8el/BIRSFCFnWAMM/vJJlHWLi4ad22sKbKr9mvjoA==}
|
resolution: {integrity: sha512-WL2p6r4AXNGwop7iwvul2BvOtuJ1YQy8EbOd0dhG1oN1q8el/BIRSFCFnWAMM/vJJlHWLi4ad22sKbKr9mvjoA==}
|
||||||
@@ -4199,8 +4202,8 @@ packages:
|
|||||||
'@supabase/storage-js@2.7.1':
|
'@supabase/storage-js@2.7.1':
|
||||||
resolution: {integrity: sha512-asYHcyDR1fKqrMpytAS1zjyEfvxuOIp1CIXX7ji4lHHcJKqyk+sLl/Vxgm4sN6u8zvuUtae9e4kDxQP2qrwWBA==}
|
resolution: {integrity: sha512-asYHcyDR1fKqrMpytAS1zjyEfvxuOIp1CIXX7ji4lHHcJKqyk+sLl/Vxgm4sN6u8zvuUtae9e4kDxQP2qrwWBA==}
|
||||||
|
|
||||||
'@supabase/supabase-js@2.49.10':
|
'@supabase/supabase-js@2.50.0':
|
||||||
resolution: {integrity: sha512-IRPcIdncuhD2m1eZ2Fkg0S1fq9SXlHfmAetBxPN66kVFtTucR8b01xKuVmKqcIJokB17umMf1bmqyS8yboXGsw==}
|
resolution: {integrity: sha512-M1Gd5tPaaghYZ9OjeO1iORRqbTWFEz/cF3pPubRnMPzA+A8SiUsXXWDP+DWsASZcjEcVEcVQIAF38i5wrijYOg==}
|
||||||
|
|
||||||
'@sveltejs/acorn-typescript@1.0.5':
|
'@sveltejs/acorn-typescript@1.0.5':
|
||||||
resolution: {integrity: sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==}
|
resolution: {integrity: sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==}
|
||||||
@@ -5322,6 +5325,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==}
|
resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
date-fns-jalali@4.1.0-0:
|
||||||
|
resolution: {integrity: sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==}
|
||||||
|
|
||||||
date-fns@4.1.0:
|
date-fns@4.1.0:
|
||||||
resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==}
|
resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==}
|
||||||
|
|
||||||
@@ -7484,11 +7490,11 @@ packages:
|
|||||||
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
|
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
react-day-picker@8.10.1:
|
react-day-picker@9.7.0:
|
||||||
resolution: {integrity: sha512-TMx7fNbhLk15eqcMt+7Z7S2KF7mfTId/XJDjKE8f+IUcFn0l08/kI4FiYTL/0yuOLmEcbR4Fwe3GJf/NiiMnPA==}
|
resolution: {integrity: sha512-urlK4C9XJZVpQ81tmVgd2O7lZ0VQldZeHzNejbwLWZSkzHH498KnArT0EHNfKBOWwKc935iMLGZdxXPRISzUxQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
date-fns: ^2.28.0 || ^3.0.0
|
react: '>=16.8.0'
|
||||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
|
||||||
|
|
||||||
react-dom@19.1.0:
|
react-dom@19.1.0:
|
||||||
resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==}
|
resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==}
|
||||||
@@ -8020,8 +8026,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
|
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
svelte@5.33.14:
|
svelte@5.33.17:
|
||||||
resolution: {integrity: sha512-kRlbhIlMTijbFmVDQFDeKXPLlX1/ovXwV0I162wRqQhRcygaqDIcu1d/Ese3H2uI+yt3uT8E7ndgDthQv5v5BA==}
|
resolution: {integrity: sha512-y453Ac1Xi/MFXbGIDK89YH1CeXlFk+aTsDQ1uMc7iE+iVau6ZnE4t3iWsr0oxKnIApjfI7CL4R1NEHzVMUrkVg==}
|
||||||
engines: {node: '>=18'}
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
svgo@3.3.2:
|
svgo@3.3.2:
|
||||||
@@ -8551,8 +8557,8 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
zod: ^3.24.1
|
zod: ^3.24.1
|
||||||
|
|
||||||
zod@3.25.53:
|
zod@3.25.56:
|
||||||
resolution: {integrity: sha512-BKOKoY3XcGUVkqaalCtFK15LhwR0G0i65AClFpWSXLN2gJNBGlTktukHgwexCTa/dAacPPp9ReryXPWyeZF4LQ==}
|
resolution: {integrity: sha512-rd6eEF3BTNvQnR2e2wwolfTmUTnp70aUTqr0oaGbHifzC3BKJsoV+Gat8vxUMR1hwOKBs6El+qWehrHbCpW6SQ==}
|
||||||
|
|
||||||
zwitch@2.0.4:
|
zwitch@2.0.4:
|
||||||
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
|
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}
|
||||||
@@ -8563,39 +8569,39 @@ snapshots:
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
graphql: 16.10.0
|
graphql: 16.10.0
|
||||||
|
|
||||||
'@ai-sdk/openai@1.3.22(zod@3.25.53)':
|
'@ai-sdk/openai@1.3.22(zod@3.25.56)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@ai-sdk/provider': 1.1.3
|
'@ai-sdk/provider': 1.1.3
|
||||||
'@ai-sdk/provider-utils': 2.2.8(zod@3.25.53)
|
'@ai-sdk/provider-utils': 2.2.8(zod@3.25.56)
|
||||||
zod: 3.25.53
|
zod: 3.25.56
|
||||||
|
|
||||||
'@ai-sdk/provider-utils@2.2.8(zod@3.25.53)':
|
'@ai-sdk/provider-utils@2.2.8(zod@3.25.56)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@ai-sdk/provider': 1.1.3
|
'@ai-sdk/provider': 1.1.3
|
||||||
nanoid: 3.3.11
|
nanoid: 3.3.11
|
||||||
secure-json-parse: 2.7.0
|
secure-json-parse: 2.7.0
|
||||||
zod: 3.25.53
|
zod: 3.25.56
|
||||||
|
|
||||||
'@ai-sdk/provider@1.1.3':
|
'@ai-sdk/provider@1.1.3':
|
||||||
dependencies:
|
dependencies:
|
||||||
json-schema: 0.4.0
|
json-schema: 0.4.0
|
||||||
|
|
||||||
'@ai-sdk/react@1.2.12(react@19.1.0)(zod@3.25.53)':
|
'@ai-sdk/react@1.2.12(react@19.1.0)(zod@3.25.56)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@ai-sdk/provider-utils': 2.2.8(zod@3.25.53)
|
'@ai-sdk/provider-utils': 2.2.8(zod@3.25.56)
|
||||||
'@ai-sdk/ui-utils': 1.2.11(zod@3.25.53)
|
'@ai-sdk/ui-utils': 1.2.11(zod@3.25.56)
|
||||||
react: 19.1.0
|
react: 19.1.0
|
||||||
swr: 2.3.3(react@19.1.0)
|
swr: 2.3.3(react@19.1.0)
|
||||||
throttleit: 2.1.0
|
throttleit: 2.1.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
zod: 3.25.53
|
zod: 3.25.56
|
||||||
|
|
||||||
'@ai-sdk/ui-utils@1.2.11(zod@3.25.53)':
|
'@ai-sdk/ui-utils@1.2.11(zod@3.25.56)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@ai-sdk/provider': 1.1.3
|
'@ai-sdk/provider': 1.1.3
|
||||||
'@ai-sdk/provider-utils': 2.2.8(zod@3.25.53)
|
'@ai-sdk/provider-utils': 2.2.8(zod@3.25.56)
|
||||||
zod: 3.25.53
|
zod: 3.25.56
|
||||||
zod-to-json-schema: 3.24.5(zod@3.25.53)
|
zod-to-json-schema: 3.24.5(zod@3.25.56)
|
||||||
|
|
||||||
'@alloc/quick-lru@5.2.0': {}
|
'@alloc/quick-lru@5.2.0': {}
|
||||||
|
|
||||||
@@ -8805,6 +8811,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/trace-mapping': 0.3.9
|
'@jridgewell/trace-mapping': 0.3.9
|
||||||
|
|
||||||
|
'@date-fns/tz@1.2.0': {}
|
||||||
|
|
||||||
'@discoveryjs/json-ext@0.5.7': {}
|
'@discoveryjs/json-ext@0.5.7': {}
|
||||||
|
|
||||||
'@edge-csrf/nextjs@2.5.3-cloudflare-rc1(next@15.3.3(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))':
|
'@edge-csrf/nextjs@2.5.3-cloudflare-rc1(next@15.3.3(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))':
|
||||||
@@ -8994,7 +9002,7 @@ snapshots:
|
|||||||
protobufjs: 7.4.0
|
protobufjs: 7.4.0
|
||||||
yargs: 17.7.2
|
yargs: 17.7.2
|
||||||
|
|
||||||
'@hookform/resolvers@5.0.1(react-hook-form@7.57.0(react@19.1.0))':
|
'@hookform/resolvers@5.1.0(react-hook-form@7.57.0(react@19.1.0))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@standard-schema/utils': 0.3.0
|
'@standard-schema/utils': 0.3.0
|
||||||
react-hook-form: 7.57.0(react@19.1.0)
|
react-hook-form: 7.57.0(react@19.1.0)
|
||||||
@@ -9333,16 +9341,16 @@ snapshots:
|
|||||||
|
|
||||||
'@lemonsqueezy/lemonsqueezy.js@4.0.0': {}
|
'@lemonsqueezy/lemonsqueezy.js@4.0.0': {}
|
||||||
|
|
||||||
'@makerkit/data-loader-supabase-core@0.0.10(@supabase/postgrest-js@1.19.4)(@supabase/supabase-js@2.49.10)':
|
'@makerkit/data-loader-supabase-core@0.0.10(@supabase/postgrest-js@1.19.4)(@supabase/supabase-js@2.50.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@supabase/postgrest-js': 1.19.4
|
'@supabase/postgrest-js': 1.19.4
|
||||||
'@supabase/supabase-js': 2.49.10
|
'@supabase/supabase-js': 2.50.0
|
||||||
ts-case-convert: 2.1.0
|
ts-case-convert: 2.1.0
|
||||||
|
|
||||||
'@makerkit/data-loader-supabase-nextjs@1.2.5(@supabase/postgrest-js@1.19.4)(@supabase/supabase-js@2.49.10)(@tanstack/react-query@5.80.6(react@19.1.0))(next@15.3.3(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)':
|
'@makerkit/data-loader-supabase-nextjs@1.2.5(@supabase/postgrest-js@1.19.4)(@supabase/supabase-js@2.50.0)(@tanstack/react-query@5.80.6(react@19.1.0))(next@15.3.3(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react@19.1.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@makerkit/data-loader-supabase-core': 0.0.10(@supabase/postgrest-js@1.19.4)(@supabase/supabase-js@2.49.10)
|
'@makerkit/data-loader-supabase-core': 0.0.10(@supabase/postgrest-js@1.19.4)(@supabase/supabase-js@2.50.0)
|
||||||
'@supabase/supabase-js': 2.49.10
|
'@supabase/supabase-js': 2.50.0
|
||||||
'@tanstack/react-query': 5.80.6(react@19.1.0)
|
'@tanstack/react-query': 5.80.6(react@19.1.0)
|
||||||
next: 15.3.3(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
next: 15.3.3(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(babel-plugin-react-compiler@19.1.0-rc.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||||
react: 19.1.0
|
react: 19.1.0
|
||||||
@@ -11884,7 +11892,7 @@ snapshots:
|
|||||||
|
|
||||||
'@stripe/stripe-js@7.3.1': {}
|
'@stripe/stripe-js@7.3.1': {}
|
||||||
|
|
||||||
'@supabase/auth-js@2.69.1':
|
'@supabase/auth-js@2.70.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@supabase/node-fetch': 2.6.15
|
'@supabase/node-fetch': 2.6.15
|
||||||
|
|
||||||
@@ -11910,18 +11918,18 @@ snapshots:
|
|||||||
- bufferutil
|
- bufferutil
|
||||||
- utf-8-validate
|
- utf-8-validate
|
||||||
|
|
||||||
'@supabase/ssr@0.6.1(@supabase/supabase-js@2.49.10)':
|
'@supabase/ssr@0.6.1(@supabase/supabase-js@2.50.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@supabase/supabase-js': 2.49.10
|
'@supabase/supabase-js': 2.50.0
|
||||||
cookie: 1.0.2
|
cookie: 1.0.2
|
||||||
|
|
||||||
'@supabase/storage-js@2.7.1':
|
'@supabase/storage-js@2.7.1':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@supabase/node-fetch': 2.6.15
|
'@supabase/node-fetch': 2.6.15
|
||||||
|
|
||||||
'@supabase/supabase-js@2.49.10':
|
'@supabase/supabase-js@2.50.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@supabase/auth-js': 2.69.1
|
'@supabase/auth-js': 2.70.0
|
||||||
'@supabase/functions-js': 2.4.4
|
'@supabase/functions-js': 2.4.4
|
||||||
'@supabase/node-fetch': 2.6.15
|
'@supabase/node-fetch': 2.6.15
|
||||||
'@supabase/postgrest-js': 1.19.4
|
'@supabase/postgrest-js': 1.19.4
|
||||||
@@ -12042,7 +12050,7 @@ snapshots:
|
|||||||
|
|
||||||
'@tootallnate/quickjs-emscripten@0.23.0': {}
|
'@tootallnate/quickjs-emscripten@0.23.0': {}
|
||||||
|
|
||||||
'@trivago/prettier-plugin-sort-imports@5.2.2(@vue/compiler-sfc@3.5.16)(prettier@3.5.3)(svelte@5.33.14)':
|
'@trivago/prettier-plugin-sort-imports@5.2.2(@vue/compiler-sfc@3.5.16)(prettier@3.5.3)(svelte@5.33.17)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/generator': 7.27.0
|
'@babel/generator': 7.27.0
|
||||||
'@babel/parser': 7.27.0
|
'@babel/parser': 7.27.0
|
||||||
@@ -12053,7 +12061,7 @@ snapshots:
|
|||||||
prettier: 3.5.3
|
prettier: 3.5.3
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@vue/compiler-sfc': 3.5.16
|
'@vue/compiler-sfc': 3.5.16
|
||||||
svelte: 5.33.14
|
svelte: 5.33.17
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
@@ -12586,15 +12594,15 @@ snapshots:
|
|||||||
clean-stack: 2.2.0
|
clean-stack: 2.2.0
|
||||||
indent-string: 4.0.0
|
indent-string: 4.0.0
|
||||||
|
|
||||||
ai@4.3.16(react@19.1.0)(zod@3.25.53):
|
ai@4.3.16(react@19.1.0)(zod@3.25.56):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@ai-sdk/provider': 1.1.3
|
'@ai-sdk/provider': 1.1.3
|
||||||
'@ai-sdk/provider-utils': 2.2.8(zod@3.25.53)
|
'@ai-sdk/provider-utils': 2.2.8(zod@3.25.56)
|
||||||
'@ai-sdk/react': 1.2.12(react@19.1.0)(zod@3.25.53)
|
'@ai-sdk/react': 1.2.12(react@19.1.0)(zod@3.25.56)
|
||||||
'@ai-sdk/ui-utils': 1.2.11(zod@3.25.53)
|
'@ai-sdk/ui-utils': 1.2.11(zod@3.25.56)
|
||||||
'@opentelemetry/api': 1.9.0
|
'@opentelemetry/api': 1.9.0
|
||||||
jsondiffpatch: 0.6.0
|
jsondiffpatch: 0.6.0
|
||||||
zod: 3.25.53
|
zod: 3.25.56
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
react: 19.1.0
|
react: 19.1.0
|
||||||
|
|
||||||
@@ -13189,6 +13197,8 @@ snapshots:
|
|||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
is-data-view: 1.0.2
|
is-data-view: 1.0.2
|
||||||
|
|
||||||
|
date-fns-jalali@4.1.0-0: {}
|
||||||
|
|
||||||
date-fns@4.1.0: {}
|
date-fns@4.1.0: {}
|
||||||
|
|
||||||
dateformat@4.6.3: {}
|
dateformat@4.6.3: {}
|
||||||
@@ -15567,11 +15577,11 @@ snapshots:
|
|||||||
|
|
||||||
prelude-ls@1.2.1: {}
|
prelude-ls@1.2.1: {}
|
||||||
|
|
||||||
prettier-plugin-tailwindcss@0.6.12(@trivago/prettier-plugin-sort-imports@5.2.2(@vue/compiler-sfc@3.5.16)(prettier@3.5.3)(svelte@5.33.14))(prettier@3.5.3):
|
prettier-plugin-tailwindcss@0.6.12(@trivago/prettier-plugin-sort-imports@5.2.2(@vue/compiler-sfc@3.5.16)(prettier@3.5.3)(svelte@5.33.17))(prettier@3.5.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
prettier: 3.5.3
|
prettier: 3.5.3
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@trivago/prettier-plugin-sort-imports': 5.2.2(@vue/compiler-sfc@3.5.16)(prettier@3.5.3)(svelte@5.33.14)
|
'@trivago/prettier-plugin-sort-imports': 5.2.2(@vue/compiler-sfc@3.5.16)(prettier@3.5.3)(svelte@5.33.17)
|
||||||
|
|
||||||
prettier@3.5.3: {}
|
prettier@3.5.3: {}
|
||||||
|
|
||||||
@@ -15693,9 +15703,11 @@ snapshots:
|
|||||||
minimist: 1.2.8
|
minimist: 1.2.8
|
||||||
strip-json-comments: 2.0.1
|
strip-json-comments: 2.0.1
|
||||||
|
|
||||||
react-day-picker@8.10.1(date-fns@4.1.0)(react@19.1.0):
|
react-day-picker@9.7.0(react@19.1.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@date-fns/tz': 1.2.0
|
||||||
date-fns: 4.1.0
|
date-fns: 4.1.0
|
||||||
|
date-fns-jalali: 4.1.0-0
|
||||||
react: 19.1.0
|
react: 19.1.0
|
||||||
|
|
||||||
react-dom@19.1.0(react@19.1.0):
|
react-dom@19.1.0(react@19.1.0):
|
||||||
@@ -16316,7 +16328,7 @@ snapshots:
|
|||||||
|
|
||||||
supports-preserve-symlinks-flag@1.0.0: {}
|
supports-preserve-symlinks-flag@1.0.0: {}
|
||||||
|
|
||||||
svelte@5.33.14:
|
svelte@5.33.17:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@ampproject/remapping': 2.3.0
|
'@ampproject/remapping': 2.3.0
|
||||||
'@jridgewell/sourcemap-codec': 1.5.0
|
'@jridgewell/sourcemap-codec': 1.5.0
|
||||||
@@ -16922,10 +16934,10 @@ snapshots:
|
|||||||
zimmerframe@1.1.2:
|
zimmerframe@1.1.2:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
zod-to-json-schema@3.24.5(zod@3.25.53):
|
zod-to-json-schema@3.24.5(zod@3.25.56):
|
||||||
dependencies:
|
dependencies:
|
||||||
zod: 3.25.53
|
zod: 3.25.56
|
||||||
|
|
||||||
zod@3.25.53: {}
|
zod@3.25.56: {}
|
||||||
|
|
||||||
zwitch@2.0.4: {}
|
zwitch@2.0.4: {}
|
||||||
|
|||||||
Reference in New Issue
Block a user