From 6b7c8116f30787fdc977db69b3351aeb93a81b50 Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Thu, 9 Oct 2025 12:26:54 +0800 Subject: [PATCH 01/16] Chore/projects pagination part 05 (#39350) * CmdK OrgProjectSwitcher to swap useProjectsQuery with useProjectsInfiniteQuery * Remove usage of useProjectsQuery in ProjectDropdown * Remove usage of useProjectsQuery in NotificationsPopover * Remove usage of useProjectsQuery in NotificationsFilter * Remove usage of useProjectsQuery from LoadingState * Clean * Remove usage of getProjects from org-ai-details and fix missing key props in AIOnboarding * Remove useAutoProjectsPrefetch from org/[slug]/index * Fix TS + clean up * Clean * Remove usage of useProjectsQuery in NewOrgForm * Remove usage of useProjectsQuery in SupportForm -> AIAssistantOption * Remove usage of useProjectsQuery in PlanUpdateSidePanel * Remove usage of useProjectsQuery in NoProjectsOnPaidPlan * Remove useProjectsQuery in IntegrationPanels * Remove useProjectsQuery from IntegrationPanels 2 * Remove useProjectsQuery from IntegrationConnection * Remove console log * Small change --- .../Billing/NoProjectsOnPaidOrgInfo.tsx | 8 +++---- .../VercelGithub/IntegrationConnection.tsx | 7 ++---- .../VercelGithub/IntegrationPanels.tsx | 12 +++------- .../Subscription/DowngradeModal.tsx | 19 +++++++++------ .../Subscription/ExitSurveyModal.tsx | 11 +++++---- .../Subscription/PlanUpdateSidePanel.tsx | 23 +++++++++++-------- .../Subscription/Subscription.tsx | 2 +- .../SubscriptionPlanUpdateDialog.tsx | 4 ++-- .../interfaces/Support/AIAssistantOption.tsx | 19 ++++----------- .../projects/org-projects-infinite-query.ts | 5 ++++ .../pages/project/_/[[...routeSlug]].tsx | 9 +++++--- 11 files changed, 58 insertions(+), 61 deletions(-) diff --git a/apps/studio/components/interfaces/Billing/NoProjectsOnPaidOrgInfo.tsx b/apps/studio/components/interfaces/Billing/NoProjectsOnPaidOrgInfo.tsx index 84f685f70bfb2..372b8257b9e2f 100644 --- a/apps/studio/components/interfaces/Billing/NoProjectsOnPaidOrgInfo.tsx +++ b/apps/studio/components/interfaces/Billing/NoProjectsOnPaidOrgInfo.tsx @@ -1,4 +1,4 @@ -import { useProjectsQuery } from 'data/projects/projects-query' +import { useOrgProjectsInfiniteQuery } from 'data/projects/org-projects-infinite-query' import Link from 'next/link' import type { Organization } from 'types' import { Admonition } from 'ui-patterns' @@ -8,10 +8,8 @@ interface NoProjectsOnPaidOrgInfoProps { } export const NoProjectsOnPaidOrgInfo = ({ organization }: NoProjectsOnPaidOrgInfoProps) => { - const { data } = useProjectsQuery({}) - const projectCount = - (data?.projects ?? []).filter((project) => project.organization_id === organization?.id) - .length ?? 0 + const { data } = useOrgProjectsInfiniteQuery({ slug: organization?.slug }) + const projectCount = data?.pages[0].pagination.count ?? 0 if ( projectCount > 0 || diff --git a/apps/studio/components/interfaces/Integrations/VercelGithub/IntegrationConnection.tsx b/apps/studio/components/interfaces/Integrations/VercelGithub/IntegrationConnection.tsx index be63d1469d6fb..f7016dc936b15 100644 --- a/apps/studio/components/interfaces/Integrations/VercelGithub/IntegrationConnection.tsx +++ b/apps/studio/components/interfaces/Integrations/VercelGithub/IntegrationConnection.tsx @@ -11,7 +11,7 @@ import { import { ButtonTooltip } from 'components/ui/ButtonTooltip' import { useIntegrationsVercelConnectionSyncEnvsMutation } from 'data/integrations/integrations-vercel-connection-sync-envs-mutation' import type { IntegrationProjectConnection } from 'data/integrations/integrations.types' -import { useProjectsQuery } from 'data/projects/projects-query' +import { useProjectDetailQuery } from 'data/projects/project-detail-query' import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization' import { Button, @@ -34,10 +34,7 @@ const IntegrationConnectionItem = forwardRef project.ref === connection.supabase_project_ref - ) + const { data: project } = useProjectDetailQuery({ ref: connection.supabase_project_ref }) const isBranchingEnabled = project?.is_branch_enabled === true const [isOpen, setIsOpen] = useState(false) diff --git a/apps/studio/components/interfaces/Integrations/VercelGithub/IntegrationPanels.tsx b/apps/studio/components/interfaces/Integrations/VercelGithub/IntegrationPanels.tsx index f394f3c1ec198..01624ba609238 100644 --- a/apps/studio/components/interfaces/Integrations/VercelGithub/IntegrationPanels.tsx +++ b/apps/studio/components/interfaces/Integrations/VercelGithub/IntegrationPanels.tsx @@ -10,7 +10,7 @@ import type { Integration, IntegrationProjectConnection, } from 'data/integrations/integrations.types' -import { useProjectsQuery } from 'data/projects/projects-query' +import { useProjectDetailQuery } from 'data/projects/project-detail-query' import { BASE_PATH } from 'lib/constants' import { getIntegrationConfigurationUrl } from 'lib/integration-utils' import { Badge, Button, cn } from 'ui' @@ -149,10 +149,7 @@ const IntegrationConnection = forwardRef { - const { data } = useProjectsQuery() - const project = (data?.projects ?? []).find( - (project) => project.ref === connection.supabase_project_ref - ) + const { data: project } = useProjectDetailQuery({ ref: connection.supabase_project_ref }) return (
  • ( ({ connection, type, ...props }, ref) => { - const { data } = useProjectsQuery() - const project = (data?.projects ?? []).find( - (project) => project.ref === connection.supabase_project_ref - ) + const { data: project } = useProjectDetailQuery({ ref: connection.supabase_project_ref }) return (
  • void onConfirm: () => void - projects: ProjectInfo[] + projects: OrgProject[] } const ProjectDowngradeListItem = ({ projectAddon }: { projectAddon: ProjectAddon }) => { @@ -73,7 +72,10 @@ const DowngradeModal = ({ } }) || [] - const hasInstancesOnMicro = projects.some((project) => project.infra_compute_size === 'micro') + const hasInstancesOnMicro = projects.some((project) => { + const computeSize = getComputeSize(project) + return computeSize === 'micro' + }) return ( it.infra_compute_size === 'micro') + .filter((it) => { + const computeSize = getComputeSize(it) + return computeSize === 'micro' + }) .map((project) => (
  • {project.name}: Compute will be downgraded. Project will also{' '} diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/ExitSurveyModal.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/ExitSurveyModal.tsx index d025396fab09d..e1c713c0e4dca 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/ExitSurveyModal.tsx +++ b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/ExitSurveyModal.tsx @@ -4,14 +4,14 @@ import { toast } from 'sonner' import { useFlag, useParams } from 'common' import { CANCELLATION_REASONS } from 'components/interfaces/Billing/Billing.constants' import { useSendDowngradeFeedbackMutation } from 'data/feedback/exit-survey-send' -import { ProjectInfo } from 'data/projects/projects-query' +import { getComputeSize, OrgProject } from 'data/projects/org-projects-infinite-query' import { useOrgSubscriptionUpdateMutation } from 'data/subscriptions/org-subscription-update-mutation' import { Alert, Button, cn, Input, Modal } from 'ui' import ProjectUpdateDisabledTooltip from '../ProjectUpdateDisabledTooltip' export interface ExitSurveyModalProps { visible: boolean - projects: ProjectInfo[] + projects: OrgProject[] onClose: (success?: boolean) => void } @@ -34,9 +34,10 @@ export const ExitSurveyModal = ({ visible, projects, onClose }: ExitSurveyModalP useSendDowngradeFeedbackMutation() const isSubmitting = isUpdating || isSubmittingFeedback - const projectsWithComputeDowngrade = projects.filter( - (project) => project.infra_compute_size !== 'nano' - ) + const projectsWithComputeDowngrade = projects.filter((project) => { + const computeSize = getComputeSize(project) + return computeSize !== 'nano' + }) const hasProjectsWithComputeDowngrade = projectsWithComputeDowngrade.length > 0 diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/PlanUpdateSidePanel.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/PlanUpdateSidePanel.tsx index 5d1f473e0b1bf..5859e95f9aa10 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/PlanUpdateSidePanel.tsx +++ b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/PlanUpdateSidePanel.tsx @@ -2,7 +2,7 @@ import { PermissionAction } from '@supabase/shared-types/out/constants' import { isArray } from 'lodash' import { Check, ExternalLink } from 'lucide-react' import { useRouter } from 'next/router' -import { useEffect, useRef, useState } from 'react' +import { useEffect, useMemo, useRef, useState } from 'react' import { useParams } from 'common' import { StudioPricingSidePanelOpenedEvent } from 'common/telemetry-constants' @@ -13,7 +13,7 @@ import ShimmeringLoader from 'components/ui/ShimmeringLoader' import { useFreeProjectLimitCheckQuery } from 'data/organizations/free-project-limit-check-query' import { useOrganizationBillingSubscriptionPreview } from 'data/organizations/organization-billing-subscription-preview' import { useOrganizationQuery } from 'data/organizations/organization-query' -import { useProjectsQuery } from 'data/projects/projects-query' +import { useOrgProjectsInfiniteQuery } from 'data/projects/org-projects-infinite-query' import { useOrgPlansQuery } from 'data/subscriptions/org-plans-query' import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query' import type { OrgPlan } from 'data/subscriptions/types' @@ -47,7 +47,8 @@ const getPartnerManagedResourceCta = (selectedOrganization: Organization) => { } } } -const PlanUpdateSidePanel = () => { + +export const PlanUpdateSidePanel = () => { const router = useRouter() const { slug } = useParams() const { data: selectedOrganization } = useSelectedOrganizationQuery() @@ -64,10 +65,13 @@ const PlanUpdateSidePanel = () => { PermissionAction.BILLING_WRITE, 'stripe.subscriptions' ) - const { data: projectsData } = useProjectsQuery() - const orgProjects = (projectsData?.projects ?? []).filter( - (it) => it.organization_id === selectedOrganization?.id - ) + + const { data: orgProjectsData } = useOrgProjectsInfiniteQuery({ slug }) + const orgProjects = + useMemo( + () => orgProjectsData?.pages.flatMap((page) => page.projects), + [orgProjectsData?.pages] + ) || [] const { data } = useOrganizationQuery({ slug }) const hasOrioleProjects = !!data?.has_oriole_project @@ -98,6 +102,9 @@ const PlanUpdateSidePanel = () => { const availablePlans: OrgPlan[] = plans?.plans ?? [] const hasMembersExceedingFreeTierLimit = (membersExceededLimit || []).length > 0 && + // [Joshen] Note that orgProjects is paginated so there's a chance this may omit certain projects + // Although I don't foresee this affecting a majority of users. Ideally perhaps we could return + // this data from the organization query orgProjects.filter((it) => it.status !== 'INACTIVE' && it.status !== 'GOING_DOWN').length > 0 useEffect(() => { @@ -357,5 +364,3 @@ const PlanUpdateSidePanel = () => { ) } - -export default PlanUpdateSidePanel diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/Subscription.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/Subscription.tsx index ca0a81d48bb02..b6c3173f9e4b6 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/Subscription.tsx +++ b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/Subscription.tsx @@ -17,7 +17,7 @@ import { Alert, Button } from 'ui' import { Admonition } from 'ui-patterns' import ProjectUpdateDisabledTooltip from '../ProjectUpdateDisabledTooltip' import { Restriction } from '../Restriction' -import PlanUpdateSidePanel from './PlanUpdateSidePanel' +import { PlanUpdateSidePanel } from './PlanUpdateSidePanel' const Subscription = () => { const { slug } = useParams() diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/SubscriptionPlanUpdateDialog.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/SubscriptionPlanUpdateDialog.tsx index ebce8bcb1bef6..778d09c10d27b 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/SubscriptionPlanUpdateDialog.tsx +++ b/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/SubscriptionPlanUpdateDialog.tsx @@ -14,7 +14,7 @@ import { import AlertError from 'components/ui/AlertError' import ShimmeringLoader from 'components/ui/ShimmeringLoader' import { OrganizationBillingSubscriptionPreviewResponse } from 'data/organizations/organization-billing-subscription-preview' -import { ProjectInfo } from 'data/projects/projects-query' +import { OrgProject } from 'data/projects/org-projects-infinite-query' import { useConfirmPendingSubscriptionChangeMutation } from 'data/subscriptions/org-subscription-confirm-pending-change' import { useOrgSubscriptionUpdateMutation } from 'data/subscriptions/org-subscription-update-mutation' import { SubscriptionTier } from 'data/subscriptions/types' @@ -64,7 +64,7 @@ interface Props { subscriptionPreview: OrganizationBillingSubscriptionPreviewResponse | undefined subscription: any currentPlanMeta: any - projects: ProjectInfo[] + projects: OrgProject[] } export const SubscriptionPlanUpdateDialog = ({ diff --git a/apps/studio/components/interfaces/Support/AIAssistantOption.tsx b/apps/studio/components/interfaces/Support/AIAssistantOption.tsx index 055ee41a9c6ff..e2b6db4f268e7 100644 --- a/apps/studio/components/interfaces/Support/AIAssistantOption.tsx +++ b/apps/studio/components/interfaces/Support/AIAssistantOption.tsx @@ -1,9 +1,9 @@ -import { useProjectsQuery } from 'data/projects/projects-query' -import { useSendEventMutation } from 'data/telemetry/send-event-mutation' import { AnimatePresence, motion } from 'framer-motion' import { MessageSquare } from 'lucide-react' import Link from 'next/link' import { useCallback, useEffect, useState } from 'react' + +import { useSendEventMutation } from 'data/telemetry/send-event-mutation' import { Button } from 'ui' interface AIAssistantOptionProps { @@ -17,9 +17,6 @@ export const AIAssistantOption = ({ organizationSlug, isCondensed = false, }: AIAssistantOptionProps) => { - const { data } = useProjectsQuery() - const projects = data?.projects ?? [] - const { mutate: sendEvent } = useSendEventMutation() const [isVisible, setIsVisible] = useState(isCondensed ? true : false) @@ -42,16 +39,8 @@ export const AIAssistantOption = ({ return null } - const getProjectRef = () => { - if (projectRef !== 'no-project') { - return projectRef - } - // If no specific project selected, use first project from the org - const orgProjects = projects?.filter((p) => p.organization_slug === organizationSlug) - return orgProjects?.[0]?.ref || '_' - } - - const aiLink = `/project/${getProjectRef()}?aiAssistantPanelOpen=true` + // If no specific project selected, use the wildcard route + const aiLink = `/project/${projectRef !== 'no-project' ? projectRef : '_'}?aiAssistantPanelOpen=true&slug=${organizationSlug}` return ( diff --git a/apps/studio/data/projects/org-projects-infinite-query.ts b/apps/studio/data/projects/org-projects-infinite-query.ts index 356cf8df0da31..69e7e24e592fe 100644 --- a/apps/studio/data/projects/org-projects-infinite-query.ts +++ b/apps/studio/data/projects/org-projects-infinite-query.ts @@ -85,3 +85,8 @@ export const useOrgProjectsInfiniteQuery = ( } ) } + +export const getComputeSize = (project: OrgProject) => { + const primaryDatabase = project.databases.find((db) => db.identifier === project.ref) + return primaryDatabase?.infra_compute_size +} diff --git a/apps/studio/pages/project/_/[[...routeSlug]].tsx b/apps/studio/pages/project/_/[[...routeSlug]].tsx index 30bdfef0c6ef1..57ff0d12d1f3a 100644 --- a/apps/studio/pages/project/_/[[...routeSlug]].tsx +++ b/apps/studio/pages/project/_/[[...routeSlug]].tsx @@ -3,7 +3,7 @@ import { NextPage } from 'next' import { useRouter } from 'next/router' import { useEffect, useState } from 'react' -import { IS_PLATFORM, LOCAL_STORAGE_KEYS } from 'common' +import { IS_PLATFORM, LOCAL_STORAGE_KEYS, useParams } from 'common' import { Header, LoadingCardView, @@ -33,6 +33,7 @@ import { const GenericProjectPage: NextPage = () => { const router = useRouter() + const { slug } = useParams() const { routeSlug, ...queryParams } = router.query const [lastVisitedOrgSlug] = useLocalStorageQuery( @@ -40,8 +41,6 @@ const GenericProjectPage: NextPage = () => { '' ) - const [selectedSlug, setSlug] = useState(lastVisitedOrgSlug) - const { data: organizations = [], isSuccess: isSuccessOrganizations, @@ -50,6 +49,10 @@ const GenericProjectPage: NextPage = () => { } = useOrganizationsQuery({ enabled: IS_PLATFORM, }) + + const [selectedSlug, setSlug] = useState( + slug || lastVisitedOrgSlug || organizations[0]?.slug + ) const selectedOrganization = organizations.find((x) => x.slug === selectedSlug) const query = Object.keys(queryParams).length From d2b267be67f2c6291a7d86e1f2250dde79ee6776 Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Thu, 9 Oct 2025 13:23:38 +0800 Subject: [PATCH 02/16] Add perms check for storage migration callout (#39363) * Add perms check for storage migration callout * Clean --- .../StorageListV2MigrationCallout.tsx | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/apps/studio/components/interfaces/Storage/StorageSettings/StorageListV2MigrationCallout.tsx b/apps/studio/components/interfaces/Storage/StorageSettings/StorageListV2MigrationCallout.tsx index 4f02d92836b06..a357faaaebf1b 100644 --- a/apps/studio/components/interfaces/Storage/StorageSettings/StorageListV2MigrationCallout.tsx +++ b/apps/studio/components/interfaces/Storage/StorageSettings/StorageListV2MigrationCallout.tsx @@ -1,10 +1,13 @@ +import { PermissionAction } from '@supabase/shared-types/out/constants' import dayjs from 'dayjs' +import { useState } from 'react' import { toast } from 'sonner' import { useParams } from 'common' +import { ButtonTooltip } from 'components/ui/ButtonTooltip' import { InlineLink } from 'components/ui/InlineLink' import { useProjectStorageConfigUpdateUpdateMutation } from 'data/config/project-storage-config-update-mutation' -import { useState } from 'react' +import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions' import { Button, Dialog, @@ -67,6 +70,10 @@ export const StorageListV2MigratingCallout = () => { const StorageListV2MigrationDialog = () => { const { ref } = useParams() + const { can: canUpdateStorageSettings } = useAsyncCheckPermissions( + PermissionAction.STORAGE_ADMIN_WRITE, + '*' + ) const [open, setOpen] = useState(false) @@ -86,7 +93,20 @@ const StorageListV2MigrationDialog = () => { return ( - + + Upgrade Storage + From 764eb8760c0191fc6af41c5d96ff50698ac2054f Mon Sep 17 00:00:00 2001 From: Han Qiao Date: Thu, 9 Oct 2025 13:44:23 +0800 Subject: [PATCH 03/16] fix: binds studio listener to both ipv4 and ipv6 (#39383) --- docker/.env.example | 1 - docker/docker-compose.yml | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docker/.env.example b/docker/.env.example index 63f2b2702a5ff..34ceb7bf99321 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -95,7 +95,6 @@ ENABLE_PHONE_AUTOCONFIRM=true STUDIO_DEFAULT_ORGANIZATION=Default Organization STUDIO_DEFAULT_PROJECT=Default Project -STUDIO_PORT=3000 # replace if you intend to use Studio outside of localhost SUPABASE_PUBLIC_URL=http://localhost:8000 diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 14f7c39f58577..9f484246be6e7 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -28,6 +28,9 @@ services: analytics: condition: service_healthy environment: + # Binds nestjs listener to both IPv4 and IPv6 network interfaces + HOSTNAME: "::" + STUDIO_PG_META_URL: http://meta:8080 POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} PG_META_CRYPTO_KEY: ${PG_META_CRYPTO_KEY} From 10d75def88cb33d416fd3e9acf39806d47a05397 Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Thu, 9 Oct 2025 13:46:56 +0800 Subject: [PATCH 04/16] Add hide/show anon key button to edge function details page (#39384) * Add hide/show anon key button to edge function details page, remove react-copy-to-clipboard package * Clean --- .../EdgeFunctionDetails.constants.ts | 33 +++++--- .../EdgeFunctionDetails.tsx | 80 ++++++++++++++----- .../QueryPerformance/SqlMonacoBlock.tsx | 24 +++--- apps/studio/package.json | 2 - .../ui/src/components/CodeBlock/CodeBlock.tsx | 44 +++++----- .../SimpleCodeBlock/SimpleCodeBlock.tsx | 10 ++- pnpm-lock.yaml | 6 -- 7 files changed, 126 insertions(+), 73 deletions(-) diff --git a/apps/studio/components/interfaces/Functions/EdgeFunctionDetails/EdgeFunctionDetails.constants.ts b/apps/studio/components/interfaces/Functions/EdgeFunctionDetails/EdgeFunctionDetails.constants.ts index 505a373fa6f9c..f8492a1c6947d 100644 --- a/apps/studio/components/interfaces/Functions/EdgeFunctionDetails/EdgeFunctionDetails.constants.ts +++ b/apps/studio/components/interfaces/Functions/EdgeFunctionDetails/EdgeFunctionDetails.constants.ts @@ -3,7 +3,12 @@ interface InvocationTab { label: string language: 'bash' | 'js' | 'ts' | 'dart' | 'python' hideLineNumbers?: boolean - code: (functionUrl: string, functionName: string, apiKey: string) => string + code: (props: { + showKey: boolean + functionUrl: string + functionName: string + apiKey: string + }) => string } export const INVOCATION_TABS: InvocationTab[] = [ @@ -11,17 +16,24 @@ export const INVOCATION_TABS: InvocationTab[] = [ id: 'curl', label: 'cURL', language: 'bash', - code: (functionUrl, _, apiKey) => `curl -L -X POST '${functionUrl}' \\ - -H 'Authorization: Bearer ${apiKey}' \\${apiKey.includes('publishable') ? `\n -H 'apikey: ${apiKey}' \\` : ''} + code: ({ showKey, functionUrl, apiKey }) => { + const obfuscatedName = apiKey.includes('publishable') + ? 'SUPABASE_PUBLISHABLE_DEFAULT_KEY' + : 'SUPABASE_ANON_KEY' + const keyValue = showKey ? apiKey : obfuscatedName + + return `curl -L -X POST '${functionUrl}' \\ + -H 'Authorization: Bearer ${keyValue}' \\${apiKey.includes('publishable') ? `\n -H 'apikey: ${keyValue}' \\` : ''} -H 'Content-Type: application/json' \\ - --data '{"name":"Functions"}'`, + --data '{"name":"Functions"}'` + }, }, { id: 'supabase-js', label: 'JavaScript', language: 'js', hideLineNumbers: true, - code: (_, functionName) => `import { createClient } from '@supabase/supabase-js' + code: ({ functionName }) => `import { createClient } from '@supabase/supabase-js' const supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_ANON_KEY) const { data, error } = await supabase.functions.invoke('${functionName}', { body: { name: 'Functions' }, @@ -32,7 +44,7 @@ const { data, error } = await supabase.functions.invoke('${functionName}', { label: 'Swift', language: 'ts', hideLineNumbers: true, - code: (_, functionName) => `struct Response: Decodable { + code: ({ functionName }) => `struct Response: Decodable { // Expected response definition } @@ -49,10 +61,9 @@ let response: Response = try await supabase.functions label: 'Flutter', language: 'dart', hideLineNumbers: true, - code: ( - _, - functionName - ) => `final res = await supabase.functions.invoke('${functionName}', body: {'name': 'Functions'}); + code: ({ + functionName, + }) => `final res = await supabase.functions.invoke('${functionName}', body: {'name': 'Functions'}); final data = res.data;`, }, { @@ -60,7 +71,7 @@ final data = res.data;`, label: 'Python', language: 'python', hideLineNumbers: true, - code: (_, functionName) => `response = supabase.functions.invoke( + code: ({ functionName }) => `response = supabase.functions.invoke( "${functionName}", invoke_options={"body": {"name": "Functions"}} )`, diff --git a/apps/studio/components/interfaces/Functions/EdgeFunctionDetails/EdgeFunctionDetails.tsx b/apps/studio/components/interfaces/Functions/EdgeFunctionDetails/EdgeFunctionDetails.tsx index 2d3f39195b068..f3d6ebe64387b 100644 --- a/apps/studio/components/interfaces/Functions/EdgeFunctionDetails/EdgeFunctionDetails.tsx +++ b/apps/studio/components/interfaces/Functions/EdgeFunctionDetails/EdgeFunctionDetails.tsx @@ -33,6 +33,7 @@ import { CardTitle, cn, CodeBlock, + copyToClipboard, CriticalIcon, Form_Shadcn_, FormControl_Shadcn_, @@ -60,11 +61,6 @@ const FormSchema = z.object({ export const EdgeFunctionDetails = () => { const router = useRouter() const { ref: projectRef, functionSlug } = useParams() - const [showDeleteModal, setShowDeleteModal] = useState(false) - const { can: canUpdateEdgeFunction } = useAsyncCheckPermissions( - PermissionAction.FUNCTIONS_WRITE, - '*' - ) const showAllEdgeFunctionInvocationExamples = useIsFeatureEnabled( 'edge_functions:show_all_edge_function_invocation_examples' @@ -74,6 +70,15 @@ export const EdgeFunctionDetails = () => { return INVOCATION_TABS.filter((tab) => tab.id === 'curl' || tab.id === 'supabase-js') }, [showAllEdgeFunctionInvocationExamples]) + const [showKey, setShowKey] = useState(false) + const [selectedTab, setSelectedTab] = useState(invocationTabs[0].id) + const [showDeleteModal, setShowDeleteModal] = useState(false) + + const { can: canUpdateEdgeFunction } = useAsyncCheckPermissions( + PermissionAction.FUNCTIONS_WRITE, + '*' + ) + const { data: apiKeys } = useAPIKeysQuery({ projectRef }) const { data: settings } = useProjectSettingsV2Query({ projectRef }) const { data: customDomainData } = useCustomDomainsQuery({ projectRef }) @@ -231,34 +236,69 @@ export const EdgeFunctionDetails = () => { + Invoke function - - - + + + {invocationTabs.map((tab) => ( {tab.label} ))} + {selectedTab === 'curl' && ( + + )} - {invocationTabs.map((tab) => ( - -
    - -
    -
    - ))} + {invocationTabs.map((tab) => { + const code = tab.code({ + showKey, + functionUrl, + functionName: selectedFunction?.name ?? '', + apiKey, + }) + + return ( + +
    + { + copyToClipboard( + tab.code({ + showKey: true, + functionUrl, + functionName: selectedFunction?.name ?? '', + apiKey, + }) + ) + }} + /> +
    +
    + ) + })}
    + Develop locally
    diff --git a/apps/studio/components/interfaces/QueryPerformance/SqlMonacoBlock.tsx b/apps/studio/components/interfaces/QueryPerformance/SqlMonacoBlock.tsx index 853d32bcfc8b9..9aab8444bffbe 100644 --- a/apps/studio/components/interfaces/QueryPerformance/SqlMonacoBlock.tsx +++ b/apps/studio/components/interfaces/QueryPerformance/SqlMonacoBlock.tsx @@ -1,9 +1,8 @@ import Editor from '@monaco-editor/react' import { Check, Copy } from 'lucide-react' import { useMemo, useState } from 'react' -import { CopyToClipboard } from 'react-copy-to-clipboard' -import { Button, cn } from 'ui' +import { Button, cn, copyToClipboard } from 'ui' type SqlMonacoBlockProps = { value?: string @@ -28,8 +27,9 @@ export const SqlMonacoBlock = ({ const content = useMemo(() => value ?? '', [value]) - const handleCopy = () => { + const handleCopy = (value: string) => { setCopied(true) + copyToClipboard(value) setTimeout(() => setCopied(false), 1000) } @@ -73,16 +73,14 @@ export const SqlMonacoBlock = ({ {!hideCopy && (
    - - - +
    )}
    diff --git a/apps/studio/package.json b/apps/studio/package.json index 51d8466275e32..c0ef84e19fe86 100644 --- a/apps/studio/package.json +++ b/apps/studio/package.json @@ -110,7 +110,6 @@ "react": "catalog:", "react-beautiful-dnd": "^13.1.0", "react-contexify": "^5.0.0", - "react-copy-to-clipboard": "^5.1.0", "react-data-grid": "7.0.0-beta.41", "react-datepicker": "^4.18.0", "react-day-picker": "^8.8.0", @@ -172,7 +171,6 @@ "@types/randombytes": "^2.0.3", "@types/react": "catalog:", "@types/react-beautiful-dnd": "^13.1.2", - "@types/react-copy-to-clipboard": "^5.0.4", "@types/react-datepicker": "^4.3.4", "@types/react-dom": "catalog:", "@types/react-grid-layout": "^1.3.0", diff --git a/packages/ui/src/components/CodeBlock/CodeBlock.tsx b/packages/ui/src/components/CodeBlock/CodeBlock.tsx index 56322df9d6a5a..039763e51a565 100644 --- a/packages/ui/src/components/CodeBlock/CodeBlock.tsx +++ b/packages/ui/src/components/CodeBlock/CodeBlock.tsx @@ -4,9 +4,9 @@ import { noop } from 'lodash' import { Check, Copy } from 'lucide-react' import { useTheme } from 'next-themes' import { Children, ReactNode, useState } from 'react' -import { CopyToClipboard } from 'react-copy-to-clipboard' import { Light as SyntaxHighlighter, SyntaxHighlighterProps } from 'react-syntax-highlighter' +import { copyToClipboard } from '../../lib/utils' import { cn } from '../../lib/utils/cn' import { Button } from '../Button/Button' import { monokaiCustomTheme } from './CodeBlock.utils' @@ -20,13 +20,13 @@ import http from 'react-syntax-highlighter/dist/cjs/languages/hljs/http' import js from 'react-syntax-highlighter/dist/cjs/languages/hljs/javascript' import json from 'react-syntax-highlighter/dist/cjs/languages/hljs/json' import kotlin from 'react-syntax-highlighter/dist/cjs/languages/hljs/kotlin' +import pgsql from 'react-syntax-highlighter/dist/cjs/languages/hljs/pgsql' import php from 'react-syntax-highlighter/dist/cjs/languages/hljs/php' import { default as py, default as python, } from 'react-syntax-highlighter/dist/cjs/languages/hljs/python' import sql from 'react-syntax-highlighter/dist/cjs/languages/hljs/sql' -import pgsql from 'react-syntax-highlighter/dist/cjs/languages/hljs/pgsql' import ts from 'react-syntax-highlighter/dist/cjs/languages/hljs/typescript' export type CodeBlockLang = @@ -63,10 +63,11 @@ export interface CodeBlockProps { value?: string theme?: any children?: string - renderer?: SyntaxHighlighterProps['renderer'] + wrapLines?: boolean focusable?: boolean + renderer?: SyntaxHighlighterProps['renderer'] + handleCopy?: (value?: string) => void onCopyCallback?: () => void - wrapLines?: boolean } /** @@ -85,6 +86,7 @@ export interface CodeBlockProps { * @param {boolean} [props.hideLineNumbers=false] - Whether to hide line numbers. * @param {SyntaxHighlighterProps['renderer']} [props.renderer] - Custom renderer for syntax highlighting. * @param {boolean} [props.focusable=true] - Whether the code block is focusable. When true, users can focus the code block to select text or use ⌘A (Cmd+A) to select all. This is so we don't need to load Monaco Editor. + * @param {function} [props.handleCopy] - Optional override behaviour for copying value. For e.g if the code block contains obfuscated values, but the copy behaviour should reveal those values instead. */ export const CodeBlock = ({ title, @@ -103,6 +105,7 @@ export const CodeBlock = ({ renderer, focusable = true, onCopyCallback = noop, + handleCopy, }: CodeBlockProps) => { const { resolvedTheme } = useTheme() const isDarkTheme = resolvedTheme?.includes('dark')! @@ -110,12 +113,17 @@ export const CodeBlock = ({ const [copied, setCopied] = useState(false) - const handleCopy = () => { + const onSelectCopy = (value?: string) => { + if (value) { + if (!!handleCopy) { + handleCopy(value) + } else { + copyToClipboard(value) + } + } setCopied(true) onCopyCallback() - setTimeout(() => { - setCopied(false) - }, 1000) + setTimeout(() => setCopied(false), 1000) } // Extract string when `children` has a single string node @@ -240,18 +248,14 @@ export const CodeBlock = ({ `${isDarkTheme ? 'dark' : ''}`, ].join(' ')} > - {/* // - @ts-ignore */} - - - + ) : null} diff --git a/packages/ui/src/components/SimpleCodeBlock/SimpleCodeBlock.tsx b/packages/ui/src/components/SimpleCodeBlock/SimpleCodeBlock.tsx index cb84acae791e4..109a9590dbfa7 100644 --- a/packages/ui/src/components/SimpleCodeBlock/SimpleCodeBlock.tsx +++ b/packages/ui/src/components/SimpleCodeBlock/SimpleCodeBlock.tsx @@ -26,14 +26,17 @@ interface SimpleCodeBlockProps { className?: string showCopy?: boolean onCopy?: () => void + handleCopy?: (value: string) => void } +// [Joshen] Refactor: De-dupe with CodeBlock.tsx export const SimpleCodeBlock = ({ children, parentClassName, className: languageClassName, showCopy = true, onCopy, + handleCopy, }: PropsWithChildren) => { const { resolvedTheme } = useTheme() const [showCopied, setShowCopied] = useState(false) @@ -53,7 +56,12 @@ export const SimpleCodeBlock = ({ } const handleCopyCode = (code: any) => { - copyToClipboard(code, () => setShowCopied(true)) + if (!!handleCopy) { + handleCopy(code) + } else { + copyToClipboard(code) + } + setShowCopied(true) onCopy?.() } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4944220ab4d5c..c7f586086bdcb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -972,9 +972,6 @@ importers: react-contexify: specifier: ^5.0.0 version: 5.0.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react-copy-to-clipboard: - specifier: ^5.1.0 - version: 5.1.0(react@18.3.1) react-data-grid: specifier: 7.0.0-beta.41 version: 7.0.0-beta.41(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -1153,9 +1150,6 @@ importers: '@types/react-beautiful-dnd': specifier: ^13.1.2 version: 13.1.5 - '@types/react-copy-to-clipboard': - specifier: ^5.0.4 - version: 5.0.5 '@types/react-datepicker': specifier: ^4.3.4 version: 4.15.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) From a50ccb80e3742245c68934408f7ea4a776d977d4 Mon Sep 17 00:00:00 2001 From: Andrew Valleteau Date: Thu, 9 Oct 2025 08:13:33 +0200 Subject: [PATCH 05/16] docs(branching): add branching deploy steps overview (#39232) * docs(branching): add branching deploy steps overview * Update apps/docs/content/guides/deployment/branching.mdx Co-authored-by: Han Qiao * Apply suggestion from @github-actions[bot] Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * Apply suggestion from @github-actions[bot] Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * chore: split up overview and troubleshooting * chore: rearrange heading for readability * chore: rephrase promoting to production * chore: clarify git push runs the same workflow * chore: more minor edits * chore: more clarity --------- Co-authored-by: Han Qiao Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Qiao Han --- apps/docs/content/guides/deployment/branching.mdx | 14 ++++++++++++++ .../deployment/branching/troubleshooting.mdx | 13 +++++++++++++ 2 files changed, 27 insertions(+) diff --git a/apps/docs/content/guides/deployment/branching.mdx b/apps/docs/content/guides/deployment/branching.mdx index 6749078bc03f0..74782ceb45579 100644 --- a/apps/docs/content/guides/deployment/branching.mdx +++ b/apps/docs/content/guides/deployment/branching.mdx @@ -14,3 +14,17 @@ Supabase branches create separate environments that spin off from your main proj - **Persistent Branches**: Persistent branches are long-lived branches. They aren't automatically paused or deleted due to non-inactivity or merging. - **Managing Branches**: You can create, review, and merge branches either automatically via our [GitHub integration](/docs/guides/deployment/branching/github-integration) or directly [through the dashboard](/docs/guides/deployment/branching/dashboard) (currently in beta). All branches show up in the branches page in the dashboard, regardless of how they were created. - **Data-less**: New branches do not start with any data from your main project. This is meant to better protect your sensitive production data. To start your branches with data, you can use a [seed file](/docs/guides/deployment/branching/github-integration#seeding) if using the GitHub integration. + +## Deploying to production + +When you merge any branch into your main project, Supabase automatically runs a deployment workflow to deploy your changes to production. The deployment workflow is expressed as a Directed Acyclic Graph where each node represents one of the following deployment steps. + +1. **Clone** - Checks out your repository at the specified git branch (optional for [Branching via Dashboard](/docs/guides/deployment/branching/dashboard)) +2. **Pull** - Retrieves database migrations from your main project (also initialises the migration history table when Branching via Dashboard) +3. **Health** - Waits up to 2 minutes for all Supabase services on your branch to be running and healthy, including Auth, API, Database, Storage, and Realtime +4. **Configure** - Updates service configurations based on your config.toml file (only available for [Branching via GitHub](/docs/guides/deployment/branching/github-integration)) +5. **Migrate** - Applies pending database migrations and vault secrets to your branch +6. **Seed** - Runs seed files to populate your branch with initial data (must be [enabled in config.toml](/docs/guides/deployment/branching/configuration#branch-configuration-with-remotes) for persistent branches) +7. **Deploy** - Deploys any changed Edge Functions and updates function secrets + +If a parent deployment step fails, all dependent children steps will be skipped. For e.g., if your database migrations failed at step 5, our runner will not seed your branch because step 6 is skipped. If you are using GitHub integration, the same deployment workflow will be run on every commit pushed to your git branch. diff --git a/apps/docs/content/guides/deployment/branching/troubleshooting.mdx b/apps/docs/content/guides/deployment/branching/troubleshooting.mdx index bc494b8b274cc..1ce577728f891 100644 --- a/apps/docs/content/guides/deployment/branching/troubleshooting.mdx +++ b/apps/docs/content/guides/deployment/branching/troubleshooting.mdx @@ -6,6 +6,19 @@ subtitle: 'Common issues and solutions for Supabase branching' This guide covers common issues you might encounter when using Supabase branching and how to resolve them. +## Monitoring deployments + +To check deployment status and troubleshoot failures: + +1. Go to your project dashboard +2. Navigate to "Manage Branches" +3. Click on your branch to view deployment logs +4. Check the "View logs" section for detailed error messages + +For programmatic monitoring, you can use the [Management API](https://api.supabase.com/api/v1#tag/environments/post/v1/projects/{ref}/branches) to poll branch status. + +For detailed troubleshooting guidance, see our [Troubleshooting guide](/docs/guides/deployment/branching/troubleshooting). + ## Common issues ### Rolling back migrations From e6548079ed369797f9ce5e49060c47e3f236afc4 Mon Sep 17 00:00:00 2001 From: Laksh Jain <151378737+LakshRJain@users.noreply.github.com> Date: Thu, 9 Oct 2025 12:02:14 +0530 Subject: [PATCH 06/16] =?UTF-8?q?=F0=9F=93=9A=20Docs:=20Clarify=20that=20`?= =?UTF-8?q?auth.uid()`=20returns=20`null`=20when=20unauthenticated=20in=20?= =?UTF-8?q?RLS=20policies=20(#37336)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 📚 Fix: Clarify behavior of auth.uid() when unauthenticated in RLS * Update row-level-security.mdx * Update row-level-security.mdx * Update row-level-security.mdx * Update apps/docs/content/guides/database/postgres/row-level-security.mdx * Update apps/docs/content/guides/database/postgres/row-level-security.mdx * Update apps/docs/content/guides/database/postgres/row-level-security.mdx * Update apps/docs/content/guides/database/postgres/row-level-security.mdx * Update warning about `auth.uid()` behavior Clarified behavior of `auth.uid()` when unauthenticated and recommended explicit authentication checks. * Change admonition type from warning to caution * Update SQL condition for row-level security Clarify row-level security SQL condition for unauthenticated users. --------- Co-authored-by: Chris Chinchilla Co-authored-by: Chris Chinchilla --- .../database/postgres/row-level-security.mdx | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/apps/docs/content/guides/database/postgres/row-level-security.mdx b/apps/docs/content/guides/database/postgres/row-level-security.mdx index b527370a33c63..2abe63dc067b6 100644 --- a/apps/docs/content/guides/database/postgres/row-level-security.mdx +++ b/apps/docs/content/guides/database/postgres/row-level-security.mdx @@ -59,6 +59,32 @@ alter table "table_name" enable row level security; Once you have enabled RLS, no data will be accessible via the [API](/docs/guides/api) when using the public `anon` key, until you create policies. + + +When a request is made without an authenticated user (e.g., no access token is provided or the session has expired), `auth.uid()` returns `null`. + +This means that a policy like: + +```sql +USING (auth.uid() = user_id) +``` + +will silently fail for unauthenticated users, because: + +```sql +null = user_id +``` + +is always false in SQL. + +To avoid confusion and make your intention clear, we recommend explicitly checking for authentication: + +```sql +USING (auth.uid() IS NOT NULL AND auth.uid() = user_id) +``` + + + ## Authenticated and unauthenticated roles Supabase maps every request to one of the roles: From 433e5788a938ab7d0872cac2e8cfa4b5c9f7dbbf Mon Sep 17 00:00:00 2001 From: Ivan Vasilov Date: Thu, 9 Oct 2025 10:27:13 +0300 Subject: [PATCH 07/16] fix: Add temp API keys to selfhosted (#39356) * Deduplicate @babel/core. * Remove explicit dependency of import-in-the-middle (it's imported in sentry deps). * Add an API route for api-keys/temporary. * Refresh the token if on self-hosted. * Readd import-in-the-middle. * Bump supabase to 2.50.3 which contains fixes for storage upload. --- .../Inspector/ChooseChannelPopover/index.tsx | 4 +- .../interfaces/Realtime/Inspector/Header.tsx | 4 +- apps/studio/package.json | 2 +- .../projects/[ref]/api-keys/temporary.ts | 33 ++ package.json | 2 +- pnpm-lock.yaml | 482 +++++------------- pnpm-workspace.yaml | 3 +- 7 files changed, 157 insertions(+), 373 deletions(-) create mode 100644 apps/studio/pages/api/platform/projects/[ref]/api-keys/temporary.ts diff --git a/apps/studio/components/interfaces/Realtime/Inspector/ChooseChannelPopover/index.tsx b/apps/studio/components/interfaces/Realtime/Inspector/ChooseChannelPopover/index.tsx index 3d16108accc52..f106a20a12054 100644 --- a/apps/studio/components/interfaces/Realtime/Inspector/ChooseChannelPopover/index.tsx +++ b/apps/studio/components/interfaces/Realtime/Inspector/ChooseChannelPopover/index.tsx @@ -1,5 +1,5 @@ import { zodResolver } from '@hookform/resolvers/zod' -import { useParams } from 'common' +import { IS_PLATFORM, useParams } from 'common' import { ChevronDown } from 'lucide-react' import { Dispatch, SetStateAction, useState } from 'react' import { useForm } from 'react-hook-form' @@ -67,7 +67,7 @@ export const ChooseChannelPopover = ({ config, onChangeConfig }: ChooseChannelPo let token = config.token // [Joshen] Refresh if starting to listen + using temp API key, since it has a low refresh rate - if (token.startsWith('sb_temp')) { + if (token.startsWith('sb_temp') || !IS_PLATFORM) { const data = await getTemporaryAPIKey({ projectRef: config.projectRef, expiry: 3600 }) token = data.api_key } diff --git a/apps/studio/components/interfaces/Realtime/Inspector/Header.tsx b/apps/studio/components/interfaces/Realtime/Inspector/Header.tsx index 10d9573184dd1..e37f6039714fa 100644 --- a/apps/studio/components/interfaces/Realtime/Inspector/Header.tsx +++ b/apps/studio/components/interfaces/Realtime/Inspector/Header.tsx @@ -2,7 +2,7 @@ import { PermissionAction } from '@supabase/shared-types/out/constants' import { PlayCircle, StopCircle } from 'lucide-react' import { Dispatch, SetStateAction } from 'react' -import { useParams } from 'common' +import { IS_PLATFORM, useParams } from 'common' import { ButtonTooltip } from 'components/ui/ButtonTooltip' import { getTemporaryAPIKey } from 'data/api-keys/temp-api-keys-query' import { useSendEventMutation } from 'data/telemetry/send-event-mutation' @@ -41,7 +41,7 @@ export const Header = ({ config, onChangeConfig }: HeaderProps) => { icon={config.enabled ? : } onClick={async () => { // [Joshen] Refresh if starting to listen + using temp API key, since it has a low refresh rate - if (!config.enabled && config.token.startsWith('sb_temp')) { + if (!config.enabled && (config.token.startsWith('sb_temp') || !IS_PLATFORM)) { const data = await getTemporaryAPIKey({ projectRef: config.projectRef, expiry: 3600 }) const token = data.api_key onChangeConfig({ ...config, token, enabled: !config.enabled }) diff --git a/apps/studio/package.json b/apps/studio/package.json index c0ef84e19fe86..5a0b527c809ee 100644 --- a/apps/studio/package.json +++ b/apps/studio/package.json @@ -191,7 +191,7 @@ "eslint-config-supabase": "workspace:*", "eslint-plugin-barrel-files": "^2.0.7", "graphql-ws": "5.14.1", - "import-in-the-middle": "^1.13.1", + "import-in-the-middle": "^1.14.2", "jsdom-testing-mocks": "^1.13.1", "msw": "^2.3.0", "next-router-mock": "^0.9.13", diff --git a/apps/studio/pages/api/platform/projects/[ref]/api-keys/temporary.ts b/apps/studio/pages/api/platform/projects/[ref]/api-keys/temporary.ts new file mode 100644 index 0000000000000..d8a098039ba49 --- /dev/null +++ b/apps/studio/pages/api/platform/projects/[ref]/api-keys/temporary.ts @@ -0,0 +1,33 @@ +import { NextApiRequest, NextApiResponse } from 'next' + +import { components } from 'api-types' +import apiWrapper from 'lib/api/apiWrapper' + +type ProjectAppConfig = components['schemas']['ProjectSettingsResponse']['app_config'] & { + protocol?: string +} +export type ProjectSettings = components['schemas']['ProjectSettingsResponse'] & { + app_config?: ProjectAppConfig +} + +export default (req: NextApiRequest, res: NextApiResponse) => apiWrapper(req, res, handler) + +async function handler(req: NextApiRequest, res: NextApiResponse) { + const { method } = req + + switch (method) { + case 'POST': + return handlePost(req, res) + default: + res.setHeader('Allow', ['POST']) + res.status(405).json({ data: null, error: { message: `Method ${method} Not Allowed` } }) + } +} + +const handlePost = async (req: NextApiRequest, res: NextApiResponse) => { + const response = { + api_key: process.env.SUPABASE_SERVICE_KEY ?? '', + } + + return res.status(200).json(response) +} diff --git a/package.json b/package.json index 9b1126f127386..d8b192fe306d6 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "prettier-plugin-sql-cst": "^0.11.0", "rimraf": "^6.0.0", "sass": "^1.72.0", - "supabase": "^1.151.1", + "supabase": "^2.50.3", "supports-color": "^8.0.0", "turbo": "2.3.3", "typescript": "catalog:" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c7f586086bdcb..2f8426a1e62b9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -83,8 +83,8 @@ importers: specifier: ^1.72.0 version: 1.72.0 supabase: - specifier: ^1.151.1 - version: 1.151.1(supports-color@8.1.1) + specifier: ^2.50.3 + version: 2.50.3(supports-color@8.1.1) supports-color: specifier: ^8.0.0 version: 8.1.1 @@ -237,10 +237,10 @@ importers: version: 1.2.0 next: specifier: 'catalog:' - version: 15.5.2(@babel/core@7.26.10(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4) + version: 15.5.2(@babel/core@7.28.4(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4) next-contentlayer2: specifier: 0.4.6 - version: 0.4.6(contentlayer2@0.4.6(esbuild@0.25.2)(markdown-wasm@1.2.0)(supports-color@8.1.1))(esbuild@0.25.2)(markdown-wasm@1.2.0)(next@15.5.2(@babel/core@7.26.10(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(supports-color@8.1.1) + version: 0.4.6(contentlayer2@0.4.6(esbuild@0.25.2)(markdown-wasm@1.2.0)(supports-color@8.1.1))(esbuild@0.25.2)(markdown-wasm@1.2.0)(next@15.5.2(@babel/core@7.28.4(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(supports-color@8.1.1) next-themes: specifier: ^0.3.0 version: 0.3.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -1205,8 +1205,8 @@ importers: specifier: 5.14.1 version: 5.14.1(graphql@16.11.0) import-in-the-middle: - specifier: ^1.13.1 - version: 1.13.1 + specifier: ^1.14.2 + version: 1.14.2 jsdom-testing-mocks: specifier: ^1.13.1 version: 1.13.1 @@ -3050,18 +3050,10 @@ packages: resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.26.5': - resolution: {integrity: sha512-XvcZi1KWf88RVbF9wn8MN6tYFloU5qX8KjuF3E1PVBmJ9eypXfs4GRiJwLuTZL0iSnJUKn1BFPa5BPZZJyFzPg==} - engines: {node: '>=6.9.0'} - '@babel/compat-data@7.28.4': resolution: {integrity: sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==} engines: {node: '>=6.9.0'} - '@babel/core@7.26.10': - resolution: {integrity: sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==} - engines: {node: '>=6.9.0'} - '@babel/core@7.28.4': resolution: {integrity: sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==} engines: {node: '>=6.9.0'} @@ -3078,10 +3070,6 @@ packages: resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.26.5': - resolution: {integrity: sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==} - engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.27.2': resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} engines: {node: '>=6.9.0'} @@ -3112,20 +3100,10 @@ packages: resolution: {integrity: sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==} engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.25.9': - resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} - engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.27.1': resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.26.0': - resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - '@babel/helper-module-transforms@7.28.3': resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} engines: {node: '>=6.9.0'} @@ -3158,26 +3136,10 @@ packages: resolution: {integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==} engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@7.24.7': - resolution: {integrity: sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==} - engines: {node: '>=6.9.0'} - - '@babel/helper-string-parser@7.25.9': - resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} - engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@7.27.1': resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.24.7': - resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-identifier@7.25.9': - resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} - engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.27.1': resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} engines: {node: '>=6.9.0'} @@ -3186,10 +3148,6 @@ packages: resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.26.10': - resolution: {integrity: sha512-UPYc3SauzZ3JGgj87GgZ89JVdC5dj0AoetR5Bw6wj4niittNyFh6+eOGonYvJ1ao6B8lEa3Q3klS7ADZ53bc5g==} - engines: {node: '>=6.9.0'} - '@babel/helpers@7.28.4': resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} engines: {node: '>=6.9.0'} @@ -4489,10 +4447,6 @@ packages: '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - '@jridgewell/gen-mapping@0.3.8': - resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} - engines: {node: '>=6.0.0'} - '@jridgewell/remapping@2.3.5': resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} @@ -4500,10 +4454,6 @@ packages: resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} - '@jridgewell/set-array@1.2.1': - resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} - engines: {node: '>=6.0.0'} - '@jridgewell/source-map@0.3.6': resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} @@ -4513,9 +4463,6 @@ packages: '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - '@jridgewell/trace-mapping@0.3.25': - resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} - '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} @@ -10519,9 +10466,9 @@ packages: big.js@5.2.2: resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} - bin-links@4.0.3: - resolution: {integrity: sha512-obsRaULtJurnfox/MDwgq6Yo9kzbv1CPTk/1/s7Z/61Lezc8IKkFCOXNeVLXz0456WRzBQmSsDWlai2tIhBsfA==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + bin-links@5.0.0: + resolution: {integrity: sha512-sdleLVfCjBtgO5cNjA2HVRvWBJAHs4zwenaCPMNJAJU0yNxpzj80IpjOIimkpkr+mhlA+how5poQtt53PygbHA==} + engines: {node: ^18.17.0 || >=20.5.0} binary-extensions@2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} @@ -10878,9 +10825,9 @@ packages: resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} engines: {node: '>=0.10.0'} - cmd-shim@6.0.2: - resolution: {integrity: sha512-+FFYbB0YLaAkhkcrjkyNLYDiOsFSfRjwjY19LXk/psmMx1z00xlCv7hhQoTGXXIKi+YXHL/iiFo8NqMVQX9nOw==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + cmd-shim@7.0.0: + resolution: {integrity: sha512-rtpaCbr164TPPh+zFdkWpCyZuKkjpAzODfaZCf/SVJZzJN+4bHQb/LP3Jzq5/+84um3XXY8r548XiWKSborwVw==} + engines: {node: ^18.17.0 || >=20.5.0} cmdk@1.0.0: resolution: {integrity: sha512-gDzVf0a09TvoJ5jnuPvygTB77+XdOSwEmJ88L6XPFPlv7T3RxbP9jgenfylrAMD0+Le1aO0nVjQUzl2g+vjz5Q==} @@ -13494,10 +13441,6 @@ packages: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} - https-proxy-agent@7.0.4: - resolution: {integrity: sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==} - engines: {node: '>= 14'} - https-proxy-agent@7.0.6: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} @@ -13586,9 +13529,6 @@ packages: resolution: {integrity: sha512-P9J71vT5nLlDeV8FHs5nNxaLbrpfAV5cF5srvbZfpwpcJoM/xZR3hiv+q+SAnuSmuGbXMWud063iIMx/V/EWZQ==} engines: {node: '>=12.2'} - import-in-the-middle@1.13.1: - resolution: {integrity: sha512-k2V9wNm9B+ysuelDTHjI9d5KPc4l8zAZTGqj+pcynvWkypZd857ryzN8jNC7Pg2YZXNMJcHRPpaDyCBbNyVRpA==} - import-in-the-middle@1.14.2: resolution: {integrity: sha512-5tCuY9BV8ujfOpwtAGgsTx9CGUapcFMEEyByLv1B+v2+6DhAcw+Zr0nhQT7uwaZ7DiourxFEscghOR8e1aPLQw==} @@ -15225,8 +15165,8 @@ packages: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} engines: {node: '>= 8'} - minizlib@3.0.1: - resolution: {integrity: sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==} + minizlib@3.1.0: + resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} engines: {node: '>= 18'} mitt@3.0.1: @@ -15621,6 +15561,10 @@ packages: resolution: {integrity: sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + npm-normalize-package-bin@4.0.0: + resolution: {integrity: sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==} + engines: {node: ^18.17.0 || >=20.5.0} + npm-package-arg@10.1.0: resolution: {integrity: sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} @@ -16693,6 +16637,10 @@ packages: resolution: {integrity: sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + proc-log@5.0.0: + resolution: {integrity: sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==} + engines: {node: ^18.17.0 || >=20.5.0} + process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} @@ -17233,9 +17181,9 @@ packages: read-cache@1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} - read-cmd-shim@4.0.0: - resolution: {integrity: sha512-yILWifhaSEEytfXI76kB9xEEiG1AiozaCJZ83A87ytjRiN+jVibXjedjCRNjoZviinhG+4UkalO3mWTd8u5O0Q==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + read-cmd-shim@5.0.0: + resolution: {integrity: sha512-SEbJV7tohp3DAAILbEMPXavBjAnMN0tVnh4+9G8ihV4Pq3HYF9h8QNez9zkJ1ILkv9G2BjdzwctznGZXgu/HGw==} + engines: {node: ^18.17.0 || >=20.5.0} read-pkg@3.0.0: resolution: {integrity: sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==} @@ -17558,10 +17506,6 @@ packages: engines: {node: '>=14'} hasBin: true - rimraf@5.0.10: - resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==} - hasBin: true - rimraf@6.0.1: resolution: {integrity: sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==} engines: {node: 20 || >=22} @@ -18370,8 +18314,8 @@ packages: engines: {node: '>=8'} hasBin: true - supabase@1.151.1: - resolution: {integrity: sha512-fl4h9mgG3z+bQ7UntymT30yqvOPJ4AfiCDKvDCFAdpkDhiozSfQqh1LwytEQSqMpgt6PEAcDJdYEbvholqPKOQ==} + supabase@2.50.3: + resolution: {integrity: sha512-G+lBC8BTZvGt+kzGdS0ltw2CLR9JZeiaXrTJxL+Cl2BELgf1LZ79GvExoNTqTIMSQFelHpYxFE6nO6BbelOWTQ==} engines: {npm: '>=8'} hasBin: true @@ -18478,8 +18422,8 @@ packages: resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} engines: {node: '>=10'} - tar@7.4.3: - resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} + tar@7.5.1: + resolution: {integrity: sha512-nlGpxf+hv0v7GkWBK2V9spgactGOp0qvfWRxUMjqHyzrt3SgwE48DIv/FhqPHJYLHpgW1opq3nERbz5Anq7n1g==} engines: {node: '>=18'} tdigest@0.1.2: @@ -19878,9 +19822,9 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - write-file-atomic@5.0.1: - resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + write-file-atomic@6.0.0: + resolution: {integrity: sha512-GmqrO8WJ1NuzJ2DrziEI2o57jKAVIQNf8a18W3nCYU3H7PNWqCCVTeH6/NQE93CIllIgQS98rrmVkYgTX9fFJQ==} + engines: {node: ^18.17.0 || >=20.5.0} ws@7.5.10: resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} @@ -21434,7 +21378,7 @@ snapshots: '@babel/code-frame@7.26.2': dependencies: - '@babel/helper-validator-identifier': 7.25.9 + '@babel/helper-validator-identifier': 7.27.1 js-tokens: 4.0.0 picocolors: 1.1.1 @@ -21444,30 +21388,8 @@ snapshots: js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.26.5': {} - '@babel/compat-data@7.28.4': {} - '@babel/core@7.26.10(supports-color@8.1.1)': - dependencies: - '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.26.2 - '@babel/generator': 7.27.0 - '@babel/helper-compilation-targets': 7.26.5 - '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.10(supports-color@8.1.1))(supports-color@8.1.1) - '@babel/helpers': 7.26.10 - '@babel/parser': 7.28.4 - '@babel/template': 7.27.0 - '@babel/traverse': 7.27.0(supports-color@8.1.1) - '@babel/types': 7.27.0 - convert-source-map: 2.0.0 - debug: 4.4.3(supports-color@8.1.1) - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - '@babel/core@7.28.4(supports-color@8.1.1)': dependencies: '@babel/code-frame': 7.27.1 @@ -21492,8 +21414,8 @@ snapshots: dependencies: '@babel/parser': 7.28.4 '@babel/types': 7.28.4 - '@jridgewell/gen-mapping': 0.3.8 - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 '@babel/generator@7.28.3': @@ -21508,14 +21430,6 @@ snapshots: dependencies: '@babel/types': 7.28.4 - '@babel/helper-compilation-targets@7.26.5': - dependencies: - '@babel/compat-data': 7.26.5 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.26.2 - lru-cache: 5.1.1 - semver: 6.3.1 - '@babel/helper-compilation-targets@7.27.2': dependencies: '@babel/compat-data': 7.28.4 @@ -21524,19 +21438,6 @@ snapshots: lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.28.3(@babel/core@7.26.10(supports-color@8.1.1))(supports-color@8.1.1)': - dependencies: - '@babel/core': 7.26.10(supports-color@8.1.1) - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.27.1(supports-color@8.1.1) - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.26.10(supports-color@8.1.1))(supports-color@8.1.1) - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1(supports-color@8.1.1) - '@babel/traverse': 7.28.4(supports-color@8.1.1) - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - '@babel/helper-create-class-features-plugin@7.28.3(@babel/core@7.28.4(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: '@babel/core': 7.28.4(supports-color@8.1.1) @@ -21572,13 +21473,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/helper-module-imports@7.25.9(supports-color@8.1.1)': - dependencies: - '@babel/traverse': 7.28.4(supports-color@8.1.1) - '@babel/types': 7.28.4 - transitivePeerDependencies: - - supports-color - '@babel/helper-module-imports@7.27.1(supports-color@8.1.1)': dependencies: '@babel/traverse': 7.28.4(supports-color@8.1.1) @@ -21586,24 +21480,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.26.0(@babel/core@7.26.10(supports-color@8.1.1))(supports-color@8.1.1)': - dependencies: - '@babel/core': 7.26.10(supports-color@8.1.1) - '@babel/helper-module-imports': 7.25.9(supports-color@8.1.1) - '@babel/helper-validator-identifier': 7.25.9 - '@babel/traverse': 7.28.4(supports-color@8.1.1) - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.28.3(@babel/core@7.26.10(supports-color@8.1.1))(supports-color@8.1.1)': - dependencies: - '@babel/core': 7.26.10(supports-color@8.1.1) - '@babel/helper-module-imports': 7.27.1(supports-color@8.1.1) - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.28.4(supports-color@8.1.1) - transitivePeerDependencies: - - supports-color - '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.4(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: '@babel/core': 7.28.4(supports-color@8.1.1) @@ -21621,15 +21497,6 @@ snapshots: '@babel/helper-plugin-utils@7.27.1': {} - '@babel/helper-replace-supers@7.27.1(@babel/core@7.26.10(supports-color@8.1.1))(supports-color@8.1.1)': - dependencies: - '@babel/core': 7.26.10(supports-color@8.1.1) - '@babel/helper-member-expression-to-functions': 7.27.1(supports-color@8.1.1) - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.28.4(supports-color@8.1.1) - transitivePeerDependencies: - - supports-color - '@babel/helper-replace-supers@7.27.1(@babel/core@7.28.4(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: '@babel/core': 7.28.4(supports-color@8.1.1) @@ -21650,25 +21517,12 @@ snapshots: dependencies: '@babel/types': 7.28.4 - '@babel/helper-string-parser@7.24.7': {} - - '@babel/helper-string-parser@7.25.9': {} - '@babel/helper-string-parser@7.27.1': {} - '@babel/helper-validator-identifier@7.24.7': {} - - '@babel/helper-validator-identifier@7.25.9': {} - '@babel/helper-validator-identifier@7.27.1': {} '@babel/helper-validator-option@7.27.1': {} - '@babel/helpers@7.26.10': - dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.4 - '@babel/helpers@7.28.4': dependencies: '@babel/template': 7.27.2 @@ -21686,9 +21540,9 @@ snapshots: dependencies: '@babel/types': 7.28.4 - '@babel/plugin-syntax-decorators@7.25.9(@babel/core@7.26.10(supports-color@8.1.1))': + '@babel/plugin-syntax-decorators@7.25.9(@babel/core@7.28.4(supports-color@8.1.1))': dependencies: - '@babel/core': 7.26.10(supports-color@8.1.1) + '@babel/core': 7.28.4(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-import-assertions@7.26.0(@babel/core@7.28.4(supports-color@8.1.1))': @@ -21696,14 +21550,9 @@ snapshots: '@babel/core': 7.28.4(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.10(supports-color@8.1.1))': - dependencies: - '@babel/core': 7.26.10(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.26.10(supports-color@8.1.1))': + '@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.28.4(supports-color@8.1.1))': dependencies: - '@babel/core': 7.26.10(supports-color@8.1.1) + '@babel/core': 7.28.4(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.4(supports-color@8.1.1))': @@ -21711,24 +21560,11 @@ snapshots: '@babel/core': 7.28.4(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.26.10(supports-color@8.1.1))': - dependencies: - '@babel/core': 7.26.10(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.4(supports-color@8.1.1))': dependencies: '@babel/core': 7.28.4(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-modules-commonjs@7.27.1(@babel/core@7.26.10(supports-color@8.1.1))(supports-color@8.1.1)': - dependencies: - '@babel/core': 7.26.10(supports-color@8.1.1) - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.26.10(supports-color@8.1.1))(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.27.1 - transitivePeerDependencies: - - supports-color - '@babel/plugin-transform-modules-commonjs@7.27.1(@babel/core@7.28.4(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: '@babel/core': 7.28.4(supports-color@8.1.1) @@ -21737,35 +21573,24 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-react-jsx-self@7.25.9(@babel/core@7.26.10(supports-color@8.1.1))': + '@babel/plugin-transform-react-jsx-self@7.25.9(@babel/core@7.28.4(supports-color@8.1.1))': dependencies: - '@babel/core': 7.26.10(supports-color@8.1.1) + '@babel/core': 7.28.4(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-react-jsx-source@7.25.9(@babel/core@7.26.10(supports-color@8.1.1))': + '@babel/plugin-transform-react-jsx-source@7.25.9(@babel/core@7.28.4(supports-color@8.1.1))': dependencies: - '@babel/core': 7.26.10(supports-color@8.1.1) + '@babel/core': 7.28.4(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-typescript@7.27.0(@babel/core@7.26.10(supports-color@8.1.1))(supports-color@8.1.1)': + '@babel/plugin-transform-typescript@7.27.0(@babel/core@7.28.4(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.26.10(supports-color@8.1.1) - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.26.10(supports-color@8.1.1))(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1(supports-color@8.1.1) - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.26.10(supports-color@8.1.1)) - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-typescript@7.28.0(@babel/core@7.26.10(supports-color@8.1.1))(supports-color@8.1.1)': - dependencies: - '@babel/core': 7.26.10(supports-color@8.1.1) + '@babel/core': 7.28.4(supports-color@8.1.1) '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.26.10(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4(supports-color@8.1.1))(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1(supports-color@8.1.1) - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.26.10(supports-color@8.1.1)) + '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.4(supports-color@8.1.1)) transitivePeerDependencies: - supports-color @@ -21780,14 +21605,14 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/preset-typescript@7.26.0(@babel/core@7.26.10(supports-color@8.1.1))(supports-color@8.1.1)': + '@babel/preset-typescript@7.26.0(@babel/core@7.28.4(supports-color@8.1.1))(supports-color@8.1.1)': dependencies: - '@babel/core': 7.26.10(supports-color@8.1.1) + '@babel/core': 7.28.4(supports-color@8.1.1) '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.26.10(supports-color@8.1.1)) - '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.26.10(supports-color@8.1.1))(supports-color@8.1.1) - '@babel/plugin-transform-typescript': 7.28.0(@babel/core@7.26.10(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.4(supports-color@8.1.1)) + '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.4(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-transform-typescript': 7.28.0(@babel/core@7.28.4(supports-color@8.1.1))(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -21820,14 +21645,14 @@ snapshots: '@babel/traverse@7.24.7(supports-color@8.1.1)': dependencies: - '@babel/code-frame': 7.26.2 - '@babel/generator': 7.27.0 + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.3 '@babel/helper-environment-visitor': 7.24.7 '@babel/helper-function-name': 7.24.7 '@babel/helper-hoist-variables': 7.24.7 '@babel/helper-split-export-declaration': 7.24.7 '@babel/parser': 7.28.4 - '@babel/types': 7.27.0 + '@babel/types': 7.28.4 debug: 4.4.3(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: @@ -21859,14 +21684,14 @@ snapshots: '@babel/types@7.24.7': dependencies: - '@babel/helper-string-parser': 7.24.7 - '@babel/helper-validator-identifier': 7.24.7 + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 to-fast-properties: 2.0.0 '@babel/types@7.27.0': dependencies: - '@babel/helper-string-parser': 7.25.9 - '@babel/helper-validator-identifier': 7.25.9 + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 '@babel/types@7.28.4': dependencies: @@ -23453,12 +23278,6 @@ snapshots: '@jridgewell/sourcemap-codec': 1.5.5 '@jridgewell/trace-mapping': 0.3.31 - '@jridgewell/gen-mapping@0.3.8': - dependencies: - '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - '@jridgewell/remapping@2.3.5': dependencies: '@jridgewell/gen-mapping': 0.3.13 @@ -23466,8 +23285,6 @@ snapshots: '@jridgewell/resolve-uri@3.1.2': {} - '@jridgewell/set-array@1.2.1': {} - '@jridgewell/source-map@0.3.6': dependencies: '@jridgewell/gen-mapping': 0.3.13 @@ -23477,11 +23294,6 @@ snapshots: '@jridgewell/sourcemap-codec@1.5.5': {} - '@jridgewell/trace-mapping@0.3.25': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping@0.3.31': dependencies: '@jridgewell/resolve-uri': 3.1.2 @@ -23736,7 +23548,7 @@ snapshots: node-fetch: 2.7.0(encoding@0.1.13) nopt: 8.1.0 semver: 7.7.2 - tar: 7.4.3 + tar: 7.5.1 transitivePeerDependencies: - encoding - supports-color @@ -27351,12 +27163,12 @@ snapshots: '@react-router/dev@7.4.0(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.5.1)(react-router@7.5.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.19.3)(typescript@5.9.2)(vite@6.3.6(@types/node@22.13.14)(jiti@2.5.1)(sass@1.77.4)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.1))(yaml@2.8.1)': dependencies: - '@babel/core': 7.26.10(supports-color@8.1.1) + '@babel/core': 7.28.4(supports-color@8.1.1) '@babel/generator': 7.27.0 '@babel/parser': 7.26.10 - '@babel/plugin-syntax-decorators': 7.25.9(@babel/core@7.26.10(supports-color@8.1.1)) - '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.10(supports-color@8.1.1)) - '@babel/preset-typescript': 7.26.0(@babel/core@7.26.10(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/plugin-syntax-decorators': 7.25.9(@babel/core@7.28.4(supports-color@8.1.1)) + '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.28.4(supports-color@8.1.1)) + '@babel/preset-typescript': 7.26.0(@babel/core@7.28.4(supports-color@8.1.1))(supports-color@8.1.1) '@babel/traverse': 7.27.0(supports-color@8.1.1) '@babel/types': 7.27.0 '@npmcli/package-json': 4.0.1 @@ -29625,7 +29437,7 @@ snapshots: '@types/babel__core@7.20.2': dependencies: '@babel/parser': 7.28.4 - '@babel/types': 7.27.0 + '@babel/types': 7.28.4 '@types/babel__generator': 7.6.5 '@types/babel__template': 7.4.2 '@types/babel__traverse': 7.20.2 @@ -29654,7 +29466,7 @@ snapshots: '@types/babel__traverse@7.20.2': dependencies: - '@babel/types': 7.27.0 + '@babel/types': 7.28.4 '@types/babel__traverse@7.20.6': dependencies: @@ -30285,8 +30097,8 @@ snapshots: dependencies: '@mapbox/node-pre-gyp': 2.0.0(encoding@0.1.13)(supports-color@8.1.1) '@rollup/pluginutils': 5.1.4(rollup@4.50.2) - acorn: 8.14.1 - acorn-import-attributes: 1.9.5(acorn@8.14.1) + acorn: 8.15.0 + acorn-import-attributes: 1.9.5(acorn@8.15.0) async-sema: 3.1.1 bindings: 1.5.0 estree-walker: 2.0.2 @@ -30304,8 +30116,8 @@ snapshots: dependencies: '@mapbox/node-pre-gyp': 2.0.0(encoding@0.1.13)(supports-color@8.1.1) '@rollup/pluginutils': 5.1.4(rollup@4.50.2) - acorn: 8.14.1 - acorn-import-attributes: 1.9.5(acorn@8.14.1) + acorn: 8.15.0 + acorn-import-attributes: 1.9.5(acorn@8.15.0) async-sema: 3.1.1 bindings: 1.5.0 estree-walker: 2.0.2 @@ -30347,9 +30159,9 @@ snapshots: '@vitejs/plugin-react@4.3.4(supports-color@8.1.1)(vite@6.3.6(@types/node@22.13.14)(jiti@2.5.1)(sass@1.77.4)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.1))': dependencies: - '@babel/core': 7.26.10(supports-color@8.1.1) - '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.10(supports-color@8.1.1)) - '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.10(supports-color@8.1.1)) + '@babel/core': 7.28.4(supports-color@8.1.1) + '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.28.4(supports-color@8.1.1)) + '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.28.4(supports-color@8.1.1)) '@types/babel__core': 7.20.5 react-refresh: 0.14.2 vite: 6.3.6(@types/node@22.13.14)(jiti@2.5.1)(sass@1.77.4)(terser@5.39.0)(tsx@4.19.3)(yaml@2.8.1) @@ -30800,10 +30612,6 @@ snapshots: acorn-walk: 8.3.4 optional: true - acorn-import-attributes@1.9.5(acorn@8.14.1): - dependencies: - acorn: 8.14.1 - acorn-import-attributes@1.9.5(acorn@8.15.0): dependencies: acorn: 8.15.0 @@ -30812,13 +30620,17 @@ snapshots: dependencies: acorn: 8.14.1 + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + acorn-typescript@1.4.13(acorn@8.11.3): dependencies: acorn: 8.11.3 acorn-walk@8.3.4: dependencies: - acorn: 8.14.1 + acorn: 8.15.0 acorn@8.11.3: {} @@ -31229,12 +31041,13 @@ snapshots: big.js@5.2.2: {} - bin-links@4.0.3: + bin-links@5.0.0: dependencies: - cmd-shim: 6.0.2 - npm-normalize-package-bin: 3.0.1 - read-cmd-shim: 4.0.0 - write-file-atomic: 5.0.1 + cmd-shim: 7.0.0 + npm-normalize-package-bin: 4.0.0 + proc-log: 5.0.0 + read-cmd-shim: 5.0.0 + write-file-atomic: 6.0.0 binary-extensions@2.2.0: {} @@ -31682,7 +31495,7 @@ snapshots: cluster-key-slot@1.1.2: {} - cmd-shim@6.0.2: {} + cmd-shim@7.0.0: {} cmdk@1.0.0(@types/react-dom@18.3.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: @@ -33228,8 +33041,8 @@ snapshots: espree@9.6.1: dependencies: - acorn: 8.14.1 - acorn-jsx: 5.3.2(acorn@8.14.1) + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) eslint-visitor-keys: 3.4.3 esprima@4.0.1: {} @@ -34638,13 +34451,6 @@ snapshots: transitivePeerDependencies: - supports-color - https-proxy-agent@7.0.4(supports-color@8.1.1): - dependencies: - agent-base: 7.1.3 - debug: 4.4.3(supports-color@8.1.1) - transitivePeerDependencies: - - supports-color - https-proxy-agent@7.0.6(supports-color@8.1.1): dependencies: agent-base: 7.1.3 @@ -34715,17 +34521,10 @@ snapshots: import-from@4.0.0: {} - import-in-the-middle@1.13.1: - dependencies: - acorn: 8.14.1 - acorn-import-attributes: 1.9.5(acorn@8.14.1) - cjs-module-lexer: 1.4.1 - module-details-from-path: 1.0.3 - import-in-the-middle@1.14.2: dependencies: - acorn: 8.14.1 - acorn-import-attributes: 1.9.5(acorn@8.14.1) + acorn: 8.15.0 + acorn-import-attributes: 1.9.5(acorn@8.15.0) cjs-module-lexer: 1.4.1 module-details-from-path: 1.0.3 @@ -36574,8 +36373,8 @@ snapshots: micromark-extension-mdxjs@3.0.0: dependencies: - acorn: 8.14.1 - acorn-jsx: 5.3.2(acorn@8.14.1) + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) micromark-extension-mdx-expression: 3.0.0 micromark-extension-mdx-jsx: 3.0.1 micromark-extension-mdx-md: 2.0.0 @@ -36969,10 +36768,9 @@ snapshots: minipass: 3.3.6 yallist: 4.0.0 - minizlib@3.0.1: + minizlib@3.1.0: dependencies: minipass: 7.1.2 - rimraf: 5.0.10 mitt@3.0.1: {} @@ -36987,7 +36785,7 @@ snapshots: mlly@1.7.4: dependencies: - acorn: 8.14.1 + acorn: 8.15.0 pathe: 2.0.3 pkg-types: 1.3.1 ufo: 1.5.4 @@ -37144,20 +36942,6 @@ snapshots: neo-async@2.6.2: {} - next-contentlayer2@0.4.6(contentlayer2@0.4.6(esbuild@0.25.2)(markdown-wasm@1.2.0)(supports-color@8.1.1))(esbuild@0.25.2)(markdown-wasm@1.2.0)(next@15.5.2(@babel/core@7.26.10(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(supports-color@8.1.1): - dependencies: - '@contentlayer2/core': 0.4.3(esbuild@0.25.2)(markdown-wasm@1.2.0)(supports-color@8.1.1) - '@contentlayer2/utils': 0.4.3 - contentlayer2: 0.4.6(esbuild@0.25.2)(markdown-wasm@1.2.0)(supports-color@8.1.1) - next: 15.5.2(@babel/core@7.26.10(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - transitivePeerDependencies: - - '@effect-ts/otel-node' - - esbuild - - markdown-wasm - - supports-color - next-contentlayer2@0.4.6(contentlayer2@0.4.6(esbuild@0.25.2)(markdown-wasm@1.2.0)(supports-color@8.1.1))(esbuild@0.25.2)(markdown-wasm@1.2.0)(next@15.5.2(@babel/core@7.28.4(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(supports-color@8.1.1): dependencies: '@contentlayer2/core': 0.4.3(esbuild@0.25.2)(markdown-wasm@1.2.0)(supports-color@8.1.1) @@ -37205,32 +36989,6 @@ snapshots: next-tick@1.1.0: {} - next@15.5.2(@babel/core@7.26.10(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4): - dependencies: - '@next/env': 15.5.2 - '@swc/helpers': 0.5.15 - caniuse-lite: 1.0.30001743 - postcss: 8.4.31 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - styled-jsx: 5.1.6(@babel/core@7.26.10(supports-color@8.1.1))(react@18.3.1) - optionalDependencies: - '@next/swc-darwin-arm64': 15.5.2 - '@next/swc-darwin-x64': 15.5.2 - '@next/swc-linux-arm64-gnu': 15.5.2 - '@next/swc-linux-arm64-musl': 15.5.2 - '@next/swc-linux-x64-gnu': 15.5.2 - '@next/swc-linux-x64-musl': 15.5.2 - '@next/swc-win32-arm64-msvc': 15.5.2 - '@next/swc-win32-x64-msvc': 15.5.2 - '@opentelemetry/api': 1.9.0 - '@playwright/test': 1.53.0 - sass: 1.77.4 - sharp: 0.34.3 - transitivePeerDependencies: - - '@babel/core' - - babel-plugin-macros - next@15.5.2(@babel/core@7.28.4(supports-color@8.1.1))(@opentelemetry/api@1.9.0)(@playwright/test@1.53.0)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.4): dependencies: '@next/env': 15.5.2 @@ -37609,6 +37367,8 @@ snapshots: npm-normalize-package-bin@3.0.1: {} + npm-normalize-package-bin@4.0.0: {} + npm-package-arg@10.1.0: dependencies: hosted-git-info: 6.1.3 @@ -38925,6 +38685,8 @@ snapshots: proc-log@4.2.0: {} + proc-log@5.0.0: {} + process-nextick-args@2.0.1: {} process-warning@3.0.0: {} @@ -39172,7 +38934,7 @@ snapshots: react-docgen@7.0.3(supports-color@8.1.1): dependencies: - '@babel/core': 7.26.10(supports-color@8.1.1) + '@babel/core': 7.28.4(supports-color@8.1.1) '@babel/traverse': 7.24.7(supports-color@8.1.1) '@babel/types': 7.24.7 '@types/babel__core': 7.20.2 @@ -39557,7 +39319,7 @@ snapshots: dependencies: pify: 2.3.0 - read-cmd-shim@4.0.0: {} + read-cmd-shim@5.0.0: {} read-pkg@3.0.0: dependencies: @@ -39965,9 +39727,9 @@ snapshots: remove-types@1.0.0(supports-color@8.1.1): dependencies: - '@babel/core': 7.26.10(supports-color@8.1.1) - '@babel/plugin-syntax-decorators': 7.25.9(@babel/core@7.26.10(supports-color@8.1.1)) - '@babel/plugin-transform-typescript': 7.27.0(@babel/core@7.26.10(supports-color@8.1.1))(supports-color@8.1.1) + '@babel/core': 7.28.4(supports-color@8.1.1) + '@babel/plugin-syntax-decorators': 7.25.9(@babel/core@7.28.4(supports-color@8.1.1)) + '@babel/plugin-transform-typescript': 7.27.0(@babel/core@7.28.4(supports-color@8.1.1))(supports-color@8.1.1) prettier: 2.8.8 transitivePeerDependencies: - supports-color @@ -40057,10 +39819,6 @@ snapshots: dependencies: glob: 9.3.5 - rimraf@5.0.10: - dependencies: - glob: 10.4.5 - rimraf@6.0.1: dependencies: glob: 11.0.0 @@ -41079,13 +40837,6 @@ snapshots: stylis: 4.3.1 tslib: 2.5.0 - styled-jsx@5.1.6(@babel/core@7.26.10(supports-color@8.1.1))(react@18.3.1): - dependencies: - client-only: 0.0.1 - react: 18.3.1 - optionalDependencies: - '@babel/core': 7.26.10(supports-color@8.1.1) - styled-jsx@5.1.6(@babel/core@7.28.4(supports-color@8.1.1))(babel-plugin-macros@3.1.0)(react@18.3.1): dependencies: client-only: 0.0.1 @@ -41116,12 +40867,12 @@ snapshots: pirates: 4.0.6 ts-interface-checker: 0.1.13 - supabase@1.151.1(supports-color@8.1.1): + supabase@2.50.3(supports-color@8.1.1): dependencies: - bin-links: 4.0.3 - https-proxy-agent: 7.0.4(supports-color@8.1.1) + bin-links: 5.0.0 + https-proxy-agent: 7.0.6(supports-color@8.1.1) node-fetch: 3.3.2 - tar: 6.2.1 + tar: 7.5.1 transitivePeerDependencies: - supports-color @@ -41263,13 +41014,12 @@ snapshots: mkdirp: 1.0.4 yallist: 4.0.0 - tar@7.4.3: + tar@7.5.1: dependencies: '@isaacs/fs-minipass': 4.0.1 chownr: 3.0.0 minipass: 7.1.2 - minizlib: 3.0.1 - mkdirp: 3.0.1 + minizlib: 3.1.0 yallist: 5.0.0 tdigest@0.1.2: @@ -41300,7 +41050,7 @@ snapshots: terser@5.39.0: dependencies: '@jridgewell/source-map': 0.3.6 - acorn: 8.14.1 + acorn: 8.15.0 commander: 2.20.3 source-map-support: 0.5.21 @@ -41729,7 +41479,7 @@ snapshots: unctx@2.4.1: dependencies: - acorn: 8.14.1 + acorn: 8.15.0 estree-walker: 3.0.3 magic-string: 0.30.19 unplugin: 2.3.10 @@ -41801,7 +41551,7 @@ snapshots: unimport@4.1.2: dependencies: - acorn: 8.14.1 + acorn: 8.15.0 escape-string-regexp: 5.0.0 estree-walker: 3.0.3 local-pkg: 1.1.2 @@ -41989,19 +41739,19 @@ snapshots: unplugin@1.0.1: dependencies: - acorn: 8.14.1 + acorn: 8.15.0 chokidar: 3.6.0 webpack-sources: 3.2.3 webpack-virtual-modules: 0.5.0 unplugin@1.16.1: dependencies: - acorn: 8.14.1 + acorn: 8.15.0 webpack-virtual-modules: 0.6.2 unplugin@2.2.2: dependencies: - acorn: 8.14.1 + acorn: 8.15.0 webpack-virtual-modules: 0.6.2 unplugin@2.3.10: @@ -42840,7 +42590,7 @@ snapshots: webpack-bundle-analyzer@4.10.1: dependencies: '@discoveryjs/json-ext': 0.5.7 - acorn: 8.14.1 + acorn: 8.15.0 acorn-walk: 8.3.4 commander: 7.2.0 debounce: 1.2.1 @@ -43040,7 +42790,7 @@ snapshots: wrappy@1.0.2: {} - write-file-atomic@5.0.1: + write-file-atomic@6.0.0: dependencies: imurmurhash: 0.1.4 signal-exit: 4.1.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 1329dfd5c7d75..c6b0e9b22f17f 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -36,9 +36,10 @@ ignoredBuiltDependencies: minimumReleaseAge: 10080 minimumReleaseAgeExclude: - - ai - '@ai-sdk/*' - '@supabase/*' + - ai + - supabase onlyBuiltDependencies: - supabase From c8ae24140b36df4ef06c7305b315fba11c544dbb Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Thu, 9 Oct 2025 15:32:16 +0800 Subject: [PATCH 08/16] Opt to ignore cannot find module errors in AIEditor (#39387) --- apps/studio/components/ui/AIEditor/index.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/studio/components/ui/AIEditor/index.tsx b/apps/studio/components/ui/AIEditor/index.tsx index b27d47061e28d..3eccb94922217 100644 --- a/apps/studio/components/ui/AIEditor/index.tsx +++ b/apps/studio/components/ui/AIEditor/index.tsx @@ -163,6 +163,12 @@ const AIEditor = ({ } } + // [Joshen] Opting to ignore "Cannot find module" errors here as users are getting + // confused with the error highlighting when importing external modules + monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({ + diagnosticCodesToIgnore: [2792], + }) + fetch(`${process.env.NEXT_PUBLIC_BASE_PATH ?? ''}/deno/lib.deno.d.ts`) .then((response) => response.text()) .then((code) => { From 9343dc524f745b6922f8b7b09698aa7c939b0b43 Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Thu, 9 Oct 2025 15:54:00 +0800 Subject: [PATCH 09/16] Fix project filter on homepage (#39343) * Fix project filter on homepage * Simplify --- .../components/interfaces/HomePageActions.tsx | 44 +++++++------------ 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/apps/studio/components/interfaces/HomePageActions.tsx b/apps/studio/components/interfaces/HomePageActions.tsx index 7e07fcce3dde2..2bfdfcb673b29 100644 --- a/apps/studio/components/interfaces/HomePageActions.tsx +++ b/apps/studio/components/interfaces/HomePageActions.tsx @@ -91,34 +91,22 @@ export const HomePageActions = ({ { key: PROJECT_STATUS.ACTIVE_HEALTHY, label: 'Active' }, { key: PROJECT_STATUS.INACTIVE, label: 'Paused' }, ].map(({ key, label }) => ( -
    -
    - { - if (filterStatus.includes(key)) { - setFilterStatus(filterStatus.filter((y) => y !== key)) - } else if (filterStatus.length === 1) { - setFilterStatus([]) - } else { - setFilterStatus(filterStatus.concat([key])) - } - }} - /> - - {label} - -
    - +
    + { + if (filterStatus.includes(key)) { + setFilterStatus(filterStatus.filter((y) => y !== key)) + } else { + setFilterStatus(filterStatus.concat([key])) + } + }} + /> + + {label} +
    ))}
    From b5a638bfc61a29fdc41b45d5869bf8b7496e0625 Mon Sep 17 00:00:00 2001 From: Jordi Enric <37541088+jordienr@users.noreply.github.com> Date: Thu, 9 Oct 2025 09:58:32 +0200 Subject: [PATCH 10/16] auth report improvements (#39013) --- .../interfaces/Reports/Reports.utils.tsx | 111 ++ .../interfaces/Reports/v2/ReportChartV2.tsx | 1 + .../Reports/v2/ReportSectionHeader.tsx | 49 + .../components/ui/Charts/ChartHeader.tsx | 12 +- .../ui/Charts/ChartHighlightActions.tsx | 7 +- .../components/ui/Charts/ComposedChart.tsx | 6 + .../ui/Charts/NoDataPlaceholder.tsx | 9 +- apps/studio/data/reports/v2/auth.config.ts | 1019 ++++++++++++----- .../data/reports/v2/edge-functions.config.ts | 54 +- .../data/reports/v2/edge-functions.test.tsx | 8 +- .../pages/project/[ref]/reports/auth.tsx | 265 ++++- packages/common/constants/auth-error-codes.ts | 250 ++++ 12 files changed, 1388 insertions(+), 403 deletions(-) create mode 100644 apps/studio/components/interfaces/Reports/v2/ReportSectionHeader.tsx create mode 100644 packages/common/constants/auth-error-codes.ts diff --git a/apps/studio/components/interfaces/Reports/Reports.utils.tsx b/apps/studio/components/interfaces/Reports/Reports.utils.tsx index f0eef8b93adaf..0be4bb7310739 100644 --- a/apps/studio/components/interfaces/Reports/Reports.utils.tsx +++ b/apps/studio/components/interfaces/Reports/Reports.utils.tsx @@ -3,6 +3,12 @@ import dayjs from 'dayjs' import useDbQuery, { DbQueryHook } from 'hooks/analytics/useDbQuery' import useLogsQuery, { LogsQueryHook } from 'hooks/analytics/useLogsQuery' import type { BaseQueries, PresetConfig, ReportQuery } from './Reports.types' +import { + isUnixMicro, + unixMicroToIsoTimestamp, +} from 'components/interfaces/Settings/Logs/Logs.utils' +import { REPORT_STATUS_CODE_COLORS } from 'data/reports/report.utils' +import { getHttpStatusCodeInfo } from 'lib/http-status-codes' /** * Converts a query params string to an object @@ -73,3 +79,108 @@ export const formatTimestamp = ( return 'Invalid Date' } } + +/** + * Extracts distinct status codes from log data rows + */ +export function extractStatusCodesFromData(data: any[]): string[] { + const statusCodes = new Set() + + data.forEach((item: any) => { + if (item.status_code !== undefined && item.status_code !== null) { + statusCodes.add(String(item.status_code)) + } + }) + + return Array.from(statusCodes).sort() +} + +/** + * Generates chart attributes for status codes with labels and colors + */ +export function generateStatusCodeAttributes(statusCodes: string[]) { + return statusCodes.map((code) => ({ + attribute: code, + label: `${code} ${getHttpStatusCodeInfo(parseInt(code, 10)).label}`, + color: REPORT_STATUS_CODE_COLORS[code] || REPORT_STATUS_CODE_COLORS.default, + })) +} + +/** + * Pivots rows of { timestamp, status_code, count } into { timestamp, [status_code]: count } + * and normalizes timestamps to ISO strings (UTC), filling missing codes with 0 per timestamp + */ +export function transformStatusCodeData(data: any[], statusCodes: string[]) { + const pivotedData = data.reduce((acc: Record, d: any) => { + const timestamp = isUnixMicro(d.timestamp) + ? unixMicroToIsoTimestamp(d.timestamp) + : dayjs.utc(d.timestamp).toISOString() + if (!acc[timestamp]) { + acc[timestamp] = { timestamp } + statusCodes.forEach((code) => { + acc[timestamp][code] = 0 + }) + } + const codeKey = String(d.status_code) + if (codeKey in acc[timestamp]) { + acc[timestamp][codeKey] = d.count + } + return acc + }, {}) + + return Object.values(pivotedData) +} + +/** + * Extract distinct string values for a given field from data rows + */ +export function extractDistinctValuesFromData(data: any[], field: string): string[] { + const values = new Set() + data.forEach((item: any) => { + if (item[field] !== undefined && item[field] !== null) { + values.add(String(item[field])) + } + }) + return Array.from(values).sort() +} + +/** + * Generates chart attributes from a list of category values + */ +export function generateCategoryAttributes( + values: string[], + labelResolver?: (v: string) => string +) { + return values.map((v) => ({ + attribute: v, + label: labelResolver ? labelResolver(v) : v, + })) +} + +/** + * Pivot rows of { timestamp, [categoryField], count } into { timestamp, [category]: count } + */ +export function transformCategoricalCountData( + data: any[], + categoryField: string, + categories: string[] +) { + const pivotedData = data.reduce((acc: Record, d: any) => { + const timestamp = isUnixMicro(d.timestamp) + ? unixMicroToIsoTimestamp(d.timestamp) + : dayjs.utc(d.timestamp).toISOString() + if (!acc[timestamp]) { + acc[timestamp] = { timestamp } + categories.forEach((c) => { + acc[timestamp][c] = 0 + }) + } + const key = String(d[categoryField]) + if (key in acc[timestamp]) { + acc[timestamp][key] = d.count + } + return acc + }, {}) + + return Object.values(pivotedData) +} diff --git a/apps/studio/components/interfaces/Reports/v2/ReportChartV2.tsx b/apps/studio/components/interfaces/Reports/v2/ReportChartV2.tsx index 57c3c07f8336f..01f9ed5f0040b 100644 --- a/apps/studio/components/interfaces/Reports/v2/ReportChartV2.tsx +++ b/apps/studio/components/interfaces/Reports/v2/ReportChartV2.tsx @@ -117,6 +117,7 @@ export const ReportChartV2 = ({ ) : (
    { + const [copiedLink, setCopiedLink] = useState(null) + + const copyLinkToClipboard = async () => { + // [jordi] We want to keep the existing query params (filters) + // But if the user has an anchor in the URL, + // we remove it and add the one for this section + // This is so the shared URL shows the exact same report as the one the user is on + const url = `${window.location.href.split('#')[0]}#${id}` + await copyToClipboard(url) + setCopiedLink(id) + setTimeout(() => setCopiedLink(null), 2000) + } + + return ( +
    +
    +

    {title}

    + : } + className="w-7 h-7 opacity-0 group-hover:opacity-100 transition-opacity" + tooltip={{ + content: { + side: 'bottom', + text: copiedLink === id ? 'Link copied!' : 'Copy link to section', + }, + }} + /> +
    +

    {description}

    +
    + ) +} diff --git a/apps/studio/components/ui/Charts/ChartHeader.tsx b/apps/studio/components/ui/Charts/ChartHeader.tsx index 60b3e870c3ed6..86a8383414632 100644 --- a/apps/studio/components/ui/Charts/ChartHeader.tsx +++ b/apps/studio/components/ui/Charts/ChartHeader.tsx @@ -15,6 +15,7 @@ import { ButtonTooltip } from 'components/ui/ButtonTooltip' import { formatBytes } from 'lib/helpers' import { numberFormatter } from './Charts.utils' import { useChartHoverState } from './useChartHoverState' +import { InfoTooltip } from 'ui-patterns/info-tooltip' export interface ChartHeaderProps { title?: string @@ -41,6 +42,7 @@ export interface ChartHeaderProps { isNetworkChart?: boolean attributes?: any[] sql?: string + titleTooltip?: string } export const ChartHeader = ({ @@ -68,6 +70,7 @@ export const ChartHeader = ({ isNetworkChart = false, attributes, sql, + titleTooltip, }: ChartHeaderProps) => { const { hoveredIndex, isHovered, isCurrentChart, setHover, clearHover } = useChartHoverState( syncId || 'default' @@ -162,9 +165,12 @@ export const ChartHeader = ({ const chartTitle = (
    -

    - {title} -

    +
    +

    + {title} +

    + {titleTooltip && {titleTooltip}} +
    {docsUrl && ( void + chartId?: string } export type ChartHighlightAction = { @@ -34,10 +35,12 @@ export const ChartHighlightActions = ({ chartHighlight, updateDateRange, actions, + chartId, }: { chartHighlight?: ChartHighlight updateDateRange?: UpdateDateRange actions?: ChartHighlightAction[] + chartId?: string }) => { const { left: selectedRangeStart, right: selectedRangeEnd, clearHighlight } = chartHighlight ?? {} const [isOpen, setIsOpen] = useState(!!chartHighlight?.popoverPosition) @@ -48,7 +51,7 @@ export const ChartHighlightActions = ({ const ctx: ChartHighlightActionContext | undefined = selectedRangeStart && selectedRangeEnd && clearHighlight - ? { start: selectedRangeStart, end: selectedRangeEnd, clear: clearHighlight } + ? { start: selectedRangeStart, end: selectedRangeEnd, clear: clearHighlight, chartId } : undefined const defaultActions: ChartHighlightAction[] = useMemo(() => { @@ -110,7 +113,7 @@ export const ChartHighlightActions = ({