diff --git a/apps/dev-tool/package.json b/apps/dev-tool/package.json index 0b7d006e2..422649818 100644 --- a/apps/dev-tool/package.json +++ b/apps/dev-tool/package.json @@ -13,7 +13,7 @@ "@hookform/resolvers": "^5.2.2", "@tanstack/react-query": "catalog:", "ai": "5.0.116", - "lucide-react": "^0.562.0", + "lucide-react": "catalog:", "next": "catalog:", "nodemailer": "^7.0.12", "react": "catalog:", diff --git a/apps/e2e/AGENTS.md b/apps/e2e/AGENTS.md index 9e2f0f8bf..4fcaa7a88 100644 --- a/apps/e2e/AGENTS.md +++ b/apps/e2e/AGENTS.md @@ -1,6 +1,26 @@ ## End-to-End Testing with Playwright +## Running Tests + +Running the tests for testing single file: +```bash +pnpm --filter web-e2e exec playwright test --workers=1 +``` + +Example: +```bash +pnpm --filter web-e2e exec playwright test --workers=1 +``` + +This is useful for quickly testing a single file or a specific feature and should be your default choice. + +Running all tests (rarely needed, only use if asked by the user): + +```bash +pnpm test +``` + ### Page Object Pattern (Required) Always use Page Objects for test organization and reusability: diff --git a/apps/e2e/CLAUDE.md b/apps/e2e/CLAUDE.md index 9e2f0f8bf..4fcaa7a88 100644 --- a/apps/e2e/CLAUDE.md +++ b/apps/e2e/CLAUDE.md @@ -1,6 +1,26 @@ ## End-to-End Testing with Playwright +## Running Tests + +Running the tests for testing single file: +```bash +pnpm --filter web-e2e exec playwright test --workers=1 +``` + +Example: +```bash +pnpm --filter web-e2e exec playwright test --workers=1 +``` + +This is useful for quickly testing a single file or a specific feature and should be your default choice. + +Running all tests (rarely needed, only use if asked by the user): + +```bash +pnpm test +``` + ### Page Object Pattern (Required) Always use Page Objects for test organization and reusability: diff --git a/apps/e2e/tests/admin/admin.spec.ts b/apps/e2e/tests/admin/admin.spec.ts index 4e93df237..c7f7ac29b 100644 --- a/apps/e2e/tests/admin/admin.spec.ts +++ b/apps/e2e/tests/admin/admin.spec.ts @@ -216,12 +216,8 @@ test.describe('Admin', () => { }); test.describe('Impersonation', () => { - test('can sign in as a user', async ({ page }) => { - // TODO: find out why it only fails in the CI - if (process.env.CI) { - test.skip(); - } - + // TODO: fix this test - unclear why it fails in the CI + test.skip('can sign in as a user', async ({ page }) => { const auth = new AuthPageObject(page); await auth.loginAsSuperAdmin({}); diff --git a/apps/e2e/tests/authentication/auth.po.ts b/apps/e2e/tests/authentication/auth.po.ts index 1580bf643..547f483d1 100644 --- a/apps/e2e/tests/authentication/auth.po.ts +++ b/apps/e2e/tests/authentication/auth.po.ts @@ -142,7 +142,7 @@ export class AuthPageObject { }) { const client = createClient( 'http://127.0.0.1:54321', - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU', + 'sb_secret_N7UND0UgjKTVK-Uodkm0Hg_xSvEMPvz', ); const { data, error } = await client.auth.admin.createUser({ diff --git a/apps/e2e/tests/team-accounts/team-accounts.spec.ts b/apps/e2e/tests/team-accounts/team-accounts.spec.ts index 2db63044f..bf7876fc4 100644 --- a/apps/e2e/tests/team-accounts/team-accounts.spec.ts +++ b/apps/e2e/tests/team-accounts/team-accounts.spec.ts @@ -282,9 +282,6 @@ test.describe('Team Ownership Transfer', () => { // Transfer ownership to the member await teamAccounts.transferOwnership(memberEmail, ownerEmail); - // Wait for the page to fully load after the transfer - await page.waitForTimeout(500); - // Verify the transfer was successful by checking if the primary owner badge // is now on the new owner's row const memberRow = page.getByRole('row', { name: memberEmail }); diff --git a/apps/web/.env.test b/apps/web/.env.test index a5282ec10..98a047352 100644 --- a/apps/web/.env.test +++ b/apps/web/.env.test @@ -19,4 +19,6 @@ EMAIL_PASSWORD=password # STRIPE NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_51K9cWKI1i3VnbZTq2HGstY2S8wt3peF1MOqPXFO4LR8ln2QgS7GxL8XyKaKLvn7iFHeqAnvdDw0o48qN7rrwwcHU00jOtKhjsf -CONTACT_EMAIL=test@makerkit.dev \ No newline at end of file +CONTACT_EMAIL=test@makerkit.dev + +NEXT_PUBLIC_ENABLE_VERSION_UPDATER=true \ No newline at end of file diff --git a/apps/web/app/api/version/route.ts b/apps/web/app/api/version/route.ts new file mode 100644 index 000000000..ed50c07f0 --- /dev/null +++ b/apps/web/app/api/version/route.ts @@ -0,0 +1,10 @@ +export const dynamic = 'force-static'; + +const BUILD_TIME = + process.env.NODE_ENV === 'development' ? 'dev' : new Date().toISOString(); + +export const GET = () => { + return new Response(BUILD_TIME, { + headers: { 'content-type': 'text/plain' }, + }); +}; diff --git a/apps/web/app/version/route.ts b/apps/web/app/version/route.ts deleted file mode 100644 index a4559270e..000000000 --- a/apps/web/app/version/route.ts +++ /dev/null @@ -1,59 +0,0 @@ -/** - * We force it to static because we want to cache for as long as the build is live. - */ -export const dynamic = 'force-static'; - -// please provide your own implementation -// if you're not using Vercel or Cloudflare Pages -const KNOWN_GIT_ENV_VARS = [ - 'CF_PAGES_COMMIT_SHA', - 'VERCEL_GIT_COMMIT_SHA', - 'GIT_HASH', -]; - -export const GET = async () => { - const currentGitHash = await getGitHash(); - - return new Response(currentGitHash, { - headers: { - 'content-type': 'text/plain', - }, - }); -}; - -async function getGitHash() { - for (const envVar of KNOWN_GIT_ENV_VARS) { - if (process.env[envVar]) { - return process.env[envVar]; - } - } - - try { - return await getHashFromProcess(); - } catch (error) { - console.warn( - `[WARN] Could not find git hash: ${JSON.stringify(error)}. You may want to provide a fallback.`, - ); - - return ''; - } -} - -async function getHashFromProcess() { - // avoid calling a Node.js command in the edge runtime - if (process.env.NEXT_RUNTIME === 'nodejs') { - if (process.env.NODE_ENV !== 'development') { - console.warn( - `[WARN] Could not find git hash in environment variables. Falling back to git command. Supply a known git hash environment variable to avoid this warning.`, - ); - } - - const { execSync } = await import('child_process'); - - return execSync('git log --pretty=format:"%h" -n1').toString().trim(); - } - - console.log( - `[INFO] Could not find git hash in environment variables. Falling back to git command. Supply a known git hash environment variable to avoid this warning.`, - ); -} diff --git a/apps/web/lib/database.types.ts b/apps/web/lib/database.types.ts index 452ae7b4b..dc409ca8c 100644 --- a/apps/web/lib/database.types.ts +++ b/apps/web/lib/database.types.ts @@ -4,1439 +4,1767 @@ export type Json = | boolean | null | { [key: string]: Json | undefined } - | Json[]; + | Json[] export type Database = { graphql_public: { Tables: { - [_ in never]: never; - }; + [_ in never]: never + } Views: { - [_ in never]: never; - }; + [_ in never]: never + } Functions: { graphql: { Args: { - operationName?: string; - query?: string; - variables?: Json; - extensions?: Json; - }; - Returns: Json; - }; - }; + extensions?: Json + operationName?: string + query?: string + variables?: Json + } + Returns: Json + } + } Enums: { - [_ in never]: never; - }; + [_ in never]: never + } CompositeTypes: { - [_ in never]: never; - }; - }; + [_ in never]: never + } + } public: { Tables: { accounts: { Row: { - created_at: string | null; - created_by: string | null; - email: string | null; - id: string; - is_personal_account: boolean; - name: string; - picture_url: string | null; - primary_owner_user_id: string; - public_data: Json; - slug: string | null; - updated_at: string | null; - updated_by: string | null; - }; + created_at: string | null + created_by: string | null + email: string | null + id: string + is_personal_account: boolean + name: string + picture_url: string | null + primary_owner_user_id: string + public_data: Json + slug: string | null + updated_at: string | null + updated_by: string | null + } Insert: { - created_at?: string | null; - created_by?: string | null; - email?: string | null; - id?: string; - is_personal_account?: boolean; - name: string; - picture_url?: string | null; - primary_owner_user_id?: string; - public_data?: Json; - slug?: string | null; - updated_at?: string | null; - updated_by?: string | null; - }; + created_at?: string | null + created_by?: string | null + email?: string | null + id?: string + is_personal_account?: boolean + name: string + picture_url?: string | null + primary_owner_user_id?: string + public_data?: Json + slug?: string | null + updated_at?: string | null + updated_by?: string | null + } Update: { - created_at?: string | null; - created_by?: string | null; - email?: string | null; - id?: string; - is_personal_account?: boolean; - name?: string; - picture_url?: string | null; - primary_owner_user_id?: string; - public_data?: Json; - slug?: string | null; - updated_at?: string | null; - updated_by?: string | null; - }; - Relationships: []; - }; + created_at?: string | null + created_by?: string | null + email?: string | null + id?: string + is_personal_account?: boolean + name?: string + picture_url?: string | null + primary_owner_user_id?: string + public_data?: Json + slug?: string | null + updated_at?: string | null + updated_by?: string | null + } + Relationships: [] + } accounts_memberships: { Row: { - account_id: string; - account_role: string; - created_at: string; - created_by: string | null; - updated_at: string; - updated_by: string | null; - user_id: string; - }; + account_id: string + account_role: string + created_at: string + created_by: string | null + updated_at: string + updated_by: string | null + user_id: string + } Insert: { - account_id: string; - account_role: string; - created_at?: string; - created_by?: string | null; - updated_at?: string; - updated_by?: string | null; - user_id: string; - }; + account_id: string + account_role: string + created_at?: string + created_by?: string | null + updated_at?: string + updated_by?: string | null + user_id: string + } Update: { - account_id?: string; - account_role?: string; - created_at?: string; - created_by?: string | null; - updated_at?: string; - updated_by?: string | null; - user_id?: string; - }; + account_id?: string + account_role?: string + created_at?: string + created_by?: string | null + updated_at?: string + updated_by?: string | null + user_id?: string + } Relationships: [ { - foreignKeyName: 'accounts_memberships_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'accounts'; - referencedColumns: ['id']; + foreignKeyName: "accounts_memberships_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "accounts" + referencedColumns: ["id"] }, { - foreignKeyName: 'accounts_memberships_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_account_workspace'; - referencedColumns: ['id']; + foreignKeyName: "accounts_memberships_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_account_workspace" + referencedColumns: ["id"] }, { - foreignKeyName: 'accounts_memberships_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_accounts'; - referencedColumns: ['id']; + foreignKeyName: "accounts_memberships_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_accounts" + referencedColumns: ["id"] }, { - foreignKeyName: 'accounts_memberships_account_role_fkey'; - columns: ['account_role']; - isOneToOne: false; - referencedRelation: 'roles'; - referencedColumns: ['name']; + foreignKeyName: "accounts_memberships_account_role_fkey" + columns: ["account_role"] + isOneToOne: false + referencedRelation: "roles" + referencedColumns: ["name"] }, - ]; - }; + ] + } billing_customers: { Row: { - account_id: string; - customer_id: string; - email: string | null; - id: number; - provider: Database['public']['Enums']['billing_provider']; - }; + account_id: string + customer_id: string + email: string | null + id: number + provider: Database["public"]["Enums"]["billing_provider"] + } Insert: { - account_id: string; - customer_id: string; - email?: string | null; - id?: number; - provider: Database['public']['Enums']['billing_provider']; - }; + account_id: string + customer_id: string + email?: string | null + id?: number + provider: Database["public"]["Enums"]["billing_provider"] + } Update: { - account_id?: string; - customer_id?: string; - email?: string | null; - id?: number; - provider?: Database['public']['Enums']['billing_provider']; - }; + account_id?: string + customer_id?: string + email?: string | null + id?: number + provider?: Database["public"]["Enums"]["billing_provider"] + } Relationships: [ { - foreignKeyName: 'billing_customers_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'accounts'; - referencedColumns: ['id']; + foreignKeyName: "billing_customers_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "accounts" + referencedColumns: ["id"] }, { - foreignKeyName: 'billing_customers_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_account_workspace'; - referencedColumns: ['id']; + foreignKeyName: "billing_customers_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_account_workspace" + referencedColumns: ["id"] }, { - foreignKeyName: 'billing_customers_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_accounts'; - referencedColumns: ['id']; + foreignKeyName: "billing_customers_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_accounts" + referencedColumns: ["id"] }, - ]; - }; + ] + } config: { Row: { - billing_provider: Database['public']['Enums']['billing_provider']; - enable_account_billing: boolean; - enable_team_account_billing: boolean; - enable_team_accounts: boolean; - }; + billing_provider: Database["public"]["Enums"]["billing_provider"] + enable_account_billing: boolean + enable_team_account_billing: boolean + enable_team_accounts: boolean + } Insert: { - billing_provider?: Database['public']['Enums']['billing_provider']; - enable_account_billing?: boolean; - enable_team_account_billing?: boolean; - enable_team_accounts?: boolean; - }; + billing_provider?: Database["public"]["Enums"]["billing_provider"] + enable_account_billing?: boolean + enable_team_account_billing?: boolean + enable_team_accounts?: boolean + } Update: { - billing_provider?: Database['public']['Enums']['billing_provider']; - enable_account_billing?: boolean; - enable_team_account_billing?: boolean; - enable_team_accounts?: boolean; - }; - Relationships: []; - }; + billing_provider?: Database["public"]["Enums"]["billing_provider"] + enable_account_billing?: boolean + enable_team_account_billing?: boolean + enable_team_accounts?: boolean + } + Relationships: [] + } invitations: { Row: { - account_id: string; - created_at: string; - email: string; - expires_at: string; - id: number; - invite_token: string; - invited_by: string; - role: string; - updated_at: string; - }; + account_id: string + created_at: string + email: string + expires_at: string + id: number + invite_token: string + invited_by: string + role: string + updated_at: string + } Insert: { - account_id: string; - created_at?: string; - email: string; - expires_at?: string; - id?: number; - invite_token: string; - invited_by: string; - role: string; - updated_at?: string; - }; + account_id: string + created_at?: string + email: string + expires_at?: string + id?: number + invite_token: string + invited_by: string + role: string + updated_at?: string + } Update: { - account_id?: string; - created_at?: string; - email?: string; - expires_at?: string; - id?: number; - invite_token?: string; - invited_by?: string; - role?: string; - updated_at?: string; - }; + account_id?: string + created_at?: string + email?: string + expires_at?: string + id?: number + invite_token?: string + invited_by?: string + role?: string + updated_at?: string + } Relationships: [ { - foreignKeyName: 'invitations_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'accounts'; - referencedColumns: ['id']; + foreignKeyName: "invitations_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "accounts" + referencedColumns: ["id"] }, { - foreignKeyName: 'invitations_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_account_workspace'; - referencedColumns: ['id']; + foreignKeyName: "invitations_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_account_workspace" + referencedColumns: ["id"] }, { - foreignKeyName: 'invitations_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_accounts'; - referencedColumns: ['id']; + foreignKeyName: "invitations_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_accounts" + referencedColumns: ["id"] }, { - foreignKeyName: 'invitations_role_fkey'; - columns: ['role']; - isOneToOne: false; - referencedRelation: 'roles'; - referencedColumns: ['name']; + foreignKeyName: "invitations_role_fkey" + columns: ["role"] + isOneToOne: false + referencedRelation: "roles" + referencedColumns: ["name"] }, - ]; - }; + ] + } nonces: { Row: { - client_token: string; - created_at: string; - description: string | null; - expires_at: string; - id: string; - last_verification_at: string | null; - last_verification_ip: unknown | null; - last_verification_user_agent: string | null; - metadata: Json | null; - nonce: string; - purpose: string; - revoked: boolean; - revoked_reason: string | null; - scopes: string[] | null; - tags: string[] | null; - used_at: string | null; - user_id: string | null; - verification_attempts: number; - }; + client_token: string + created_at: string + expires_at: string + id: string + last_verification_at: string | null + last_verification_ip: unknown + last_verification_user_agent: string | null + metadata: Json | null + nonce: string + purpose: string + revoked: boolean + revoked_reason: string | null + scopes: string[] | null + used_at: string | null + user_id: string | null + verification_attempts: number + } Insert: { - client_token: string; - created_at?: string; - description?: string | null; - expires_at: string; - id?: string; - last_verification_at?: string | null; - last_verification_ip?: unknown | null; - last_verification_user_agent?: string | null; - metadata?: Json | null; - nonce: string; - purpose: string; - revoked?: boolean; - revoked_reason?: string | null; - scopes?: string[] | null; - tags?: string[] | null; - used_at?: string | null; - user_id?: string | null; - verification_attempts?: number; - }; + client_token: string + created_at?: string + expires_at: string + id?: string + last_verification_at?: string | null + last_verification_ip?: unknown + last_verification_user_agent?: string | null + metadata?: Json | null + nonce: string + purpose: string + revoked?: boolean + revoked_reason?: string | null + scopes?: string[] | null + used_at?: string | null + user_id?: string | null + verification_attempts?: number + } Update: { - client_token?: string; - created_at?: string; - description?: string | null; - expires_at?: string; - id?: string; - last_verification_at?: string | null; - last_verification_ip?: unknown | null; - last_verification_user_agent?: string | null; - metadata?: Json | null; - nonce?: string; - purpose?: string; - revoked?: boolean; - revoked_reason?: string | null; - scopes?: string[] | null; - tags?: string[] | null; - used_at?: string | null; - user_id?: string | null; - verification_attempts?: number; - }; - Relationships: []; - }; + client_token?: string + created_at?: string + expires_at?: string + id?: string + last_verification_at?: string | null + last_verification_ip?: unknown + last_verification_user_agent?: string | null + metadata?: Json | null + nonce?: string + purpose?: string + revoked?: boolean + revoked_reason?: string | null + scopes?: string[] | null + used_at?: string | null + user_id?: string | null + verification_attempts?: number + } + Relationships: [] + } notifications: { Row: { - account_id: string; - body: string; - channel: Database['public']['Enums']['notification_channel']; - created_at: string; - dismissed: boolean; - expires_at: string | null; - id: number; - link: string | null; - type: Database['public']['Enums']['notification_type']; - }; + account_id: string + body: string + channel: Database["public"]["Enums"]["notification_channel"] + created_at: string + dismissed: boolean + expires_at: string | null + id: number + link: string | null + type: Database["public"]["Enums"]["notification_type"] + } Insert: { - account_id: string; - body: string; - channel?: Database['public']['Enums']['notification_channel']; - created_at?: string; - dismissed?: boolean; - expires_at?: string | null; - id?: never; - link?: string | null; - type?: Database['public']['Enums']['notification_type']; - }; + account_id: string + body: string + channel?: Database["public"]["Enums"]["notification_channel"] + created_at?: string + dismissed?: boolean + expires_at?: string | null + id?: never + link?: string | null + type?: Database["public"]["Enums"]["notification_type"] + } Update: { - account_id?: string; - body?: string; - channel?: Database['public']['Enums']['notification_channel']; - created_at?: string; - dismissed?: boolean; - expires_at?: string | null; - id?: never; - link?: string | null; - type?: Database['public']['Enums']['notification_type']; - }; + account_id?: string + body?: string + channel?: Database["public"]["Enums"]["notification_channel"] + created_at?: string + dismissed?: boolean + expires_at?: string | null + id?: never + link?: string | null + type?: Database["public"]["Enums"]["notification_type"] + } Relationships: [ { - foreignKeyName: 'notifications_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'accounts'; - referencedColumns: ['id']; + foreignKeyName: "notifications_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "accounts" + referencedColumns: ["id"] }, { - foreignKeyName: 'notifications_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_account_workspace'; - referencedColumns: ['id']; + foreignKeyName: "notifications_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_account_workspace" + referencedColumns: ["id"] }, { - foreignKeyName: 'notifications_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_accounts'; - referencedColumns: ['id']; + foreignKeyName: "notifications_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_accounts" + referencedColumns: ["id"] }, - ]; - }; + ] + } order_items: { Row: { - created_at: string; - id: string; - order_id: string; - price_amount: number | null; - product_id: string; - quantity: number; - updated_at: string; - variant_id: string; - }; + created_at: string + id: string + order_id: string + price_amount: number | null + product_id: string + quantity: number + updated_at: string + variant_id: string + } Insert: { - created_at?: string; - id: string; - order_id: string; - price_amount?: number | null; - product_id: string; - quantity?: number; - updated_at?: string; - variant_id: string; - }; + created_at?: string + id: string + order_id: string + price_amount?: number | null + product_id: string + quantity?: number + updated_at?: string + variant_id: string + } Update: { - created_at?: string; - id?: string; - order_id?: string; - price_amount?: number | null; - product_id?: string; - quantity?: number; - updated_at?: string; - variant_id?: string; - }; + created_at?: string + id?: string + order_id?: string + price_amount?: number | null + product_id?: string + quantity?: number + updated_at?: string + variant_id?: string + } Relationships: [ { - foreignKeyName: 'order_items_order_id_fkey'; - columns: ['order_id']; - isOneToOne: false; - referencedRelation: 'orders'; - referencedColumns: ['id']; + foreignKeyName: "order_items_order_id_fkey" + columns: ["order_id"] + isOneToOne: false + referencedRelation: "orders" + referencedColumns: ["id"] }, - ]; - }; + ] + } orders: { Row: { - account_id: string; - billing_customer_id: number; - billing_provider: Database['public']['Enums']['billing_provider']; - created_at: string; - currency: string; - id: string; - status: Database['public']['Enums']['payment_status']; - total_amount: number; - updated_at: string; - }; + account_id: string + billing_customer_id: number + billing_provider: Database["public"]["Enums"]["billing_provider"] + created_at: string + currency: string + id: string + status: Database["public"]["Enums"]["payment_status"] + total_amount: number + updated_at: string + } Insert: { - account_id: string; - billing_customer_id: number; - billing_provider: Database['public']['Enums']['billing_provider']; - created_at?: string; - currency: string; - id: string; - status: Database['public']['Enums']['payment_status']; - total_amount: number; - updated_at?: string; - }; + account_id: string + billing_customer_id: number + billing_provider: Database["public"]["Enums"]["billing_provider"] + created_at?: string + currency: string + id: string + status: Database["public"]["Enums"]["payment_status"] + total_amount: number + updated_at?: string + } Update: { - account_id?: string; - billing_customer_id?: number; - billing_provider?: Database['public']['Enums']['billing_provider']; - created_at?: string; - currency?: string; - id?: string; - status?: Database['public']['Enums']['payment_status']; - total_amount?: number; - updated_at?: string; - }; + account_id?: string + billing_customer_id?: number + billing_provider?: Database["public"]["Enums"]["billing_provider"] + created_at?: string + currency?: string + id?: string + status?: Database["public"]["Enums"]["payment_status"] + total_amount?: number + updated_at?: string + } Relationships: [ { - foreignKeyName: 'orders_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'accounts'; - referencedColumns: ['id']; + foreignKeyName: "orders_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "accounts" + referencedColumns: ["id"] }, { - foreignKeyName: 'orders_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_account_workspace'; - referencedColumns: ['id']; + foreignKeyName: "orders_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_account_workspace" + referencedColumns: ["id"] }, { - foreignKeyName: 'orders_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_accounts'; - referencedColumns: ['id']; + foreignKeyName: "orders_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_accounts" + referencedColumns: ["id"] }, { - foreignKeyName: 'orders_billing_customer_id_fkey'; - columns: ['billing_customer_id']; - isOneToOne: false; - referencedRelation: 'billing_customers'; - referencedColumns: ['id']; + foreignKeyName: "orders_billing_customer_id_fkey" + columns: ["billing_customer_id"] + isOneToOne: false + referencedRelation: "billing_customers" + referencedColumns: ["id"] }, - ]; - }; + ] + } role_permissions: { Row: { - id: number; - permission: Database['public']['Enums']['app_permissions']; - role: string; - }; + id: number + permission: Database["public"]["Enums"]["app_permissions"] + role: string + } Insert: { - id?: number; - permission: Database['public']['Enums']['app_permissions']; - role: string; - }; + id?: number + permission: Database["public"]["Enums"]["app_permissions"] + role: string + } Update: { - id?: number; - permission?: Database['public']['Enums']['app_permissions']; - role?: string; - }; + id?: number + permission?: Database["public"]["Enums"]["app_permissions"] + role?: string + } Relationships: [ { - foreignKeyName: 'role_permissions_role_fkey'; - columns: ['role']; - isOneToOne: false; - referencedRelation: 'roles'; - referencedColumns: ['name']; + foreignKeyName: "role_permissions_role_fkey" + columns: ["role"] + isOneToOne: false + referencedRelation: "roles" + referencedColumns: ["name"] }, - ]; - }; + ] + } roles: { Row: { - hierarchy_level: number; - name: string; - }; + hierarchy_level: number + name: string + } Insert: { - hierarchy_level: number; - name: string; - }; + hierarchy_level: number + name: string + } Update: { - hierarchy_level?: number; - name?: string; - }; - Relationships: []; - }; + hierarchy_level?: number + name?: string + } + Relationships: [] + } subscription_items: { Row: { - created_at: string; - id: string; - interval: string; - interval_count: number; - price_amount: number | null; - product_id: string; - quantity: number; - subscription_id: string; - type: Database['public']['Enums']['subscription_item_type']; - updated_at: string; - variant_id: string; - }; + created_at: string + id: string + interval: string + interval_count: number + price_amount: number | null + product_id: string + quantity: number + subscription_id: string + type: Database["public"]["Enums"]["subscription_item_type"] + updated_at: string + variant_id: string + } Insert: { - created_at?: string; - id: string; - interval: string; - interval_count: number; - price_amount?: number | null; - product_id: string; - quantity?: number; - subscription_id: string; - type: Database['public']['Enums']['subscription_item_type']; - updated_at?: string; - variant_id: string; - }; + created_at?: string + id: string + interval: string + interval_count: number + price_amount?: number | null + product_id: string + quantity?: number + subscription_id: string + type: Database["public"]["Enums"]["subscription_item_type"] + updated_at?: string + variant_id: string + } Update: { - created_at?: string; - id?: string; - interval?: string; - interval_count?: number; - price_amount?: number | null; - product_id?: string; - quantity?: number; - subscription_id?: string; - type?: Database['public']['Enums']['subscription_item_type']; - updated_at?: string; - variant_id?: string; - }; + created_at?: string + id?: string + interval?: string + interval_count?: number + price_amount?: number | null + product_id?: string + quantity?: number + subscription_id?: string + type?: Database["public"]["Enums"]["subscription_item_type"] + updated_at?: string + variant_id?: string + } Relationships: [ { - foreignKeyName: 'subscription_items_subscription_id_fkey'; - columns: ['subscription_id']; - isOneToOne: false; - referencedRelation: 'subscriptions'; - referencedColumns: ['id']; + foreignKeyName: "subscription_items_subscription_id_fkey" + columns: ["subscription_id"] + isOneToOne: false + referencedRelation: "subscriptions" + referencedColumns: ["id"] }, - ]; - }; + ] + } subscriptions: { Row: { - account_id: string; - active: boolean; - billing_customer_id: number; - billing_provider: Database['public']['Enums']['billing_provider']; - cancel_at_period_end: boolean; - created_at: string; - currency: string; - id: string; - period_ends_at: string; - period_starts_at: string; - status: Database['public']['Enums']['subscription_status']; - trial_ends_at: string | null; - trial_starts_at: string | null; - updated_at: string; - }; + account_id: string + active: boolean + billing_customer_id: number + billing_provider: Database["public"]["Enums"]["billing_provider"] + cancel_at_period_end: boolean + created_at: string + currency: string + id: string + period_ends_at: string + period_starts_at: string + status: Database["public"]["Enums"]["subscription_status"] + trial_ends_at: string | null + trial_starts_at: string | null + updated_at: string + } Insert: { - account_id: string; - active: boolean; - billing_customer_id: number; - billing_provider: Database['public']['Enums']['billing_provider']; - cancel_at_period_end: boolean; - created_at?: string; - currency: string; - id: string; - period_ends_at: string; - period_starts_at: string; - status: Database['public']['Enums']['subscription_status']; - trial_ends_at?: string | null; - trial_starts_at?: string | null; - updated_at?: string; - }; + account_id: string + active: boolean + billing_customer_id: number + billing_provider: Database["public"]["Enums"]["billing_provider"] + cancel_at_period_end: boolean + created_at?: string + currency: string + id: string + period_ends_at: string + period_starts_at: string + status: Database["public"]["Enums"]["subscription_status"] + trial_ends_at?: string | null + trial_starts_at?: string | null + updated_at?: string + } Update: { - account_id?: string; - active?: boolean; - billing_customer_id?: number; - billing_provider?: Database['public']['Enums']['billing_provider']; - cancel_at_period_end?: boolean; - created_at?: string; - currency?: string; - id?: string; - period_ends_at?: string; - period_starts_at?: string; - status?: Database['public']['Enums']['subscription_status']; - trial_ends_at?: string | null; - trial_starts_at?: string | null; - updated_at?: string; - }; + account_id?: string + active?: boolean + billing_customer_id?: number + billing_provider?: Database["public"]["Enums"]["billing_provider"] + cancel_at_period_end?: boolean + created_at?: string + currency?: string + id?: string + period_ends_at?: string + period_starts_at?: string + status?: Database["public"]["Enums"]["subscription_status"] + trial_ends_at?: string | null + trial_starts_at?: string | null + updated_at?: string + } Relationships: [ { - foreignKeyName: 'subscriptions_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'accounts'; - referencedColumns: ['id']; + foreignKeyName: "subscriptions_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "accounts" + referencedColumns: ["id"] }, { - foreignKeyName: 'subscriptions_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_account_workspace'; - referencedColumns: ['id']; + foreignKeyName: "subscriptions_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_account_workspace" + referencedColumns: ["id"] }, { - foreignKeyName: 'subscriptions_account_id_fkey'; - columns: ['account_id']; - isOneToOne: false; - referencedRelation: 'user_accounts'; - referencedColumns: ['id']; + foreignKeyName: "subscriptions_account_id_fkey" + columns: ["account_id"] + isOneToOne: false + referencedRelation: "user_accounts" + referencedColumns: ["id"] }, { - foreignKeyName: 'subscriptions_billing_customer_id_fkey'; - columns: ['billing_customer_id']; - isOneToOne: false; - referencedRelation: 'billing_customers'; - referencedColumns: ['id']; + foreignKeyName: "subscriptions_billing_customer_id_fkey" + columns: ["billing_customer_id"] + isOneToOne: false + referencedRelation: "billing_customers" + referencedColumns: ["id"] }, - ]; - }; - }; + ] + } + } Views: { user_account_workspace: { Row: { - id: string | null; - name: string | null; - picture_url: string | null; + id: string | null + name: string | null + picture_url: string | null subscription_status: - | Database['public']['Enums']['subscription_status'] - | null; - }; - Relationships: []; - }; + | Database["public"]["Enums"]["subscription_status"] + | null + } + Relationships: [] + } user_accounts: { Row: { - id: string | null; - name: string | null; - picture_url: string | null; - role: string | null; - slug: string | null; - }; + id: string | null + name: string | null + picture_url: string | null + role: string | null + slug: string | null + } Relationships: [ { - foreignKeyName: 'accounts_memberships_account_role_fkey'; - columns: ['role']; - isOneToOne: false; - referencedRelation: 'roles'; - referencedColumns: ['name']; + foreignKeyName: "accounts_memberships_account_role_fkey" + columns: ["role"] + isOneToOne: false + referencedRelation: "roles" + referencedColumns: ["name"] }, - ]; - }; - }; + ] + } + } Functions: { accept_invitation: { - Args: { - token: string; - user_id: string; - }; - Returns: string; - }; + Args: { token: string; user_id: string } + Returns: string + } add_invitations_to_account: { Args: { - account_slug: string; - invitations: Database['public']['CompositeTypes']['invitation'][]; - }; - Returns: Database['public']['Tables']['invitations']['Row'][]; - }; + account_slug: string + invitations: Database["public"]["CompositeTypes"]["invitation"][] + invited_by: string + } + Returns: Database["public"]["Tables"]["invitations"]["Row"][] + } can_action_account_member: { - Args: { - target_team_account_id: string; - target_user_id: string; - }; - Returns: boolean; - }; + Args: { target_team_account_id: string; target_user_id: string } + Returns: boolean + } create_invitation: { - Args: { - account_id: string; - email: string; - role: string; - }; + Args: { account_id: string; email: string; role: string } Returns: { - account_id: string; - created_at: string; - email: string; - expires_at: string; - id: number; - invite_token: string; - invited_by: string; - role: string; - updated_at: string; - }; - }; + account_id: string + created_at: string + email: string + expires_at: string + id: number + invite_token: string + invited_by: string + role: string + updated_at: string + } + SetofOptions: { + from: "*" + to: "invitations" + isOneToOne: true + isSetofReturn: false + } + } create_nonce: { Args: { - p_user_id?: string; - p_purpose?: string; - p_expires_in_seconds?: number; - p_metadata?: Json; - p_description?: string; - p_tags?: string[]; - p_scopes?: string[]; - p_revoke_previous?: boolean; - }; - Returns: Json; - }; + p_expires_in_seconds?: number + p_metadata?: Json + p_purpose?: string + p_revoke_previous?: boolean + p_scopes?: string[] + p_user_id?: string + } + Returns: Json + } create_team_account: { - Args: { - account_name: string; - }; + Args: { account_name: string } Returns: { - created_at: string | null; - created_by: string | null; - email: string | null; - id: string; - is_personal_account: boolean; - name: string; - picture_url: string | null; - primary_owner_user_id: string; - public_data: Json; - slug: string | null; - updated_at: string | null; - updated_by: string | null; - }; - }; + created_at: string | null + created_by: string | null + email: string | null + id: string + is_personal_account: boolean + name: string + picture_url: string | null + primary_owner_user_id: string + public_data: Json + slug: string | null + updated_at: string | null + updated_by: string | null + } + SetofOptions: { + from: "*" + to: "accounts" + isOneToOne: true + isSetofReturn: false + } + } get_account_invitations: { - Args: { - account_slug: string; - }; + Args: { account_slug: string } Returns: { - id: number; - email: string; - account_id: string; - invited_by: string; - role: string; - created_at: string; - updated_at: string; - expires_at: string; - inviter_name: string; - inviter_email: string; - }[]; - }; + account_id: string + created_at: string + email: string + expires_at: string + id: number + invited_by: string + inviter_email: string + inviter_name: string + role: string + updated_at: string + }[] + } get_account_members: { - Args: { - account_slug: string; - }; + Args: { account_slug: string } Returns: { - id: string; - user_id: string; - account_id: string; - role: string; - role_hierarchy_level: number; - primary_owner_user_id: string; - name: string; - email: string; - picture_url: string; - created_at: string; - updated_at: string; - }[]; - }; - get_config: { - Args: Record; - Returns: Json; - }; - get_nonce_status: { - Args: { - p_id: string; - }; - Returns: Json; - }; - get_upper_system_role: { - Args: Record; - Returns: string; - }; + account_id: string + created_at: string + email: string + id: string + name: string + picture_url: string + primary_owner_user_id: string + role: string + role_hierarchy_level: number + updated_at: string + user_id: string + }[] + } + get_config: { Args: never; Returns: Json } + get_nonce_status: { Args: { p_id: string }; Returns: Json } + get_upper_system_role: { Args: never; Returns: string } has_active_subscription: { - Args: { - target_account_id: string; - }; - Returns: boolean; - }; + Args: { target_account_id: string } + Returns: boolean + } has_more_elevated_role: { Args: { - target_user_id: string; - target_account_id: string; - role_name: string; - }; - Returns: boolean; - }; + role_name: string + target_account_id: string + target_user_id: string + } + Returns: boolean + } has_permission: { Args: { - user_id: string; - account_id: string; - permission_name: Database['public']['Enums']['app_permissions']; - }; - Returns: boolean; - }; + account_id: string + permission_name: Database["public"]["Enums"]["app_permissions"] + user_id: string + } + Returns: boolean + } has_role_on_account: { - Args: { - account_id: string; - account_role?: string; - }; - Returns: boolean; - }; + Args: { account_id: string; account_role?: string } + Returns: boolean + } has_same_role_hierarchy_level: { Args: { - target_user_id: string; - target_account_id: string; - role_name: string; - }; - Returns: boolean; - }; - install_extensions: { - Args: Record; - Returns: undefined; - }; - is_aal2: { - Args: Record; - Returns: boolean; - }; - is_account_owner: { - Args: { - account_id: string; - }; - Returns: boolean; - }; + role_name: string + target_account_id: string + target_user_id: string + } + Returns: boolean + } + is_aal2: { Args: never; Returns: boolean } + is_account_owner: { Args: { account_id: string }; Returns: boolean } is_account_team_member: { - Args: { - target_account_id: string; - }; - Returns: boolean; - }; - is_mfa_compliant: { - Args: Record; - Returns: boolean; - }; - is_set: { - Args: { - field_name: string; - }; - Returns: boolean; - }; - is_super_admin: { - Args: Record; - Returns: boolean; - }; + Args: { target_account_id: string } + Returns: boolean + } + is_mfa_compliant: { Args: never; Returns: boolean } + is_set: { Args: { field_name: string }; Returns: boolean } + is_super_admin: { Args: never; Returns: boolean } is_team_member: { - Args: { - account_id: string; - user_id: string; - }; - Returns: boolean; - }; + Args: { account_id: string; user_id: string } + Returns: boolean + } revoke_nonce: { - Args: { - p_id: string; - p_reason?: string; - }; - Returns: boolean; - }; + Args: { p_id: string; p_reason?: string } + Returns: boolean + } team_account_workspace: { - Args: { - account_slug: string; - }; + Args: { account_slug: string } Returns: { - id: string; - name: string; - picture_url: string; - slug: string; - role: string; - role_hierarchy_level: number; - primary_owner_user_id: string; - subscription_status: Database['public']['Enums']['subscription_status']; - permissions: Database['public']['Enums']['app_permissions'][]; - }[]; - }; + id: string + name: string + permissions: Database["public"]["Enums"]["app_permissions"][] + picture_url: string + primary_owner_user_id: string + role: string + role_hierarchy_level: number + slug: string + subscription_status: Database["public"]["Enums"]["subscription_status"] + }[] + } transfer_team_account_ownership: { - Args: { - target_account_id: string; - new_owner_id: string; - }; - Returns: undefined; - }; + Args: { new_owner_id: string; target_account_id: string } + Returns: undefined + } upsert_order: { Args: { - target_account_id: string; - target_customer_id: string; - target_order_id: string; - status: Database['public']['Enums']['payment_status']; - billing_provider: Database['public']['Enums']['billing_provider']; - total_amount: number; - currency: string; - line_items: Json; - }; + billing_provider: Database["public"]["Enums"]["billing_provider"] + currency: string + line_items: Json + status: Database["public"]["Enums"]["payment_status"] + target_account_id: string + target_customer_id: string + target_order_id: string + total_amount: number + } Returns: { - account_id: string; - billing_customer_id: number; - billing_provider: Database['public']['Enums']['billing_provider']; - created_at: string; - currency: string; - id: string; - status: Database['public']['Enums']['payment_status']; - total_amount: number; - updated_at: string; - }; - }; + account_id: string + billing_customer_id: number + billing_provider: Database["public"]["Enums"]["billing_provider"] + created_at: string + currency: string + id: string + status: Database["public"]["Enums"]["payment_status"] + total_amount: number + updated_at: string + } + SetofOptions: { + from: "*" + to: "orders" + isOneToOne: true + isSetofReturn: false + } + } upsert_subscription: { Args: { - target_account_id: string; - target_customer_id: string; - target_subscription_id: string; - active: boolean; - status: Database['public']['Enums']['subscription_status']; - billing_provider: Database['public']['Enums']['billing_provider']; - cancel_at_period_end: boolean; - currency: string; - period_starts_at: string; - period_ends_at: string; - line_items: Json; - trial_starts_at?: string; - trial_ends_at?: string; - }; + active: boolean + billing_provider: Database["public"]["Enums"]["billing_provider"] + cancel_at_period_end: boolean + currency: string + line_items: Json + period_ends_at: string + period_starts_at: string + status: Database["public"]["Enums"]["subscription_status"] + target_account_id: string + target_customer_id: string + target_subscription_id: string + trial_ends_at?: string + trial_starts_at?: string + } Returns: { - account_id: string; - active: boolean; - billing_customer_id: number; - billing_provider: Database['public']['Enums']['billing_provider']; - cancel_at_period_end: boolean; - created_at: string; - currency: string; - id: string; - period_ends_at: string; - period_starts_at: string; - status: Database['public']['Enums']['subscription_status']; - trial_ends_at: string | null; - trial_starts_at: string | null; - updated_at: string; - }; - }; + account_id: string + active: boolean + billing_customer_id: number + billing_provider: Database["public"]["Enums"]["billing_provider"] + cancel_at_period_end: boolean + created_at: string + currency: string + id: string + period_ends_at: string + period_starts_at: string + status: Database["public"]["Enums"]["subscription_status"] + trial_ends_at: string | null + trial_starts_at: string | null + updated_at: string + } + SetofOptions: { + from: "*" + to: "subscriptions" + isOneToOne: true + isSetofReturn: false + } + } verify_nonce: { Args: { - p_token: string; - p_purpose: string; - p_user_id?: string; - p_required_scopes?: string[]; - p_max_verification_attempts?: number; - p_ip?: unknown; - p_user_agent?: string; - }; - Returns: Json; - }; - }; + p_ip?: unknown + p_max_verification_attempts?: number + p_purpose: string + p_required_scopes?: string[] + p_token: string + p_user_agent?: string + p_user_id?: string + } + Returns: Json + } + } Enums: { app_permissions: - | 'roles.manage' - | 'billing.manage' - | 'settings.manage' - | 'members.manage' - | 'invites.manage'; - billing_provider: 'stripe' | 'lemon-squeezy' | 'paddle'; - notification_channel: 'in_app' | 'email'; - notification_type: 'info' | 'warning' | 'error'; - payment_status: 'pending' | 'succeeded' | 'failed'; - subscription_item_type: 'flat' | 'per_seat' | 'metered'; + | "roles.manage" + | "billing.manage" + | "settings.manage" + | "members.manage" + | "invites.manage" + billing_provider: "stripe" | "lemon-squeezy" | "paddle" + notification_channel: "in_app" | "email" + notification_type: "info" | "warning" | "error" + payment_status: "pending" | "succeeded" | "failed" + subscription_item_type: "flat" | "per_seat" | "metered" subscription_status: - | 'active' - | 'trialing' - | 'past_due' - | 'canceled' - | 'unpaid' - | 'incomplete' - | 'incomplete_expired' - | 'paused'; - }; + | "active" + | "trialing" + | "past_due" + | "canceled" + | "unpaid" + | "incomplete" + | "incomplete_expired" + | "paused" + } CompositeTypes: { invitation: { - email: string | null; - role: string | null; - }; - }; - }; + email: string | null + role: string | null + } + } + } storage: { Tables: { buckets: { Row: { - allowed_mime_types: string[] | null; - avif_autodetection: boolean | null; - created_at: string | null; - file_size_limit: number | null; - id: string; - name: string; - owner: string | null; - owner_id: string | null; - public: boolean | null; - updated_at: string | null; - }; + allowed_mime_types: string[] | null + avif_autodetection: boolean | null + created_at: string | null + file_size_limit: number | null + id: string + name: string + owner: string | null + owner_id: string | null + public: boolean | null + type: Database["storage"]["Enums"]["buckettype"] + updated_at: string | null + } Insert: { - allowed_mime_types?: string[] | null; - avif_autodetection?: boolean | null; - created_at?: string | null; - file_size_limit?: number | null; - id: string; - name: string; - owner?: string | null; - owner_id?: string | null; - public?: boolean | null; - updated_at?: string | null; - }; + allowed_mime_types?: string[] | null + avif_autodetection?: boolean | null + created_at?: string | null + file_size_limit?: number | null + id: string + name: string + owner?: string | null + owner_id?: string | null + public?: boolean | null + type?: Database["storage"]["Enums"]["buckettype"] + updated_at?: string | null + } Update: { - allowed_mime_types?: string[] | null; - avif_autodetection?: boolean | null; - created_at?: string | null; - file_size_limit?: number | null; - id?: string; - name?: string; - owner?: string | null; - owner_id?: string | null; - public?: boolean | null; - updated_at?: string | null; - }; - Relationships: []; - }; + allowed_mime_types?: string[] | null + avif_autodetection?: boolean | null + created_at?: string | null + file_size_limit?: number | null + id?: string + name?: string + owner?: string | null + owner_id?: string | null + public?: boolean | null + type?: Database["storage"]["Enums"]["buckettype"] + updated_at?: string | null + } + Relationships: [] + } + buckets_analytics: { + Row: { + created_at: string + deleted_at: string | null + format: string + id: string + name: string + type: Database["storage"]["Enums"]["buckettype"] + updated_at: string + } + Insert: { + created_at?: string + deleted_at?: string | null + format?: string + id?: string + name: string + type?: Database["storage"]["Enums"]["buckettype"] + updated_at?: string + } + Update: { + created_at?: string + deleted_at?: string | null + format?: string + id?: string + name?: string + type?: Database["storage"]["Enums"]["buckettype"] + updated_at?: string + } + Relationships: [] + } + buckets_vectors: { + Row: { + created_at: string + id: string + type: Database["storage"]["Enums"]["buckettype"] + updated_at: string + } + Insert: { + created_at?: string + id: string + type?: Database["storage"]["Enums"]["buckettype"] + updated_at?: string + } + Update: { + created_at?: string + id?: string + type?: Database["storage"]["Enums"]["buckettype"] + updated_at?: string + } + Relationships: [] + } + iceberg_namespaces: { + Row: { + bucket_name: string + catalog_id: string + created_at: string + id: string + metadata: Json + name: string + updated_at: string + } + Insert: { + bucket_name: string + catalog_id: string + created_at?: string + id?: string + metadata?: Json + name: string + updated_at?: string + } + Update: { + bucket_name?: string + catalog_id?: string + created_at?: string + id?: string + metadata?: Json + name?: string + updated_at?: string + } + Relationships: [ + { + foreignKeyName: "iceberg_namespaces_catalog_id_fkey" + columns: ["catalog_id"] + isOneToOne: false + referencedRelation: "buckets_analytics" + referencedColumns: ["id"] + }, + ] + } + iceberg_tables: { + Row: { + bucket_name: string + catalog_id: string + created_at: string + id: string + location: string + name: string + namespace_id: string + remote_table_id: string | null + shard_id: string | null + shard_key: string | null + updated_at: string + } + Insert: { + bucket_name: string + catalog_id: string + created_at?: string + id?: string + location: string + name: string + namespace_id: string + remote_table_id?: string | null + shard_id?: string | null + shard_key?: string | null + updated_at?: string + } + Update: { + bucket_name?: string + catalog_id?: string + created_at?: string + id?: string + location?: string + name?: string + namespace_id?: string + remote_table_id?: string | null + shard_id?: string | null + shard_key?: string | null + updated_at?: string + } + Relationships: [ + { + foreignKeyName: "iceberg_tables_catalog_id_fkey" + columns: ["catalog_id"] + isOneToOne: false + referencedRelation: "buckets_analytics" + referencedColumns: ["id"] + }, + { + foreignKeyName: "iceberg_tables_namespace_id_fkey" + columns: ["namespace_id"] + isOneToOne: false + referencedRelation: "iceberg_namespaces" + referencedColumns: ["id"] + }, + ] + } migrations: { Row: { - executed_at: string | null; - hash: string; - id: number; - name: string; - }; + executed_at: string | null + hash: string + id: number + name: string + } Insert: { - executed_at?: string | null; - hash: string; - id: number; - name: string; - }; + executed_at?: string | null + hash: string + id: number + name: string + } Update: { - executed_at?: string | null; - hash?: string; - id?: number; - name?: string; - }; - Relationships: []; - }; + executed_at?: string | null + hash?: string + id?: number + name?: string + } + Relationships: [] + } objects: { Row: { - bucket_id: string | null; - created_at: string | null; - id: string; - last_accessed_at: string | null; - metadata: Json | null; - name: string | null; - owner: string | null; - owner_id: string | null; - path_tokens: string[] | null; - updated_at: string | null; - user_metadata: Json | null; - version: string | null; - }; + bucket_id: string | null + created_at: string | null + id: string + last_accessed_at: string | null + level: number | null + metadata: Json | null + name: string | null + owner: string | null + owner_id: string | null + path_tokens: string[] | null + updated_at: string | null + user_metadata: Json | null + version: string | null + } Insert: { - bucket_id?: string | null; - created_at?: string | null; - id?: string; - last_accessed_at?: string | null; - metadata?: Json | null; - name?: string | null; - owner?: string | null; - owner_id?: string | null; - path_tokens?: string[] | null; - updated_at?: string | null; - user_metadata?: Json | null; - version?: string | null; - }; + bucket_id?: string | null + created_at?: string | null + id?: string + last_accessed_at?: string | null + level?: number | null + metadata?: Json | null + name?: string | null + owner?: string | null + owner_id?: string | null + path_tokens?: string[] | null + updated_at?: string | null + user_metadata?: Json | null + version?: string | null + } Update: { - bucket_id?: string | null; - created_at?: string | null; - id?: string; - last_accessed_at?: string | null; - metadata?: Json | null; - name?: string | null; - owner?: string | null; - owner_id?: string | null; - path_tokens?: string[] | null; - updated_at?: string | null; - user_metadata?: Json | null; - version?: string | null; - }; + bucket_id?: string | null + created_at?: string | null + id?: string + last_accessed_at?: string | null + level?: number | null + metadata?: Json | null + name?: string | null + owner?: string | null + owner_id?: string | null + path_tokens?: string[] | null + updated_at?: string | null + user_metadata?: Json | null + version?: string | null + } Relationships: [ { - foreignKeyName: 'objects_bucketId_fkey'; - columns: ['bucket_id']; - isOneToOne: false; - referencedRelation: 'buckets'; - referencedColumns: ['id']; + foreignKeyName: "objects_bucketId_fkey" + columns: ["bucket_id"] + isOneToOne: false + referencedRelation: "buckets" + referencedColumns: ["id"] }, - ]; - }; + ] + } + prefixes: { + Row: { + bucket_id: string + created_at: string | null + level: number + name: string + updated_at: string | null + } + Insert: { + bucket_id: string + created_at?: string | null + level?: number + name: string + updated_at?: string | null + } + Update: { + bucket_id?: string + created_at?: string | null + level?: number + name?: string + updated_at?: string | null + } + Relationships: [ + { + foreignKeyName: "prefixes_bucketId_fkey" + columns: ["bucket_id"] + isOneToOne: false + referencedRelation: "buckets" + referencedColumns: ["id"] + }, + ] + } s3_multipart_uploads: { Row: { - bucket_id: string; - created_at: string; - id: string; - in_progress_size: number; - key: string; - owner_id: string | null; - upload_signature: string; - user_metadata: Json | null; - version: string; - }; + bucket_id: string + created_at: string + id: string + in_progress_size: number + key: string + owner_id: string | null + upload_signature: string + user_metadata: Json | null + version: string + } Insert: { - bucket_id: string; - created_at?: string; - id: string; - in_progress_size?: number; - key: string; - owner_id?: string | null; - upload_signature: string; - user_metadata?: Json | null; - version: string; - }; + bucket_id: string + created_at?: string + id: string + in_progress_size?: number + key: string + owner_id?: string | null + upload_signature: string + user_metadata?: Json | null + version: string + } Update: { - bucket_id?: string; - created_at?: string; - id?: string; - in_progress_size?: number; - key?: string; - owner_id?: string | null; - upload_signature?: string; - user_metadata?: Json | null; - version?: string; - }; + bucket_id?: string + created_at?: string + id?: string + in_progress_size?: number + key?: string + owner_id?: string | null + upload_signature?: string + user_metadata?: Json | null + version?: string + } Relationships: [ { - foreignKeyName: 's3_multipart_uploads_bucket_id_fkey'; - columns: ['bucket_id']; - isOneToOne: false; - referencedRelation: 'buckets'; - referencedColumns: ['id']; + foreignKeyName: "s3_multipart_uploads_bucket_id_fkey" + columns: ["bucket_id"] + isOneToOne: false + referencedRelation: "buckets" + referencedColumns: ["id"] }, - ]; - }; + ] + } s3_multipart_uploads_parts: { Row: { - bucket_id: string; - created_at: string; - etag: string; - id: string; - key: string; - owner_id: string | null; - part_number: number; - size: number; - upload_id: string; - version: string; - }; + bucket_id: string + created_at: string + etag: string + id: string + key: string + owner_id: string | null + part_number: number + size: number + upload_id: string + version: string + } Insert: { - bucket_id: string; - created_at?: string; - etag: string; - id?: string; - key: string; - owner_id?: string | null; - part_number: number; - size?: number; - upload_id: string; - version: string; - }; + bucket_id: string + created_at?: string + etag: string + id?: string + key: string + owner_id?: string | null + part_number: number + size?: number + upload_id: string + version: string + } Update: { - bucket_id?: string; - created_at?: string; - etag?: string; - id?: string; - key?: string; - owner_id?: string | null; - part_number?: number; - size?: number; - upload_id?: string; - version?: string; - }; + bucket_id?: string + created_at?: string + etag?: string + id?: string + key?: string + owner_id?: string | null + part_number?: number + size?: number + upload_id?: string + version?: string + } Relationships: [ { - foreignKeyName: 's3_multipart_uploads_parts_bucket_id_fkey'; - columns: ['bucket_id']; - isOneToOne: false; - referencedRelation: 'buckets'; - referencedColumns: ['id']; + foreignKeyName: "s3_multipart_uploads_parts_bucket_id_fkey" + columns: ["bucket_id"] + isOneToOne: false + referencedRelation: "buckets" + referencedColumns: ["id"] }, { - foreignKeyName: 's3_multipart_uploads_parts_upload_id_fkey'; - columns: ['upload_id']; - isOneToOne: false; - referencedRelation: 's3_multipart_uploads'; - referencedColumns: ['id']; + foreignKeyName: "s3_multipart_uploads_parts_upload_id_fkey" + columns: ["upload_id"] + isOneToOne: false + referencedRelation: "s3_multipart_uploads" + referencedColumns: ["id"] }, - ]; - }; - }; + ] + } + vector_indexes: { + Row: { + bucket_id: string + created_at: string + data_type: string + dimension: number + distance_metric: string + id: string + metadata_configuration: Json | null + name: string + updated_at: string + } + Insert: { + bucket_id: string + created_at?: string + data_type: string + dimension: number + distance_metric: string + id?: string + metadata_configuration?: Json | null + name: string + updated_at?: string + } + Update: { + bucket_id?: string + created_at?: string + data_type?: string + dimension?: number + distance_metric?: string + id?: string + metadata_configuration?: Json | null + name?: string + updated_at?: string + } + Relationships: [ + { + foreignKeyName: "vector_indexes_bucket_id_fkey" + columns: ["bucket_id"] + isOneToOne: false + referencedRelation: "buckets_vectors" + referencedColumns: ["id"] + }, + ] + } + } Views: { - [_ in never]: never; - }; + [_ in never]: never + } Functions: { + add_prefixes: { + Args: { _bucket_id: string; _name: string } + Returns: undefined + } can_insert_object: { - Args: { - bucketid: string; - name: string; - owner: string; - metadata: Json; - }; - Returns: undefined; - }; - extension: { - Args: { - name: string; - }; - Returns: string; - }; - filename: { - Args: { - name: string; - }; - Returns: string; - }; - foldername: { - Args: { - name: string; - }; - Returns: string[]; - }; + Args: { bucketid: string; metadata: Json; name: string; owner: string } + Returns: undefined + } + delete_leaf_prefixes: { + Args: { bucket_ids: string[]; names: string[] } + Returns: undefined + } + delete_prefix: { + Args: { _bucket_id: string; _name: string } + Returns: boolean + } + extension: { Args: { name: string }; Returns: string } + filename: { Args: { name: string }; Returns: string } + foldername: { Args: { name: string }; Returns: string[] } + get_level: { Args: { name: string }; Returns: number } + get_prefix: { Args: { name: string }; Returns: string } + get_prefixes: { Args: { name: string }; Returns: string[] } get_size_by_bucket: { - Args: Record; + Args: never Returns: { - size: number; - bucket_id: string; - }[]; - }; + bucket_id: string + size: number + }[] + } list_multipart_uploads_with_delimiter: { Args: { - bucket_id: string; - prefix_param: string; - delimiter_param: string; - max_keys?: number; - next_key_token?: string; - next_upload_token?: string; - }; + bucket_id: string + delimiter_param: string + max_keys?: number + next_key_token?: string + next_upload_token?: string + prefix_param: string + } Returns: { - key: string; - id: string; - created_at: string; - }[]; - }; + created_at: string + id: string + key: string + }[] + } list_objects_with_delimiter: { Args: { - bucket_id: string; - prefix_param: string; - delimiter_param: string; - max_keys?: number; - start_after?: string; - next_token?: string; - }; + bucket_id: string + delimiter_param: string + max_keys?: number + next_token?: string + prefix_param: string + start_after?: string + } Returns: { - name: string; - id: string; - metadata: Json; - updated_at: string; - }[]; - }; - operation: { - Args: Record; - Returns: string; - }; - search: { + id: string + metadata: Json + name: string + updated_at: string + }[] + } + lock_top_prefixes: { + Args: { bucket_ids: string[]; names: string[] } + Returns: undefined + } + operation: { Args: never; Returns: string } + search: + | { + Args: { + bucketname: string + levels?: number + limits?: number + offsets?: number + prefix: string + } + Returns: { + created_at: string + id: string + last_accessed_at: string + metadata: Json + name: string + updated_at: string + }[] + } + | { + Args: { + bucketname: string + levels?: number + limits?: number + offsets?: number + prefix: string + search?: string + sortcolumn?: string + sortorder?: string + } + Returns: { + created_at: string + id: string + last_accessed_at: string + metadata: Json + name: string + updated_at: string + }[] + } + search_legacy_v1: { Args: { - prefix: string; - bucketname: string; - limits?: number; - levels?: number; - offsets?: number; - search?: string; - sortcolumn?: string; - sortorder?: string; - }; + bucketname: string + levels?: number + limits?: number + offsets?: number + prefix: string + search?: string + sortcolumn?: string + sortorder?: string + } Returns: { - name: string; - id: string; - updated_at: string; - created_at: string; - last_accessed_at: string; - metadata: Json; - }[]; - }; - }; + created_at: string + id: string + last_accessed_at: string + metadata: Json + name: string + updated_at: string + }[] + } + search_v1_optimised: { + Args: { + bucketname: string + levels?: number + limits?: number + offsets?: number + prefix: string + search?: string + sortcolumn?: string + sortorder?: string + } + Returns: { + created_at: string + id: string + last_accessed_at: string + metadata: Json + name: string + updated_at: string + }[] + } + search_v2: + | { + Args: { + bucket_name: string + levels?: number + limits?: number + prefix: string + start_after?: string + } + Returns: { + created_at: string + id: string + key: string + metadata: Json + name: string + updated_at: string + }[] + } + | { + Args: { + bucket_name: string + levels?: number + limits?: number + prefix: string + sort_column?: string + sort_column_after?: string + sort_order?: string + start_after?: string + } + Returns: { + created_at: string + id: string + key: string + last_accessed_at: string + metadata: Json + name: string + updated_at: string + }[] + } + } Enums: { - [_ in never]: never; - }; + buckettype: "STANDARD" | "ANALYTICS" | "VECTOR" + } CompositeTypes: { - [_ in never]: never; - }; - }; -}; + [_ in never]: never + } + } +} -type PublicSchema = Database[Extract]; +type DatabaseWithoutInternals = Omit + +type DefaultSchema = DatabaseWithoutInternals[Extract] export type Tables< - PublicTableNameOrOptions extends - | keyof (PublicSchema['Tables'] & PublicSchema['Views']) - | { schema: keyof Database }, - TableName extends PublicTableNameOrOptions extends { schema: keyof Database } - ? keyof (Database[PublicTableNameOrOptions['schema']]['Tables'] & - Database[PublicTableNameOrOptions['schema']]['Views']) + DefaultSchemaTableNameOrOptions extends + | keyof (DefaultSchema["Tables"] & DefaultSchema["Views"]) + | { schema: keyof DatabaseWithoutInternals }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals + } + ? keyof (DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] & + DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Views"]) : never = never, -> = PublicTableNameOrOptions extends { schema: keyof Database } - ? (Database[PublicTableNameOrOptions['schema']]['Tables'] & - Database[PublicTableNameOrOptions['schema']]['Views'])[TableName] extends { - Row: infer R; +> = DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals +} + ? (DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] & + DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Views"])[TableName] extends { + Row: infer R } ? R : never - : PublicTableNameOrOptions extends keyof (PublicSchema['Tables'] & - PublicSchema['Views']) - ? (PublicSchema['Tables'] & - PublicSchema['Views'])[PublicTableNameOrOptions] extends { - Row: infer R; + : DefaultSchemaTableNameOrOptions extends keyof (DefaultSchema["Tables"] & + DefaultSchema["Views"]) + ? (DefaultSchema["Tables"] & + DefaultSchema["Views"])[DefaultSchemaTableNameOrOptions] extends { + Row: infer R } ? R : never - : never; + : never export type TablesInsert< - PublicTableNameOrOptions extends - | keyof PublicSchema['Tables'] - | { schema: keyof Database }, - TableName extends PublicTableNameOrOptions extends { schema: keyof Database } - ? keyof Database[PublicTableNameOrOptions['schema']]['Tables'] + DefaultSchemaTableNameOrOptions extends + | keyof DefaultSchema["Tables"] + | { schema: keyof DatabaseWithoutInternals }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals + } + ? keyof DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] : never = never, -> = PublicTableNameOrOptions extends { schema: keyof Database } - ? Database[PublicTableNameOrOptions['schema']]['Tables'][TableName] extends { - Insert: infer I; +> = DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals +} + ? DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends { + Insert: infer I } ? I : never - : PublicTableNameOrOptions extends keyof PublicSchema['Tables'] - ? PublicSchema['Tables'][PublicTableNameOrOptions] extends { - Insert: infer I; + : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"] + ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { + Insert: infer I } ? I : never - : never; + : never export type TablesUpdate< - PublicTableNameOrOptions extends - | keyof PublicSchema['Tables'] - | { schema: keyof Database }, - TableName extends PublicTableNameOrOptions extends { schema: keyof Database } - ? keyof Database[PublicTableNameOrOptions['schema']]['Tables'] + DefaultSchemaTableNameOrOptions extends + | keyof DefaultSchema["Tables"] + | { schema: keyof DatabaseWithoutInternals }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals + } + ? keyof DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] : never = never, -> = PublicTableNameOrOptions extends { schema: keyof Database } - ? Database[PublicTableNameOrOptions['schema']]['Tables'][TableName] extends { - Update: infer U; +> = DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals +} + ? DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"][TableName] extends { + Update: infer U } ? U : never - : PublicTableNameOrOptions extends keyof PublicSchema['Tables'] - ? PublicSchema['Tables'][PublicTableNameOrOptions] extends { - Update: infer U; + : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema["Tables"] + ? DefaultSchema["Tables"][DefaultSchemaTableNameOrOptions] extends { + Update: infer U } ? U : never - : never; + : never export type Enums< - PublicEnumNameOrOptions extends - | keyof PublicSchema['Enums'] - | { schema: keyof Database }, - EnumName extends PublicEnumNameOrOptions extends { schema: keyof Database } - ? keyof Database[PublicEnumNameOrOptions['schema']]['Enums'] + DefaultSchemaEnumNameOrOptions extends + | keyof DefaultSchema["Enums"] + | { schema: keyof DatabaseWithoutInternals }, + EnumName extends DefaultSchemaEnumNameOrOptions extends { + schema: keyof DatabaseWithoutInternals + } + ? keyof DatabaseWithoutInternals[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"] : never = never, -> = PublicEnumNameOrOptions extends { schema: keyof Database } - ? Database[PublicEnumNameOrOptions['schema']]['Enums'][EnumName] - : PublicEnumNameOrOptions extends keyof PublicSchema['Enums'] - ? PublicSchema['Enums'][PublicEnumNameOrOptions] - : never; +> = DefaultSchemaEnumNameOrOptions extends { + schema: keyof DatabaseWithoutInternals +} + ? DatabaseWithoutInternals[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"][EnumName] + : DefaultSchemaEnumNameOrOptions extends keyof DefaultSchema["Enums"] + ? DefaultSchema["Enums"][DefaultSchemaEnumNameOrOptions] + : never export type CompositeTypes< PublicCompositeTypeNameOrOptions extends - | keyof PublicSchema['CompositeTypes'] - | { schema: keyof Database }, + | keyof DefaultSchema["CompositeTypes"] + | { schema: keyof DatabaseWithoutInternals }, CompositeTypeName extends PublicCompositeTypeNameOrOptions extends { - schema: keyof Database; + schema: keyof DatabaseWithoutInternals } - ? keyof Database[PublicCompositeTypeNameOrOptions['schema']]['CompositeTypes'] + ? keyof DatabaseWithoutInternals[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"] : never = never, -> = PublicCompositeTypeNameOrOptions extends { schema: keyof Database } - ? Database[PublicCompositeTypeNameOrOptions['schema']]['CompositeTypes'][CompositeTypeName] - : PublicCompositeTypeNameOrOptions extends keyof PublicSchema['CompositeTypes'] - ? PublicSchema['CompositeTypes'][PublicCompositeTypeNameOrOptions] - : never; +> = PublicCompositeTypeNameOrOptions extends { + schema: keyof DatabaseWithoutInternals +} + ? DatabaseWithoutInternals[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"][CompositeTypeName] + : PublicCompositeTypeNameOrOptions extends keyof DefaultSchema["CompositeTypes"] + ? DefaultSchema["CompositeTypes"][PublicCompositeTypeNameOrOptions] + : never + +export const Constants = { + graphql_public: { + Enums: {}, + }, + public: { + Enums: { + app_permissions: [ + "roles.manage", + "billing.manage", + "settings.manage", + "members.manage", + "invites.manage", + ], + billing_provider: ["stripe", "lemon-squeezy", "paddle"], + notification_channel: ["in_app", "email"], + notification_type: ["info", "warning", "error"], + payment_status: ["pending", "succeeded", "failed"], + subscription_item_type: ["flat", "per_seat", "metered"], + subscription_status: [ + "active", + "trialing", + "past_due", + "canceled", + "unpaid", + "incomplete", + "incomplete_expired", + "paused", + ], + }, + }, + storage: { + Enums: { + buckettype: ["STANDARD", "ANALYTICS", "VECTOR"], + }, + }, +} as const + diff --git a/apps/web/package.json b/apps/web/package.json index 9c92a93f0..50206190f 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -53,14 +53,14 @@ "@kit/ui": "workspace:*", "@makerkit/data-loader-supabase-core": "^0.0.10", "@makerkit/data-loader-supabase-nextjs": "^1.2.5", - "@marsidev/react-turnstile": "^1.4.0", - "@nosecone/next": "1.0.0-beta.15", + "@marsidev/react-turnstile": "^1.4.1", + "@nosecone/next": "1.0.0-beta.16", "@radix-ui/react-icons": "^1.3.2", "@supabase/supabase-js": "catalog:", "@tanstack/react-query": "catalog:", "@tanstack/react-table": "^8.21.3", "date-fns": "^4.1.0", - "lucide-react": "^0.562.0", + "lucide-react": "catalog:", "next": "catalog:", "next-sitemap": "^4.2.3", "next-themes": "0.4.6", diff --git a/apps/web/public/locales/en/auth.json b/apps/web/public/locales/en/auth.json index 90ddba17e..a6a91423b 100644 --- a/apps/web/public/locales/en/auth.json +++ b/apps/web/public/locales/en/auth.json @@ -100,6 +100,15 @@ "uppercasePassword": "Password must contain at least one uppercase letter", "insufficient_aal": "Please sign-in with your current multi-factor authentication to perform this action", "otp_expired": "The email link has expired. Please try again.", - "same_password": "The password cannot be the same as the current password" + "same_password": "The password cannot be the same as the current password", + "weakPassword": { + "title": "Password is too weak", + "description": "Your password does not meet the security requirements:", + "reasons": { + "length": "Password must be at least 8 characters long", + "characters": "Password must contain lowercase, uppercase, numbers, and special characters", + "pwned": "This password has been found in a data breach. Please choose a different password" + } + } } } diff --git a/apps/web/supabase/migrations/20260107093634_secure-invitations-function.sql b/apps/web/supabase/migrations/20260107093634_secure-invitations-function.sql new file mode 100644 index 000000000..ec13115dd --- /dev/null +++ b/apps/web/supabase/migrations/20260107093634_secure-invitations-function.sql @@ -0,0 +1,64 @@ +-- Remove invitations INSERT policy +-- Permission and role hierarchy checks are now enforced in the server action. +-- Invitations are created through server actions using admin client. + +drop policy if exists invitations_create_self on public.invitations; + +-- Update invitations RPC to accept invited_by and restrict execution. + +drop function if exists public.add_invitations_to_account(text, public.invitation[]); + +create +or replace function public.add_invitations_to_account ( + account_slug text, + invitations public.invitation[], + invited_by uuid +) returns public.invitations[] +set + search_path = '' as $$ +declare + new_invitation public.invitations; + all_invitations public.invitations[] := array[]::public.invitations[]; + invite_token text; + email text; + role varchar(50); +begin + FOREACH email, + role in array invitations loop + invite_token := extensions.uuid_generate_v4(); + + insert into public.invitations( + email, + account_id, + invited_by, + role, + invite_token) + values ( + email, +( + select + id + from + public.accounts + where + slug = account_slug), + invited_by, + role, + invite_token) + returning + * into new_invitation; + + all_invitations := array_append(all_invitations, new_invitation); + + end loop; + + return all_invitations; + +end; + +$$ language plpgsql; + +revoke execute on function public.add_invitations_to_account (text, public.invitation[], uuid) from authenticated; + +grant +execute on function public.add_invitations_to_account (text, public.invitation[], uuid) to service_role; diff --git a/apps/web/supabase/schemas/03-accounts.sql b/apps/web/supabase/schemas/03-accounts.sql index 0b695f880..d1be10337 100644 --- a/apps/web/supabase/schemas/03-accounts.sql +++ b/apps/web/supabase/schemas/03-accounts.sql @@ -501,15 +501,6 @@ grant execute on function public.create_team_account (text) to authenticated, service_role; --- RLS(public.accounts) --- Authenticated users can create team accounts -create policy create_org_account on public.accounts for insert to authenticated -with - check ( - public.is_set ('enable_team_accounts') - and public.accounts.is_personal_account = false - ); - -- RLS(public.accounts) -- Authenticated users can delete team accounts create policy delete_team_account diff --git a/apps/web/supabase/schemas/07-invitations.sql b/apps/web/supabase/schemas/07-invitations.sql index ca0859f65..97be8c78e 100644 --- a/apps/web/supabase/schemas/07-invitations.sql +++ b/apps/web/supabase/schemas/07-invitations.sql @@ -96,36 +96,9 @@ select to authenticated using (public.has_role_on_account (account_id)); -- INSERT(invitations): --- Users can create invitations to users of an account they are --- a member of and have the 'invites.manage' permission AND the target role is not higher than the user's role -create policy invitations_create_self on public.invitations for insert to authenticated -with - check ( - public.is_set ('enable_team_accounts') - and public.has_permission ( - ( - select - auth.uid () - ), - account_id, - 'invites.manage'::public.app_permissions - ) - and (public.has_more_elevated_role ( - ( - select - auth.uid () - ), - account_id, - role - ) or public.has_same_role_hierarchy_level( - ( - select - auth.uid () - ), - account_id, - role - )) - ); +-- Invitations are created through server actions using admin client. +-- Permission and role hierarchy checks are enforced in the server action. +-- No RLS policy needed for INSERT. -- UPDATE(invitations): -- Users can update invitations to users of an account they are a member of and have the 'invites.manage' permission AND @@ -311,7 +284,8 @@ service_role; create or replace function public.add_invitations_to_account ( account_slug text, - invitations public.invitation[] + invitations public.invitation[], + invited_by uuid ) returns public.invitations[] set search_path = '' as $$ @@ -340,7 +314,10 @@ begin from public.accounts where - slug = account_slug), auth.uid(), role, invite_token) + slug = account_slug), + invited_by, + role, + invite_token) returning * into new_invitation; @@ -355,5 +332,4 @@ end; $$ language plpgsql; grant -execute on function public.add_invitations_to_account (text, public.invitation[]) to authenticated, -service_role; +execute on function public.add_invitations_to_account (text, public.invitation[], uuid) to service_role; diff --git a/apps/web/supabase/tests/database/invitations.test.sql b/apps/web/supabase/tests/database/invitations.test.sql index 757397b7c..0151516d9 100644 --- a/apps/web/supabase/tests/database/invitations.test.sql +++ b/apps/web/supabase/tests/database/invitations.test.sql @@ -12,49 +12,53 @@ select makerkit.set_identifier('owner', 'owner@makerkit.dev'); select makerkit.authenticate_as('test'); -select lives_ok( +select throws_ok( $$ insert into public.invitations (email, invited_by, account_id, role, invite_token) values ('invite1@makerkit.dev', auth.uid(), makerkit.get_account_id_by_slug('makerkit'), 'member', gen_random_uuid()); $$, -'owner should be able to create invitations' + 'new row violates row-level security policy for table "invitations"', + 'direct inserts should be blocked' ); --- check two invitations to the same email/account are not allowed +-- direct inserts are blocked even for duplicates select throws_ok( $$ insert into public.invitations (email, invited_by, account_id, role, invite_token) values ('invite1@makerkit.dev', auth.uid(), makerkit.get_account_id_by_slug('makerkit'), 'member', gen_random_uuid()) $$, - 'duplicate key value violates unique constraint "invitations_email_account_id_key"' + 'new row violates row-level security policy for table "invitations"', + 'direct inserts should be blocked' ); select makerkit.authenticate_as('member'); --- check a member cannot invite members with higher roles +-- direct inserts are blocked regardless of role select throws_ok( $$ insert into public.invitations (email, invited_by, account_id, role, invite_token) values ('invite2@makerkit.dev', auth.uid(), makerkit.get_account_id_by_slug('makerkit'), 'owner', gen_random_uuid()) $$, 'new row violates row-level security policy for table "invitations"' ); --- check a member can invite members with the same or lower roles -select lives_ok( +-- direct inserts are blocked regardless of role +select throws_ok( $$ insert into public.invitations (email, invited_by, account_id, role, invite_token) values ('invite2@makerkit.dev', auth.uid(), makerkit.get_account_id_by_slug('makerkit'), 'member', gen_random_uuid()) $$, - 'member should be able to create invitations for members or lower roles' + 'new row violates row-level security policy for table "invitations"', + 'direct inserts should be blocked' ); --- test invite exists -select isnt_empty( +-- direct inserts should not create invitations +select is_empty( $$ select * from public.invitations where account_id = makerkit.get_account_id_by_slug('makerkit') $$, - 'invitations should be listed' + 'invitations should not be listed when inserts are blocked' ); select makerkit.authenticate_as('owner'); --- check the owner can invite members with lower roles -select lives_ok( +-- direct inserts are blocked regardless of role +select throws_ok( $$ insert into public.invitations (email, invited_by, account_id, role, invite_token) values ('invite3@makerkit.dev', auth.uid(), makerkit.get_account_id_by_slug('makerkit'), 'member', gen_random_uuid()) $$, - 'owner should be able to create invitations' + 'new row violates row-level security policy for table "invitations"', + 'direct inserts should be blocked' ); -- authenticate_as the custom role select makerkit.authenticate_as('custom'); --- it will fail because the custom role does not have the invites.manage permission +-- direct inserts are blocked regardless of role select throws_ok( $$ insert into public.invitations (email, invited_by, account_id, role, invite_token) values ('invite3@makerkit.dev', auth.uid(), makerkit.get_account_id_by_slug('makerkit'), 'custom-role', gen_random_uuid()) $$, 'new row violates row-level security policy for table "invitations"' @@ -62,26 +66,28 @@ select throws_ok( set local role postgres; --- add permissions to invite members to the custom role +-- adding permissions should not bypass direct insert restrictions insert into public.role_permissions (role, permission) values ('custom-role', 'invites.manage'); -- authenticate_as the custom role select makerkit.authenticate_as('custom'); -select lives_ok( +select throws_ok( $$ insert into public.invitations (email, invited_by, account_id, role, invite_token) values ('invite4@makerkit.dev', auth.uid(), makerkit.get_account_id_by_slug('makerkit'), 'custom-role', gen_random_uuid()) $$, - 'custom role should be able to create invitations' -); - -select lives_ok( - $$ SELECT public.add_invitations_to_account('makerkit', ARRAY[ROW('example@makerkit.dev', 'custom-role')::public.invitation]); $$, - 'custom role should be able to create invitations using the function public.add_invitations_to_account' + 'new row violates row-level security policy for table "invitations"', + 'direct inserts should be blocked' ); select throws_ok( - $$ SELECT public.add_invitations_to_account('makerkit', ARRAY[ROW('example2@makerkit.dev', 'owner')::public.invitation]); $$, - 'new row violates row-level security policy for table "invitations"', - 'cannot invite members with higher roles' + $$ SELECT public.add_invitations_to_account('makerkit', ARRAY[ROW('example@makerkit.dev', 'custom-role')::public.invitation], auth.uid()); $$, + 'permission denied for function add_invitations_to_account', + 'authenticated users cannot call add_invitations_to_account' +); + +select throws_ok( + $$ SELECT public.add_invitations_to_account('makerkit', ARRAY[ROW('example2@makerkit.dev', 'owner')::public.invitation], auth.uid()); $$, + 'permission denied for function add_invitations_to_account', + 'authenticated users cannot call add_invitations_to_account' ); -- Foreigners should not be able to create invitations @@ -90,15 +96,15 @@ select tests.create_supabase_user('user'); select makerkit.authenticate_as('user'); --- it will fail because the user is not a member of the account +-- direct inserts are blocked regardless of membership select throws_ok( $$ insert into public.invitations (email, invited_by, account_id, role, invite_token) values ('invite4@makerkit.dev', auth.uid(), makerkit.get_account_id_by_slug('makerkit'), 'member', gen_random_uuid()) $$, 'new row violates row-level security policy for table "invitations"' ); select throws_ok( - $$ SELECT public.add_invitations_to_account('makerkit', ARRAY[ROW('example@example.com', 'member')::public.invitation]); $$, - 'new row violates row-level security policy for table "invitations"' + $$ SELECT public.add_invitations_to_account('makerkit', ARRAY[ROW('example@example.com', 'member')::public.invitation], auth.uid()); $$, + 'permission denied for function add_invitations_to_account' ); select is_empty($$ diff --git a/apps/web/supabase/tests/database/triggers-timestamps-simple.test.sql b/apps/web/supabase/tests/database/triggers-timestamps-simple.test.sql index 30019b66e..47f19c966 100644 --- a/apps/web/supabase/tests/database/triggers-timestamps-simple.test.sql +++ b/apps/web/supabase/tests/database/triggers-timestamps-simple.test.sql @@ -42,6 +42,9 @@ SELECT ok( INSERT INTO public.accounts (name, is_personal_account) VALUES ('Invitation Test Team', false); +-- Switch to service_role to insert invitations (INSERT policy removed, handled by server action) +set role service_role; + -- Test invitation insert INSERT INTO public.invitations (email, account_id, invited_by, role, invite_token, expires_at) VALUES ( @@ -53,6 +56,9 @@ VALUES ( now() + interval '7 days' ); +-- Switch back to authenticated user for assertion +select makerkit.authenticate_as('trigger_test_user1'); + SELECT ok( (SELECT created_at IS NOT NULL FROM public.invitations WHERE email = 'invitee@example.com'), 'invitations: created_at should be set automatically on insert' diff --git a/apps/web/supabase/tests/database/update-membership.test.sql b/apps/web/supabase/tests/database/update-membership.test.sql index c5364a743..f895db07a 100644 --- a/apps/web/supabase/tests/database/update-membership.test.sql +++ b/apps/web/supabase/tests/database/update-membership.test.sql @@ -3,25 +3,42 @@ create extension "basejump-supabase_test_helpers" version '0.0.6'; select no_plan(); -select makerkit.set_identifier('primary_owner', 'test@makerkit.dev'); -select makerkit.set_identifier('owner', 'owner@makerkit.dev'); -select makerkit.set_identifier('member', 'member@makerkit.dev'); -select makerkit.set_identifier('custom', 'custom@makerkit.dev'); +-- Create fresh test users +select tests.create_supabase_user('update_test_owner', 'update-owner@test.com'); +select tests.create_supabase_user('update_test_member', 'update-member@test.com'); --- another user not in the team -select tests.create_supabase_user('test', 'test@supabase.com'); +-- Authenticate as owner to create team account +select makerkit.authenticate_as('update_test_owner'); -select makerkit.authenticate_as('member'); +-- Create a team account (owner is added automatically via trigger) +insert into public.accounts (name, is_personal_account) +values ('Update Test Team', false); --- run an update query -update public.accounts_memberships set account_role = 'owner' where user_id = auth.uid() and account_id = makerkit.get_account_id_by_slug('makerkit'); +-- Add member to the team with 'member' role using service_role +set role service_role; + +insert into public.accounts_memberships (account_id, user_id, account_role) +values ( + (select id from public.accounts where name = 'Update Test Team'), + tests.get_supabase_uid('update_test_member'), + 'member' +); + +-- Authenticate as member +select makerkit.authenticate_as('update_test_member'); + +-- Member tries to update their own role to 'owner' - should fail silently +update public.accounts_memberships +set account_role = 'owner' +where user_id = auth.uid() +and account_id = (select id from public.accounts where name = 'Update Test Team'); select row_eq( - $$ select account_role from public.accounts_memberships where user_id = auth.uid() and account_id = makerkit.get_account_id_by_slug('makerkit'); $$, + $$ select account_role from public.accounts_memberships where user_id = auth.uid() and account_id = (select id from public.accounts where name = 'Update Test Team'); $$, row('member'::varchar), 'Updates fail silently to any field of the accounts_membership table' ); select * from finish(); -rollback; \ No newline at end of file +rollback; diff --git a/package.json b/package.json index 8940eef05..be36ff41e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "next-supabase-saas-kit-turbo", - "version": "2.22.0", + "version": "2.23.0", "private": true, "sideEffects": false, "engines": { @@ -48,7 +48,7 @@ "@turbo/gen": "^2.7.0", "cross-env": "^10.0.0", "prettier": "^3.7.4", - "turbo": "2.7.1", + "turbo": "2.7.3", "typescript": "^5.9.3" } } diff --git a/packages/billing/gateway/package.json b/packages/billing/gateway/package.json index 46f898f04..6d49e5179 100644 --- a/packages/billing/gateway/package.json +++ b/packages/billing/gateway/package.json @@ -29,7 +29,7 @@ "@supabase/supabase-js": "catalog:", "@types/react": "catalog:", "date-fns": "^4.1.0", - "lucide-react": "^0.562.0", + "lucide-react": "catalog:", "next": "catalog:", "react": "catalog:", "react-hook-form": "catalog:", diff --git a/packages/billing/stripe/package.json b/packages/billing/stripe/package.json index 980db5218..0296465e9 100644 --- a/packages/billing/stripe/package.json +++ b/packages/billing/stripe/package.json @@ -15,9 +15,9 @@ "./components": "./src/components/index.ts" }, "dependencies": { - "@stripe/react-stripe-js": "^5.4.1", - "@stripe/stripe-js": "^8.6.0", - "stripe": "^20.1.0" + "@stripe/react-stripe-js": "catalog:", + "@stripe/stripe-js": "catalog:", + "stripe": "catalog:" }, "devDependencies": { "@kit/billing": "workspace:*", diff --git a/packages/email-templates/package.json b/packages/email-templates/package.json index f1f5ce76d..09e61a43c 100644 --- a/packages/email-templates/package.json +++ b/packages/email-templates/package.json @@ -13,7 +13,7 @@ ".": "./src/index.ts" }, "dependencies": { - "@react-email/components": "1.0.2" + "@react-email/components": "1.0.3" }, "devDependencies": { "@kit/eslint-config": "workspace:*", diff --git a/packages/features/accounts/package.json b/packages/features/accounts/package.json index daf6a442c..3173e844d 100644 --- a/packages/features/accounts/package.json +++ b/packages/features/accounts/package.json @@ -38,7 +38,7 @@ "@tanstack/react-query": "catalog:", "@types/react": "catalog:", "@types/react-dom": "catalog:", - "lucide-react": "^0.562.0", + "lucide-react": "catalog:", "next": "catalog:", "next-themes": "0.4.6", "react": "catalog:", diff --git a/packages/features/admin/package.json b/packages/features/admin/package.json index a121a0ac2..39c568eb4 100644 --- a/packages/features/admin/package.json +++ b/packages/features/admin/package.json @@ -24,7 +24,7 @@ "@tanstack/react-query": "catalog:", "@tanstack/react-table": "^8.21.3", "@types/react": "catalog:", - "lucide-react": "^0.562.0", + "lucide-react": "catalog:", "next": "catalog:", "react": "catalog:", "react-dom": "catalog:", diff --git a/packages/features/auth/package.json b/packages/features/auth/package.json index 164cb7af3..3313e3ee3 100644 --- a/packages/features/auth/package.json +++ b/packages/features/auth/package.json @@ -27,13 +27,13 @@ "@kit/supabase": "workspace:*", "@kit/tsconfig": "workspace:*", "@kit/ui": "workspace:*", - "@marsidev/react-turnstile": "^1.4.0", + "@marsidev/react-turnstile": "catalog:", "@radix-ui/react-icons": "^1.3.2", "@supabase/supabase-js": "catalog:", "@tanstack/react-query": "catalog:", "@types/node": "catalog:", "@types/react": "catalog:", - "lucide-react": "^0.562.0", + "lucide-react": "catalog:", "next": "catalog:", "react-hook-form": "catalog:", "react-i18next": "catalog:", diff --git a/packages/features/auth/src/components/auth-error-alert.tsx b/packages/features/auth/src/components/auth-error-alert.tsx index 7da96e56c..e4cda20d8 100644 --- a/packages/features/auth/src/components/auth-error-alert.tsx +++ b/packages/features/auth/src/components/auth-error-alert.tsx @@ -1,8 +1,16 @@ import { ExclamationTriangleIcon } from '@radix-ui/react-icons'; +import { + WeakPasswordError, + WeakPasswordReason, +} from '@kit/supabase/hooks/use-sign-up-with-email-password'; import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert'; import { Trans } from '@kit/ui/trans'; +function isWeakPasswordError(error: unknown): error is WeakPasswordError { + return error instanceof Error && error.name === 'WeakPasswordError'; +} + /** * @name AuthErrorAlert * @param error This error comes from Supabase as the code returned on errors @@ -20,6 +28,11 @@ export function AuthErrorAlert({ return null; } + // Handle weak password errors specially + if (isWeakPasswordError(error)) { + return ; + } + const DefaultError = ; const errorCode = error instanceof Error ? error.message : error; @@ -41,3 +54,36 @@ export function AuthErrorAlert({ ); } + +function WeakPasswordErrorAlert({ + reasons, +}: { + reasons: WeakPasswordReason[]; +}) { + return ( + + + + + + + + + + + {reasons.length > 0 && ( +
    + {reasons.map((reason) => ( +
  • + +
  • + ))} +
+ )} +
+
+ ); +} diff --git a/packages/features/notifications/package.json b/packages/features/notifications/package.json index 47b5db374..385b9fbde 100644 --- a/packages/features/notifications/package.json +++ b/packages/features/notifications/package.json @@ -22,7 +22,7 @@ "@supabase/supabase-js": "catalog:", "@tanstack/react-query": "catalog:", "@types/react": "catalog:", - "lucide-react": "^0.562.0", + "lucide-react": "catalog:", "react": "catalog:", "react-dom": "catalog:", "react-i18next": "catalog:" diff --git a/packages/features/team-accounts/package.json b/packages/features/team-accounts/package.json index 0565bb432..070c7251e 100644 --- a/packages/features/team-accounts/package.json +++ b/packages/features/team-accounts/package.json @@ -42,7 +42,7 @@ "@types/react-dom": "catalog:", "class-variance-authority": "^0.7.1", "date-fns": "^4.1.0", - "lucide-react": "^0.562.0", + "lucide-react": "catalog:", "next": "catalog:", "react": "catalog:", "react-dom": "catalog:", diff --git a/packages/features/team-accounts/src/components/members/transfer-ownership-dialog.tsx b/packages/features/team-accounts/src/components/members/transfer-ownership-dialog.tsx index 834ff8fd5..25198cded 100644 --- a/packages/features/team-accounts/src/components/members/transfer-ownership-dialog.tsx +++ b/packages/features/team-accounts/src/components/members/transfer-ownership-dialog.tsx @@ -37,8 +37,10 @@ export function TransferOwnershipDialog({ userId: string; targetDisplayName: string; }) { + const [open, setOpen] = useState(false); + return ( - + {children} @@ -56,6 +58,7 @@ export function TransferOwnershipDialog({ accountId={accountId} userId={userId} targetDisplayName={targetDisplayName} + onSuccess={() => setOpen(false)} /> @@ -66,10 +69,12 @@ function TransferOrganizationOwnershipForm({ accountId, userId, targetDisplayName, + onSuccess, }: { userId: string; accountId: string; targetDisplayName: string; + onSuccess: () => unknown; }) { const [pending, startTransition] = useTransition(); const [error, setError] = useState(); @@ -115,6 +120,8 @@ function TransferOrganizationOwnershipForm({ startTransition(async () => { try { await transferOwnershipAction(data); + + onSuccess(); } catch { setError(true); } diff --git a/packages/features/team-accounts/src/components/members/update-member-role-dialog.tsx b/packages/features/team-accounts/src/components/members/update-member-role-dialog.tsx index 8ea0e12fc..9313d358a 100644 --- a/packages/features/team-accounts/src/components/members/update-member-role-dialog.tsx +++ b/packages/features/team-accounts/src/components/members/update-member-role-dialog.tsx @@ -45,9 +45,12 @@ export function UpdateMemberRoleDialog({ userRole: Role; userRoleHierarchy: number; }>) { + const [open, setOpen] = useState(false); + return ( - + {children} + @@ -66,6 +69,7 @@ export function UpdateMemberRoleDialog({ teamAccountId={teamAccountId} userRole={userRole} roles={data} + onSuccess={() => setOpen(false)} /> )} @@ -79,11 +83,13 @@ function UpdateMemberForm({ userRole, teamAccountId, roles, + onSuccess, }: React.PropsWithChildren<{ userId: string; userRole: Role; teamAccountId: string; roles: Role[]; + onSuccess: () => unknown; }>) { const [pending, startTransition] = useTransition(); const [error, setError] = useState(); @@ -97,6 +103,8 @@ function UpdateMemberForm({ userId, role, }); + + onSuccess(); } catch { setError(true); } diff --git a/packages/features/team-accounts/src/server/actions/team-invitations-server-actions.ts b/packages/features/team-accounts/src/server/actions/team-invitations-server-actions.ts index b7b396326..3c27ee3e1 100644 --- a/packages/features/team-accounts/src/server/actions/team-invitations-server-actions.ts +++ b/packages/features/team-accounts/src/server/actions/team-invitations-server-actions.ts @@ -7,6 +7,7 @@ import { z } from 'zod'; import { enhanceAction } from '@kit/next/actions'; import { getLogger } from '@kit/shared/logger'; +import { Database } from '@kit/supabase/database'; import { getSupabaseServerAdminClient } from '@kit/supabase/server-admin-client'; import { getSupabaseServerClient } from '@kit/supabase/server-client'; import { JWTUserData } from '@kit/supabase/types'; @@ -34,8 +35,52 @@ export const createInvitationsAction = enhanceAction( 'User requested to send invitations', ); - // Evaluate invitation policies - const policiesResult = await evaluateInvitationsPolicies(params, user); + const client = getSupabaseServerClient(); + + // Get account ID from slug (needed for permission checks and policies) + const { data: account, error: accountError } = await client + .from('accounts') + .select('id') + .eq('slug', params.accountSlug) + .single(); + + if (accountError || !account) { + logger.error( + { accountSlug: params.accountSlug, error: accountError }, + 'Account not found', + ); + + return { + success: false, + reasons: ['Account not found'], + }; + } + + // Check invitation permissions (replaces RLS policy checks) + const permissionsResult = await checkInvitationPermissions( + account.id, + user.id, + params.invitations, + ); + + if (!permissionsResult.allowed) { + logger.info( + { reason: permissionsResult.reason, userId: user.id }, + 'Invitations blocked by permission check', + ); + + return { + success: false, + reasons: permissionsResult.reason ? [permissionsResult.reason] : [], + }; + } + + // Evaluate custom invitation policies + const policiesResult = await evaluateInvitationsPolicies( + params, + user, + account.id, + ); // If the invitations are not allowed, throw an error if (!policiesResult.allowed) { @@ -51,11 +96,15 @@ export const createInvitationsAction = enhanceAction( } // invitations are allowed, so continue with the action - const client = getSupabaseServerClient(); - const service = createAccountInvitationsService(client); + // Use admin client since we've already validated permissions + const adminClient = getSupabaseServerAdminClient(); + const service = createAccountInvitationsService(adminClient); try { - await service.sendInvitations(params); + await service.sendInvitations({ + ...params, + invitedBy: user.id, + }); revalidateMemberPage(); @@ -194,10 +243,13 @@ function revalidateMemberPage() { * @name evaluateInvitationsPolicies * @description Evaluates invitation policies with performance optimization. * @param params - The invitations to evaluate (emails and roles). + * @param user - The user performing the invitation. + * @param accountId - The account ID (already fetched to avoid duplicate queries). */ async function evaluateInvitationsPolicies( params: z.infer & { accountSlug: string }, user: JWTUserData, + accountId: string, ) { const evaluator = createInvitationsPolicyEvaluator(); const hasPolicies = await evaluator.hasPoliciesForStage('submission'); @@ -212,7 +264,92 @@ async function evaluateInvitationsPolicies( const client = getSupabaseServerClient(); const builder = createInvitationContextBuilder(client); - const context = await builder.buildContext(params, user); + const context = await builder.buildContextWithAccountId( + params, + user, + accountId, + ); return evaluator.canInvite(context, 'submission'); } + +/** + * @name checkInvitationPermissions + * @description Checks if the user has permission to invite members and + * validates role hierarchy for each invitation. + * Optimized to batch all checks in parallel. + */ +async function checkInvitationPermissions( + accountId: string, + userId: string, + invitations: z.infer['invitations'], +): Promise<{ + allowed: boolean; + reason?: string; +}> { + const client = getSupabaseServerClient(); + const logger = await getLogger(); + + const ctx = { + name: 'checkInvitationPermissions', + userId, + accountId, + }; + + // Get unique roles from invitations to minimize RPC calls + const uniqueRoles = [...new Set(invitations.map((inv) => inv.role))]; + + // Run all checks in parallel: permission check + role hierarchy checks for each unique role + const [permissionResult, ...roleResults] = await Promise.all([ + client.rpc('has_permission', { + user_id: userId, + account_id: accountId, + permission_name: + 'invites.manage' as Database['public']['Enums']['app_permissions'], + }), + ...uniqueRoles.map((role) => + Promise.all([ + client.rpc('has_more_elevated_role', { + target_user_id: userId, + target_account_id: accountId, + role_name: role, + }), + client.rpc('has_same_role_hierarchy_level', { + target_user_id: userId, + target_account_id: accountId, + role_name: role, + }), + ]).then(([elevated, sameLevel]) => ({ + role, + allowed: elevated.data || sameLevel.data, + })), + ), + ]); + + // Check permission first + if (!permissionResult.data) { + logger.info(ctx, 'User does not have invites.manage permission'); + + return { + allowed: false, + reason: 'You do not have permission to invite members', + }; + } + + // Check role hierarchy results + const failedRole = roleResults.find((result) => !result.allowed); + + if (failedRole) { + logger.info( + { ...ctx, role: failedRole.role }, + 'User cannot invite to a role higher than their own', + ); + + return { + allowed: false, + reason: `You cannot invite members with the "${failedRole.role}" role`, + }; + } + + return { allowed: true }; +} diff --git a/packages/features/team-accounts/src/server/policies/invitation-context-builder.ts b/packages/features/team-accounts/src/server/policies/invitation-context-builder.ts index 3cc8548d1..b79d5a25d 100644 --- a/packages/features/team-accounts/src/server/policies/invitation-context-builder.ts +++ b/packages/features/team-accounts/src/server/policies/invitation-context-builder.ts @@ -35,10 +35,22 @@ class InvitationContextBuilder { // Fetch all data in parallel for optimal performance const account = await this.getAccount(params.accountSlug); - // Fetch subscription and member count in parallel using account ID + return this.buildContextWithAccountId(params, user, account.id); + } + + /** + * Build policy context when account ID is already known + * (avoids duplicate account lookup) + */ + async buildContextWithAccountId( + params: z.infer & { accountSlug: string }, + user: JWTUserData, + accountId: string, + ): Promise { + // Fetch subscription and member count in parallel const [subscription, memberCount] = await Promise.all([ - this.getSubscription(account.id), - this.getMemberCount(account.id), + this.getSubscription(accountId), + this.getMemberCount(accountId), ]); return { @@ -52,7 +64,7 @@ class InvitationContextBuilder { // Invitation-specific fields accountSlug: params.accountSlug, - accountId: account.id, + accountId, subscription, currentMemberCount: memberCount, invitations: params.invitations, diff --git a/packages/features/team-accounts/src/server/services/account-invitations.service.ts b/packages/features/team-accounts/src/server/services/account-invitations.service.ts index 2bf0088ba..8992e2eca 100644 --- a/packages/features/team-accounts/src/server/services/account-invitations.service.ts +++ b/packages/features/team-accounts/src/server/services/account-invitations.service.ts @@ -139,9 +139,11 @@ class AccountInvitationsService { async sendInvitations({ accountSlug, invitations, + invitedBy, }: { invitations: z.infer['invitations']; accountSlug: string; + invitedBy: string; }) { const logger = await getLogger(); @@ -188,6 +190,7 @@ class AccountInvitationsService { const response = await this.client.rpc('add_invitations_to_account', { invitations, account_slug: accountSlug, + invited_by: invitedBy, }); if (response.error) { diff --git a/packages/supabase/src/database.types.ts b/packages/supabase/src/database.types.ts index 452ae7b4b..0913014b9 100644 --- a/packages/supabase/src/database.types.ts +++ b/packages/supabase/src/database.types.ts @@ -17,10 +17,10 @@ export type Database = { Functions: { graphql: { Args: { + extensions?: Json; operationName?: string; query?: string; variables?: Json; - extensions?: Json; }; Returns: Json; }; @@ -274,11 +274,10 @@ export type Database = { Row: { client_token: string; created_at: string; - description: string | null; expires_at: string; id: string; last_verification_at: string | null; - last_verification_ip: unknown | null; + last_verification_ip: unknown; last_verification_user_agent: string | null; metadata: Json | null; nonce: string; @@ -286,7 +285,6 @@ export type Database = { revoked: boolean; revoked_reason: string | null; scopes: string[] | null; - tags: string[] | null; used_at: string | null; user_id: string | null; verification_attempts: number; @@ -294,11 +292,10 @@ export type Database = { Insert: { client_token: string; created_at?: string; - description?: string | null; expires_at: string; id?: string; last_verification_at?: string | null; - last_verification_ip?: unknown | null; + last_verification_ip?: unknown; last_verification_user_agent?: string | null; metadata?: Json | null; nonce: string; @@ -306,7 +303,6 @@ export type Database = { revoked?: boolean; revoked_reason?: string | null; scopes?: string[] | null; - tags?: string[] | null; used_at?: string | null; user_id?: string | null; verification_attempts?: number; @@ -314,11 +310,10 @@ export type Database = { Update: { client_token?: string; created_at?: string; - description?: string | null; expires_at?: string; id?: string; last_verification_at?: string | null; - last_verification_ip?: unknown | null; + last_verification_ip?: unknown; last_verification_user_agent?: string | null; metadata?: Json | null; nonce?: string; @@ -326,7 +321,6 @@ export type Database = { revoked?: boolean; revoked_reason?: string | null; scopes?: string[] | null; - tags?: string[] | null; used_at?: string | null; user_id?: string | null; verification_attempts?: number; @@ -702,32 +696,23 @@ export type Database = { }; Functions: { accept_invitation: { - Args: { - token: string; - user_id: string; - }; + Args: { token: string; user_id: string }; Returns: string; }; add_invitations_to_account: { Args: { account_slug: string; invitations: Database['public']['CompositeTypes']['invitation'][]; + invited_by: string; }; Returns: Database['public']['Tables']['invitations']['Row'][]; }; can_action_account_member: { - Args: { - target_team_account_id: string; - target_user_id: string; - }; + Args: { target_team_account_id: string; target_user_id: string }; Returns: boolean; }; create_invitation: { - Args: { - account_id: string; - email: string; - role: string; - }; + Args: { account_id: string; email: string; role: string }; Returns: { account_id: string; created_at: string; @@ -739,24 +724,26 @@ export type Database = { role: string; updated_at: string; }; + SetofOptions: { + from: '*'; + to: 'invitations'; + isOneToOne: true; + isSetofReturn: false; + }; }; create_nonce: { Args: { - p_user_id?: string; - p_purpose?: string; p_expires_in_seconds?: number; p_metadata?: Json; - p_description?: string; - p_tags?: string[]; - p_scopes?: string[]; + p_purpose?: string; p_revoke_previous?: boolean; + p_scopes?: string[]; + p_user_id?: string; }; Returns: Json; }; create_team_account: { - Args: { - account_name: string; - }; + Args: { account_name: string }; Returns: { created_at: string | null; created_by: string | null; @@ -771,174 +758,124 @@ export type Database = { updated_at: string | null; updated_by: string | null; }; + SetofOptions: { + from: '*'; + to: 'accounts'; + isOneToOne: true; + isSetofReturn: false; + }; }; get_account_invitations: { - Args: { - account_slug: string; - }; + Args: { account_slug: string }; Returns: { - id: number; - email: string; account_id: string; - invited_by: string; - role: string; created_at: string; - updated_at: string; + email: string; expires_at: string; - inviter_name: string; + id: number; + invited_by: string; inviter_email: string; + inviter_name: string; + role: string; + updated_at: string; }[]; }; get_account_members: { - Args: { - account_slug: string; - }; + Args: { account_slug: string }; Returns: { - id: string; - user_id: string; account_id: string; + created_at: string; + email: string; + id: string; + name: string; + picture_url: string; + primary_owner_user_id: string; role: string; role_hierarchy_level: number; - primary_owner_user_id: string; - name: string; - email: string; - picture_url: string; - created_at: string; updated_at: string; + user_id: string; }[]; }; - get_config: { - Args: Record; - Returns: Json; - }; - get_nonce_status: { - Args: { - p_id: string; - }; - Returns: Json; - }; - get_upper_system_role: { - Args: Record; - Returns: string; - }; + get_config: { Args: never; Returns: Json }; + get_nonce_status: { Args: { p_id: string }; Returns: Json }; + get_upper_system_role: { Args: never; Returns: string }; has_active_subscription: { - Args: { - target_account_id: string; - }; + Args: { target_account_id: string }; Returns: boolean; }; has_more_elevated_role: { Args: { - target_user_id: string; - target_account_id: string; role_name: string; + target_account_id: string; + target_user_id: string; }; Returns: boolean; }; has_permission: { Args: { - user_id: string; account_id: string; permission_name: Database['public']['Enums']['app_permissions']; + user_id: string; }; Returns: boolean; }; has_role_on_account: { - Args: { - account_id: string; - account_role?: string; - }; + Args: { account_id: string; account_role?: string }; Returns: boolean; }; has_same_role_hierarchy_level: { Args: { - target_user_id: string; - target_account_id: string; role_name: string; - }; - Returns: boolean; - }; - install_extensions: { - Args: Record; - Returns: undefined; - }; - is_aal2: { - Args: Record; - Returns: boolean; - }; - is_account_owner: { - Args: { - account_id: string; - }; - Returns: boolean; - }; - is_account_team_member: { - Args: { target_account_id: string; + target_user_id: string; }; Returns: boolean; }; - is_mfa_compliant: { - Args: Record; - Returns: boolean; - }; - is_set: { - Args: { - field_name: string; - }; - Returns: boolean; - }; - is_super_admin: { - Args: Record; + is_aal2: { Args: never; Returns: boolean }; + is_account_owner: { Args: { account_id: string }; Returns: boolean }; + is_account_team_member: { + Args: { target_account_id: string }; Returns: boolean; }; + is_mfa_compliant: { Args: never; Returns: boolean }; + is_set: { Args: { field_name: string }; Returns: boolean }; + is_super_admin: { Args: never; Returns: boolean }; is_team_member: { - Args: { - account_id: string; - user_id: string; - }; + Args: { account_id: string; user_id: string }; Returns: boolean; }; revoke_nonce: { - Args: { - p_id: string; - p_reason?: string; - }; + Args: { p_id: string; p_reason?: string }; Returns: boolean; }; team_account_workspace: { - Args: { - account_slug: string; - }; + Args: { account_slug: string }; Returns: { id: string; name: string; + permissions: Database['public']['Enums']['app_permissions'][]; picture_url: string; - slug: string; + primary_owner_user_id: string; role: string; role_hierarchy_level: number; - primary_owner_user_id: string; + slug: string; subscription_status: Database['public']['Enums']['subscription_status']; - permissions: Database['public']['Enums']['app_permissions'][]; }[]; }; transfer_team_account_ownership: { - Args: { - target_account_id: string; - new_owner_id: string; - }; + Args: { new_owner_id: string; target_account_id: string }; Returns: undefined; }; upsert_order: { Args: { + billing_provider: Database['public']['Enums']['billing_provider']; + currency: string; + line_items: Json; + status: Database['public']['Enums']['payment_status']; target_account_id: string; target_customer_id: string; target_order_id: string; - status: Database['public']['Enums']['payment_status']; - billing_provider: Database['public']['Enums']['billing_provider']; total_amount: number; - currency: string; - line_items: Json; }; Returns: { account_id: string; @@ -951,22 +888,28 @@ export type Database = { total_amount: number; updated_at: string; }; + SetofOptions: { + from: '*'; + to: 'orders'; + isOneToOne: true; + isSetofReturn: false; + }; }; upsert_subscription: { Args: { - target_account_id: string; - target_customer_id: string; - target_subscription_id: string; active: boolean; - status: Database['public']['Enums']['subscription_status']; billing_provider: Database['public']['Enums']['billing_provider']; cancel_at_period_end: boolean; currency: string; - period_starts_at: string; - period_ends_at: string; line_items: Json; - trial_starts_at?: string; + period_ends_at: string; + period_starts_at: string; + status: Database['public']['Enums']['subscription_status']; + target_account_id: string; + target_customer_id: string; + target_subscription_id: string; trial_ends_at?: string; + trial_starts_at?: string; }; Returns: { account_id: string; @@ -984,16 +927,22 @@ export type Database = { trial_starts_at: string | null; updated_at: string; }; + SetofOptions: { + from: '*'; + to: 'subscriptions'; + isOneToOne: true; + isSetofReturn: false; + }; }; verify_nonce: { Args: { - p_token: string; - p_purpose: string; - p_user_id?: string; - p_required_scopes?: string[]; - p_max_verification_attempts?: number; p_ip?: unknown; + p_max_verification_attempts?: number; + p_purpose: string; + p_required_scopes?: string[]; + p_token: string; p_user_agent?: string; + p_user_id?: string; }; Returns: Json; }; @@ -1040,6 +989,7 @@ export type Database = { owner: string | null; owner_id: string | null; public: boolean | null; + type: Database['storage']['Enums']['buckettype']; updated_at: string | null; }; Insert: { @@ -1052,6 +1002,7 @@ export type Database = { owner?: string | null; owner_id?: string | null; public?: boolean | null; + type?: Database['storage']['Enums']['buckettype']; updated_at?: string | null; }; Update: { @@ -1064,10 +1015,157 @@ export type Database = { owner?: string | null; owner_id?: string | null; public?: boolean | null; + type?: Database['storage']['Enums']['buckettype']; updated_at?: string | null; }; Relationships: []; }; + buckets_analytics: { + Row: { + created_at: string; + deleted_at: string | null; + format: string; + id: string; + name: string; + type: Database['storage']['Enums']['buckettype']; + updated_at: string; + }; + Insert: { + created_at?: string; + deleted_at?: string | null; + format?: string; + id?: string; + name: string; + type?: Database['storage']['Enums']['buckettype']; + updated_at?: string; + }; + Update: { + created_at?: string; + deleted_at?: string | null; + format?: string; + id?: string; + name?: string; + type?: Database['storage']['Enums']['buckettype']; + updated_at?: string; + }; + Relationships: []; + }; + buckets_vectors: { + Row: { + created_at: string; + id: string; + type: Database['storage']['Enums']['buckettype']; + updated_at: string; + }; + Insert: { + created_at?: string; + id: string; + type?: Database['storage']['Enums']['buckettype']; + updated_at?: string; + }; + Update: { + created_at?: string; + id?: string; + type?: Database['storage']['Enums']['buckettype']; + updated_at?: string; + }; + Relationships: []; + }; + iceberg_namespaces: { + Row: { + bucket_name: string; + catalog_id: string; + created_at: string; + id: string; + metadata: Json; + name: string; + updated_at: string; + }; + Insert: { + bucket_name: string; + catalog_id: string; + created_at?: string; + id?: string; + metadata?: Json; + name: string; + updated_at?: string; + }; + Update: { + bucket_name?: string; + catalog_id?: string; + created_at?: string; + id?: string; + metadata?: Json; + name?: string; + updated_at?: string; + }; + Relationships: [ + { + foreignKeyName: 'iceberg_namespaces_catalog_id_fkey'; + columns: ['catalog_id']; + isOneToOne: false; + referencedRelation: 'buckets_analytics'; + referencedColumns: ['id']; + }, + ]; + }; + iceberg_tables: { + Row: { + bucket_name: string; + catalog_id: string; + created_at: string; + id: string; + location: string; + name: string; + namespace_id: string; + remote_table_id: string | null; + shard_id: string | null; + shard_key: string | null; + updated_at: string; + }; + Insert: { + bucket_name: string; + catalog_id: string; + created_at?: string; + id?: string; + location: string; + name: string; + namespace_id: string; + remote_table_id?: string | null; + shard_id?: string | null; + shard_key?: string | null; + updated_at?: string; + }; + Update: { + bucket_name?: string; + catalog_id?: string; + created_at?: string; + id?: string; + location?: string; + name?: string; + namespace_id?: string; + remote_table_id?: string | null; + shard_id?: string | null; + shard_key?: string | null; + updated_at?: string; + }; + Relationships: [ + { + foreignKeyName: 'iceberg_tables_catalog_id_fkey'; + columns: ['catalog_id']; + isOneToOne: false; + referencedRelation: 'buckets_analytics'; + referencedColumns: ['id']; + }, + { + foreignKeyName: 'iceberg_tables_namespace_id_fkey'; + columns: ['namespace_id']; + isOneToOne: false; + referencedRelation: 'iceberg_namespaces'; + referencedColumns: ['id']; + }, + ]; + }; migrations: { Row: { executed_at: string | null; @@ -1095,6 +1193,7 @@ export type Database = { created_at: string | null; id: string; last_accessed_at: string | null; + level: number | null; metadata: Json | null; name: string | null; owner: string | null; @@ -1109,6 +1208,7 @@ export type Database = { created_at?: string | null; id?: string; last_accessed_at?: string | null; + level?: number | null; metadata?: Json | null; name?: string | null; owner?: string | null; @@ -1123,6 +1223,7 @@ export type Database = { created_at?: string | null; id?: string; last_accessed_at?: string | null; + level?: number | null; metadata?: Json | null; name?: string | null; owner?: string | null; @@ -1142,6 +1243,38 @@ export type Database = { }, ]; }; + prefixes: { + Row: { + bucket_id: string; + created_at: string | null; + level: number; + name: string; + updated_at: string | null; + }; + Insert: { + bucket_id: string; + created_at?: string | null; + level?: number; + name: string; + updated_at?: string | null; + }; + Update: { + bucket_id?: string; + created_at?: string | null; + level?: number; + name?: string; + updated_at?: string | null; + }; + Relationships: [ + { + foreignKeyName: 'prefixes_bucketId_fkey'; + columns: ['bucket_id']; + isOneToOne: false; + referencedRelation: 'buckets'; + referencedColumns: ['id']; + }, + ]; + }; s3_multipart_uploads: { Row: { bucket_id: string; @@ -1240,103 +1373,240 @@ export type Database = { }, ]; }; + vector_indexes: { + Row: { + bucket_id: string; + created_at: string; + data_type: string; + dimension: number; + distance_metric: string; + id: string; + metadata_configuration: Json | null; + name: string; + updated_at: string; + }; + Insert: { + bucket_id: string; + created_at?: string; + data_type: string; + dimension: number; + distance_metric: string; + id?: string; + metadata_configuration?: Json | null; + name: string; + updated_at?: string; + }; + Update: { + bucket_id?: string; + created_at?: string; + data_type?: string; + dimension?: number; + distance_metric?: string; + id?: string; + metadata_configuration?: Json | null; + name?: string; + updated_at?: string; + }; + Relationships: [ + { + foreignKeyName: 'vector_indexes_bucket_id_fkey'; + columns: ['bucket_id']; + isOneToOne: false; + referencedRelation: 'buckets_vectors'; + referencedColumns: ['id']; + }, + ]; + }; }; Views: { [_ in never]: never; }; Functions: { - can_insert_object: { - Args: { - bucketid: string; - name: string; - owner: string; - metadata: Json; - }; + add_prefixes: { + Args: { _bucket_id: string; _name: string }; Returns: undefined; }; - extension: { - Args: { - name: string; - }; - Returns: string; + can_insert_object: { + Args: { bucketid: string; metadata: Json; name: string; owner: string }; + Returns: undefined; }; - filename: { - Args: { - name: string; - }; - Returns: string; + delete_leaf_prefixes: { + Args: { bucket_ids: string[]; names: string[] }; + Returns: undefined; }; - foldername: { - Args: { - name: string; - }; - Returns: string[]; + delete_prefix: { + Args: { _bucket_id: string; _name: string }; + Returns: boolean; }; + extension: { Args: { name: string }; Returns: string }; + filename: { Args: { name: string }; Returns: string }; + foldername: { Args: { name: string }; Returns: string[] }; + get_level: { Args: { name: string }; Returns: number }; + get_prefix: { Args: { name: string }; Returns: string }; + get_prefixes: { Args: { name: string }; Returns: string[] }; get_size_by_bucket: { - Args: Record; + Args: never; Returns: { - size: number; bucket_id: string; + size: number; }[]; }; list_multipart_uploads_with_delimiter: { Args: { bucket_id: string; - prefix_param: string; delimiter_param: string; max_keys?: number; next_key_token?: string; next_upload_token?: string; + prefix_param: string; }; Returns: { - key: string; - id: string; created_at: string; + id: string; + key: string; }[]; }; list_objects_with_delimiter: { Args: { bucket_id: string; - prefix_param: string; delimiter_param: string; max_keys?: number; - start_after?: string; next_token?: string; + prefix_param: string; + start_after?: string; }; Returns: { - name: string; id: string; metadata: Json; + name: string; updated_at: string; }[]; }; - operation: { - Args: Record; - Returns: string; + lock_top_prefixes: { + Args: { bucket_ids: string[]; names: string[] }; + Returns: undefined; }; - search: { + operation: { Args: never; Returns: string }; + search: + | { + Args: { + bucketname: string; + levels?: number; + limits?: number; + offsets?: number; + prefix: string; + }; + Returns: { + created_at: string; + id: string; + last_accessed_at: string; + metadata: Json; + name: string; + updated_at: string; + }[]; + } + | { + Args: { + bucketname: string; + levels?: number; + limits?: number; + offsets?: number; + prefix: string; + search?: string; + sortcolumn?: string; + sortorder?: string; + }; + Returns: { + created_at: string; + id: string; + last_accessed_at: string; + metadata: Json; + name: string; + updated_at: string; + }[]; + }; + search_legacy_v1: { Args: { - prefix: string; bucketname: string; - limits?: number; levels?: number; + limits?: number; offsets?: number; + prefix: string; search?: string; sortcolumn?: string; sortorder?: string; }; Returns: { - name: string; - id: string; - updated_at: string; created_at: string; + id: string; last_accessed_at: string; metadata: Json; + name: string; + updated_at: string; }[]; }; + search_v1_optimised: { + Args: { + bucketname: string; + levels?: number; + limits?: number; + offsets?: number; + prefix: string; + search?: string; + sortcolumn?: string; + sortorder?: string; + }; + Returns: { + created_at: string; + id: string; + last_accessed_at: string; + metadata: Json; + name: string; + updated_at: string; + }[]; + }; + search_v2: + | { + Args: { + bucket_name: string; + levels?: number; + limits?: number; + prefix: string; + start_after?: string; + }; + Returns: { + created_at: string; + id: string; + key: string; + metadata: Json; + name: string; + updated_at: string; + }[]; + } + | { + Args: { + bucket_name: string; + levels?: number; + limits?: number; + prefix: string; + sort_column?: string; + sort_column_after?: string; + sort_order?: string; + start_after?: string; + }; + Returns: { + created_at: string; + id: string; + key: string; + last_accessed_at: string; + metadata: Json; + name: string; + updated_at: string; + }[]; + }; }; Enums: { - [_ in never]: never; + buckettype: 'STANDARD' | 'ANALYTICS' | 'VECTOR'; }; CompositeTypes: { [_ in never]: never; @@ -1344,27 +1614,36 @@ export type Database = { }; }; -type PublicSchema = Database[Extract]; +type DatabaseWithoutInternals = Omit; + +type DefaultSchema = DatabaseWithoutInternals[Extract< + keyof Database, + 'public' +>]; export type Tables< - PublicTableNameOrOptions extends - | keyof (PublicSchema['Tables'] & PublicSchema['Views']) - | { schema: keyof Database }, - TableName extends PublicTableNameOrOptions extends { schema: keyof Database } - ? keyof (Database[PublicTableNameOrOptions['schema']]['Tables'] & - Database[PublicTableNameOrOptions['schema']]['Views']) + DefaultSchemaTableNameOrOptions extends + | keyof (DefaultSchema['Tables'] & DefaultSchema['Views']) + | { schema: keyof DatabaseWithoutInternals }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals; + } + ? keyof (DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions['schema']]['Tables'] & + DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions['schema']]['Views']) : never = never, -> = PublicTableNameOrOptions extends { schema: keyof Database } - ? (Database[PublicTableNameOrOptions['schema']]['Tables'] & - Database[PublicTableNameOrOptions['schema']]['Views'])[TableName] extends { +> = DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals; +} + ? (DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions['schema']]['Tables'] & + DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions['schema']]['Views'])[TableName] extends { Row: infer R; } ? R : never - : PublicTableNameOrOptions extends keyof (PublicSchema['Tables'] & - PublicSchema['Views']) - ? (PublicSchema['Tables'] & - PublicSchema['Views'])[PublicTableNameOrOptions] extends { + : DefaultSchemaTableNameOrOptions extends keyof (DefaultSchema['Tables'] & + DefaultSchema['Views']) + ? (DefaultSchema['Tables'] & + DefaultSchema['Views'])[DefaultSchemaTableNameOrOptions] extends { Row: infer R; } ? R @@ -1372,20 +1651,24 @@ export type Tables< : never; export type TablesInsert< - PublicTableNameOrOptions extends - | keyof PublicSchema['Tables'] - | { schema: keyof Database }, - TableName extends PublicTableNameOrOptions extends { schema: keyof Database } - ? keyof Database[PublicTableNameOrOptions['schema']]['Tables'] + DefaultSchemaTableNameOrOptions extends + | keyof DefaultSchema['Tables'] + | { schema: keyof DatabaseWithoutInternals }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals; + } + ? keyof DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions['schema']]['Tables'] : never = never, -> = PublicTableNameOrOptions extends { schema: keyof Database } - ? Database[PublicTableNameOrOptions['schema']]['Tables'][TableName] extends { +> = DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals; +} + ? DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions['schema']]['Tables'][TableName] extends { Insert: infer I; } ? I : never - : PublicTableNameOrOptions extends keyof PublicSchema['Tables'] - ? PublicSchema['Tables'][PublicTableNameOrOptions] extends { + : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema['Tables'] + ? DefaultSchema['Tables'][DefaultSchemaTableNameOrOptions] extends { Insert: infer I; } ? I @@ -1393,20 +1676,24 @@ export type TablesInsert< : never; export type TablesUpdate< - PublicTableNameOrOptions extends - | keyof PublicSchema['Tables'] - | { schema: keyof Database }, - TableName extends PublicTableNameOrOptions extends { schema: keyof Database } - ? keyof Database[PublicTableNameOrOptions['schema']]['Tables'] + DefaultSchemaTableNameOrOptions extends + | keyof DefaultSchema['Tables'] + | { schema: keyof DatabaseWithoutInternals }, + TableName extends DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals; + } + ? keyof DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions['schema']]['Tables'] : never = never, -> = PublicTableNameOrOptions extends { schema: keyof Database } - ? Database[PublicTableNameOrOptions['schema']]['Tables'][TableName] extends { +> = DefaultSchemaTableNameOrOptions extends { + schema: keyof DatabaseWithoutInternals; +} + ? DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions['schema']]['Tables'][TableName] extends { Update: infer U; } ? U : never - : PublicTableNameOrOptions extends keyof PublicSchema['Tables'] - ? PublicSchema['Tables'][PublicTableNameOrOptions] extends { + : DefaultSchemaTableNameOrOptions extends keyof DefaultSchema['Tables'] + ? DefaultSchema['Tables'][DefaultSchemaTableNameOrOptions] extends { Update: infer U; } ? U @@ -1414,29 +1701,72 @@ export type TablesUpdate< : never; export type Enums< - PublicEnumNameOrOptions extends - | keyof PublicSchema['Enums'] - | { schema: keyof Database }, - EnumName extends PublicEnumNameOrOptions extends { schema: keyof Database } - ? keyof Database[PublicEnumNameOrOptions['schema']]['Enums'] + DefaultSchemaEnumNameOrOptions extends + | keyof DefaultSchema['Enums'] + | { schema: keyof DatabaseWithoutInternals }, + EnumName extends DefaultSchemaEnumNameOrOptions extends { + schema: keyof DatabaseWithoutInternals; + } + ? keyof DatabaseWithoutInternals[DefaultSchemaEnumNameOrOptions['schema']]['Enums'] : never = never, -> = PublicEnumNameOrOptions extends { schema: keyof Database } - ? Database[PublicEnumNameOrOptions['schema']]['Enums'][EnumName] - : PublicEnumNameOrOptions extends keyof PublicSchema['Enums'] - ? PublicSchema['Enums'][PublicEnumNameOrOptions] +> = DefaultSchemaEnumNameOrOptions extends { + schema: keyof DatabaseWithoutInternals; +} + ? DatabaseWithoutInternals[DefaultSchemaEnumNameOrOptions['schema']]['Enums'][EnumName] + : DefaultSchemaEnumNameOrOptions extends keyof DefaultSchema['Enums'] + ? DefaultSchema['Enums'][DefaultSchemaEnumNameOrOptions] : never; export type CompositeTypes< PublicCompositeTypeNameOrOptions extends - | keyof PublicSchema['CompositeTypes'] - | { schema: keyof Database }, + | keyof DefaultSchema['CompositeTypes'] + | { schema: keyof DatabaseWithoutInternals }, CompositeTypeName extends PublicCompositeTypeNameOrOptions extends { - schema: keyof Database; + schema: keyof DatabaseWithoutInternals; } - ? keyof Database[PublicCompositeTypeNameOrOptions['schema']]['CompositeTypes'] + ? keyof DatabaseWithoutInternals[PublicCompositeTypeNameOrOptions['schema']]['CompositeTypes'] : never = never, -> = PublicCompositeTypeNameOrOptions extends { schema: keyof Database } - ? Database[PublicCompositeTypeNameOrOptions['schema']]['CompositeTypes'][CompositeTypeName] - : PublicCompositeTypeNameOrOptions extends keyof PublicSchema['CompositeTypes'] - ? PublicSchema['CompositeTypes'][PublicCompositeTypeNameOrOptions] +> = PublicCompositeTypeNameOrOptions extends { + schema: keyof DatabaseWithoutInternals; +} + ? DatabaseWithoutInternals[PublicCompositeTypeNameOrOptions['schema']]['CompositeTypes'][CompositeTypeName] + : PublicCompositeTypeNameOrOptions extends keyof DefaultSchema['CompositeTypes'] + ? DefaultSchema['CompositeTypes'][PublicCompositeTypeNameOrOptions] : never; + +export const Constants = { + graphql_public: { + Enums: {}, + }, + public: { + Enums: { + app_permissions: [ + 'roles.manage', + 'billing.manage', + 'settings.manage', + 'members.manage', + 'invites.manage', + ], + billing_provider: ['stripe', 'lemon-squeezy', 'paddle'], + notification_channel: ['in_app', 'email'], + notification_type: ['info', 'warning', 'error'], + payment_status: ['pending', 'succeeded', 'failed'], + subscription_item_type: ['flat', 'per_seat', 'metered'], + subscription_status: [ + 'active', + 'trialing', + 'past_due', + 'canceled', + 'unpaid', + 'incomplete', + 'incomplete_expired', + 'paused', + ], + }, + }, + storage: { + Enums: { + buckettype: ['STANDARD', 'ANALYTICS', 'VECTOR'], + }, + }, +} as const; diff --git a/packages/supabase/src/hooks/use-sign-up-with-email-password.ts b/packages/supabase/src/hooks/use-sign-up-with-email-password.ts index 821482f93..7523b96b9 100644 --- a/packages/supabase/src/hooks/use-sign-up-with-email-password.ts +++ b/packages/supabase/src/hooks/use-sign-up-with-email-password.ts @@ -9,6 +9,21 @@ interface Credentials { captchaToken?: string; } +const _WeakPasswordReasons = ['length', 'characters', 'pwned'] as const; + +export type WeakPasswordReason = (typeof _WeakPasswordReasons)[number]; + +export class WeakPasswordError extends Error { + readonly code = 'weak_password'; + readonly reasons: WeakPasswordReason[]; + + constructor(reasons: WeakPasswordReason[]) { + super('weak_password'); + this.name = 'WeakPasswordError'; + this.reasons = reasons; + } +} + export function useSignUpWithEmailAndPassword() { const client = useSupabase(); const mutationKey = ['auth', 'sign-up-with-email-password']; @@ -25,6 +40,15 @@ export function useSignUpWithEmailAndPassword() { }); if (response.error) { + // Handle weak password errors specially (AuthWeakPasswordError from Supabase) + if (response.error.code === 'weak_password') { + const errorObj = response.error as unknown as { + reasons?: WeakPasswordReason[]; + }; + + throw new WeakPasswordError(errorObj.reasons ?? []); + } + throw response.error.message; } diff --git a/packages/ui/package.json b/packages/ui/package.json index 8fb0cc0f0..68f7a2619 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -14,7 +14,7 @@ "clsx": "^2.1.1", "cmdk": "1.1.1", "input-otp": "1.4.2", - "lucide-react": "^0.562.0", + "lucide-react": "catalog:", "radix-ui": "1.4.3", "react-dropzone": "^14.3.8", "react-top-loading-bar": "3.0.2", diff --git a/packages/ui/src/makerkit/version-updater.tsx b/packages/ui/src/makerkit/version-updater.tsx index cac6d5e57..a99b2bede 100644 --- a/packages/ui/src/makerkit/version-updater.tsx +++ b/packages/ui/src/makerkit/version-updater.tsx @@ -23,9 +23,9 @@ let version: string | null = null; /** * Default interval time in seconds to check for new version - * By default, it is set to 120 seconds + * By default, it is set to 60 seconds */ -const DEFAULT_REFETCH_INTERVAL = 120; +const DEFAULT_REFETCH_INTERVAL = 60; /** * Default interval time in seconds to check for new version @@ -99,7 +99,9 @@ function useVersionUpdater(props: { intervalTimeInSecond?: number } = {}) { refetchInterval, initialData: null, queryFn: async () => { - const response = await fetch('/version'); + const url = new URL('/api/version', process.env.NEXT_PUBLIC_SITE_URL); + const response = await fetch(url.toString()); + const currentVersion = await response.text(); const oldVersion = version; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 072c7f742..017e535c3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,12 +6,21 @@ settings: catalogs: default: + '@marsidev/react-turnstile': + specifier: 1.4.1 + version: 1.4.1 '@next/bundle-analyzer': specifier: 16.1.1 version: 16.1.1 '@next/eslint-plugin-next': specifier: 16.1.1 version: 16.1.1 + '@stripe/react-stripe-js': + specifier: 5.4.1 + version: 5.4.1 + '@stripe/stripe-js': + specifier: 8.6.1 + version: 8.6.1 '@supabase/supabase-js': specifier: 2.89.0 version: 2.89.0 @@ -19,8 +28,8 @@ catalogs: specifier: 4.1.18 version: 4.1.18 '@tanstack/react-query': - specifier: 5.90.12 - version: 5.90.12 + specifier: 5.90.16 + version: 5.90.16 '@types/node': specifier: 25.0.3 version: 25.0.3 @@ -33,6 +42,9 @@ catalogs: eslint-config-next: specifier: 16.1.1 version: 16.1.1 + lucide-react: + specifier: 0.562.0 + version: 0.562.0 next: specifier: 16.1.1 version: 16.1.1 @@ -43,14 +55,17 @@ catalogs: specifier: 19.2.3 version: 19.2.3 react-hook-form: - specifier: 7.69.0 - version: 7.69.0 + specifier: 7.70.0 + version: 7.70.0 react-i18next: - specifier: 16.5.0 - version: 16.5.0 + specifier: 16.5.1 + version: 16.5.1 + stripe: + specifier: 20.1.1 + version: 20.1.1 supabase: - specifier: 2.70.3 - version: 2.70.3 + specifier: 2.71.1 + version: 2.71.1 tailwindcss: specifier: 4.1.18 version: 4.1.18 @@ -70,7 +85,7 @@ importers: version: 0.25.1 '@turbo/gen': specifier: ^2.7.0 - version: 2.7.0(@types/node@25.0.3)(typescript@5.9.3) + version: 2.7.3(@types/node@25.0.3)(typescript@5.9.3) cross-env: specifier: ^10.0.0 version: 10.1.0 @@ -78,8 +93,8 @@ importers: specifier: ^3.7.4 version: 3.7.4 turbo: - specifier: 2.7.1 - version: 2.7.1 + specifier: 2.7.3 + version: 2.7.3 typescript: specifier: ^5.9.3 version: 5.9.3 @@ -94,15 +109,15 @@ importers: version: 10.1.0 '@hookform/resolvers': specifier: ^5.2.2 - version: 5.2.2(react-hook-form@7.69.0(react@19.2.3)) + version: 5.2.2(react-hook-form@7.70.0(react@19.2.3)) '@tanstack/react-query': specifier: 'catalog:' - version: 5.90.12(react@19.2.3) + version: 5.90.16(react@19.2.3) ai: specifier: 5.0.116 version: 5.0.116(zod@3.25.76) lucide-react: - specifier: ^0.562.0 + specifier: 'catalog:' version: 0.562.0(react@19.2.3) next: specifier: 'catalog:' @@ -167,7 +182,7 @@ importers: version: 13.0.0 react-hook-form: specifier: 'catalog:' - version: 7.69.0(react@19.2.3) + version: 7.70.0(react@19.2.3) recharts: specifier: 2.15.3 version: 2.15.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -212,7 +227,7 @@ importers: version: 2.5.3-cloudflare-rc1(next@16.1.1(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)) '@hookform/resolvers': specifier: ^5.2.2 - version: 5.2.2(react-hook-form@7.69.0(react@19.2.3)) + version: 5.2.2(react-hook-form@7.70.0(react@19.2.3)) '@kit/accounts': specifier: workspace:* version: link:../../packages/features/accounts @@ -272,13 +287,13 @@ importers: version: 0.0.10(@supabase/postgrest-js@2.89.0)(@supabase/supabase-js@2.89.0) '@makerkit/data-loader-supabase-nextjs': specifier: ^1.2.5 - version: 1.2.5(@supabase/postgrest-js@2.89.0)(@supabase/supabase-js@2.89.0)(@tanstack/react-query@5.90.12(react@19.2.3))(next@16.1.1(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3) + version: 1.2.5(@supabase/postgrest-js@2.89.0)(@supabase/supabase-js@2.89.0)(@tanstack/react-query@5.90.16(react@19.2.3))(next@16.1.1(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3) '@marsidev/react-turnstile': - specifier: ^1.4.0 - version: 1.4.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + specifier: ^1.4.1 + version: 1.4.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@nosecone/next': - specifier: 1.0.0-beta.15 - version: 1.0.0-beta.15(next@16.1.1(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)) + specifier: 1.0.0-beta.16 + version: 1.0.0-beta.16(next@16.1.1(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)) '@radix-ui/react-icons': specifier: ^1.3.2 version: 1.3.2(react@19.2.3) @@ -287,7 +302,7 @@ importers: version: 2.89.0 '@tanstack/react-query': specifier: 'catalog:' - version: 5.90.12(react@19.2.3) + version: 5.90.16(react@19.2.3) '@tanstack/react-table': specifier: ^8.21.3 version: 8.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -295,7 +310,7 @@ importers: specifier: ^4.1.0 version: 4.1.0 lucide-react: - specifier: ^0.562.0 + specifier: 'catalog:' version: 0.562.0(react@19.2.3) next: specifier: 'catalog:' @@ -314,10 +329,10 @@ importers: version: 19.2.3(react@19.2.3) react-hook-form: specifier: 'catalog:' - version: 7.69.0(react@19.2.3) + version: 7.70.0(react@19.2.3) react-i18next: specifier: 'catalog:' - version: 16.5.0(i18next@25.7.3(typescript@5.9.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + version: 16.5.1(i18next@25.7.3(typescript@5.9.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) recharts: specifier: 2.15.3 version: 2.15.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -372,7 +387,7 @@ importers: version: 3.7.4 supabase: specifier: 'catalog:' - version: 2.70.3 + version: 2.71.1 tailwindcss: specifier: 'catalog:' version: 4.1.18 @@ -420,7 +435,7 @@ importers: devDependencies: '@hookform/resolvers': specifier: ^5.2.2 - version: 5.2.2(react-hook-form@7.69.0(react@19.2.3)) + version: 5.2.2(react-hook-form@7.70.0(react@19.2.3)) '@kit/billing': specifier: workspace:* version: link:../core @@ -458,7 +473,7 @@ importers: specifier: ^4.1.0 version: 4.1.0 lucide-react: - specifier: ^0.562.0 + specifier: 'catalog:' version: 0.562.0(react@19.2.3) next: specifier: 'catalog:' @@ -468,10 +483,10 @@ importers: version: 19.2.3 react-hook-form: specifier: 'catalog:' - version: 7.69.0(react@19.2.3) + version: 7.70.0(react@19.2.3) react-i18next: specifier: 'catalog:' - version: 16.5.0(i18next@25.7.3(typescript@5.9.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + version: 16.5.1(i18next@25.7.3(typescript@5.9.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) zod: specifier: 3.25.76 version: 3.25.76 @@ -519,14 +534,14 @@ importers: packages/billing/stripe: dependencies: '@stripe/react-stripe-js': - specifier: ^5.4.1 - version: 5.4.1(@stripe/stripe-js@8.6.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + specifier: 'catalog:' + version: 5.4.1(@stripe/stripe-js@8.6.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@stripe/stripe-js': - specifier: ^8.6.0 - version: 8.6.0 + specifier: 'catalog:' + version: 8.6.1 stripe: - specifier: ^20.1.0 - version: 20.1.0(@types/node@25.0.3) + specifier: 'catalog:' + version: 20.1.1(@types/node@25.0.3) devDependencies: '@kit/billing': specifier: workspace:* @@ -707,8 +722,8 @@ importers: packages/email-templates: dependencies: '@react-email/components': - specifier: 1.0.2 - version: 1.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + specifier: 1.0.3 + version: 1.0.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) devDependencies: '@kit/eslint-config': specifier: workspace:* @@ -731,7 +746,7 @@ importers: devDependencies: '@hookform/resolvers': specifier: ^5.2.2 - version: 5.2.2(react-hook-form@7.69.0(react@19.2.3)) + version: 5.2.2(react-hook-form@7.70.0(react@19.2.3)) '@kit/billing-gateway': specifier: workspace:* version: link:../../billing/gateway @@ -776,7 +791,7 @@ importers: version: 2.89.0 '@tanstack/react-query': specifier: 'catalog:' - version: 5.90.12(react@19.2.3) + version: 5.90.16(react@19.2.3) '@types/react': specifier: 'catalog:' version: 19.2.7 @@ -784,7 +799,7 @@ importers: specifier: 'catalog:' version: 19.2.3(@types/react@19.2.7) lucide-react: - specifier: ^0.562.0 + specifier: 'catalog:' version: 0.562.0(react@19.2.3) next: specifier: 'catalog:' @@ -800,10 +815,10 @@ importers: version: 19.2.3(react@19.2.3) react-hook-form: specifier: 'catalog:' - version: 7.69.0(react@19.2.3) + version: 7.70.0(react@19.2.3) react-i18next: specifier: 'catalog:' - version: 16.5.0(i18next@25.7.3(typescript@5.9.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + version: 16.5.1(i18next@25.7.3(typescript@5.9.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) zod: specifier: 3.25.76 version: 3.25.76 @@ -812,7 +827,7 @@ importers: devDependencies: '@hookform/resolvers': specifier: ^5.2.2 - version: 5.2.2(react-hook-form@7.69.0(react@19.2.3)) + version: 5.2.2(react-hook-form@7.70.0(react@19.2.3)) '@kit/eslint-config': specifier: workspace:* version: link:../../../tooling/eslint @@ -839,13 +854,13 @@ importers: version: 0.0.10(@supabase/postgrest-js@2.89.0)(@supabase/supabase-js@2.89.0) '@makerkit/data-loader-supabase-nextjs': specifier: ^1.2.5 - version: 1.2.5(@supabase/postgrest-js@2.89.0)(@supabase/supabase-js@2.89.0)(@tanstack/react-query@5.90.12(react@19.2.3))(next@16.1.1(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3) + version: 1.2.5(@supabase/postgrest-js@2.89.0)(@supabase/supabase-js@2.89.0)(@tanstack/react-query@5.90.16(react@19.2.3))(next@16.1.1(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3) '@supabase/supabase-js': specifier: 'catalog:' version: 2.89.0 '@tanstack/react-query': specifier: 'catalog:' - version: 5.90.12(react@19.2.3) + version: 5.90.16(react@19.2.3) '@tanstack/react-table': specifier: ^8.21.3 version: 8.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -853,7 +868,7 @@ importers: specifier: 'catalog:' version: 19.2.7 lucide-react: - specifier: ^0.562.0 + specifier: 'catalog:' version: 0.562.0(react@19.2.3) next: specifier: 'catalog:' @@ -866,7 +881,7 @@ importers: version: 19.2.3(react@19.2.3) react-hook-form: specifier: 'catalog:' - version: 7.69.0(react@19.2.3) + version: 7.70.0(react@19.2.3) zod: specifier: 3.25.76 version: 3.25.76 @@ -875,7 +890,7 @@ importers: devDependencies: '@hookform/resolvers': specifier: ^5.2.2 - version: 5.2.2(react-hook-form@7.69.0(react@19.2.3)) + version: 5.2.2(react-hook-form@7.70.0(react@19.2.3)) '@kit/eslint-config': specifier: workspace:* version: link:../../../tooling/eslint @@ -895,8 +910,8 @@ importers: specifier: workspace:* version: link:../../ui '@marsidev/react-turnstile': - specifier: ^1.4.0 - version: 1.4.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + specifier: 'catalog:' + version: 1.4.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@radix-ui/react-icons': specifier: ^1.3.2 version: 1.3.2(react@19.2.3) @@ -905,7 +920,7 @@ importers: version: 2.89.0 '@tanstack/react-query': specifier: 'catalog:' - version: 5.90.12(react@19.2.3) + version: 5.90.16(react@19.2.3) '@types/node': specifier: 'catalog:' version: 25.0.3 @@ -913,17 +928,17 @@ importers: specifier: 'catalog:' version: 19.2.7 lucide-react: - specifier: ^0.562.0 + specifier: 'catalog:' version: 0.562.0(react@19.2.3) next: specifier: 'catalog:' version: 16.1.1(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react-hook-form: specifier: 'catalog:' - version: 7.69.0(react@19.2.3) + version: 7.70.0(react@19.2.3) react-i18next: specifier: 'catalog:' - version: 16.5.0(i18next@25.7.3(typescript@5.9.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + version: 16.5.1(i18next@25.7.3(typescript@5.9.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) sonner: specifier: ^2.0.7 version: 2.0.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -957,12 +972,12 @@ importers: version: 2.89.0 '@tanstack/react-query': specifier: 'catalog:' - version: 5.90.12(react@19.2.3) + version: 5.90.16(react@19.2.3) '@types/react': specifier: 'catalog:' version: 19.2.7 lucide-react: - specifier: ^0.562.0 + specifier: 'catalog:' version: 0.562.0(react@19.2.3) react: specifier: 'catalog:' @@ -972,7 +987,7 @@ importers: version: 19.2.3(react@19.2.3) react-i18next: specifier: 'catalog:' - version: 16.5.0(i18next@25.7.3(typescript@5.9.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + version: 16.5.1(i18next@25.7.3(typescript@5.9.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) packages/features/team-accounts: dependencies: @@ -982,7 +997,7 @@ importers: devDependencies: '@hookform/resolvers': specifier: ^5.2.2 - version: 5.2.2(react-hook-form@7.69.0(react@19.2.3)) + version: 5.2.2(react-hook-form@7.70.0(react@19.2.3)) '@kit/accounts': specifier: workspace:* version: link:../accounts @@ -1030,7 +1045,7 @@ importers: version: 2.89.0 '@tanstack/react-query': specifier: 'catalog:' - version: 5.90.12(react@19.2.3) + version: 5.90.16(react@19.2.3) '@tanstack/react-table': specifier: ^8.21.3 version: 8.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -1047,7 +1062,7 @@ importers: specifier: ^4.1.0 version: 4.1.0 lucide-react: - specifier: ^0.562.0 + specifier: 'catalog:' version: 0.562.0(react@19.2.3) next: specifier: 'catalog:' @@ -1060,10 +1075,10 @@ importers: version: 19.2.3(react@19.2.3) react-hook-form: specifier: 'catalog:' - version: 7.69.0(react@19.2.3) + version: 7.70.0(react@19.2.3) react-i18next: specifier: 'catalog:' - version: 16.5.0(i18next@25.7.3(typescript@5.9.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + version: 16.5.1(i18next@25.7.3(typescript@5.9.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) zod: specifier: 3.25.76 version: 3.25.76 @@ -1094,7 +1109,7 @@ importers: version: link:../../tooling/typescript '@tanstack/react-query': specifier: 'catalog:' - version: 5.90.12(react@19.2.3) + version: 5.90.16(react@19.2.3) next: specifier: 'catalog:' version: 16.1.1(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -1106,7 +1121,7 @@ importers: version: 19.2.3(react@19.2.3) react-i18next: specifier: 'catalog:' - version: 16.5.0(i18next@25.7.3(typescript@5.9.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + version: 16.5.1(i18next@25.7.3(typescript@5.9.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) packages/mailers/core: devDependencies: @@ -1330,7 +1345,7 @@ importers: devDependencies: '@hookform/resolvers': specifier: ^5.2.2 - version: 5.2.2(react-hook-form@7.69.0(react@19.2.3)) + version: 5.2.2(react-hook-form@7.70.0(react@19.2.3)) '@kit/email-templates': specifier: workspace:* version: link:../email-templates @@ -1378,7 +1393,7 @@ importers: version: 19.2.3(react@19.2.3) react-hook-form: specifier: 'catalog:' - version: 7.69.0(react@19.2.3) + version: 7.70.0(react@19.2.3) zod: specifier: 3.25.76 version: 3.25.76 @@ -1443,7 +1458,7 @@ importers: version: 2.89.0 '@tanstack/react-query': specifier: 'catalog:' - version: 5.90.12(react@19.2.3) + version: 5.90.16(react@19.2.3) '@types/node': specifier: 'catalog:' version: 25.0.3 @@ -1464,7 +1479,7 @@ importers: dependencies: '@hookform/resolvers': specifier: ^5.2.2 - version: 5.2.2(react-hook-form@7.69.0(react@19.2.3)) + version: 5.2.2(react-hook-form@7.70.0(react@19.2.3)) '@radix-ui/react-icons': specifier: ^1.3.2 version: 1.3.2(react@19.2.3) @@ -1478,7 +1493,7 @@ importers: specifier: 1.4.2 version: 1.4.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) lucide-react: - specifier: ^0.562.0 + specifier: 'catalog:' version: 0.562.0(react@19.2.3) radix-ui: specifier: 1.4.3 @@ -1510,7 +1525,7 @@ importers: version: 2.89.0 '@tanstack/react-query': specifier: 'catalog:' - version: 5.90.12(react@19.2.3) + version: 5.90.16(react@19.2.3) '@tanstack/react-table': specifier: ^8.21.3 version: 8.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -1543,10 +1558,10 @@ importers: version: 9.13.0(react@19.2.3) react-hook-form: specifier: 'catalog:' - version: 7.69.0(react@19.2.3) + version: 7.70.0(react@19.2.3) react-i18next: specifier: 'catalog:' - version: 16.5.0(i18next@25.7.3(typescript@5.9.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + version: 16.5.1(i18next@25.7.3(typescript@5.9.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3) sonner: specifier: ^2.0.7 version: 2.0.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -1575,8 +1590,8 @@ importers: specifier: 'catalog:' version: 16.1.1(@typescript-eslint/parser@8.50.1(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) eslint-config-turbo: - specifier: ^2.7.1 - version: 2.7.1(eslint@9.39.2(jiti@2.6.1))(turbo@2.7.1) + specifier: ^2.7.3 + version: 2.7.3(eslint@9.39.2(jiti@2.6.1))(turbo@2.7.3) devDependencies: '@kit/prettier-config': specifier: workspace:* @@ -1588,14 +1603,14 @@ importers: tooling/prettier: dependencies: '@trivago/prettier-plugin-sort-imports': - specifier: 6.0.0 - version: 6.0.0(prettier@3.7.4) + specifier: 6.0.2 + version: 6.0.2(prettier@3.7.4) prettier: specifier: ^3.7.4 version: 3.7.4 prettier-plugin-tailwindcss: specifier: ^0.7.2 - version: 0.7.2(@trivago/prettier-plugin-sort-imports@6.0.0(prettier@3.7.4))(prettier@3.7.4) + version: 0.7.2(@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.7.4))(prettier@3.7.4) devDependencies: '@kit/tsconfig': specifier: workspace:* @@ -2297,8 +2312,8 @@ packages: react: optional: true - '@marsidev/react-turnstile@1.4.0': - resolution: {integrity: sha512-3aR7mh4lATeayWt6GjWuYyLjM0GL148z7/ZQl0rLKGpDYIrWgoU2PYsdAdA9fzH+JysW3Q2OaPfHvv66cwcAZg==} + '@marsidev/react-turnstile@1.4.1': + resolution: {integrity: sha512-1jE0IjvB8z+q1NFRs3149gXzXwIzXQWqQjn9fmAr13BiE3RYLWck5Me6flHYE90shW5L12Jkm6R1peS1OnA9oQ==} peerDependencies: react: ^17.0.2 || ^18.0.0 || ^19.0 react-dom: ^17.0.2 || ^18.0.0 || ^19.0 @@ -2392,8 +2407,8 @@ packages: resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} engines: {node: '>=12.4.0'} - '@nosecone/next@1.0.0-beta.15': - resolution: {integrity: sha512-uX3pnSeengqiPnKa06mq2X/e4AKnu0WeLd1mGrjVGYU0eB1inRgvmn3Vsxk1cauEQ5NLw+RhK6MPJYaO1l6cdA==} + '@nosecone/next@1.0.0-beta.16': + resolution: {integrity: sha512-IinvVTyO4MPdDGJPqRWNE9iXhBbefey9XhTZdi7UHh/trNU5dr/7YE7AnF2BYMLbWaWkkq5GN2Jq+zIQEob+FQ==} engines: {node: '>=20'} peerDependencies: next: '>=14' @@ -3592,134 +3607,136 @@ packages: react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 react-dom: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1 - '@react-email/body@0.2.0': - resolution: {integrity: sha512-9GCWmVmKUAoRfloboCd+RKm6X17xn7eGL7HnpAZUnjBXBilWCxsKnLMTC/ixSHDKS/A/057M1Tx6ZUXd89sVBw==} - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/button@0.2.0': - resolution: {integrity: sha512-8i+v6cMxr2emz4ihCrRiYJPp2/sdYsNNsBzXStlcA+/B9Umpm5Jj3WJKYpgTPM+aeyiqlG/MMI1AucnBm4f1oQ==} - engines: {node: '>=18.0.0'} - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/code-block@0.2.0': - resolution: {integrity: sha512-eIrPW9PIFgDopQU0e/OPpwCW2QWQDtNZDSsiN4sJO8KdMnWWnXJicnRfzrit5rHwFo+Y98i+w/Y5ScnBAFr1dQ==} - engines: {node: '>=22.0.0'} - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/code-inline@0.0.5': - resolution: {integrity: sha512-MmAsOzdJpzsnY2cZoPHFPk6uDO/Ncpb4Kh1hAt9UZc1xOW3fIzpe1Pi9y9p6wwUmpaeeDalJxAxH6/fnTquinA==} - engines: {node: '>=18.0.0'} - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/column@0.0.13': - resolution: {integrity: sha512-Lqq17l7ShzJG/d3b1w/+lVO+gp2FM05ZUo/nW0rjxB8xBICXOVv6PqjDnn3FXKssvhO5qAV20lHM6S+spRhEwQ==} - engines: {node: '>=18.0.0'} - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/components@1.0.2': - resolution: {integrity: sha512-VKQR/motrySQMvy+ZUwPjdeD9iI9mCt8cfXuJAX8cK16rtzkEe12yq6/pXyW7c6qEMj7d+PNsoAcO+3AbJSfPg==} + '@react-email/body@0.2.1': + resolution: {integrity: sha512-ljDiQiJDu/Fq//vSIIP0z5Nuvt4+DX1RqGasstChDGJB/14ogd4VdNS9aacoede/ZjGy3o3Qb+cxyS+XgM6SwQ==} engines: {node: '>=20.0.0'} peerDependencies: react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/container@0.0.15': - resolution: {integrity: sha512-Qo2IQo0ru2kZq47REmHW3iXjAQaKu4tpeq/M8m1zHIVwKduL2vYOBQWbC2oDnMtWPmkBjej6XxgtZByxM6cCFg==} - engines: {node: '>=18.0.0'} + '@react-email/button@0.2.1': + resolution: {integrity: sha512-qXyj7RZLE7POy9BMKSoqQ00tOXThjOZSUnI2Yu9i29IHngPlmrNayIWBoVKtElES7OWwypUcpiajwi1mUWx6/A==} + engines: {node: '>=20.0.0'} peerDependencies: react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/font@0.0.9': - resolution: {integrity: sha512-4zjq23oT9APXkerqeslPH3OZWuh5X4crHK6nx82mVHV2SrLba8+8dPEnWbaACWTNjOCbcLIzaC9unk7Wq2MIXw==} + '@react-email/code-block@0.2.1': + resolution: {integrity: sha512-M3B7JpVH4ytgn83/ujRR1k1DQHvTeABiDM61OvAbjLRPhC/5KLHU5KkzIbbuGIrjWwxAbL1kSQzU8MhLEtSxyw==} + engines: {node: '>=20.0.0'} peerDependencies: react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/head@0.0.12': - resolution: {integrity: sha512-X2Ii6dDFMF+D4niNwMAHbTkeCjlYYnMsd7edXOsi0JByxt9wNyZ9EnhFiBoQdqkE+SMDcu8TlNNttMrf5sJeMA==} - engines: {node: '>=18.0.0'} + '@react-email/code-inline@0.0.6': + resolution: {integrity: sha512-jfhebvv3dVsp3OdPgKXnk8+e2pBiDVZejDOBFzBa/IblrAJ9cQDkN6rBD5IyEg8hTOxwbw3iaI/yZFmDmIguIA==} + engines: {node: '>=20.0.0'} peerDependencies: react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/heading@0.0.15': - resolution: {integrity: sha512-xF2GqsvBrp/HbRHWEfOgSfRFX+Q8I5KBEIG5+Lv3Vb2R/NYr0s8A5JhHHGf2pWBMJdbP4B2WHgj/VUrhy8dkIg==} - engines: {node: '>=18.0.0'} + '@react-email/column@0.0.14': + resolution: {integrity: sha512-f+W+Bk2AjNO77zynE33rHuQhyqVICx4RYtGX9NKsGUg0wWjdGP0qAuIkhx9Rnmk4/hFMo1fUrtYNqca9fwJdHg==} + engines: {node: '>=20.0.0'} peerDependencies: react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/hr@0.0.11': - resolution: {integrity: sha512-S1gZHVhwOsd1Iad5IFhpfICwNPMGPJidG/Uysy1AwmspyoAP5a4Iw3OWEpINFdgh9MHladbxcLKO2AJO+cA9Lw==} - engines: {node: '>=18.0.0'} + '@react-email/components@1.0.3': + resolution: {integrity: sha512-RbleOT35XSCWM54Rs76/BgfPA0Son55OH4awBYlkHZgLw0AdbPwobhE7izNDFqY4nHW7+omLfe3CByWbsg/hEw==} + engines: {node: '>=20.0.0'} peerDependencies: react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/html@0.0.11': - resolution: {integrity: sha512-qJhbOQy5VW5qzU74AimjAR9FRFQfrMa7dn4gkEXKMB/S9xZN8e1yC1uA9C15jkXI/PzmJ0muDIWmFwatm5/+VA==} - engines: {node: '>=18.0.0'} + '@react-email/container@0.0.16': + resolution: {integrity: sha512-QWBB56RkkU0AJ9h+qy33gfT5iuZknPC7Un/IjZv9B0QmMIK+WWacc0cH6y2SV5Cv/b99hU94fjEMOOO4enpkbQ==} + engines: {node: '>=20.0.0'} peerDependencies: react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/img@0.0.11': - resolution: {integrity: sha512-aGc8Y6U5C3igoMaqAJKsCpkbm1XjguQ09Acd+YcTKwjnC2+0w3yGUJkjWB2vTx4tN8dCqQCXO8FmdJpMfOA9EQ==} - engines: {node: '>=18.0.0'} + '@react-email/font@0.0.10': + resolution: {integrity: sha512-0urVSgCmQIfx5r7Xc586miBnQUVnGp3OTYUm8m5pwtQRdTRO5XrTtEfNJ3JhYhSOruV0nD8fd+dXtKXobum6tA==} + engines: {node: '>=20.0.0'} peerDependencies: react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/link@0.0.12': - resolution: {integrity: sha512-vF+xxQk2fGS1CN7UPQDbzvcBGfffr+GjTPNiWM38fhBfsLv6A/YUfaqxWlmL7zLzVmo0K2cvvV9wxlSyNba1aQ==} - engines: {node: '>=18.0.0'} + '@react-email/head@0.0.13': + resolution: {integrity: sha512-AJg6le/08Gz4tm+6MtKXqtNNyKHzmooOCdmtqmWxD7FxoAdU1eVcizhtQ0gcnVaY6ethEyE/hnEzQxt1zu5Kog==} + engines: {node: '>=20.0.0'} peerDependencies: react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/markdown@0.0.17': - resolution: {integrity: sha512-6op3AfsBC9BJKkhG+eoMFRFWlr0/f3FYbtQrK+VhGzJocEAY0WINIFN+W8xzXr//3IL0K/aKtnH3FtpIuescQQ==} - engines: {node: '>=22.0.0'} + '@react-email/heading@0.0.16': + resolution: {integrity: sha512-jmsKnQm1ykpBzw4hCYHwBkt5pW2jScXffPeEH5ZRF5tZeF5b1pvlFTO9han7C0pCkZYo1kEvWiRtx69yfCIwuw==} + engines: {node: '>=20.0.0'} peerDependencies: react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/preview@0.0.13': - resolution: {integrity: sha512-F7j9FJ0JN/A4d7yr+aw28p4uX7VLWs7hTHtLo7WRyw4G+Lit6Zucq4UWKRxJC8lpsUdzVmG7aBJnKOT+urqs/w==} - engines: {node: '>=18.0.0'} + '@react-email/hr@0.0.12': + resolution: {integrity: sha512-TwmOmBDibavUQpXBxpmZYi2Iks/yeZOzFYh+di9EltMSnEabH8dMZXrl+pxNXzCgZ2XE8HY7VmUL65Lenfu5PA==} + engines: {node: '>=20.0.0'} peerDependencies: react: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/render@2.0.0': - resolution: {integrity: sha512-rdjNj6iVzv8kRKDPFas+47nnoe6B40+nwukuXwY4FCwM7XBg6tmYr+chQryCuavUj2J65MMf6fztk1bxOUiSVA==} - engines: {node: '>=22.0.0'} + '@react-email/html@0.0.12': + resolution: {integrity: sha512-KTShZesan+UsreU7PDUV90afrZwU5TLwYlALuCSU0OT+/U8lULNNbAUekg+tGwCnOfIKYtpDPKkAMRdYlqUznw==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + + '@react-email/img@0.0.12': + resolution: {integrity: sha512-sRCpEARNVTf3FQhZOC+JTvu5r6ubiYWkT0ucYXg8ctkyi4G8QG+jgYPiNUqVeTLA2STOfmPM/nrk1nb84y6CPQ==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + + '@react-email/link@0.0.13': + resolution: {integrity: sha512-lkWc/NjOcefRZMkQoSDDbuKBEBDES9aXnFEOuPH845wD3TxPwh+QTf0fStuzjoRLUZWpHnio4z7qGGRYusn/sw==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + + '@react-email/markdown@0.0.18': + resolution: {integrity: sha512-gSuYK5fsMbGk87jDebqQ6fa2fKcWlkf2Dkva8kMONqLgGCq8/0d+ZQYMEJsdidIeBo3kmsnHZPrwdFB4HgjUXg==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + + '@react-email/preview@0.0.14': + resolution: {integrity: sha512-aYK8q0IPkBXyMsbpMXgxazwHxYJxTrXrV95GFuu2HbEiIToMwSyUgb8HDFYwPqqfV03/jbwqlsXmFxsOd+VNaw==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + + '@react-email/render@2.0.1': + resolution: {integrity: sha512-eYNL4+SSrV1+58MIcT4znarX4YTMuYBr1uzhI6U8fBFvRMZPryxNOnD7jnZ/Ser3MtJEquQNbXjrAP+RVkfLbg==} + engines: {node: '>=20.0.0'} peerDependencies: react: ^18.0 || ^19.0 || ^19.0.0-rc react-dom: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/row@0.0.12': - resolution: {integrity: sha512-HkCdnEjvK3o+n0y0tZKXYhIXUNPDx+2vq1dJTmqappVHXS5tXS6W5JOPZr5j+eoZ8gY3PShI2LWj5rWF7ZEtIQ==} - engines: {node: '>=18.0.0'} - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/section@0.0.16': - resolution: {integrity: sha512-FjqF9xQ8FoeUZYKSdt8sMIKvoT9XF8BrzhT3xiFKdEMwYNbsDflcjfErJe3jb7Wj/es/lKTbV5QR1dnLzGpL3w==} - engines: {node: '>=18.0.0'} - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/tailwind@2.0.2': - resolution: {integrity: sha512-ooi1H77+w+MN3a3Yps66GYTMoo9PvLtzJ1bTEI+Ta58MUUEQOcdxxXPwbnox+xj2kSwv0g/B63qquNTabKI8Bw==} + '@react-email/row@0.0.13': + resolution: {integrity: sha512-bYnOac40vIKCId7IkwuLAAsa3fKfSfqCvv6epJKmPE0JBuu5qI4FHFCl9o9dVpIIS08s/ub+Y/txoMt0dYziGw==} engines: {node: '>=20.0.0'} peerDependencies: - '@react-email/body': 0.2.0 - '@react-email/button': 0.2.0 - '@react-email/code-block': 0.2.0 - '@react-email/code-inline': 0.0.5 - '@react-email/container': 0.0.15 - '@react-email/heading': 0.0.15 - '@react-email/hr': 0.0.11 - '@react-email/img': 0.0.11 - '@react-email/link': 0.0.12 - '@react-email/preview': 0.0.13 - '@react-email/text': 0.1.5 + react: ^18.0 || ^19.0 || ^19.0.0-rc + + '@react-email/section@0.0.17': + resolution: {integrity: sha512-qNl65ye3W0Rd5udhdORzTV9ezjb+GFqQQSae03NDzXtmJq6sqVXNWNiVolAjvJNypim+zGXmv6J9TcV5aNtE/w==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + + '@react-email/tailwind@2.0.3': + resolution: {integrity: sha512-URXb/T2WS4RlNGM5QwekYnivuiVUcU87H0y5sqLl6/Oi3bMmgL0Bmw/W9GeJylC+876Vw+E6NkE0uRiUFIQwGg==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@react-email/body': 0.2.1 + '@react-email/button': 0.2.1 + '@react-email/code-block': 0.2.1 + '@react-email/code-inline': 0.0.6 + '@react-email/container': 0.0.16 + '@react-email/heading': 0.0.16 + '@react-email/hr': 0.0.12 + '@react-email/img': 0.0.12 + '@react-email/link': 0.0.13 + '@react-email/preview': 0.0.14 + '@react-email/text': 0.1.6 react: ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@react-email/body': @@ -3743,9 +3760,9 @@ packages: '@react-email/preview': optional: true - '@react-email/text@0.1.5': - resolution: {integrity: sha512-o5PNHFSE085VMXayxH+SJ1LSOtGsTv+RpNKnTiJDrJUwoBu77G3PlKOsZZQHCNyD28WsQpl9v2WcJLbQudqwPg==} - engines: {node: '>=18.0.0'} + '@react-email/text@0.1.6': + resolution: {integrity: sha512-TYqkioRS45wTR5il3dYk/SbUjjEdhSwh9BtRNB99qNH1pXAwA45H7rAuxehiu8iJQJH0IyIr+6n62gBz9ezmsw==} + engines: {node: '>=20.0.0'} peerDependencies: react: ^18.0 || ^19.0 || ^19.0.0-rc @@ -4473,8 +4490,8 @@ packages: react: '>=16.8.0 <20.0.0' react-dom: '>=16.8.0 <20.0.0' - '@stripe/stripe-js@8.6.0': - resolution: {integrity: sha512-EB0/GGgs4hfezzkiMkinlRgWtjz8fSdwVQhwYS7Sg/RQrSvuNOz+ssPjD+lAzqaYTCB0zlbrt0fcqVziLJrufQ==} + '@stripe/stripe-js@8.6.1': + resolution: {integrity: sha512-UJ05U2062XDgydbUcETH1AoRQLNhigQ2KmDn1BG8sC3xfzu6JKg95Qt6YozdzFpxl1Npii/02m2LEWFt1RYjVA==} engines: {node: '>=12.16'} '@supabase/auth-js@2.89.0': @@ -4600,11 +4617,11 @@ packages: '@tailwindcss/postcss@4.1.18': resolution: {integrity: sha512-Ce0GFnzAOuPyfV5SxjXGn0CubwGcuDB0zcdaPuCSzAa/2vII24JTkH+I6jcbXLb1ctjZMZZI6OjDaLPJQL1S0g==} - '@tanstack/query-core@5.90.12': - resolution: {integrity: sha512-T1/8t5DhV/SisWjDnaiU2drl6ySvsHj1bHBCWNXd+/T+Hh1cf6JodyEYMd5sgwm+b/mETT4EV3H+zCVczCU5hg==} + '@tanstack/query-core@5.90.16': + resolution: {integrity: sha512-MvtWckSVufs/ja463/K4PyJeqT+HMlJWtw6PrCpywznd2NSgO3m4KwO9RqbFqGg6iDE8vVMFWMeQI4Io3eEYww==} - '@tanstack/react-query@5.90.12': - resolution: {integrity: sha512-graRZspg7EoEaw0a8faiUASCyJrqjKPdqJ9EwuDRUF9mEYJ1YPczI9H+/agJ0mOJkPCJDk0lsz5QTrLZ/jQ2rg==} + '@tanstack/react-query@5.90.16': + resolution: {integrity: sha512-bpMGOmV4OPmif7TNMteU/Ehf/hoC0Kf98PDc0F4BZkFrEapRMEqI/V6YS0lyzwSV6PQpY1y4xxArUIfBW5LVxQ==} peerDependencies: react: ^18 || ^19 @@ -4627,8 +4644,8 @@ packages: '@tootallnate/quickjs-emscripten@0.23.0': resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} - '@trivago/prettier-plugin-sort-imports@6.0.0': - resolution: {integrity: sha512-Xarx55ow0R8oC7ViL5fPmDsg1EBa1dVhyZFVbFXNtPPJyW2w9bJADIla8YFSaNG9N06XfcklA9O9vmw4noNxkQ==} + '@trivago/prettier-plugin-sort-imports@6.0.2': + resolution: {integrity: sha512-3DgfkukFyC/sE/VuYjaUUWoFfuVjPK55vOFDsxD56XXynFMCZDYFogH2l/hDfOsQAm1myoU/1xByJ3tWqtulXA==} engines: {node: '>= 20'} peerDependencies: '@vue/compiler-sfc': 3.x @@ -4663,12 +4680,12 @@ packages: '@tsconfig/node16@1.0.4': resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - '@turbo/gen@2.7.0': - resolution: {integrity: sha512-3S16qpAMKV+9GYyLcZxBYvwtJVKrwjqi4TacQr1H8pjt8aCL8Dzat4Hsuf739HsiwtSmL+QMNMKXhOiRqzW6UQ==} + '@turbo/gen@2.7.3': + resolution: {integrity: sha512-lvjv1/fwUewFqew/qdNM//6cC32EIjEAJ2rCx5blL4+BVX16ubHroEGUJRNQegW0hpglTztdJW6DdS3hIuqoCA==} hasBin: true - '@turbo/workspaces@2.7.0': - resolution: {integrity: sha512-qOpfJI6Uuh24FlbHtXzkiIgUrMZ8XVNvj4+1SGrL7eVUwABeZs+Qk7QzAy3WOVzN5agIxw9sNF8XV/2trxus1w==} + '@turbo/workspaces@2.7.3': + resolution: {integrity: sha512-opYsHNZo3qhGJ+qxLSEhNcnf+e8beha/bfinwUH857NFL7oYHsOpVtNJIiwcJYKjZjJO4XtxTLsvAo3CQ5/R5A==} hasBin: true '@tybys/wasm-util@0.10.1': @@ -5237,8 +5254,8 @@ packages: resolution: {integrity: sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==} hasBin: true - basic-ftp@5.0.5: - resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==} + basic-ftp@5.1.0: + resolution: {integrity: sha512-RkaJzeJKDbaDWTIPiJwubyljaEPwpVWkm9Rt5h9Nd6h7tEXTJ3VB4qxdZBioV7JO5yLUaOKwz7vDOzlncUsegw==} engines: {node: '>=10.0.0'} bin-links@6.0.0: @@ -5892,8 +5909,8 @@ packages: typescript: optional: true - eslint-config-turbo@2.7.1: - resolution: {integrity: sha512-w4xejK/txhKoKbNM10Zrm1IUWbmtynw7lOWqR32hBebc9HP7K1us7ivp9mzn924DQlldlgzMY6ngFrm67N2fPw==} + eslint-config-turbo@2.7.3: + resolution: {integrity: sha512-1ik3XQLJoE9d9ljhw60wTQf7rlwnz8tc6vnhSL7/Ciep2+qPMJpNg+mapcmGhirfDSceVNI8r9pv+HyvrBXhpQ==} peerDependencies: eslint: '>6.6.0' turbo: '>2.0.0' @@ -5963,8 +5980,8 @@ packages: peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 - eslint-plugin-turbo@2.7.1: - resolution: {integrity: sha512-ZC7dTOdw6tGuvx1CeC1WQ0pMkgT/Jmj69QW93d63nysiLbbKRLiDKKA9s/TvwJHq8Uvbou2+hnU8if1L0jHsVQ==} + eslint-plugin-turbo@2.7.3: + resolution: {integrity: sha512-q7kYzJCyvceSLVwHgmn3ZBhqpUihQHxC7LEddq5a1eLe5P+/Ob4TnJrdocP38qO1n9MCuO+cJSUTGUtZb1X3bQ==} peerDependencies: eslint: '>6.6.0' turbo: '>2.0.0' @@ -6885,8 +6902,8 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} - lodash-es@4.17.21: - resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + lodash-es@4.17.22: + resolution: {integrity: sha512-XEawp1t0gxSi9x01glktRZ5HDy0HXqrM0x5pXQM98EaI0NxO6jVM7omDOxsuEo5UIASAnm2bRp1Jt/e0a2XU8Q==} lodash.deburr@4.1.0: resolution: {integrity: sha512-m/M1U1f3ddMCs6Hq2tAsYThTBDaAKFDX3dwDo97GEYzamXi9SqUpjWi/Rrj/gf3X2n8ktwgZrlP1z6E3v/IExQ==} @@ -7283,8 +7300,8 @@ packages: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - nosecone@1.0.0-beta.15: - resolution: {integrity: sha512-e3D16yrYQKu+qtILUNEoopdhloAjBcjpREwi2XSyi9tt6Tupk+rPEh/omydf9OJqkBZaM05hyFcBpBJbYvndIg==} + nosecone@1.0.0-beta.16: + resolution: {integrity: sha512-wQVLcOORPivGzMLY539uyLPRxP7OSPx1njj47ebcxD+/TL8flWCJj+egYpNJkEYBhrd4ETyIxicBiCz/WISO7w==} engines: {node: '>=20'} npm-normalize-package-bin@5.0.0: @@ -7854,8 +7871,8 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - qs@6.14.0: - resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + qs@6.14.1: + resolution: {integrity: sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==} engines: {node: '>=0.6'} queue-microtask@1.2.3: @@ -7909,14 +7926,14 @@ packages: peerDependencies: react: '>= 16.8 || 18.0.0' - react-hook-form@7.69.0: - resolution: {integrity: sha512-yt6ZGME9f4F6WHwevrvpAjh42HMvocuSnSIHUGycBqXIJdhqGSPQzTpGF+1NLREk/58IdPxEMfPcFCjlMhclGw==} + react-hook-form@7.70.0: + resolution: {integrity: sha512-COOMajS4FI3Wuwrs3GPpi/Jeef/5W1DRR84Yl5/ShlT3dKVFUfoGiEZ/QE6Uw8P4T2/CLJdcTVYKvWBMQTEpvw==} engines: {node: '>=18.0.0'} peerDependencies: react: ^16.8.0 || ^17 || ^18 || ^19 - react-i18next@16.5.0: - resolution: {integrity: sha512-IMpPTyCTKxEj8klCrLKUTIUa8uYTd851+jcu2fJuUB9Agkk9Qq8asw4omyeHVnOXHrLgQJGTm5zTvn8HpaPiqw==} + react-i18next@16.5.1: + resolution: {integrity: sha512-Hks6UIRZWW4c+qDAnx1csVsCGYeIR4MoBGQgJ+NUoNnO6qLxXuf8zu0xdcinyXUORgGzCdRsexxO1Xzv3sTdnw==} peerDependencies: i18next: '>= 25.6.2' react: '>= 16.8.0' @@ -8378,8 +8395,8 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - stripe@20.1.0: - resolution: {integrity: sha512-o1VNRuMkY76ZCq92U3EH3/XHm/WHp7AerpzDs4Zyo8uE5mFL4QUcv/2SudWsSnhBSp4moO2+ZoGCZ7mT8crPmQ==} + stripe@20.1.1: + resolution: {integrity: sha512-yD2jgS2QfqQOXxF3ByB/BcRTGChor/OxhK1211AvQPkzkTV7qCg7z/whOdhNCX0AZkNjBpicoViqC5TMvaxM9w==} engines: {node: '>=16'} peerDependencies: '@types/node': '>=16' @@ -8412,8 +8429,8 @@ packages: stylis@4.2.0: resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} - supabase@2.70.3: - resolution: {integrity: sha512-gtcc1eVMoRnyMC5BVd7iAvpncGJXRb0kbu44CAuVzFxL3fPfmdxjQTsMPPz0cNyn8glF7MIU+s2SW9knsTCVtQ==} + supabase@2.71.1: + resolution: {integrity: sha512-ICuVAkCrGde9gulis5JcqpN8osGllbFStcMjssOq97Kn/TMGX6Ngoo4mhHva9CZY/UvYyfcbph9QbY8fzZ8b/Q==} engines: {npm: '>=8'} hasBin: true @@ -8574,38 +8591,38 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - turbo-darwin-64@2.7.1: - resolution: {integrity: sha512-EaA7UfYujbY9/Ku0WqPpvfctxm91h9LF7zo8vjielz+omfAPB54Si+ADmUoBczBDC6RoLgbURC3GmUW2alnjJg==} + turbo-darwin-64@2.7.3: + resolution: {integrity: sha512-aZHhvRiRHXbJw1EcEAq4aws1hsVVUZ9DPuSFaq9VVFAKCup7niIEwc22glxb7240yYEr1vLafdQ2U294Vcwz+w==} cpu: [x64] os: [darwin] - turbo-darwin-arm64@2.7.1: - resolution: {integrity: sha512-/pWGSygtBugd7sKQOeMm+jKY3qN1vyB0RiHBM6bN/6qUOo2VHo8IQwBTIaSgINN4Ue6fzEU+WfePNvonSU9yXw==} + turbo-darwin-arm64@2.7.3: + resolution: {integrity: sha512-CkVrHSq+Bnhl9sX2LQgqQYVfLTWC2gvI74C4758OmU0djfrssDKU9d4YQF0AYXXhIIRZipSXfxClQziIMD+EAg==} cpu: [arm64] os: [darwin] - turbo-linux-64@2.7.1: - resolution: {integrity: sha512-Y5H11mdhASw/dJuRFyGtTCDFX5/MPT73EKsVEiHbw5MkFc77lx3nMc5L/Q7bKEhef/vYJAsAb61QuHsB6qdP8Q==} + turbo-linux-64@2.7.3: + resolution: {integrity: sha512-GqDsCNnzzr89kMaLGpRALyigUklzgxIrSy2pHZVXyifgczvYPnLglex78Aj3T2gu+T3trPPH2iJ+pWucVOCC2Q==} cpu: [x64] os: [linux] - turbo-linux-arm64@2.7.1: - resolution: {integrity: sha512-L/r77jD7cqIEXoyu2LGBUrTY5GJSi/XcGLsQ2nZ/fefk6x3MpljTvwsXUVG1BUkiBPc4zaKRj6yGyWMo5MbLxQ==} + turbo-linux-arm64@2.7.3: + resolution: {integrity: sha512-NdCDTfIcIo3dWjsiaAHlxu5gW61Ed/8maah1IAF/9E3EtX0aAHNiBMbuYLZaR4vRJ7BeVkYB6xKWRtdFLZ0y3g==} cpu: [arm64] os: [linux] - turbo-windows-64@2.7.1: - resolution: {integrity: sha512-rkeuviXZ/1F7lCare7TNKvYtT/SH9dZR55FAMrxrFRh88b+ZKwlXEBfq5/1OctEzRUo/VLIm+s5LJMOEy+QshA==} + turbo-windows-64@2.7.3: + resolution: {integrity: sha512-7bVvO987daXGSJVYBoG8R4Q+csT1pKIgLJYZevXRQ0Hqw0Vv4mKme/TOjYXs9Qb1xMKh51Tb3bXKDbd8/4G08g==} cpu: [x64] os: [win32] - turbo-windows-arm64@2.7.1: - resolution: {integrity: sha512-1rZk9htm3+iP/rWCf/h4/DFQey9sMs2TJPC4T5QQfwqAdMWsphgrxBuFqHdxczlbBCgbWNhVw0CH2bTxe1/GFg==} + turbo-windows-arm64@2.7.3: + resolution: {integrity: sha512-nTodweTbPmkvwMu/a55XvjMsPtuyUSC+sV7f/SR57K36rB2I0YG21qNETN+00LOTUW9B3omd8XkiXJkt4kx/cw==} cpu: [arm64] os: [win32] - turbo@2.7.1: - resolution: {integrity: sha512-zAj9jGc7VDvuAo/5Jbos4QTtWz9uUpkMhMKGyTjDJkx//hdL2bM31qQoJSAbU+7JyK5vb0LPzpwf6DUt3zayqg==} + turbo@2.7.3: + resolution: {integrity: sha512-+HjKlP4OfYk+qzvWNETA3cUO5UuK6b5MSc2UJOKyvBceKucQoQGb2g7HlC2H1GHdkfKrk4YF1VPvROkhVZDDLQ==} hasBin: true tw-animate-css@1.4.0: @@ -9713,10 +9730,10 @@ snapshots: dependencies: hono: 4.11.1 - '@hookform/resolvers@5.2.2(react-hook-form@7.69.0(react@19.2.3))': + '@hookform/resolvers@5.2.2(react-hook-form@7.70.0(react@19.2.3))': dependencies: '@standard-schema/utils': 0.3.0 - react-hook-form: 7.69.0(react@19.2.3) + react-hook-form: 7.70.0(react@19.2.3) '@humanfs/core@0.19.1': {} @@ -10081,11 +10098,11 @@ snapshots: '@supabase/supabase-js': 2.89.0 ts-case-convert: 2.1.0 - '@makerkit/data-loader-supabase-nextjs@1.2.5(@supabase/postgrest-js@2.89.0)(@supabase/supabase-js@2.89.0)(@tanstack/react-query@5.90.12(react@19.2.3))(next@16.1.1(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)': + '@makerkit/data-loader-supabase-nextjs@1.2.5(@supabase/postgrest-js@2.89.0)(@supabase/supabase-js@2.89.0)(@tanstack/react-query@5.90.16(react@19.2.3))(next@16.1.1(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3)': dependencies: '@makerkit/data-loader-supabase-core': 0.0.10(@supabase/postgrest-js@2.89.0)(@supabase/supabase-js@2.89.0) '@supabase/supabase-js': 2.89.0 - '@tanstack/react-query': 5.90.12(react@19.2.3) + '@tanstack/react-query': 5.90.16(react@19.2.3) next: 16.1.1(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react: 19.2.3 transitivePeerDependencies: @@ -10133,7 +10150,7 @@ snapshots: '@types/react': 19.2.7 react: 19.2.3 - '@marsidev/react-turnstile@1.4.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@marsidev/react-turnstile@1.4.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: react: 19.2.3 react-dom: 19.2.3(react@19.2.3) @@ -10220,10 +10237,10 @@ snapshots: '@nolyfill/is-core-module@1.0.39': {} - '@nosecone/next@1.0.0-beta.15(next@16.1.1(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))': + '@nosecone/next@1.0.0-beta.16(next@16.1.1(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))': dependencies: next: 16.1.1(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(@playwright/test@1.57.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - nosecone: 1.0.0-beta.15 + nosecone: 1.0.0-beta.16 '@opentelemetry/api-logs@0.208.0': dependencies: @@ -11814,127 +11831,127 @@ snapshots: react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - '@react-email/body@0.2.0(react@19.2.3)': + '@react-email/body@0.2.1(react@19.2.3)': dependencies: react: 19.2.3 - '@react-email/button@0.2.0(react@19.2.3)': + '@react-email/button@0.2.1(react@19.2.3)': dependencies: react: 19.2.3 - '@react-email/code-block@0.2.0(react@19.2.3)': + '@react-email/code-block@0.2.1(react@19.2.3)': dependencies: prismjs: 1.30.0 react: 19.2.3 - '@react-email/code-inline@0.0.5(react@19.2.3)': + '@react-email/code-inline@0.0.6(react@19.2.3)': dependencies: react: 19.2.3 - '@react-email/column@0.0.13(react@19.2.3)': + '@react-email/column@0.0.14(react@19.2.3)': dependencies: react: 19.2.3 - '@react-email/components@1.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@react-email/components@1.0.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@react-email/body': 0.2.0(react@19.2.3) - '@react-email/button': 0.2.0(react@19.2.3) - '@react-email/code-block': 0.2.0(react@19.2.3) - '@react-email/code-inline': 0.0.5(react@19.2.3) - '@react-email/column': 0.0.13(react@19.2.3) - '@react-email/container': 0.0.15(react@19.2.3) - '@react-email/font': 0.0.9(react@19.2.3) - '@react-email/head': 0.0.12(react@19.2.3) - '@react-email/heading': 0.0.15(react@19.2.3) - '@react-email/hr': 0.0.11(react@19.2.3) - '@react-email/html': 0.0.11(react@19.2.3) - '@react-email/img': 0.0.11(react@19.2.3) - '@react-email/link': 0.0.12(react@19.2.3) - '@react-email/markdown': 0.0.17(react@19.2.3) - '@react-email/preview': 0.0.13(react@19.2.3) - '@react-email/render': 2.0.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@react-email/row': 0.0.12(react@19.2.3) - '@react-email/section': 0.0.16(react@19.2.3) - '@react-email/tailwind': 2.0.2(@react-email/body@0.2.0(react@19.2.3))(@react-email/button@0.2.0(react@19.2.3))(@react-email/code-block@0.2.0(react@19.2.3))(@react-email/code-inline@0.0.5(react@19.2.3))(@react-email/container@0.0.15(react@19.2.3))(@react-email/heading@0.0.15(react@19.2.3))(@react-email/hr@0.0.11(react@19.2.3))(@react-email/img@0.0.11(react@19.2.3))(@react-email/link@0.0.12(react@19.2.3))(@react-email/preview@0.0.13(react@19.2.3))(@react-email/text@0.1.5(react@19.2.3))(react@19.2.3) - '@react-email/text': 0.1.5(react@19.2.3) + '@react-email/body': 0.2.1(react@19.2.3) + '@react-email/button': 0.2.1(react@19.2.3) + '@react-email/code-block': 0.2.1(react@19.2.3) + '@react-email/code-inline': 0.0.6(react@19.2.3) + '@react-email/column': 0.0.14(react@19.2.3) + '@react-email/container': 0.0.16(react@19.2.3) + '@react-email/font': 0.0.10(react@19.2.3) + '@react-email/head': 0.0.13(react@19.2.3) + '@react-email/heading': 0.0.16(react@19.2.3) + '@react-email/hr': 0.0.12(react@19.2.3) + '@react-email/html': 0.0.12(react@19.2.3) + '@react-email/img': 0.0.12(react@19.2.3) + '@react-email/link': 0.0.13(react@19.2.3) + '@react-email/markdown': 0.0.18(react@19.2.3) + '@react-email/preview': 0.0.14(react@19.2.3) + '@react-email/render': 2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@react-email/row': 0.0.13(react@19.2.3) + '@react-email/section': 0.0.17(react@19.2.3) + '@react-email/tailwind': 2.0.3(@react-email/body@0.2.1(react@19.2.3))(@react-email/button@0.2.1(react@19.2.3))(@react-email/code-block@0.2.1(react@19.2.3))(@react-email/code-inline@0.0.6(react@19.2.3))(@react-email/container@0.0.16(react@19.2.3))(@react-email/heading@0.0.16(react@19.2.3))(@react-email/hr@0.0.12(react@19.2.3))(@react-email/img@0.0.12(react@19.2.3))(@react-email/link@0.0.13(react@19.2.3))(@react-email/preview@0.0.14(react@19.2.3))(@react-email/text@0.1.6(react@19.2.3))(react@19.2.3) + '@react-email/text': 0.1.6(react@19.2.3) react: 19.2.3 transitivePeerDependencies: - react-dom - '@react-email/container@0.0.15(react@19.2.3)': + '@react-email/container@0.0.16(react@19.2.3)': dependencies: react: 19.2.3 - '@react-email/font@0.0.9(react@19.2.3)': + '@react-email/font@0.0.10(react@19.2.3)': dependencies: react: 19.2.3 - '@react-email/head@0.0.12(react@19.2.3)': + '@react-email/head@0.0.13(react@19.2.3)': dependencies: react: 19.2.3 - '@react-email/heading@0.0.15(react@19.2.3)': + '@react-email/heading@0.0.16(react@19.2.3)': dependencies: react: 19.2.3 - '@react-email/hr@0.0.11(react@19.2.3)': + '@react-email/hr@0.0.12(react@19.2.3)': dependencies: react: 19.2.3 - '@react-email/html@0.0.11(react@19.2.3)': + '@react-email/html@0.0.12(react@19.2.3)': dependencies: react: 19.2.3 - '@react-email/img@0.0.11(react@19.2.3)': + '@react-email/img@0.0.12(react@19.2.3)': dependencies: react: 19.2.3 - '@react-email/link@0.0.12(react@19.2.3)': + '@react-email/link@0.0.13(react@19.2.3)': dependencies: react: 19.2.3 - '@react-email/markdown@0.0.17(react@19.2.3)': + '@react-email/markdown@0.0.18(react@19.2.3)': dependencies: marked: 15.0.12 react: 19.2.3 - '@react-email/preview@0.0.13(react@19.2.3)': + '@react-email/preview@0.0.14(react@19.2.3)': dependencies: react: 19.2.3 - '@react-email/render@2.0.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@react-email/render@2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: html-to-text: 9.0.5 prettier: 3.7.4 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - '@react-email/row@0.0.12(react@19.2.3)': + '@react-email/row@0.0.13(react@19.2.3)': dependencies: react: 19.2.3 - '@react-email/section@0.0.16(react@19.2.3)': + '@react-email/section@0.0.17(react@19.2.3)': dependencies: react: 19.2.3 - '@react-email/tailwind@2.0.2(@react-email/body@0.2.0(react@19.2.3))(@react-email/button@0.2.0(react@19.2.3))(@react-email/code-block@0.2.0(react@19.2.3))(@react-email/code-inline@0.0.5(react@19.2.3))(@react-email/container@0.0.15(react@19.2.3))(@react-email/heading@0.0.15(react@19.2.3))(@react-email/hr@0.0.11(react@19.2.3))(@react-email/img@0.0.11(react@19.2.3))(@react-email/link@0.0.12(react@19.2.3))(@react-email/preview@0.0.13(react@19.2.3))(@react-email/text@0.1.5(react@19.2.3))(react@19.2.3)': + '@react-email/tailwind@2.0.3(@react-email/body@0.2.1(react@19.2.3))(@react-email/button@0.2.1(react@19.2.3))(@react-email/code-block@0.2.1(react@19.2.3))(@react-email/code-inline@0.0.6(react@19.2.3))(@react-email/container@0.0.16(react@19.2.3))(@react-email/heading@0.0.16(react@19.2.3))(@react-email/hr@0.0.12(react@19.2.3))(@react-email/img@0.0.12(react@19.2.3))(@react-email/link@0.0.13(react@19.2.3))(@react-email/preview@0.0.14(react@19.2.3))(@react-email/text@0.1.6(react@19.2.3))(react@19.2.3)': dependencies: - '@react-email/text': 0.1.5(react@19.2.3) + '@react-email/text': 0.1.6(react@19.2.3) react: 19.2.3 tailwindcss: 4.1.18 optionalDependencies: - '@react-email/body': 0.2.0(react@19.2.3) - '@react-email/button': 0.2.0(react@19.2.3) - '@react-email/code-block': 0.2.0(react@19.2.3) - '@react-email/code-inline': 0.0.5(react@19.2.3) - '@react-email/container': 0.0.15(react@19.2.3) - '@react-email/heading': 0.0.15(react@19.2.3) - '@react-email/hr': 0.0.11(react@19.2.3) - '@react-email/img': 0.0.11(react@19.2.3) - '@react-email/link': 0.0.12(react@19.2.3) - '@react-email/preview': 0.0.13(react@19.2.3) + '@react-email/body': 0.2.1(react@19.2.3) + '@react-email/button': 0.2.1(react@19.2.3) + '@react-email/code-block': 0.2.1(react@19.2.3) + '@react-email/code-inline': 0.0.6(react@19.2.3) + '@react-email/container': 0.0.16(react@19.2.3) + '@react-email/heading': 0.0.16(react@19.2.3) + '@react-email/hr': 0.0.12(react@19.2.3) + '@react-email/img': 0.0.12(react@19.2.3) + '@react-email/link': 0.0.13(react@19.2.3) + '@react-email/preview': 0.0.14(react@19.2.3) - '@react-email/text@0.1.5(react@19.2.3)': + '@react-email/text@0.1.6(react@19.2.3)': dependencies: react: 19.2.3 @@ -12883,14 +12900,14 @@ snapshots: '@standard-schema/utils@0.3.0': {} - '@stripe/react-stripe-js@5.4.1(@stripe/stripe-js@8.6.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@stripe/react-stripe-js@5.4.1(@stripe/stripe-js@8.6.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@stripe/stripe-js': 8.6.0 + '@stripe/stripe-js': 8.6.1 prop-types: 15.8.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - '@stripe/stripe-js@8.6.0': {} + '@stripe/stripe-js@8.6.1': {} '@supabase/auth-js@2.89.0': dependencies: @@ -13012,11 +13029,11 @@ snapshots: postcss: 8.5.6 tailwindcss: 4.1.18 - '@tanstack/query-core@5.90.12': {} + '@tanstack/query-core@5.90.16': {} - '@tanstack/react-query@5.90.12(react@19.2.3)': + '@tanstack/react-query@5.90.16(react@19.2.3)': dependencies: - '@tanstack/query-core': 5.90.12 + '@tanstack/query-core': 5.90.16 react: 19.2.3 '@tanstack/react-table@8.21.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': @@ -13036,14 +13053,14 @@ snapshots: '@tootallnate/quickjs-emscripten@0.23.0': {} - '@trivago/prettier-plugin-sort-imports@6.0.0(prettier@3.7.4)': + '@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.7.4)': dependencies: '@babel/generator': 7.28.5 '@babel/parser': 7.28.5 '@babel/traverse': 7.28.5 '@babel/types': 7.28.5 javascript-natural-sort: 0.7.1 - lodash-es: 4.17.21 + lodash-es: 4.17.22 minimatch: 9.0.5 parse-imports-exports: 0.2.4 prettier: 3.7.4 @@ -13064,9 +13081,9 @@ snapshots: '@tsconfig/node16@1.0.4': {} - '@turbo/gen@2.7.0(@types/node@25.0.3)(typescript@5.9.3)': + '@turbo/gen@2.7.3(@types/node@25.0.3)(typescript@5.9.3)': dependencies: - '@turbo/workspaces': 2.7.0 + '@turbo/workspaces': 2.7.3 commander: 10.0.0 fs-extra: 10.1.0 inquirer: 8.2.4 @@ -13084,7 +13101,7 @@ snapshots: - supports-color - typescript - '@turbo/workspaces@2.7.0': + '@turbo/workspaces@2.7.3': dependencies: commander: 10.0.0 execa: 5.1.1 @@ -13191,7 +13208,7 @@ snapshots: '@types/minimatch@6.0.0': dependencies: - minimatch: 9.0.0 + minimatch: 9.0.5 '@types/ms@2.1.0': {} @@ -13718,7 +13735,7 @@ snapshots: baseline-browser-mapping@2.9.11: {} - basic-ftp@5.0.5: {} + basic-ftp@5.1.0: {} bin-links@6.0.0: dependencies: @@ -13744,7 +13761,7 @@ snapshots: http-errors: 2.0.1 iconv-lite: 0.7.1 on-finished: 2.4.1 - qs: 6.14.0 + qs: 6.14.1 raw-body: 3.0.2 type-is: 2.0.1 transitivePeerDependencies: @@ -14462,11 +14479,11 @@ snapshots: - eslint-plugin-import-x - supports-color - eslint-config-turbo@2.7.1(eslint@9.39.2(jiti@2.6.1))(turbo@2.7.1): + eslint-config-turbo@2.7.3(eslint@9.39.2(jiti@2.6.1))(turbo@2.7.3): dependencies: eslint: 9.39.2(jiti@2.6.1) - eslint-plugin-turbo: 2.7.1(eslint@9.39.2(jiti@2.6.1))(turbo@2.7.1) - turbo: 2.7.1 + eslint-plugin-turbo: 2.7.3(eslint@9.39.2(jiti@2.6.1))(turbo@2.7.3) + turbo: 2.7.3 eslint-import-resolver-node@0.3.9: dependencies: @@ -14583,11 +14600,11 @@ snapshots: string.prototype.matchall: 4.0.12 string.prototype.repeat: 1.0.0 - eslint-plugin-turbo@2.7.1(eslint@9.39.2(jiti@2.6.1))(turbo@2.7.1): + eslint-plugin-turbo@2.7.3(eslint@9.39.2(jiti@2.6.1))(turbo@2.7.3): dependencies: dotenv: 16.0.3 eslint: 9.39.2(jiti@2.6.1) - turbo: 2.7.1 + turbo: 2.7.3 eslint-scope@5.1.1: dependencies: @@ -14727,7 +14744,7 @@ snapshots: once: 1.4.0 parseurl: 1.3.3 proxy-addr: 2.0.7 - qs: 6.14.0 + qs: 6.14.1 range-parser: 1.2.1 router: 2.2.0 send: 1.2.1 @@ -14926,7 +14943,7 @@ snapshots: get-uri@6.0.5: dependencies: - basic-ftp: 5.0.5 + basic-ftp: 5.1.0 data-uri-to-buffer: 6.0.2 debug: 4.4.3 transitivePeerDependencies: @@ -15556,7 +15573,7 @@ snapshots: dependencies: p-locate: 5.0.0 - lodash-es@4.17.21: {} + lodash-es@4.17.22: {} lodash.deburr@4.1.0: {} @@ -16132,7 +16149,7 @@ snapshots: normalize-path@3.0.0: {} - nosecone@1.0.0-beta.15: {} + nosecone@1.0.0-beta.16: {} npm-normalize-package-bin@5.0.0: {} @@ -16609,11 +16626,11 @@ snapshots: prelude-ls@1.2.1: {} - prettier-plugin-tailwindcss@0.7.2(@trivago/prettier-plugin-sort-imports@6.0.0(prettier@3.7.4))(prettier@3.7.4): + prettier-plugin-tailwindcss@0.7.2(@trivago/prettier-plugin-sort-imports@6.0.2(prettier@3.7.4))(prettier@3.7.4): dependencies: prettier: 3.7.4 optionalDependencies: - '@trivago/prettier-plugin-sort-imports': 6.0.0(prettier@3.7.4) + '@trivago/prettier-plugin-sort-imports': 6.0.2(prettier@3.7.4) prettier@3.7.4: {} @@ -16706,7 +16723,7 @@ snapshots: punycode@2.3.1: {} - qs@6.14.0: + qs@6.14.1: dependencies: side-channel: 1.1.0 @@ -16816,11 +16833,11 @@ snapshots: prop-types: 15.8.1 react: 19.2.3 - react-hook-form@7.69.0(react@19.2.3): + react-hook-form@7.70.0(react@19.2.3): dependencies: react: 19.2.3 - react-i18next@16.5.0(i18next@25.7.3(typescript@5.9.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3): + react-i18next@16.5.1(i18next@25.7.3(typescript@5.9.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3): dependencies: '@babel/runtime': 7.28.4 html-parse-stringify: 3.0.1 @@ -17416,9 +17433,9 @@ snapshots: strip-json-comments@3.1.1: {} - stripe@20.1.0(@types/node@25.0.3): + stripe@20.1.1(@types/node@25.0.3): dependencies: - qs: 6.14.0 + qs: 6.14.1 optionalDependencies: '@types/node': 25.0.3 @@ -17439,7 +17456,7 @@ snapshots: stylis@4.2.0: {} - supabase@2.70.3: + supabase@2.71.1: dependencies: bin-links: 6.0.0 https-proxy-agent: 7.0.6 @@ -17599,32 +17616,32 @@ snapshots: tslib@2.8.1: {} - turbo-darwin-64@2.7.1: + turbo-darwin-64@2.7.3: optional: true - turbo-darwin-arm64@2.7.1: + turbo-darwin-arm64@2.7.3: optional: true - turbo-linux-64@2.7.1: + turbo-linux-64@2.7.3: optional: true - turbo-linux-arm64@2.7.1: + turbo-linux-arm64@2.7.3: optional: true - turbo-windows-64@2.7.1: + turbo-windows-64@2.7.3: optional: true - turbo-windows-arm64@2.7.1: + turbo-windows-arm64@2.7.3: optional: true - turbo@2.7.1: + turbo@2.7.3: optionalDependencies: - turbo-darwin-64: 2.7.1 - turbo-darwin-arm64: 2.7.1 - turbo-linux-64: 2.7.1 - turbo-linux-arm64: 2.7.1 - turbo-windows-64: 2.7.1 - turbo-windows-arm64: 2.7.1 + turbo-darwin-64: 2.7.3 + turbo-darwin-arm64: 2.7.3 + turbo-linux-64: 2.7.3 + turbo-linux-arm64: 2.7.3 + turbo-windows-64: 2.7.3 + turbo-windows-arm64: 2.7.3 tw-animate-css@1.4.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 042a2579d..9c7e71aa1 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -4,21 +4,26 @@ packages: - tooling/* catalog: + '@marsidev/react-turnstile': 1.4.1 '@next/bundle-analyzer': 16.1.1 '@next/eslint-plugin-next': 16.1.1 + '@stripe/react-stripe-js': 5.4.1 + '@stripe/stripe-js': 8.6.1 '@supabase/supabase-js': 2.89.0 '@tailwindcss/postcss': 4.1.18 - '@tanstack/react-query': 5.90.12 + '@tanstack/react-query': 5.90.16 '@types/node': 25.0.3 '@types/react': 19.2.7 '@types/react-dom': 19.2.3 eslint-config-next: 16.1.1 + lucide-react: 0.562.0 next: 16.1.1 react: 19.2.3 react-dom: 19.2.3 - react-hook-form: 7.69.0 - react-i18next: 16.5.0 - supabase: 2.70.3 + react-hook-form: 7.70.0 + react-i18next: 16.5.1 + stripe: 20.1.1 + supabase: 2.71.1 tailwindcss: 4.1.18 tw-animate-css: 1.4.0 zod: 3.25.76 diff --git a/tooling/eslint/package.json b/tooling/eslint/package.json index 6463dc0c0..9ed45ac6c 100644 --- a/tooling/eslint/package.json +++ b/tooling/eslint/package.json @@ -16,7 +16,7 @@ "@next/eslint-plugin-next": "catalog:", "@types/eslint": "9.6.1", "eslint-config-next": "catalog:", - "eslint-config-turbo": "^2.7.1" + "eslint-config-turbo": "^2.7.3" }, "devDependencies": { "@kit/prettier-config": "workspace:*", diff --git a/tooling/prettier/package.json b/tooling/prettier/package.json index b4df77620..d5f132269 100644 --- a/tooling/prettier/package.json +++ b/tooling/prettier/package.json @@ -9,7 +9,7 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@trivago/prettier-plugin-sort-imports": "6.0.0", + "@trivago/prettier-plugin-sort-imports": "6.0.2", "prettier": "^3.7.4", "prettier-plugin-tailwindcss": "^0.7.2" },