diff --git a/apps/studio/.github/eslint-rule-baselines.json b/apps/studio/.github/eslint-rule-baselines.json index 0dd5b3fe2f12b..3137e6c6f5421 100644 --- a/apps/studio/.github/eslint-rule-baselines.json +++ b/apps/studio/.github/eslint-rule-baselines.json @@ -87,7 +87,6 @@ "components/interfaces/Settings/Database/ConnectionPooling/ConnectionPooling.tsx": 1, "components/interfaces/Settings/Database/SSLConfiguration.tsx": 1, "components/interfaces/Settings/General/ComplianceConfig/ProjectComplianceMode.tsx": 1, - "components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DeployNewReplicaPanel.tsx": 1, "components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/InstanceConfiguration.tsx": 1, "components/interfaces/Settings/Logs/LogTable.tsx": 2, "components/interfaces/Settings/Logs/LogsPreviewer.tsx": 2, @@ -948,7 +947,6 @@ "components/interfaces/Settings/General/CustomDomainConfig/DNSRecord.tsx": 1, "components/interfaces/Settings/General/Infrastructure/PauseProjectButton.tsx": 1, "components/interfaces/Settings/General/Infrastructure/RestartServerButton.tsx": 1, - "components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DeployNewReplicaPanel.tsx": 1, "components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DropAllReplicasConfirmationModal.tsx": 1, "components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/MapView.tsx": 1, "components/interfaces/Settings/Integrations/GithubIntegration/GitHubIntegrationConnectionForm.tsx": 1, @@ -1110,7 +1108,6 @@ "components/interfaces/Organization/Usage/UsageBarChart.tsx": 1, "components/interfaces/ProjectAPIDocs/FirstLevelNav.tsx": 1, "components/interfaces/Settings/General/TransferProjectPanel/TransferProjectButton.tsx": 1, - "components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/DeployNewReplicaPanel.tsx": 1, "components/interfaces/Settings/Logs/LogSelection.tsx": 1, "components/interfaces/Settings/Logs/LogTable.tsx": 3, "components/interfaces/Settings/Logs/LogsFormatters.tsx": 2, diff --git a/apps/studio/components/grid/SupabaseGrid.tsx b/apps/studio/components/grid/SupabaseGrid.tsx index be97e1cefa5c7..04990fd8d494b 100644 --- a/apps/studio/components/grid/SupabaseGrid.tsx +++ b/apps/studio/components/grid/SupabaseGrid.tsx @@ -77,7 +77,6 @@ export const SupabaseGrid = ({ } = useTableRowsQuery( { projectRef: project?.ref, - connectionString: project?.connectionString, tableId, sorts, filters, diff --git a/apps/studio/components/grid/components/footer/pagination/Pagination.tsx b/apps/studio/components/grid/components/footer/pagination/Pagination.tsx index 50d3b92f8b9be..4a4b2914742d9 100644 --- a/apps/studio/components/grid/components/footer/pagination/Pagination.tsx +++ b/apps/studio/components/grid/components/footer/pagination/Pagination.tsx @@ -9,7 +9,7 @@ import { useTableRowsCountQuery } from 'data/table-rows/table-rows-count-query' import { useTableRowsQuery } from 'data/table-rows/table-rows-query' import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' import { RoleImpersonationState } from 'lib/role-impersonation' -import { ArrowLeft, ArrowRight, HelpCircle, Loader2 } from 'lucide-react' +import { AlertCircle, ArrowLeft, ArrowRight, HelpCircle, Loader2 } from 'lucide-react' import { useEffect, useState } from 'react' import { useRoleImpersonationStateSnapshot } from 'state/role-impersonation-state' import { useTableEditorStateSnapshot } from 'state/table-editor' @@ -90,7 +90,6 @@ export const Pagination = ({ enableForeignRowsQuery = true }: PaginationProps) = } = useTableRowsCountQuery( { projectRef: project?.ref, - connectionString: project?.connectionString, tableId: snap.table.id, filters, enforceExactCount: snap.enforceExactCount, @@ -102,6 +101,8 @@ export const Pagination = ({ enableForeignRowsQuery = true }: PaginationProps) = } ) const count = data?.count ?? 0 + const hasCountData = count >= 0 + const isEstimateCount = data?.is_estimate ?? false const countString = data?.is_estimate ? formatEstimatedCount(count) : count.toLocaleString() const maxPages = Math.ceil(count / tableEditorSnap.rowsPerPage) const totalPages = count > 0 ? maxPages : 1 @@ -113,7 +114,6 @@ export const Pagination = ({ enableForeignRowsQuery = true }: PaginationProps) = const { data: rowsData, isPending: isLoadingRows } = useTableRowsQuery( { projectRef: project?.ref, - connectionString: project?.connectionString, tableId: id, sorts, filters, @@ -144,12 +144,10 @@ export const Pagination = ({ enableForeignRowsQuery = true }: PaginationProps) = } const onNextPage = () => { - if (page < maxPages) { - if (snap.selectedRows.size >= 1) { - setIsConfirmNextModalOpen(true) - } else { - goToNextPage() - } + if (snap.selectedRows.size >= 1) { + setIsConfirmNextModalOpen(true) + } else { + goToNextPage() } } @@ -176,6 +174,7 @@ export const Pagination = ({ enableForeignRowsQuery = true }: PaginationProps) = const onRowsPerPageChange = (value: string | number) => { const rowsPerPage = Number(value) tableEditorSnap.setRowsPerPage(isNaN(rowsPerPage) ? 100 : rowsPerPage) + snap.setPage(1) } // keep input value in-sync with actual page @@ -183,20 +182,6 @@ export const Pagination = ({ enableForeignRowsQuery = true }: PaginationProps) = setValue(String(page)) }, [page]) - useEffect(() => { - if (!isForeignTableSelected && page && page > totalPages) { - snap.setPage(totalPages) - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isForeignTableSelected, page, totalPages]) - - useEffect(() => { - if (id !== undefined) { - snap.setEnforceExactCount(rowsCountEstimate !== null && rowsCountEstimate <= THRESHOLD_COUNT) - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [id]) - useEffect(() => { // If the count query encountered a timeout error with exact count // turn off the exact count to rely on approximate @@ -206,6 +191,7 @@ export const Pagination = ({ enableForeignRowsQuery = true }: PaginationProps) = // eslint-disable-next-line react-hooks/exhaustive-deps }, [isError, snap.enforceExactCount, error?.code]) + // [Joshen] One to revisit if we can consolidate this and the main return statement if (isForeignTableSelected) { return (
@@ -251,102 +237,107 @@ export const Pagination = ({ enableForeignRowsQuery = true }: PaginationProps) = return (
- {isLoading && ( -
- -

Loading records count...

-
- )} +
+
+ {isLoading ? ( +
- - {!isForeignTableSelected && ( -
-

- {`${countString} ${count === 0 || count > 1 ? `records` : 'record'}`}{' '} - {data.is_estimate ? '(estimated)' : ''} -

- - {data.is_estimate && ( - - -
+ + Failed to retrieve count: {error?.message} + + ) : !isForeignTableSelected ? ( +
+ {hasCountData && ( +

+ {`${countString} ${count === 0 || count > 1 ? `records` : 'record'}`}{' '} + {data.is_estimate ? '(estimated)' : ''} +

)} - - )} - {isError && ( -

- Error fetching records count. Please refresh the page. -

- )} + {data.is_estimate && ( + + +
+ ) : null} { export const useIsBranching2Enabled = () => { const { flags } = useFeaturePreviewContext() - const gitlessBranchingEnabled = useFlag('gitlessBranching') - return gitlessBranchingEnabled && flags[LOCAL_STORAGE_KEYS.UI_PREVIEW_BRANCHING_2_0] + return flags[LOCAL_STORAGE_KEYS.UI_PREVIEW_BRANCHING_2_0] } export const useIsPgDeltaDiffEnabled = () => { @@ -105,8 +104,7 @@ export const useIsPgDeltaDiffEnabled = () => { export const useIsAdvisorRulesEnabled = () => { const { flags } = useFeaturePreviewContext() - const advisorRulesEnabled = useFlag('advisorRules') - return advisorRulesEnabled && flags[LOCAL_STORAGE_KEYS.UI_PREVIEW_ADVISOR_RULES] + return flags[LOCAL_STORAGE_KEYS.UI_PREVIEW_ADVISOR_RULES] } export const useIsQueueOperationsEnabled = () => { diff --git a/apps/studio/components/interfaces/App/FeaturePreview/useFeaturePreviews.ts b/apps/studio/components/interfaces/App/FeaturePreview/useFeaturePreviews.ts index ce54a339df146..c0c957bce911d 100644 --- a/apps/studio/components/interfaces/App/FeaturePreview/useFeaturePreviews.ts +++ b/apps/studio/components/interfaces/App/FeaturePreview/useFeaturePreviews.ts @@ -14,8 +14,6 @@ type FeaturePreview = { } export const useFeaturePreviews = (): FeaturePreview[] => { - const gitlessBranchingEnabled = useFlag('gitlessBranching') - const advisorRulesEnabled = useFlag('advisorRules') const isUnifiedLogsPreviewAvailable = useFlag('unifiedLogs') const tableEditorNewFilterBar = useFlag('tableEditorNewFilterBar') const pgDeltaDiffEnabled = useFlag('pgdeltaDiff') @@ -34,7 +32,7 @@ export const useFeaturePreviews = (): FeaturePreview[] => { key: LOCAL_STORAGE_KEYS.UI_PREVIEW_BRANCHING_2_0, name: 'Branching via dashboard', discussionsUrl: 'https://github.com/orgs/supabase/discussions/branching-2-0', - enabled: gitlessBranchingEnabled, + enabled: true, isNew: false, isPlatformOnly: true, isDefaultOptIn: false, @@ -43,7 +41,7 @@ export const useFeaturePreviews = (): FeaturePreview[] => { key: LOCAL_STORAGE_KEYS.UI_PREVIEW_ADVISOR_RULES, name: 'Disable Advisor rules', discussionsUrl: undefined, - enabled: advisorRulesEnabled, + enabled: true, isNew: false, isPlatformOnly: true, isDefaultOptIn: false, diff --git a/apps/studio/components/interfaces/Auth/ThirdPartyAuthForm/AddIntegrationDropdown.tsx b/apps/studio/components/interfaces/Auth/ThirdPartyAuthForm/AddIntegrationDropdown.tsx index 6b76fa8c9ef0f..d5ab1fa1936a7 100644 --- a/apps/studio/components/interfaces/Auth/ThirdPartyAuthForm/AddIntegrationDropdown.tsx +++ b/apps/studio/components/interfaces/Auth/ThirdPartyAuthForm/AddIntegrationDropdown.tsx @@ -1,7 +1,5 @@ import { ChevronDown } from 'lucide-react' import Image from 'next/image' - -import { useFlag } from 'common' import { Button, cn, @@ -12,6 +10,7 @@ import { DropdownMenuSeparator, DropdownMenuTrigger, } from 'ui' + import { getIntegrationTypeIcon, getIntegrationTypeLabel, @@ -52,8 +51,6 @@ export const AddIntegrationDropdown = ({ align = 'end', onSelectIntegrationType, }: AddIntegrationDropdownProps) => { - const isWorkOSEnabled = useFlag('isWorkOSTPAEnabled') - return ( @@ -64,12 +61,9 @@ export const AddIntegrationDropdown = ({ Select provider - - {isWorkOSEnabled && ( - - )} + diff --git a/apps/studio/components/interfaces/Database/Replication/ComingSoon.tsx b/apps/studio/components/interfaces/Database/Replication/ComingSoon.tsx deleted file mode 100644 index 0816a5cd1fe65..0000000000000 --- a/apps/studio/components/interfaces/Database/Replication/ComingSoon.tsx +++ /dev/null @@ -1,232 +0,0 @@ -import { ArrowRight, ArrowUpRight, Circle, Database, Plus } from 'lucide-react' -import { useTheme } from 'next-themes' -import Link from 'next/link' -import { useMemo } from 'react' -import ReactFlow, { Background, Handle, Position, ReactFlowProvider } from 'reactflow' - -import 'reactflow/dist/style.css' - -import { useParams } from 'common' -import { BASE_PATH } from 'lib/constants' -import { Button, Card, CardContent } from 'ui' - -import { NODE_WIDTH } from '../../Settings/Infrastructure/InfrastructureConfiguration/InstanceConfiguration.constants' - -const STATIC_NODES = [ - { - id: '1', - type: 'primary', - data: { - label: 'Primary Database', - region: 'East US (Ohio)', - provider: 'AWS', - regionIcon: 'us-east-1', - }, - position: { x: 825, y: 0 }, - }, - { - id: '2', - type: 'replica', - data: { - label: 'Iceberg', - details: '3 tables', - regionIcon: 'us-west-1', - }, - position: { x: 875, y: 110 }, - }, - { - id: '3', - type: 'replica', - data: { - label: 'BigQuery', - details: '5 tables', - regionIcon: 'us-west-1', - }, - position: { x: 875, y: 200 }, - }, - { - id: '4', - type: 'blank', - position: { x: 875, y: 290 }, - data: {}, - }, - { - id: '5', - type: 'cta', - position: { x: 125, y: 20 }, - data: {}, - }, -] - -const STATIC_EDGES = [ - { id: 'e1-2', source: '1', target: '2', type: 'smoothstep', animated: true }, - { id: 'e1-3', source: '1', target: '3', type: 'smoothstep', animated: true }, - { id: 'e1-4', source: '1', target: '4', type: 'smoothstep', animated: true }, -] - -export const ReplicationComingSoon = () => { - return ( - - - - ) -} - -const ReplicationStaticMockup = () => { - const { ref: projectRef = '_' } = useParams() - const nodes = useMemo(() => STATIC_NODES, []) - const edges = useMemo(() => STATIC_EDGES, []) - - const { resolvedTheme } = useTheme() - - const backgroundPatternColor = - resolvedTheme === 'dark' && projectRef !== '_' - ? 'rgba(255, 255, 255, 0.3)' - : 'rgba(0, 0, 0, 0.4)' - - const nodeTypes = useMemo( - () => ({ - primary: PrimaryNode, - replica: ReplicaNode, - blank: BlankNode, - cta: () => CTANode({ projectRef }), - }), - [projectRef] - ) - - return ( -
- - - -
- ) -} - -const PrimaryNode = ({ - data, -}: { - data: { label: string; region: string; provider: string; regionIcon: string } -}) => { - return ( -
-
-
-
- -
-
-

{data.label}

-

- {data.region} -

-

- {data.provider} -

-
-
-
- region icon - -
-
- -
- ) -} -const ReplicaNode = ({ - data, -}: { - data: { label: string; details: string; regionIcon: string } -}) => { - return ( -
-
-
-
-

{data.label}

-

- {data.details} -

-
-
-
- region icon - -
-
- - -
- ) -} - -const BlankNode = () => { - return ( -
-
-
-
- - Add new -
-
- -
-
- ) -} - -const CTANode = ({ projectRef }: { projectRef: string }) => { - return ( - - -

Stream database changes to external destinations

-

- Automatically replicate your data to external data warehouses and analytics platforms in - real-time. No manual exports, no lag. -

-

- We are currently in private alpha and slowly - onboarding new customers to ensure stable data pipelines. Request access below to join the - waitlist. Read replicas are available now. -

-
- - -
-
-
- ) -} diff --git a/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationPanel.tsx b/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationPanel.tsx index 68e51584c9b61..475513d75e547 100644 --- a/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationPanel.tsx +++ b/apps/studio/components/interfaces/Database/Replication/DestinationPanel/DestinationPanel.tsx @@ -1,4 +1,3 @@ -import { useFlag } from 'common' import { useCheckEntitlements } from 'hooks/misc/useCheckEntitlements' import { ArrowUpRight } from 'lucide-react' import Link from 'next/link' @@ -34,7 +33,6 @@ interface DestinationPanelProps { export const DestinationPanel = ({ onSuccessCreateReadReplica }: DestinationPanelProps) => { const enablePgReplicate = useIsETLPrivateAlpha() - const unifiedReplication = useFlag('unifiedReplication') const { hasAccess: hasETLReplicationAccess } = useCheckEntitlements('replication.etl') const [urlDestinationType, setDestinationType] = useQueryState( @@ -97,11 +95,7 @@ export const DestinationPanel = ({ onSuccessCreateReadReplica }: DestinationPane return ( <> - +
{editMode ? 'Edit destination' : 'Create a new destination'} @@ -118,7 +112,7 @@ export const DestinationPanel = ({ onSuccessCreateReadReplica }: DestinationPane {destinationType === 'Read Replica' ? ( onSuccessCreateReadReplica?.()} /> - ) : unifiedReplication && !enablePgReplicate ? ( + ) : !enablePgReplicate ? (
@@ -147,7 +141,7 @@ export const DestinationPanel = ({ onSuccessCreateReadReplica }: DestinationPane
- ) : unifiedReplication && replicationNotEnabled ? ( + ) : replicationNotEnabled ? ( { - const unifiedReplication = useFlag('unifiedReplication') const etlEnableBigQuery = useIsETLBigQueryPrivateAlpha() const etlEnableIceberg = useIsETLIcebergPrivateAlpha() + const { infrastructureReadReplicas } = useIsFeatureEnabled(['infrastructure:read_replicas']) - const numberOfTypes = [unifiedReplication, etlEnableBigQuery, etlEnableIceberg].filter( + const numberOfTypes = [infrastructureReadReplicas, etlEnableBigQuery, etlEnableIceberg].filter( Boolean ).length @@ -57,7 +57,7 @@ export const DestinationTypeSelection = () => { '[&>button:first-of-type]:!rounded-l-lg [&>button:last-of-type]:!rounded-r-lg' )} > - {((!editMode && unifiedReplication) || + {((!editMode && infrastructureReadReplicas) || (editMode && destinationType === 'Read Replica')) && ( {

BigQuery

- {unifiedReplication && Alpha} + Alpha

Send data to Google Cloud's data warehouse for analytics and business intelligence @@ -108,7 +108,7 @@ export const DestinationTypeSelection = () => {

Analytics Bucket

- {unifiedReplication && Alpha} + Alpha

Send data to Apache Iceberg tables in your Supabase Storage for flexible analytics diff --git a/apps/studio/components/interfaces/Database/Replication/Destinations.tsx b/apps/studio/components/interfaces/Database/Replication/Destinations.tsx index 76b467a77dedb..0c9c8343e1a10 100644 --- a/apps/studio/components/interfaces/Database/Replication/Destinations.tsx +++ b/apps/studio/components/interfaces/Database/Replication/Destinations.tsx @@ -1,13 +1,11 @@ import { useQueryClient } from '@tanstack/react-query' -import { useFlag, useParams } from 'common' +import { useParams } from 'common' import { AlertError } from 'components/ui/AlertError' import { DocsButton } from 'components/ui/DocsButton' import { useReplicationDestinationsQuery } from 'data/replication/destinations-query' import { replicationKeys } from 'data/replication/keys' import { fetchReplicationPipelineVersion } from 'data/replication/pipeline-version-query' import { useReplicationPipelinesQuery } from 'data/replication/pipelines-query' -import { useReplicationSourcesQuery } from 'data/replication/sources-query' -import { useCheckEntitlements } from 'hooks/misc/useCheckEntitlements' import { DOCS_URL } from 'lib/constants' import { Plus, Search, X } from 'lucide-react' import { parseAsStringEnum, useQueryState } from 'nuqs' @@ -16,13 +14,13 @@ import { Button, Card, CardContent, + cn, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, - cn, } from 'ui' import { GenericSkeletonLoader } from 'ui-patterns' import { Input } from 'ui-patterns/DataInputs/Input' @@ -31,18 +29,27 @@ import { REPLICA_STATUS } from '../../Settings/Infrastructure/InfrastructureConf import { DestinationPanel } from './DestinationPanel/DestinationPanel' import { DestinationType } from './DestinationPanel/DestinationPanel.types' import { DestinationRow } from './DestinationRow' -import { EnableReplicationCallout } from './EnableReplicationCallout' import { PIPELINE_ERROR_MESSAGES } from './Pipeline.utils' import { ReadReplicaRow } from './ReadReplicas/ReadReplicaRow' +import { useIsETLBigQueryPrivateAlpha, useIsETLIcebergPrivateAlpha } from './useIsETLPrivateAlpha' import { useReadReplicasQuery } from '@/data/read-replicas/replicas-query' +import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled' export const Destinations = () => { const queryClient = useQueryClient() const { ref: projectRef } = useParams() - const { hasAccess: hasETLReplicationAccess, isLoading: isLoadingEntitlement } = - useCheckEntitlements('replication.etl') - const unifiedReplication = useFlag('unifiedReplication') + const etlEnableBigQuery = useIsETLBigQueryPrivateAlpha() + const etlEnableIceberg = useIsETLIcebergPrivateAlpha() + const { infrastructureReadReplicas } = useIsFeatureEnabled(['infrastructure:read_replicas']) + + const newDestinationDefaultType = infrastructureReadReplicas + ? 'Read Replica' + : etlEnableBigQuery + ? 'BigQuery' + : etlEnableIceberg + ? 'Analytics Bucket' + : null const prefetchedRef = useRef(false) const [filterString, setFilterString] = useState('') @@ -74,18 +81,6 @@ export const Destinations = () => { ? readReplicas : readReplicas.filter((replica) => replica.identifier.includes(filterString.toLowerCase())) - const { - data: sourcesData, - error: sourcesError, - isPending: isSourcesLoading, - isError: isSourcesError, - isSuccess: isSourcesSuccess, - } = useReplicationSourcesQuery({ - projectRef, - }) - const sourceId = sourcesData?.sources.find((s) => s.name === projectRef)?.id - const replicationNotEnabled = isSourcesSuccess && !sourceId - const { data: destinationsData, error: destinationsError, @@ -104,19 +99,12 @@ export const Destinations = () => { destination.name.toLowerCase().includes(filterString.toLowerCase()) ) - const { - data: pipelinesData, - error: pipelinesError, - isPending: isPipelinesLoading, - isError: isPipelinesError, - isSuccess: isPipelinesSuccess, - } = useReplicationPipelinesQuery({ + const { data: pipelinesData, isSuccess: isPipelinesSuccess } = useReplicationPipelinesQuery({ projectRef, }) - const isLoading = - isSourcesLoading || isDestinationsLoading || isDatabasesLoading || isLoadingEntitlement - const hasErrorsFetchingData = isSourcesError || isDestinationsError || isDatabasesError + const isLoading = isDestinationsLoading || isDatabasesLoading + const hasErrorsFetchingData = isDestinationsError || isDatabasesError useEffect(() => { if ( @@ -184,15 +172,14 @@ export const Destinations = () => { />

- {(unifiedReplication || !!sourceId) && ( - - )} +
@@ -201,16 +188,14 @@ export const Destinations = () => {
{hasErrorsFetchingData && ( )} {isLoading ? ( - ) : !unifiedReplication && replicationNotEnabled ? ( - - ) : (unifiedReplication && hasReplicas) || hasDestinations ? ( + ) : hasReplicas || hasDestinations ? ( @@ -231,16 +216,15 @@ export const Destinations = () => { - {unifiedReplication && - filteredReplicas.map((replica) => { - return ( - setStatusRefetchInterval(5000)} - /> - ) - })} + {filteredReplicas.map((replica) => { + return ( + setStatusRefetchInterval(5000)} + /> + ) + })} {filteredDestinations.map((destination) => ( @@ -249,7 +233,7 @@ export const Destinations = () => { {!isLoading && filteredDestinations.length === 0 && filteredReplicas.length === 0 && - ((unifiedReplication && hasReplicas) || hasDestinations) && ( + (hasReplicas || hasDestinations) && (

No results found

@@ -273,15 +257,10 @@ export const Destinations = () => { 'flex flex-col px-16 rounded-lg justify-center items-center py-8 mt-4' )} > -

- {unifiedReplication - ? 'Replication keeps your data in sync across systems' - : 'Create your first destination'} -

+

Replication keeps your data in sync across systems

- {unifiedReplication - ? 'Deploy read replicas for lower latency and better resource management, or capture database changes to external platforms for real-time data pipelines.' - : 'Destinations are external platforms where your database changes are automatically sent. Connect to various data warehouses and analytics platforms to enable real-time data pipelines.'} + Deploy read replicas for lower latency and better resource management, or capture + database changes to external platforms for real-time data pipelines.

- ) : !canGenerateNewJWTSecret ? ( - } - tooltip={{ - content: { - side: 'bottom', - text: 'You need additional permissions to generate a new JWT secret', - }, - }} - > - Generate a new secret - - ) : ( - - - - - - setIsGeneratingKey(true)} - > - -

Generate a random secret

-
- - setIsCreatingKey(true)} - > - -

Create my own secret

-
-
-
- )} - - - - )} - - {isJwtSecretUpdateFailed ? ( - - Please try again. If the failures persist, please contact Supabase - support with the following details:
- Change tracking ID: {data?.changeTrackingId}
- Error message: {jwtSecretUpdateErrorMessage} -
- ) : null} - - )} )} diff --git a/apps/studio/components/interfaces/JwtSecrets/signing-keys-coming-soon.tsx b/apps/studio/components/interfaces/JwtSecrets/signing-keys-coming-soon.tsx deleted file mode 100644 index dcfdb7999ff84..0000000000000 --- a/apps/studio/components/interfaces/JwtSecrets/signing-keys-coming-soon.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { Github } from 'lucide-react' -import { Button } from 'ui' - -import { FeatureBanner } from 'components/ui/FeatureBanner' - -export const SigningKeysComingSoonBanner = () => { - return ( - -
-

JWT signing keys are coming soon

-

- We're rolling out JWT signing keys to better support your application needs. -

-
- -
-
-
- ) -} diff --git a/apps/studio/components/interfaces/Observability/ObservabilityOverview.tsx b/apps/studio/components/interfaces/Observability/ObservabilityOverview.tsx index a41b5d6e045b4..998916d89243b 100644 --- a/apps/studio/components/interfaces/Observability/ObservabilityOverview.tsx +++ b/apps/studio/components/interfaces/Observability/ObservabilityOverview.tsx @@ -1,5 +1,5 @@ import { useQueryClient } from '@tanstack/react-query' -import { useFlag, useParams } from 'common' +import { useParams } from 'common' import ReportHeader from 'components/interfaces/Reports/ReportHeader' import ReportPadding from 'components/interfaces/Reports/ReportPadding' import { ChartIntervalDropdown } from 'components/ui/Logs/ChartIntervalDropdown' @@ -28,11 +28,6 @@ export const ObservabilityOverview = () => { const { plan } = useCurrentOrgPlan() const queryClient = useQueryClient() - const authReportEnabled = useFlag('authreportv2') - const edgeFnReportEnabled = useFlag('edgefunctionreport') - const realtimeReportEnabled = useFlag('realtimeReport') - const storageReportEnabled = useFlag('storagereport') - const postgrestReportEnabled = useFlag('postgrestreport') const { projectStorageAll: storageSupported } = useIsFeatureEnabled(['project_storage:all']) const DEFAULT_INTERVAL: ChartIntervalKey = '1day' @@ -77,7 +72,7 @@ export const ObservabilityOverview = () => { reportUrl: `/project/${projectRef}/observability/auth`, logsUrl: `/project/${projectRef}/logs/auth-logs`, enabled: true, - hasReport: authReportEnabled, + hasReport: true, }, { key: 'functions' as const, @@ -85,7 +80,7 @@ export const ObservabilityOverview = () => { reportUrl: `/project/${projectRef}/observability/edge-functions`, logsUrl: `/project/${projectRef}/logs/edge-functions-logs`, enabled: true, - hasReport: edgeFnReportEnabled, + hasReport: true, }, { key: 'realtime' as const, @@ -93,7 +88,7 @@ export const ObservabilityOverview = () => { reportUrl: `/project/${projectRef}/observability/realtime`, logsUrl: `/project/${projectRef}/logs/realtime-logs`, enabled: true, - hasReport: realtimeReportEnabled, + hasReport: true, }, { key: 'storage' as const, @@ -101,7 +96,7 @@ export const ObservabilityOverview = () => { reportUrl: `/project/${projectRef}/observability/storage`, logsUrl: `/project/${projectRef}/logs/storage-logs`, enabled: storageSupported, - hasReport: storageReportEnabled, + hasReport: true, }, { key: 'postgrest' as const, @@ -109,18 +104,10 @@ export const ObservabilityOverview = () => { reportUrl: `/project/${projectRef}/observability/postgrest`, logsUrl: `/project/${projectRef}/logs/postgrest-logs`, enabled: true, - hasReport: postgrestReportEnabled, + hasReport: true, }, ], - [ - projectRef, - authReportEnabled, - edgeFnReportEnabled, - realtimeReportEnabled, - storageReportEnabled, - storageSupported, - postgrestReportEnabled, - ] + [projectRef, storageSupported] ) const enabledServices = serviceBase.filter((s) => s.enabled) diff --git a/apps/studio/components/interfaces/QueryPerformance/QueryDetail.tsx b/apps/studio/components/interfaces/QueryPerformance/QueryDetail.tsx index 4aa6696c21e2d..3d1bcdcf98f82 100644 --- a/apps/studio/components/interfaces/QueryPerformance/QueryDetail.tsx +++ b/apps/studio/components/interfaces/QueryPerformance/QueryDetail.tsx @@ -1,4 +1,3 @@ -import { useFlag } from 'common' import { SIDEBAR_KEYS } from 'components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider' import { AiAssistantDropdown } from 'components/ui/AiAssistantDropdown' import { formatSql } from 'lib/formatSql' @@ -40,8 +39,6 @@ export const QueryDetail = ({ selectedRow, onClickViewSuggestion, onClose }: Que const aiSnap = useAiAssistantStateSnapshot() const track = useTrack() - const showExplainWithAiInQueryPerformance = useFlag('ShowExplainWithAiInQueryPerformance') - useEffect(() => { if (selectedRow !== undefined) { const formattedQuery = formatSql(selectedRow['query']) @@ -85,16 +82,14 @@ export const QueryDetail = ({ selectedRow, onClickViewSuggestion, onClose }: Que

Query pattern

- {showExplainWithAiInQueryPerformance && ( - - )} +
void - onClose: () => void -} - -const DeployNewReplicaPanel = ({ - visible, - selectedDefaultRegion, - onSuccess, - onClose, -}: DeployNewReplicaPanelProps) => { - const { ref: projectRef } = useParams() - const { data: project } = useSelectedProjectQuery() - const { data: org } = useSelectedOrganizationQuery() - const { hasAccess: hasReadReplicaAccess } = useCheckEntitlements('instances.read_replicas') - - const { data } = useReadReplicasQuery({ projectRef }) - const { data: addons, isSuccess } = useProjectAddonsQuery({ projectRef }) - const { data: diskConfiguration } = useDiskAttributesQuery({ projectRef }) - - const isNotOnHigherPlan = useMemo( - () => !['team', 'enterprise', 'platform'].includes(org?.plan.id ?? ''), - [org] - ) - const { data: allOverdueInvoices } = useOverdueInvoicesQuery({ - enabled: isNotOnHigherPlan, - }) - const overdueInvoices = (allOverdueInvoices ?? []).filter( - (x) => x.organization_id === project?.organization_id - ) - const hasOverdueInvoices = overdueInvoices.length > 0 && isNotOnHigherPlan - const isAwsK8s = useIsAwsK8sCloudProvider() - - // Opting for useState temporarily as Listbox doesn't seem to work with react-hook-form yet - const [defaultRegion] = Object.entries(AWS_REGIONS).find( - ([_, name]) => name === AWS_REGIONS_DEFAULT - ) ?? ['ap-southeast-1'] - // Will be following the primary's compute size for the time being - const defaultCompute = - addons?.selected_addons.find((addon) => addon.type === 'compute_instance')?.variant - .identifier ?? 'ci_micro' - - // @ts-ignore - const { size_gb, type, throughput_mbps, iops } = diskConfiguration?.attributes ?? {} - const showNewDiskManagementUI = project?.cloud_provider === 'AWS' - const readReplicaDiskSizes = (size_gb ?? 0) * 1.25 - const additionalCostDiskSize = - readReplicaDiskSizes * (DISK_PRICING[type as DiskType]?.storage ?? 0) - const additionalCostIOPS = calculateIOPSPrice({ - oldStorageType: type as DiskType, - newStorageType: type as DiskType, - oldProvisionedIOPS: 0, - newProvisionedIOPS: iops ?? 0, - numReplicas: 0, - }).newPrice - const additionalCostThroughput = - type === 'gp3' - ? calculateThroughputPrice({ - storageType: type as DiskType, - newThroughput: throughput_mbps ?? 0, - oldThroughput: 0, - numReplicas: 0, - }).newPrice - : 0 - - const [refetchInterval, setRefetchInterval] = useState(false) - const [selectedRegion, setSelectedRegion] = useState(defaultRegion) - const [selectedCompute, setSelectedCompute] = useState(defaultCompute) - - const { data: projectDetail, isSuccess: isProjectDetailSuccess } = useProjectDetailQuery( - { ref: projectRef }, - { - refetchInterval, - refetchOnWindowFocus: false, - } - ) - - useEffect(() => { - if (!isProjectDetailSuccess) return - if (projectDetail.is_physical_backups_enabled) { - setRefetchInterval(false) - } - }, [projectDetail?.is_physical_backups_enabled, isProjectDetailSuccess]) - - const { mutate: enablePhysicalBackups, isPending: isEnabling } = useEnablePhysicalBackupsMutation( - { - onSuccess: () => { - toast.success( - 'Physical backups are currently being enabled, please check back in a few minutes!' - ) - setRefetchInterval(5000) - }, - } - ) - - const { mutate: setUpReplica, isPending: isSettingUp } = useReadReplicaSetUpMutation({ - onSuccess: () => { - const region = AVAILABLE_REPLICA_REGIONS.find((r) => r.key === selectedRegion)?.name - toast.success(`Spinning up new replica in ${region ?? ' Unknown'}...`) - onSuccess() - onClose() - }, - }) - - const currentPgVersion = Number( - (project?.dbVersion ?? '').split('supabase-postgres-')[1]?.split('.')[0] - ) - - const maxNumberOfReplicas = ['ci_micro', 'ci_small', 'ci_medium', 'ci_large'].includes( - selectedCompute - ) - ? MAX_REPLICAS_BELOW_XL - : MAX_REPLICAS_ABOVE_XL - const reachedMaxReplicas = - (data ?? []).filter((db) => db.identifier !== projectRef).length >= maxNumberOfReplicas - const isAWSProvider = project?.cloud_provider === 'AWS' - const isWalgEnabled = project?.is_physical_backups_enabled - const currentComputeAddon = addons?.selected_addons.find( - (addon) => addon.type === 'compute_instance' - ) - const isProWithSpendCapEnabled = org?.plan.id === 'pro' && !org.usage_billing_enabled - const isMinimallyOnSmallCompute = - currentComputeAddon?.variant.identifier !== undefined && - currentComputeAddon?.variant.identifier !== 'ci_micro' - const canDeployReplica = - !reachedMaxReplicas && - currentPgVersion >= 15 && - isAWSProvider && - hasReadReplicaAccess && - isWalgEnabled && - currentComputeAddon !== undefined && - !hasOverdueInvoices && - !isAwsK8s && - !isProWithSpendCapEnabled - - const computeAddons = - addons?.available_addons.find((addon) => addon.type === 'compute_instance')?.variants ?? [] - const selectedComputeMeta = computeAddons.find((addon) => addon.identifier === selectedCompute) - const estComputeMonthlyCost = Math.floor((selectedComputeMeta?.price ?? 0) * 730) // 730 hours in a month - - const availableRegions = - process.env.NEXT_PUBLIC_ENVIRONMENT === 'staging' - ? AVAILABLE_REPLICA_REGIONS.filter((x) => - ['SOUTHEAST_ASIA', 'CENTRAL_EU', 'EAST_US'].includes(x.key) - ) - : AVAILABLE_REPLICA_REGIONS - - const onSubmit = async () => { - const regionKey = AWS_REGIONS[selectedRegion as AWS_REGIONS_KEYS].code - if (!projectRef) return console.error('Project is required') - if (!regionKey) return toast.error('Unable to deploy replica: Unsupported region selected') - - const primary = data?.find((db) => db.identifier === projectRef) - setUpReplica({ projectRef, region: regionKey as Region, size: primary?.size ?? 't4g.small' }) - } - - useEffect(() => { - if (visible && isSuccess) { - if (selectedDefaultRegion !== undefined) { - setSelectedRegion(selectedDefaultRegion) - } else if (defaultRegion) { - setSelectedRegion(defaultRegion) - } - if (defaultCompute !== undefined) setSelectedCompute(defaultCompute) - } - }, [visible, isSuccess]) - - return ( - onSubmit()} - confirmText="Deploy replica" - > - - {hasOverdueInvoices ? ( - - - Your organization has overdue invoices - - - Please resolve all outstanding invoices first before deploying a new read replica - -
- -
-
-
- ) : !isAWSProvider ? ( - - - - Read replicas are only supported for projects provisioned via AWS - - - - Projects provisioned by other cloud providers currently will not be able to use read - replicas - - - - - ) : isAwsK8s ? ( - - - - Read replicas are not supported for AWS (Revamped) projects - - - - Projects provisioned by other cloud providers currently will not be able to use read - replicas - - - - ) : currentPgVersion < 15 ? ( - - - - Read replicas can only be deployed with projects on Postgres version 15 and above - - - If you'd like to use read replicas, please contact us via support - - - - - - ) : !isMinimallyOnSmallCompute ? ( - - - - Project required to at least be on a Small compute - - - - This is to ensure that read replicas can keep up with the primary databases' - activities. - -
- - -
-
-
- ) : !isWalgEnabled ? ( - - - - {refetchInterval !== false - ? 'Physical backups are currently being enabled' - : 'Physical backups are required to deploy replicas'} - - {refetchInterval === false && ( - - Physical backups are used under the hood to spin up read replicas for your project. - - )} - - {refetchInterval !== false - ? 'This warning will go away once physical backups have been enabled - check back in a few minutes!' - : 'Enabling physical backups will take a few minutes, after which you will be able to deploy read replicas.'} - - {refetchInterval !== false ? ( - - You may start deploying read replicas thereafter once this is completed. - - ) : ( - - - - - )} - - ) : isProWithSpendCapEnabled ? ( - - - - Spend cap needs to be disabled to deploy replicas - - - - Launching a replica incurs additional disk size that will exceed the plan's quota. - Disable the spend cap first to allow overages before launching a replica. - -
- -
-
-
- ) : reachedMaxReplicas ? ( - - - - You can only deploy up to {maxNumberOfReplicas} read replicas at once - - - If you'd like to spin up another read replica, please drop an existing replica first. - - {maxNumberOfReplicas === MAX_REPLICAS_BELOW_XL && ( - <> - - - Alternatively, you may deploy up to{' '} - {MAX_REPLICAS_ABOVE_XL} replicas if - your project is on an XL compute or higher. - -
- -
-
- - )} -
- ) : null} - -
- - {availableRegions.map((region) => ( - ( - region icon - )} - > -

- {region.name} - {region.region} -

-
- ))} -
- -
- {showNewDiskManagementUI ? ( - <> - - -

- New replica will cost an additional{' '} - - {formatCurrency( - estComputeMonthlyCost + - additionalCostDiskSize + - Number(additionalCostIOPS) + - Number(additionalCostThroughput) - )} - /month - -

- -
- -

- Read replicas will match the compute size of your primary database and will - include 25% more disk size than the primary database to accommodate WAL files. -

-

- The additional cost for the replica breaks down to: -

-
- - - Item - Description - Cost (/month) - - - - - Compute size - {selectedComputeMeta?.name} - - {formatCurrency(estComputeMonthlyCost)} - - - - Disk size - - {((size_gb ?? 0) * 1.25).toLocaleString()} GB ({type}) - - - {formatCurrency(additionalCostDiskSize)} - - - - IOPS - {iops?.toLocaleString()} IOPS - - {formatCurrency(+additionalCostIOPS)} - - - {type === 'gp3' && ( - - Throughput - {throughput_mbps?.toLocaleString()} MB/s - - {formatCurrency(+additionalCostThroughput)} - - - )} - -
- - - - ) : ( -

- Read replicas will be on the same compute size as your primary database. Deploying a - read replica on the{' '} - {selectedComputeMeta?.name} size incurs - additional{' '} - - {selectedComputeMeta?.price_description} - - . -

- )} - -

- Read more about{' '} - - billing - {' '} - for read replicas. -

-
-
- - - ) -} - -export default DeployNewReplicaPanel diff --git a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/InstanceConfiguration.tsx b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/InstanceConfiguration.tsx index a66053296b734..e5376107aef61 100644 --- a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/InstanceConfiguration.tsx +++ b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/InstanceConfiguration.tsx @@ -5,6 +5,7 @@ import { useTheme } from 'next-themes' import Link from 'next/link' import { useEffect, useMemo, useState } from 'react' import ReactFlow, { Background, Edge, ReactFlowProvider, useReactFlow } from 'reactflow' + import 'reactflow/dist/style.css' import { useParams } from 'common' @@ -24,17 +25,17 @@ import { useSelectedProjectQuery, } from 'hooks/misc/useSelectedProject' import { timeout } from 'lib/helpers' -import { type AWS_REGIONS_KEYS } from 'shared-data' +import { useRouter } from 'next/router' import { Button, + cn, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, - cn, } from 'ui' -import DeployNewReplicaPanel from './DeployNewReplicaPanel' + import DropAllReplicasConfirmationModal from './DropAllReplicasConfirmationModal' import { DropReplicaConfirmationModal } from './DropReplicaConfirmationModal' import { SmoothstepEdge } from './Edge' @@ -43,13 +44,13 @@ import { addRegionNodes, generateNodes, getDagreGraphLayout } from './InstanceCo import { LoadBalancerNode, PrimaryNode, RegionNode, ReplicaNode } from './InstanceNode' import MapView from './MapView' import { RestartReplicaConfirmationModal } from './RestartReplicaConfirmationModal' -import { useShowNewReplicaPanel } from './use-show-new-replica' interface InstanceConfigurationUIProps { diagramOnly?: boolean } const InstanceConfigurationUI = ({ diagramOnly = false }: InstanceConfigurationUIProps) => { + const router = useRouter() const reactFlow = useReactFlow() const isOrioleDb = useIsOrioleDb() const { resolvedTheme } = useTheme() @@ -58,12 +59,11 @@ const InstanceConfigurationUI = ({ diagramOnly = false }: InstanceConfigurationU const isAws = useIsAwsCloudProvider() const { infrastructureReadReplicas } = useIsFeatureEnabled(['infrastructure:read_replicas']) + const newReplicaURL = `/project/${projectRef}/database/replication?type=Read+Replica` const [view, setView] = useState<'flow' | 'map'>('flow') const [showDeleteAllModal, setShowDeleteAllModal] = useState(false) - const { showNewReplicaPanel, setShowNewReplicaPanel } = useShowNewReplicaPanel() const [refetchInterval, setRefetchInterval] = useState(10000) - const [newReplicaRegion, setNewReplicaRegion] = useState() const [selectedReplicaToDrop, setSelectedReplicaToDrop] = useState() const [selectedReplicaToRestart, setSelectedReplicaToRestart] = useState() @@ -86,6 +86,7 @@ const InstanceConfigurationUI = ({ diagramOnly = false }: InstanceConfigurationU () => partition(data ?? [], (db) => db.identifier === projectRef), [data, projectRef] ) + const numReplicas = useMemo(() => data?.length ?? 0, [data]) const { data: replicasStatuses, isSuccess: isSuccessReplicasStatuses } = useReadReplicasStatusesQuery( @@ -96,7 +97,6 @@ const InstanceConfigurationUI = ({ diagramOnly = false }: InstanceConfigurationU } ) - const numReplicas = useMemo(() => data?.length ?? 0, [data]) useEffect(() => { if (!isSuccessReplicasStatuses) return const refetch = async () => { @@ -241,10 +241,10 @@ const InstanceConfigurationUI = ({ diagramOnly = false }: InstanceConfigurationU
0 ? 'rounded-r-none' : '')} - onClick={() => setShowNewReplicaPanel(true)} tooltip={{ content: { side: 'bottom', @@ -256,7 +256,7 @@ const InstanceConfigurationUI = ({ diagramOnly = false }: InstanceConfigurationU }, }} > - Deploy a new replica + Deploy a new replica {replicas.length > 0 && ( @@ -325,10 +325,7 @@ const InstanceConfigurationUI = ({ diagramOnly = false }: InstanceConfigurationU ) : ( { - setNewReplicaRegion(region) - setShowNewReplicaPanel(true) - }} + onSelectDeployNewReplica={() => router.push(newReplicaURL)} onSelectRestartReplica={setSelectedReplicaToRestart} onSelectDropReplica={setSelectedReplicaToDrop} /> @@ -339,16 +336,6 @@ const InstanceConfigurationUI = ({ diagramOnly = false }: InstanceConfigurationU {!diagramOnly && ( <> - setRefetchInterval(5000)} - onClose={() => { - setNewReplicaRegion(undefined) - setShowNewReplicaPanel(false) - }} - /> - setRefetchInterval(5000)} diff --git a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/InstanceNode.tsx b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/InstanceNode.tsx index 30c9b1ab01475..a462177540810 100644 --- a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/InstanceNode.tsx +++ b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/InstanceNode.tsx @@ -1,6 +1,4 @@ -import { PermissionAction } from '@supabase/shared-types/out/constants' import { useParams } from 'common' -import { DropdownMenuItemTooltip } from 'components/ui/DropdownMenuItemTooltip' import SparkBar from 'components/ui/SparkBar' import { DatabaseInitEstimations, @@ -9,15 +7,12 @@ import { } from 'data/read-replicas/replicas-status-query' import { formatDatabaseID } from 'data/read-replicas/replicas.utils' import dayjs from 'dayjs' -import { useCustomContent } from 'hooks/custom-content/useCustomContent' -import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions' import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled' import { BASE_PATH } from 'lib/constants' import { Database, DatabaseBackup, HelpCircle, Loader2, MoreVertical } from 'lucide-react' import Link from 'next/link' -import { parseAsBoolean, useQueryState } from 'nuqs' +import { parseAsBoolean, parseAsString, useQueryStates } from 'nuqs' import { Handle, NodeProps, Position } from 'reactflow' -import { useDatabaseSelectorStateSnapshot } from 'state/database-selector' import { Badge, Button, @@ -41,6 +36,7 @@ import { REPLICA_STATUS, } from './InstanceConfiguration.constants' import { formatSeconds } from './InstanceConfiguration.utils' +import { useDatabaseSelectorStateSnapshot } from '@/state/database-selector' interface NodeData { id: string @@ -111,13 +107,11 @@ export const LoadBalancerNode = ({ data }: NodeProps) => { export const PrimaryNode = ({ data }: NodeProps) => { // [Joshen] Just FYI Handles cannot be conditionally rendered - const { provider, region, computeSize, numReplicas, numRegions, hasLoadBalancer } = data + const { region, computeSize, numReplicas, numRegions, hasLoadBalancer } = data const { projectHomepageShowInstanceSize } = useIsFeatureEnabled([ 'project_homepage:show_instance_size', ]) - const { infraAwsNimbusLabel } = useCustomContent(['infra:aws_nimbus_label']) - const providerLabel = provider === 'AWS_NIMBUS' ? infraAwsNimbusLabel : provider return ( <> @@ -183,23 +177,17 @@ export const PrimaryNode = ({ data }: NodeProps) => { } export const ReplicaNode = ({ data }: NodeProps) => { - const { - id, - region, - computeSize, - status, - inserted_at, - onSelectRestartReplica, - onSelectDropReplica, - } = data const { ref } = useParams() - const dbSelectorState = useDatabaseSelectorStateSnapshot() - const { can: canManageReplicas } = useAsyncCheckPermissions(PermissionAction.CREATE, 'projects') + const { id, region, computeSize, status, inserted_at } = data const { projectHomepageShowInstanceSize } = useIsFeatureEnabled([ 'project_homepage:show_instance_size', ]) - const [, setShowConnect] = useQueryState('showConnect', parseAsBoolean.withDefault(false)) + const state = useDatabaseSelectorStateSnapshot() + const [, setConnect] = useQueryStates({ + showConnect: parseAsBoolean.withDefault(false), + source: parseAsString, + }) const { data: databaseStatuses } = useReadReplicasStatusesQuery({ projectRef: ref }) const { replicaInitializationStatus } = @@ -358,43 +346,20 @@ export const ReplicaNode = ({ data }: NodeProps) => { { - setShowConnect(true) - dbSelectorState.setSelectedDatabaseId(id) + setConnect({ showConnect: true, source: id }) + state.setSelectedDatabaseId(id) }} > View connection string - - - View replication lag - - - onSelectRestartReplica()} - disabled={status !== REPLICA_STATUS.ACTIVE_HEALTHY} - > - Restart replica + + + Manage replica + - { - if (canManageReplicas) onSelectDropReplica() - }} - tooltip={{ - content: { side: 'left', text: 'You need additional permissions to drop replicas' }, - }} - > - Drop replica -
diff --git a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/use-show-new-replica.tsx b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/use-show-new-replica.tsx deleted file mode 100644 index 5b89cceade392..0000000000000 --- a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/use-show-new-replica.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { parseAsBoolean, useQueryState } from 'nuqs' - -/** - * @deprecated Can remove after read replicas is fully moved into database replication page - */ -export function useShowNewReplicaPanel() { - const [showNewReplicaPanel, setShowNewReplicaPanel] = useQueryState( - 'createReplica', - parseAsBoolean.withDefault(false) - ) - - return { showNewReplicaPanel, setShowNewReplicaPanel } -} diff --git a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureInfo.tsx b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureInfo.tsx index ab0e6de4b7968..2fdfcf89b680e 100644 --- a/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureInfo.tsx +++ b/apps/studio/components/interfaces/Settings/Infrastructure/InfrastructureInfo.tsx @@ -1,4 +1,4 @@ -import { useFlag, useParams } from 'common' +import { useParams } from 'common' import { NoticeBar } from 'components/interfaces/DiskManagement/ui/NoticeBar' import { ScaffoldContainer, @@ -19,15 +19,12 @@ import { Admonition } from 'ui-patterns/admonition' import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader' import { ProjectUpgradeAlert } from '../General/Infrastructure/ProjectUpgradeAlert' -import { InstanceConfiguration } from './InfrastructureConfiguration/InstanceConfiguration' import { ReadReplicasWarning, ValidationErrorsWarning } from './UpgradeWarnings' export const InfrastructureInfo = () => { const { ref } = useParams() const { data: project } = useSelectedProjectQuery() - const unifiedReplication = useFlag('unifiedReplication') - const { projectAuthAll: authEnabled, projectSettingsDatabaseUpgrades: showDatabaseUpgrades } = useIsFeatureEnabled(['project_auth:all', 'project_settings:database_upgrades']) @@ -73,31 +70,26 @@ export const InfrastructureInfo = () => { return ( <> - {project?.cloud_provider !== 'FLY' && - (unifiedReplication ? ( - - - - - Go to Replication - - - } - /> - - - ) : ( - <> - - - - ))} + + {project?.cloud_provider !== 'FLY' && ( + + + + + Go to Replication + + + } + /> + + + )} diff --git a/apps/studio/components/interfaces/Settings/Infrastructure/UpgradeWarnings.tsx b/apps/studio/components/interfaces/Settings/Infrastructure/UpgradeWarnings.tsx index 660a5fc060cd5..7086d3657659c 100644 --- a/apps/studio/components/interfaces/Settings/Infrastructure/UpgradeWarnings.tsx +++ b/apps/studio/components/interfaces/Settings/Infrastructure/UpgradeWarnings.tsx @@ -1,15 +1,14 @@ -import Link from 'next/link' - -import { ProjectUpgradeEligibilityValidationError } from '@/data/config/project-upgrade-eligibility-query' -import { useFlag, useParams } from 'common' +import { useParams } from 'common' import { InlineLink } from 'components/ui/InlineLink' import { DOCS_URL } from 'lib/constants' +import Link from 'next/link' import { Button } from 'ui' import { Admonition } from 'ui-patterns/admonition' +import { ProjectUpgradeEligibilityValidationError } from '@/data/config/project-upgrade-eligibility-query' + export const ReadReplicasWarning = ({ latestPgVersion }: { latestPgVersion: string }) => { const { ref } = useParams() - const unifiedReplication = useFlag('unifiedReplication') return ( - Manage read replicas - - ) : undefined + } /> ) diff --git a/apps/studio/components/interfaces/Settings/Integrations/IntegrationsSettings.tsx b/apps/studio/components/interfaces/Settings/Integrations/IntegrationsSettings.tsx index be9acc2a78c26..b64cbfe56ed54 100644 --- a/apps/studio/components/interfaces/Settings/Integrations/IntegrationsSettings.tsx +++ b/apps/studio/components/interfaces/Settings/Integrations/IntegrationsSettings.tsx @@ -1,13 +1,12 @@ -import Link from 'next/link' - -import { useFlag } from 'common' import { SidePanelVercelProjectLinker } from 'components/interfaces/Organization/IntegrationSettings/SidePanelVercelProjectLinker' import { ScaffoldContainer, ScaffoldDivider } from 'components/layouts/Scaffold' import { useProjectDetailQuery } from 'data/projects/project-detail-query' import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled' import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' import { BASE_PATH } from 'lib/constants' -import { AlertDescription_Shadcn_, AlertTitle_Shadcn_, Alert_Shadcn_, WarningIcon } from 'ui' +import Link from 'next/link' +import { Alert_Shadcn_, AlertDescription_Shadcn_, AlertTitle_Shadcn_, WarningIcon } from 'ui' + import { AWSPrivateLinkSection } from './AWSPrivateLink/AWSPrivateLinkSection' import { GitHubSection } from './GithubIntegration/GithubSection' import { VercelSection } from './VercelIntegration/VercelSection' @@ -29,11 +28,9 @@ const IntegrationSettings = () => { const showVercelIntegration = useIsFeatureEnabled('integrations:vercel') const showAWSPrivateLinkFeature = useIsFeatureEnabled('integrations:aws_private_link') - const showAWSPrivateLinkConfigCat = useFlag('awsPrivateLinkIntegration') // PrivateLink is not available in eu-central-2 (Zurich) until Feb 2026 const isPrivateLinkUnsupportedRegion = project?.region === 'eu-central-2' - const showAWSPrivateLink = - showAWSPrivateLinkFeature && showAWSPrivateLinkConfigCat && !isPrivateLinkUnsupportedRegion + const showAWSPrivateLink = showAWSPrivateLinkFeature && !isPrivateLinkUnsupportedRegion return ( <> diff --git a/apps/studio/components/interfaces/Storage/AnalyticsBuckets/AnalyticsBucketDetails/ConnectTablesDialog.tsx b/apps/studio/components/interfaces/Storage/AnalyticsBuckets/AnalyticsBucketDetails/ConnectTablesDialog.tsx index 62075f62eb89c..4d29c5a141b86 100644 --- a/apps/studio/components/interfaces/Storage/AnalyticsBuckets/AnalyticsBucketDetails/ConnectTablesDialog.tsx +++ b/apps/studio/components/interfaces/Storage/AnalyticsBuckets/AnalyticsBucketDetails/ConnectTablesDialog.tsx @@ -1,16 +1,8 @@ import { zodResolver } from '@hookform/resolvers/zod' import { PermissionAction } from '@supabase/shared-types/out/constants' -import { AnimatePresence, motion } from 'framer-motion' -import { Loader2, Plus } from 'lucide-react' -import { useEffect, useMemo, useState } from 'react' -import { SubmitHandler, useForm } from 'react-hook-form' -import { toast } from 'sonner' -import z from 'zod' - -import { useFlag, useParams } from 'common' +import { useParams } from 'common' import { useIsETLPrivateAlpha } from 'components/interfaces/Database/Replication/useIsETLPrivateAlpha' import { convertKVStringArrayToJson } from 'components/interfaces/Integrations/Wrappers/Wrappers.utils' -import { ButtonTooltip } from 'components/ui/ButtonTooltip' import { getKeys, useAPIKeysQuery } from 'data/api-keys/api-keys-query' import { useProjectSettingsV2Query } from 'data/config/project-settings-v2-query' import { useCreateDestinationPipelineMutation } from 'data/replication/create-destination-pipeline-mutation' @@ -21,8 +13,13 @@ import { useReplicationSourcesQuery } from 'data/replication/sources-query' import { useStartPipelineMutation } from 'data/replication/start-pipeline-mutation' import { useReplicationTablesQuery } from 'data/replication/tables-query' import { getDecryptedValues } from 'data/vault/vault-secret-decrypted-value-query' +import { AnimatePresence, motion } from 'framer-motion' import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions' import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' +import { Loader2, Plus } from 'lucide-react' +import { useEffect, useMemo, useState } from 'react' +import { SubmitHandler, useForm } from 'react-hook-form' +import { toast } from 'sonner' import { Button, Dialog, @@ -42,6 +39,8 @@ import { import { Admonition } from 'ui-patterns' import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' import { MultiSelector } from 'ui-patterns/multi-select' +import z from 'zod' + import { getAnalyticsBucketPublicationName, getAnalyticsBucketsDestinationName, @@ -100,12 +99,11 @@ interface ConnectTablesDialogProps { onSuccessConnectTables: () => void } +/** [Joshen] This component is currently not user-facing atm, might opt to clean up as we're likely not going to use this UI flow */ export const ConnectTablesDialog = ({ onSuccessConnectTables }: ConnectTablesDialogProps) => { const { ref: projectRef, bucketId } = useParams() const [visible, setVisible] = useState(false) - const isEnabled = useFlag('storageAnalyticsVector') // Kill switch if we wanna hold off supporting connecting tables - const { sourceId, pipeline, publication } = useAnalyticsBucketAssociatedEntities({ projectRef, bucketId, @@ -115,16 +113,9 @@ export const ConnectTablesDialog = ({ onSuccessConnectTables }: ConnectTablesDia return ( - } - onClick={() => setVisible(true)} - tooltip={{ content: { side: 'bottom', text: !isEnabled ? 'Coming soon' : undefined } }} - > + {!sourceId ? ( diff --git a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/ForeignRowSelector/ForeignRowSelector.tsx b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/ForeignRowSelector/ForeignRowSelector.tsx index d03ce03b372b0..bdc3d5f8b2b5a 100644 --- a/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/ForeignRowSelector/ForeignRowSelector.tsx +++ b/apps/studio/components/interfaces/TableGridEditor/SidePanelEditor/RowEditor/ForeignRowSelector/ForeignRowSelector.tsx @@ -1,29 +1,29 @@ -import { Loader2, X } from 'lucide-react' -import { useEffect, useState } from 'react' -import { DndProvider } from 'react-dnd' -import { HTML5Backend } from 'react-dnd-html5-backend' - import { keepPreviousData } from '@tanstack/react-query' import { useParams } from 'common' +import { FilterPopoverPrimitive } from 'components/grid/components/header/filter/FilterPopoverPrimitive' +import { RefreshButton } from 'components/grid/components/header/RefreshButton' +import { SortPopoverPrimitive } from 'components/grid/components/header/sort/SortPopoverPrimitive' import { formatSortURLParams, loadTableEditorStateFromLocalStorage, saveTableEditorStateToLocalStorage, sortsToUrlParams, } from 'components/grid/SupabaseGrid.utils' -import { RefreshButton } from 'components/grid/components/header/RefreshButton' -import { FilterPopoverPrimitive } from 'components/grid/components/header/filter/FilterPopoverPrimitive' -import { SortPopoverPrimitive } from 'components/grid/components/header/sort/SortPopoverPrimitive' import type { Filter, Sort } from 'components/grid/types' import { useTableEditorQuery } from 'data/table-editor/table-editor-query' import { useTableRowsQuery } from 'data/table-rows/table-rows-query' import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' +import { Loader2, X } from 'lucide-react' +import { useEffect, useState } from 'react' +import { DndProvider } from 'react-dnd' +import { HTML5Backend } from 'react-dnd-html5-backend' import { RoleImpersonationState, useRoleImpersonationStateSnapshot, } from 'state/role-impersonation-state' import { TableEditorTableStateContextProvider } from 'state/table-editor-table' import { Button, SidePanel } from 'ui' + import { ForeignKey } from '../../ForeignKeySelector/ForeignKeySelector.types' import { convertByteaToHex } from '../RowEditor.utils' import Pagination from './Pagination' @@ -110,7 +110,6 @@ export const ForeignRowSelector = ({ } = useTableRowsQuery( { projectRef: project?.ref, - connectionString: project?.connectionString, tableId: table?.id, sorts, filters, diff --git a/apps/studio/components/layouts/AdvisorsLayout/AdvisorsMenu.utils.tsx b/apps/studio/components/layouts/AdvisorsLayout/AdvisorsMenu.utils.tsx index 64ae4be38c5ea..142d8f93ac1dc 100644 --- a/apps/studio/components/layouts/AdvisorsLayout/AdvisorsMenu.utils.tsx +++ b/apps/studio/components/layouts/AdvisorsLayout/AdvisorsMenu.utils.tsx @@ -3,10 +3,7 @@ import type { Project } from 'data/projects/project-detail-query' import { IS_PLATFORM } from 'lib/constants' import { ArrowUpRight } from 'lucide-react' -export const generateAdvisorsMenu = ( - project?: Project, - features?: { advisorRules: boolean } -): ProductMenuGroup[] => { +export const generateAdvisorsMenu = (project?: Project): ProductMenuGroup[] => { const ref = project?.ref ?? 'default' return [ @@ -34,7 +31,7 @@ export const generateAdvisorsMenu = ( }, ], }, - ...(IS_PLATFORM && features?.advisorRules + ...(IS_PLATFORM ? [ { title: 'Configuration', diff --git a/apps/studio/components/layouts/AdvisorsLayout/AdvisorsSidebarMenu.tsx b/apps/studio/components/layouts/AdvisorsLayout/AdvisorsSidebarMenu.tsx index 1e37981afd9a2..770e078842058 100644 --- a/apps/studio/components/layouts/AdvisorsLayout/AdvisorsSidebarMenu.tsx +++ b/apps/studio/components/layouts/AdvisorsLayout/AdvisorsSidebarMenu.tsx @@ -1,9 +1,9 @@ -import { useIsAdvisorRulesEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext' import { SIDEBAR_KEYS } from 'components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider' import { ProductMenu } from 'components/ui/ProductMenu' import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' import { useSidebarManagerSnapshot } from 'state/sidebar-manager-state' import { Badge, Button } from 'ui' + import { FeaturePreviewSidebarPanel } from '../../ui/FeaturePreviewSidebarPanel' import { generateAdvisorsMenu } from './AdvisorsMenu.utils' @@ -13,7 +13,6 @@ interface AdvisorsSidebarMenuProps { export function AdvisorsSidebarMenu({ page }: AdvisorsSidebarMenuProps) { const { data: project } = useSelectedProjectQuery() - const advisorRules = useIsAdvisorRulesEnabled() const { toggleSidebar } = useSidebarManagerSnapshot() const handleOpenAdvisor = () => { @@ -34,7 +33,7 @@ export function AdvisorsSidebarMenu({ page }: AdvisorsSidebarMenuProps) { } /> - +
) } diff --git a/apps/studio/components/layouts/AuthLayout/AuthLayout.tsx b/apps/studio/components/layouts/AuthLayout/AuthLayout.tsx index 1c0d21ef48edd..716618a764524 100644 --- a/apps/studio/components/layouts/AuthLayout/AuthLayout.tsx +++ b/apps/studio/components/layouts/AuthLayout/AuthLayout.tsx @@ -1,55 +1,23 @@ -import { useRouter } from 'next/router' -import { PropsWithChildren } from 'react' - -import { useFlag, useParams } from 'common' +import { useParams } from 'common' import { ProductMenu } from 'components/ui/ProductMenu' import { useAuthConfigPrefetch } from 'data/auth/auth-config-query' -import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled' import { withAuth } from 'hooks/misc/withAuth' +import { useRouter } from 'next/router' +import { PropsWithChildren } from 'react' + import { ProjectLayout } from '../ProjectLayout' -import { generateAuthMenu } from './AuthLayout.utils' +import { useGenerateAuthMenu } from './AuthLayout.utils' const AuthProductMenu = () => { const router = useRouter() const { ref: projectRef = 'default' } = useParams() - const authenticationShowOverview = useFlag('authOverviewPage') - const authenticationOauth21 = useFlag('EnableOAuth21') - - const { - authenticationSignInProviders, - authenticationRateLimits, - authenticationEmails, - authenticationMultiFactor, - authenticationAttackProtection, - authenticationPerformance, - } = useIsFeatureEnabled([ - 'authentication:sign_in_providers', - 'authentication:rate_limits', - 'authentication:emails', - 'authentication:multi_factor', - 'authentication:attack_protection', - 'authentication:performance', - ]) - useAuthConfigPrefetch({ projectRef }) const page = router.pathname.split('/')[4] - return ( - - ) + const menu = useGenerateAuthMenu() + + return } const AuthLayout = ({ children }: PropsWithChildren<{}>) => { diff --git a/apps/studio/components/layouts/AuthLayout/AuthLayout.utils.ts b/apps/studio/components/layouts/AuthLayout/AuthLayout.utils.ts index 478aea254863e..1fe0504cf670e 100644 --- a/apps/studio/components/layouts/AuthLayout/AuthLayout.utils.ts +++ b/apps/studio/components/layouts/AuthLayout/AuthLayout.utils.ts @@ -1,48 +1,45 @@ +import { useFlag, useParams } from 'common' import type { ProductMenuGroup } from 'components/ui/ProductMenu/ProductMenu.types' import { IS_PLATFORM } from 'lib/constants' -export const generateAuthMenu = ( - ref: string, - flags?: { - authenticationSignInProviders: boolean - authenticationRateLimits: boolean - authenticationEmails: boolean - authenticationMultiFactor: boolean - authenticationAttackProtection: boolean - authenticationShowOverview: boolean - authenticationOauth21: boolean - authenticationPerformance: boolean - } -): ProductMenuGroup[] => { +import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled' + +export const useGenerateAuthMenu = (): ProductMenuGroup[] => { + const { ref } = useParams() + const authenticationShowOverview = useFlag('authOverviewPage') + const { authenticationSignInProviders, authenticationRateLimits, authenticationEmails, authenticationMultiFactor, authenticationAttackProtection, - authenticationShowOverview, - authenticationOauth21, authenticationPerformance, - } = flags ?? {} + } = useIsFeatureEnabled([ + 'authentication:sign_in_providers', + 'authentication:rate_limits', + 'authentication:emails', + 'authentication:multi_factor', + 'authentication:attack_protection', + 'authentication:performance', + ]) + + const baseUrl = `/project/${ref}/auth` return [ { title: 'Manage', items: [ ...(authenticationShowOverview - ? [{ name: 'Overview', key: 'overview', url: `/project/${ref}/auth/overview`, items: [] }] - : []), - { name: 'Users', key: 'users', url: `/project/${ref}/auth/users`, items: [] }, - ...(authenticationOauth21 - ? [ - { - name: 'OAuth Apps', - key: 'oauth-apps', - url: `/project/${ref}/auth/oauth-apps`, - items: [], - }, - ] + ? [{ name: 'Overview', key: 'overview', url: `${baseUrl}/overview`, items: [] }] : []), + { name: 'Users', key: 'users', url: `${baseUrl}/users`, items: [] }, + { + name: 'OAuth Apps', + key: 'oauth-apps', + url: `${baseUrl}/oauth-apps`, + items: [], + }, ], }, ...(authenticationEmails && IS_PLATFORM @@ -56,7 +53,7 @@ export const generateAuthMenu = ( name: 'Email', key: 'email', pages: ['templates', 'smtp'], - url: `/project/${ref}/auth/templates`, + url: `${baseUrl}/templates`, items: [], }, ] @@ -71,7 +68,7 @@ export const generateAuthMenu = ( { name: 'Policies', key: 'policies', - url: `/project/${ref}/auth/policies`, + url: `${baseUrl}/policies`, items: [], }, ...(IS_PLATFORM @@ -82,25 +79,21 @@ export const generateAuthMenu = ( name: 'Sign In / Providers', key: 'sign-in-up', pages: ['providers', 'third-party'], - url: `/project/${ref}/auth/providers`, + url: `${baseUrl}/providers`, items: [], }, ] : []), - ...(authenticationOauth21 - ? [ - { - name: 'OAuth Server', - key: 'oauth-server', - url: `/project/${ref}/auth/oauth-server`, - label: 'Beta', - }, - ] - : []), + { + name: 'OAuth Server', + key: 'oauth-server', + url: `${baseUrl}/oauth-server`, + label: 'Beta', + }, { name: 'Sessions', key: 'sessions', - url: `/project/${ref}/auth/sessions`, + url: `${baseUrl}/sessions`, items: [], }, ...(authenticationRateLimits @@ -108,7 +101,7 @@ export const generateAuthMenu = ( { name: 'Rate Limits', key: 'rate-limits', - url: `/project/${ref}/auth/rate-limits`, + url: `${baseUrl}/rate-limits`, items: [], }, ] @@ -118,7 +111,7 @@ export const generateAuthMenu = ( { name: 'Multi-Factor', key: 'mfa', - url: `/project/${ref}/auth/mfa`, + url: `${baseUrl}/mfa`, items: [], }, ] @@ -126,7 +119,7 @@ export const generateAuthMenu = ( { name: 'URL Configuration', key: 'url-configuration', - url: `/project/${ref}/auth/url-configuration`, + url: `${baseUrl}/url-configuration`, items: [], }, ...(authenticationAttackProtection @@ -134,7 +127,7 @@ export const generateAuthMenu = ( { name: 'Attack Protection', key: 'protection', - url: `/project/${ref}/auth/protection`, + url: `${baseUrl}/protection`, items: [], }, ] @@ -142,14 +135,14 @@ export const generateAuthMenu = ( { name: 'Auth Hooks', key: 'hooks', - url: `/project/${ref}/auth/hooks`, + url: `${baseUrl}/hooks`, items: [], label: 'Beta', }, { name: 'Audit Logs', key: 'audit-logs', - url: `/project/${ref}/auth/audit-logs`, + url: `${baseUrl}/audit-logs`, items: [], }, ...(authenticationPerformance @@ -157,7 +150,7 @@ export const generateAuthMenu = ( { name: 'Performance', key: 'performance', - url: `/project/${ref}/auth/performance`, + url: `${baseUrl}/performance`, items: [], }, ] diff --git a/apps/studio/components/layouts/ObservabilityLayout/ObservabilityMenu.tsx b/apps/studio/components/layouts/ObservabilityLayout/ObservabilityMenu.tsx index b0e186cbb4e0c..6c7d4df97423e 100644 --- a/apps/studio/components/layouts/ObservabilityLayout/ObservabilityMenu.tsx +++ b/apps/studio/components/layouts/ObservabilityLayout/ObservabilityMenu.tsx @@ -16,7 +16,7 @@ import { parseAsBoolean, useQueryState } from 'nuqs' import { Fragment, useMemo, useState } from 'react' import { toast } from 'sonner' import type { Dashboards } from 'types' -import { Menu, cn } from 'ui' +import { cn, Menu } from 'ui' import { InnerSideBarEmptyPanel } from 'ui-patterns' import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader' @@ -29,15 +29,9 @@ const ObservabilityMenu = () => { const { ref, id } = useParams() const pageKey = (id || router.pathname.split('/')[4] || 'observability') as string const showOverview = useFlag('observabilityOverview') - const authEnabled = useFlag('authreportv2') - const edgeFnEnabled = useFlag('edgefunctionreport') - const realtimeEnabled = useFlag('realtimeReport') - const storageReportEnabled = useFlag('storagereport') - const postgrestReportEnabled = useFlag('postgrestreport') // b/c fly doesn't support storage const storageSupported = useIsFeatureEnabled('project_storage:all') - const storageEnabled = storageReportEnabled && storageSupported const { can: canCreateCustomReport } = useAsyncCheckPermissions( PermissionAction.CREATE, @@ -162,43 +156,27 @@ const ObservabilityMenu = () => { title: 'PRODUCT', key: 'product-section', items: [ - ...(IS_PLATFORM - ? [ - { - name: 'Database', - key: 'database', - url: `/project/${ref}/observability/database${preservedQueryParams}`, - }, - ] - : []), - ...(postgrestReportEnabled - ? [ - { - name: 'Data API', - key: 'postgrest', - url: `/project/${ref}/observability/postgrest${preservedQueryParams}`, - }, - ] - : []), - ...(authEnabled - ? [ - { - name: 'Auth', - key: 'auth', - url: `/project/${ref}/observability/auth${preservedQueryParams}`, - }, - ] - : []), - ...(edgeFnEnabled - ? [ - { - name: 'Edge Functions', - key: 'edge-functions', - url: `/project/${ref}/observability/edge-functions${preservedQueryParams}`, - }, - ] - : []), - ...(storageEnabled + { + name: 'Database', + key: 'database', + url: `/project/${ref}/observability/database${preservedQueryParams}`, + }, + { + name: 'Data API', + key: 'postgrest', + url: `/project/${ref}/observability/postgrest${preservedQueryParams}`, + }, + { + name: 'Auth', + key: 'auth', + url: `/project/${ref}/observability/auth${preservedQueryParams}`, + }, + { + name: 'Edge Functions', + key: 'edge-functions', + url: `/project/${ref}/observability/edge-functions${preservedQueryParams}`, + }, + ...(storageSupported ? [ { name: 'Storage', @@ -207,15 +185,11 @@ const ObservabilityMenu = () => { }, ] : []), - ...(realtimeEnabled - ? [ - { - name: 'Realtime', - key: 'realtime', - url: `/project/${ref}/observability/realtime${preservedQueryParams}`, - }, - ] - : []), + { + name: 'Realtime', + key: 'realtime', + url: `/project/${ref}/observability/realtime${preservedQueryParams}`, + }, ], }, ] diff --git a/apps/studio/components/layouts/ReportsLayout/ReportsMenu.tsx b/apps/studio/components/layouts/ReportsLayout/ReportsMenu.tsx index 6d4f00599ac4d..312840a4ea840 100644 --- a/apps/studio/components/layouts/ReportsLayout/ReportsMenu.tsx +++ b/apps/studio/components/layouts/ReportsLayout/ReportsMenu.tsx @@ -1,11 +1,5 @@ import { PermissionAction } from '@supabase/shared-types/out/constants' -import { Plus } from 'lucide-react' -import Link from 'next/link' -import { useRouter } from 'next/router' -import { useMemo, useState } from 'react' -import { toast } from 'sonner' - -import { useFlag, useParams } from 'common' +import { useParams } from 'common' import { CreateReportModal } from 'components/interfaces/Reports/CreateReportModal' import { UpdateCustomReportModal } from 'components/interfaces/Reports/UpdateModal' import { ButtonTooltip } from 'components/ui/ButtonTooltip' @@ -14,26 +8,26 @@ import { Content, useContentQuery } from 'data/content/content-query' import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions' import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled' import { useProfile } from 'lib/profile' -import { Menu, cn } from 'ui' +import { Plus } from 'lucide-react' +import Link from 'next/link' +import { useRouter } from 'next/router' +import { parseAsBoolean, useQueryState } from 'nuqs' +import { useMemo, useState } from 'react' +import { toast } from 'sonner' +import { cn, Menu } from 'ui' import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader' + import { ReportMenuItem } from './ReportMenuItem' -import { useQueryState, parseAsBoolean } from 'nuqs' const ReportsMenu = () => { const router = useRouter() const { profile } = useProfile() const { ref, id } = useParams() const pageKey = (id || router.pathname.split('/')[4]) as string - const authEnabled = useFlag('authreportv2') - const edgeFnEnabled = useFlag('edgefunctionreport') - const realtimeEnabled = useFlag('realtimeReport') - const storageReportEnabled = useFlag('storagereport') - const postgrestReportEnabled = useFlag('postgrestreport') // b/c fly doesn't support storage const storageSupported = useIsFeatureEnabled('project_storage:all') - const storageEnabled = storageReportEnabled && storageSupported const { can: canCreateCustomReport } = useAsyncCheckPermissions( PermissionAction.CREATE, @@ -127,54 +121,37 @@ const ReportsMenu = () => { key: 'api-overview', url: `/project/${ref}/reports/api-overview${preservedQueryParams}`, }, - ...(authEnabled - ? [ - { - name: 'Auth', - key: 'auth', - url: `/project/${ref}/reports/auth${preservedQueryParams}`, - }, - ] - : []), + { + name: 'Auth', + key: 'auth', + url: `/project/${ref}/reports/auth${preservedQueryParams}`, + }, { name: 'Database', key: 'database', url: `/project/${ref}/reports/database${preservedQueryParams}`, }, - ...(edgeFnEnabled - ? [ - { - name: 'Edge Functions', - key: 'edge-functions', - url: `/project/${ref}/reports/edge-functions${preservedQueryParams}`, - }, - ] - : []), + { + name: 'Edge Functions', + key: 'edge-functions', + url: `/project/${ref}/reports/edge-functions${preservedQueryParams}`, + }, { name: 'Query Performance', key: 'query-performance', url: `/project/${ref}/reports/query-performance${preservedQueryParams}`, }, - ...(postgrestReportEnabled - ? [ - { - name: 'PostgREST', - key: 'postgrest', - url: `/project/${ref}/reports/postgrest${preservedQueryParams}`, - }, - ] - : []), - ...(realtimeEnabled - ? [ - { - name: 'Realtime', - key: 'realtime', - url: `/project/${ref}/reports/realtime${preservedQueryParams}`, - }, - ] - : []), - - ...(storageEnabled + { + name: 'PostgREST', + key: 'postgrest', + url: `/project/${ref}/reports/postgrest${preservedQueryParams}`, + }, + { + name: 'Realtime', + key: 'realtime', + url: `/project/${ref}/reports/realtime${preservedQueryParams}`, + }, + ...(storageSupported ? [ { name: 'Storage', diff --git a/apps/studio/components/layouts/TableEditorLayout/EntityListItem.tsx b/apps/studio/components/layouts/TableEditorLayout/EntityListItem.tsx index 1e33bfeb2844c..6ced4961bb4ab 100644 --- a/apps/studio/components/layouts/TableEditorLayout/EntityListItem.tsx +++ b/apps/studio/components/layouts/TableEditorLayout/EntityListItem.tsx @@ -90,7 +90,6 @@ export const EntityListItem = ({ const { data: countData } = useTableRowsCountQuery( { projectRef, - connectionString: project?.connectionString, tableId: entity.id, filters, enforceExactCount: false, diff --git a/apps/studio/components/ui/DatabaseSelector.tsx b/apps/studio/components/ui/DatabaseSelector.tsx index cc0166f9d856f..23143762b627e 100644 --- a/apps/studio/components/ui/DatabaseSelector.tsx +++ b/apps/studio/components/ui/DatabaseSelector.tsx @@ -1,12 +1,10 @@ -import { useFlag, useParams } from 'common' +import { useParams } from 'common' import { Markdown } from 'components/interfaces/Markdown' import { REPLICA_STATUS } from 'components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/InstanceConfiguration.constants' -import { useShowNewReplicaPanel } from 'components/interfaces/Settings/Infrastructure/InfrastructureConfiguration/use-show-new-replica' import { useReadReplicasQuery } from 'data/read-replicas/replicas-query' import { formatDatabaseID, formatDatabaseRegion } from 'data/read-replicas/replicas.utils' import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled' import { IS_PLATFORM } from 'lib/constants' -import { timeout } from 'lib/helpers' import { noop } from 'lodash' import { Check, ChevronDown, Loader2, Plus } from 'lucide-react' import Link from 'next/link' @@ -17,18 +15,18 @@ import { useDatabaseSelectorStateSnapshot } from 'state/database-selector' import { Button, ButtonProps, + cn, + Command_Shadcn_, CommandGroup_Shadcn_, CommandItem_Shadcn_, CommandList_Shadcn_, - Command_Shadcn_, + Popover_Shadcn_, PopoverContent_Shadcn_, PopoverTrigger_Shadcn_, - Popover_Shadcn_, ScrollArea, Tooltip, TooltipContent, TooltipTrigger, - cn, } from 'ui' interface DatabaseSelectorProps { @@ -54,9 +52,7 @@ export const DatabaseSelector = ({ const { ref: projectRef } = useParams() const [open, setOpen] = useState(false) const [, setShowConnect] = useQueryState('showConnect', parseAsBoolean.withDefault(false)) - const { setShowNewReplicaPanel } = useShowNewReplicaPanel() - const unifiedReplication = useFlag('unifiedReplication') const { infrastructureReadReplicas } = useIsFeatureEnabled(['infrastructure:read_replicas']) const state = useDatabaseSelectorStateSnapshot() @@ -74,9 +70,7 @@ export const DatabaseSelector = ({ const selectedAdditionalOption = additionalOptions.find((x) => x.id === selectedDatabaseId) - const newReplicaURL = unifiedReplication - ? `/project/${projectRef}/database/replication?type=Read+Replica` - : `/project/${projectRef}/settings/infrastructure` + const newReplicaURL = `/project/${projectRef}/database/replication?type=Read+Replica` useEffect(() => { if (_selectedDatabaseId) state.setSelectedDatabaseId(_selectedDatabaseId) @@ -229,12 +223,6 @@ export const DatabaseSelector = ({ setOpen(false) // [Joshen] This is used in the Connect UI which is available across all pages setShowConnect(false) - - // [Joshen] Adding a short timeout to compensate for the shift in focus - // the replica panel from a "portal" based component (e.g dialog, sheet, dropdown, etc) - // Although I'd prefer if there's a better way to resolve this - await timeout(50) - if (!unifiedReplication) setShowNewReplicaPanel(true) }} className="w-full flex items-center gap-2" > diff --git a/apps/studio/data/database/foreign-key-constraints-query.ts b/apps/studio/data/database/foreign-key-constraints-query.ts index 797d09ffd200f..5b6782a51b9c8 100644 --- a/apps/studio/data/database/foreign-key-constraints-query.ts +++ b/apps/studio/data/database/foreign-key-constraints-query.ts @@ -1,6 +1,8 @@ import { QueryClient, useQuery } from '@tanstack/react-query' - +import { IS_PLATFORM } from 'common' import { UseCustomQueryOptions } from 'types' + +import { useConnectionStringForReadOps } from '../read-replicas/replicas-query' import { executeSql, ExecuteSqlError } from '../sql/execute-sql-query' import { databaseKeys } from './keys' @@ -127,23 +129,32 @@ export type ForeignKeyConstraintsData = Awaited( - { projectRef, connectionString, schema }: ForeignKeyConstraintsVariables, + { + projectRef, + connectionString: connectionStringOverride, + schema, + }: ForeignKeyConstraintsVariables, { enabled = true, ...options }: UseCustomQueryOptions = {} -) => - useQuery({ - queryKey: databaseKeys.foreignKeyConstraints(projectRef, schema), +) => { + const { connectionString: connectionStringReadOps } = useConnectionStringForReadOps() + const connectionString = connectionStringOverride || connectionStringReadOps + + return useQuery({ + queryKey: databaseKeys.foreignKeyConstraints(projectRef, schema, { connectionString }), queryFn: ({ signal }) => getForeignKeyConstraints({ projectRef, connectionString, schema }, signal), enabled: enabled && typeof projectRef !== 'undefined' && typeof schema !== 'undefined' && + (!IS_PLATFORM || typeof connectionString !== 'undefined') && schema.length > 0, ...options, }) +} export function prefetchForeignKeyConstraints( client: QueryClient, diff --git a/apps/studio/data/database/keys.ts b/apps/studio/data/database/keys.ts index 941609fe0f0cf..e0e1b9bbc532f 100644 --- a/apps/studio/data/database/keys.ts +++ b/apps/studio/data/database/keys.ts @@ -27,8 +27,8 @@ export const databaseKeys = { ['projects', projectRef, 'index-advisor', { query }] as const, tableConstraints: (projectRef: string | undefined, id?: number) => ['projects', projectRef, 'table-constraints', id] as const, - foreignKeyConstraints: (projectRef: string | undefined, schema?: string) => - ['projects', projectRef, 'foreign-key-constraints', schema] as const, + foreignKeyConstraints: (projectRef: string | undefined, schema?: string, options = {}) => + ['projects', projectRef, 'foreign-key-constraints', schema, options] as const, databaseSize: (projectRef: string | undefined) => ['projects', projectRef, 'database-size'] as const, maxConnections: (projectRef: string | undefined) => diff --git a/apps/studio/data/prefetchers/project.$ref.editor.$id.tsx b/apps/studio/data/prefetchers/project.$ref.editor.$id.tsx index 36e8cb25162b3..254098c9029c3 100644 --- a/apps/studio/data/prefetchers/project.$ref.editor.$id.tsx +++ b/apps/studio/data/prefetchers/project.$ref.editor.$id.tsx @@ -1,7 +1,4 @@ import { QueryClient, useQueryClient } from '@tanstack/react-query' -import { useRouter } from 'next/router' -import { PropsWithChildren, useCallback } from 'react' - import { formatFilterURLParams, formatSortURLParams, @@ -13,8 +10,12 @@ import { prefetchTableEditor } from 'data/table-editor/table-editor-query' import { prefetchTableRows } from 'data/table-rows/table-rows-query' import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' import { RoleImpersonationState } from 'lib/role-impersonation' +import { useRouter } from 'next/router' +import { PropsWithChildren, useCallback } from 'react' import { useRoleImpersonationStateSnapshot } from 'state/role-impersonation-state' import { TABLE_EDITOR_DEFAULT_ROWS_PER_PAGE } from 'state/table-editor' + +import { useConnectionStringForReadOps } from '../read-replicas/replicas-query' import PrefetchableLink, { PrefetchableLinkProps } from './PrefetchableLink' interface PrefetchEditorTablePageArgs { @@ -65,6 +66,7 @@ export function usePrefetchEditorTablePage() { const router = useRouter() const queryClient = useQueryClient() const { data: project } = useSelectedProjectQuery() + const { connectionString } = useConnectionStringForReadOps() const roleImpersonationState = useRoleImpersonationStateSnapshot() return useCallback( @@ -79,7 +81,7 @@ export function usePrefetchEditorTablePage() { prefetchEditorTablePage({ queryClient, projectRef: project.ref, - connectionString: project.connectionString, + connectionString, id, sorts, filters, @@ -88,7 +90,7 @@ export function usePrefetchEditorTablePage() { // eat prefetching errors as they are not critical }) }, - [project, queryClient, roleImpersonationState, router] + [connectionString, project, queryClient, roleImpersonationState, router] ) } diff --git a/apps/studio/data/read-replicas/replicas-query.ts b/apps/studio/data/read-replicas/replicas-query.ts index 30214522541c9..e4dc14ba65564 100644 --- a/apps/studio/data/read-replicas/replicas-query.ts +++ b/apps/studio/data/read-replicas/replicas-query.ts @@ -1,9 +1,11 @@ import { useQuery } from '@tanstack/react-query' - +import { useFeatureFlags, useFlag } from 'common' import type { components } from 'data/api' import { get, handleError } from 'data/fetchers' import type { ResponseError, UseCustomQueryOptions } from 'types' + import { replicaKeys } from './keys' +import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' export const MAX_REPLICAS_BELOW_XL = 2 export const MAX_REPLICAS_ABOVE_XL = 5 @@ -55,3 +57,44 @@ export const usePrimaryDatabase = ({ projectRef }: { projectRef?: string }) => { const primaryDatabase = databases.find((x) => x.identifier === projectRef) return { database: primaryDatabase, error, isLoading, isError, isSuccess } } + +/** + * [Joshen] JFYI this logic here can and should be optimized + * Returns the connection string of read replica if available, otherwise default to project's (primary) + * If multiple read replicas available, (naively) prioritise replica in the same region as primary + * to minimize any latency. Otherwise just use the first available read replica + */ +export const useConnectionStringForReadOps = (): { + type: 'replica' | 'primary' | undefined + identifier: string | undefined + connectionString: string | undefined | null +} => { + const { hasLoaded: flagsLoaded } = useFeatureFlags() + const defaultToReadReplicaConnectionString = useFlag('defaultToReadReplicaConnectionString') + + const { data: project, isSuccess: isSuccessProject } = useSelectedProjectQuery() + const { data: databases = [], isLoading: isLoadingDatabases } = useReadReplicasQuery({ + projectRef: project?.ref, + }) + + const readReplicas = databases.filter( + (x) => x.identifier !== project?.ref && x.status === 'ACTIVE_HEALTHY' + ) + const readReplica = readReplicas.some((x) => x.region === project?.region) + ? readReplicas.find((x) => x.region === project?.region) + : readReplicas[0] + + if (!isSuccessProject || isLoadingDatabases || !flagsLoaded) { + return { connectionString: undefined, type: undefined, identifier: undefined } + } + + if (!defaultToReadReplicaConnectionString) { + return { type: 'primary', identifier: project.ref, connectionString: project.connectionString } + } + + return { + type: !!readReplica ? 'replica' : 'primary', + identifier: !!readReplica ? readReplica.identifier : project.ref, + connectionString: !!readReplica ? readReplica.connectionString : project.connectionString, + } +} diff --git a/apps/studio/data/table-rows/table-rows-count-query.ts b/apps/studio/data/table-rows/table-rows-count-query.ts index 4016f7949b5dc..481787c29bcc8 100644 --- a/apps/studio/data/table-rows/table-rows-count-query.ts +++ b/apps/studio/data/table-rows/table-rows-count-query.ts @@ -1,86 +1,23 @@ -import { Query } from '@supabase/pg-meta/src/query' -import { - COUNT_ESTIMATE_SQL, - THRESHOLD_COUNT, -} from '@supabase/pg-meta/src/sql/studio/get-count-estimate' import { QueryClient, useQuery, useQueryClient } from '@tanstack/react-query' - +import { IS_PLATFORM } from 'common' import { parseSupaTable } from 'components/grid/SupabaseGrid.utils' import type { Filter, SupaTable } from 'components/grid/types' import { prefetchTableEditor } from 'data/table-editor/table-editor-query' import { RoleImpersonationState, wrapWithRoleImpersonation } from 'lib/role-impersonation' import { isRoleImpersonationEnabled } from 'state/role-impersonation-state' +import { UseCustomQueryOptions } from 'types' + +import { useConnectionStringForReadOps } from '../read-replicas/replicas-query' import { executeSql, ExecuteSqlError } from '../sql/execute-sql-query' import { tableRowKeys } from './keys' -import { formatFilterValue } from './utils' -import { UseCustomQueryOptions } from 'types' +import { getTableRowsCountSql } from './table-rows.sql' -type GetTableRowsCountArgs = { +export type GetTableRowsCountArgs = { table?: SupaTable filters?: Filter[] enforceExactCount?: boolean } -export const getTableRowsCountSql = ({ - table, - filters = [], - enforceExactCount = false, -}: GetTableRowsCountArgs) => { - if (!table) return `` - - if (enforceExactCount) { - const query = new Query() - let queryChains = query.from(table.name, table.schema ?? undefined).count() - filters - .filter((x) => x.value && x.value !== '') - .forEach((x) => { - const value = formatFilterValue(table, x) - queryChains = queryChains.filter(x.column, x.operator, value) - }) - return `select (${queryChains.toSql().slice(0, -1)}), false as is_estimate;` - } else { - const selectQuery = new Query() - let selectQueryChains = selectQuery.from(table.name, table.schema ?? undefined).select('*') - filters - .filter((x) => x.value && x.value != '') - .forEach((x) => { - const value = formatFilterValue(table, x) - selectQueryChains = selectQueryChains.filter(x.column, x.operator, value) - }) - const selectBaseSql = selectQueryChains.toSql() - - const countQuery = new Query() - let countQueryChains = countQuery.from(table.name, table.schema ?? undefined).count() - filters - .filter((x) => x.value && x.value != '') - .forEach((x) => { - const value = formatFilterValue(table, x) - countQueryChains = countQueryChains.filter(x.column, x.operator, value) - }) - const countBaseSql = countQueryChains.toSql().slice(0, -1) - - const sql = ` -${COUNT_ESTIMATE_SQL} - -with approximation as ( - select reltuples as estimate - from pg_class - where oid = ${table.id} -) -select - case - when estimate = -1 then (select pg_temp.count_estimate('${selectBaseSql.replaceAll("'", "''")}')) - when estimate > ${THRESHOLD_COUNT} then ${filters.length > 0 ? `pg_temp.count_estimate('${selectBaseSql.replaceAll("'", "''")}')` : 'estimate'} - else (${countBaseSql}) - end as count, - estimate = -1 or estimate > ${THRESHOLD_COUNT} as is_estimate -from approximation; -`.trim() - - return sql - } -} - export type TableRowsCount = { count?: number is_estimate?: boolean @@ -106,7 +43,8 @@ export async function getTableRowsCount( filters, roleImpersonationState, enforceExactCount, - }: TableRowsCountVariables, + isUsingReadReplica = false, + }: TableRowsCountVariables & { isUsingReadReplica?: boolean }, signal?: AbortSignal ) { const entity = await prefetchTableEditor(queryClient, { @@ -121,7 +59,7 @@ export async function getTableRowsCount( const table = parseSupaTable(entity) const sql = wrapWithRoleImpersonation( - getTableRowsCountSql({ table, filters, enforceExactCount }), + getTableRowsCountSql({ table, filters, enforceExactCount, isUsingReadReplica }), roleImpersonationState ) const { result } = await executeSql( @@ -142,18 +80,44 @@ export async function getTableRowsCount( } export const useTableRowsCountQuery = ( - { projectRef, connectionString, tableId, ...args }: Omit, + { + projectRef, + connectionString: connectionStringOverride, + tableId, + ...args + }: Omit, { enabled = true, ...options }: UseCustomQueryOptions = {} ) => { const queryClient = useQueryClient() + const { connectionString: connectionStringReadOps, type } = useConnectionStringForReadOps() + const connectionString = connectionStringOverride || connectionStringReadOps + return useQuery({ - queryKey: tableRowKeys.tableRowsCount(projectRef, { table: { id: tableId }, ...args }), + queryKey: tableRowKeys.tableRowsCount(projectRef, { + table: { id: tableId }, + connectionString, + ...args, + }), queryFn: ({ signal }) => - getTableRowsCount({ queryClient, projectRef, connectionString, tableId, ...args }, signal), - enabled: enabled && typeof projectRef !== 'undefined' && typeof tableId !== 'undefined', + getTableRowsCount( + { + queryClient, + projectRef, + connectionString, + tableId, + isUsingReadReplica: type === 'replica', + ...args, + }, + signal + ), + enabled: + enabled && + typeof projectRef !== 'undefined' && + typeof tableId !== 'undefined' && + (!IS_PLATFORM || typeof connectionString !== 'undefined'), ...options, }) } diff --git a/apps/studio/data/table-rows/table-rows-query.ts b/apps/studio/data/table-rows/table-rows-query.ts index 12e726730963e..2b76076672fd5 100644 --- a/apps/studio/data/table-rows/table-rows-query.ts +++ b/apps/studio/data/table-rows/table-rows-query.ts @@ -16,6 +16,7 @@ import { isRoleImpersonationEnabled } from 'state/role-impersonation-state' import { ResponseError, UseCustomQueryOptions } from 'types' import { handleError } from '../fetchers' +import { useConnectionStringForReadOps } from '../read-replicas/replicas-query' import { executeSql, ExecuteSqlError } from '../sql/execute-sql-query' import { tableRowKeys } from './keys' import { formatFilterValue } from './utils' @@ -390,10 +391,17 @@ async function getTableRows( } export const useTableRowsQuery = ( - { projectRef, connectionString, tableId, ...args }: Omit, + { + projectRef, + connectionString: connectionStringOverride, + tableId, + ...args + }: Omit, { enabled = true, ...options }: UseCustomQueryOptions = {} ) => { const queryClient = useQueryClient() + const { connectionString: connectionStringReadOps } = useConnectionStringForReadOps() + const connectionString = connectionStringOverride || connectionStringReadOps // [Joshen] Exclude preflightCheck from query key const { preflightCheck, ...othersArgs } = args @@ -401,11 +409,16 @@ export const useTableRowsQuery = ( return useQuery({ queryKey: tableRowKeys.tableRows(projectRef, { table: { id: tableId }, + connectionString, ...othersArgs, }), queryFn: ({ signal }) => getTableRows({ queryClient, projectRef, connectionString, tableId, ...args }, signal), - enabled: enabled && typeof projectRef !== 'undefined' && typeof tableId !== 'undefined', + enabled: + enabled && + typeof projectRef !== 'undefined' && + typeof tableId !== 'undefined' && + (!IS_PLATFORM || typeof connectionString !== 'undefined'), ...options, }) } @@ -417,6 +430,7 @@ export function prefetchTableRows( return client.fetchQuery({ queryKey: tableRowKeys.tableRows(projectRef, { table: { id: tableId }, + connectionString, ...args, }), queryFn: ({ signal }) => diff --git a/apps/studio/data/table-rows/table-rows.sql.ts b/apps/studio/data/table-rows/table-rows.sql.ts new file mode 100644 index 0000000000000..5c5d0947bc5b5 --- /dev/null +++ b/apps/studio/data/table-rows/table-rows.sql.ts @@ -0,0 +1,93 @@ +import { Query } from '@supabase/pg-meta/src/query' +import { + COUNT_ESTIMATE_SQL, + THRESHOLD_COUNT, +} from '@supabase/pg-meta/src/sql/studio/get-count-estimate' + +import { GetTableRowsCountArgs } from './table-rows-count-query' +import { formatFilterValue } from './utils' + +/** + * [Joshen] Initially check reltuples from pg_class for an estimate of row count on the table + * - If reltuples = -1, table never been analyzed, assume small table -> return exact count + * - If reltuples exceeds threshold, return estimate count + * - Else return exact count + */ +export const getTableRowsCountSql = ({ + table, + filters = [], + enforceExactCount = false, + isUsingReadReplica = false, +}: GetTableRowsCountArgs & { isUsingReadReplica?: boolean }) => { + if (!table) return `` + + if (enforceExactCount) { + const query = new Query() + let queryChains = query.from(table.name, table.schema ?? undefined).count() + filters + .filter((x) => x.value && x.value !== '') + .forEach((x) => { + const value = formatFilterValue(table, x) + queryChains = queryChains.filter(x.column, x.operator, value) + }) + return `select (${queryChains.toSql().slice(0, -1)}), false as is_estimate;` + } else { + const selectQuery = new Query() + let selectQueryChains = selectQuery.from(table.name, table.schema ?? undefined).select('*') + filters + .filter((x) => x.value && x.value != '') + .forEach((x) => { + const value = formatFilterValue(table, x) + selectQueryChains = selectQueryChains.filter(x.column, x.operator, value) + }) + const selectBaseSql = selectQueryChains.toSql() + + const countQuery = new Query() + let countQueryChains = countQuery.from(table.name, table.schema ?? undefined).count() + filters + .filter((x) => x.value && x.value != '') + .forEach((x) => { + const value = formatFilterValue(table, x) + countQueryChains = countQueryChains.filter(x.column, x.operator, value) + }) + const countBaseSql = countQueryChains.toSql().slice(0, -1) + + if (isUsingReadReplica) { + const sql = ` +with approximation as ( + select reltuples as estimate + from pg_class + where oid = ${table.id} +) +select + case + when estimate > ${THRESHOLD_COUNT} then (select -1) + else (${countBaseSql}) + end as count, + estimate > ${THRESHOLD_COUNT} as is_estimate +from approximation; +`.trim() + + return sql + } else { + const sql = ` +${COUNT_ESTIMATE_SQL} + +with approximation as ( + select reltuples as estimate + from pg_class + where oid = ${table.id} +) +select + case + when estimate > ${THRESHOLD_COUNT} then ${filters.length > 0 ? `pg_temp.count_estimate('${selectBaseSql.replaceAll("'", "''")}')` : 'estimate'} + else (${countBaseSql}) + end as count, + estimate > ${THRESHOLD_COUNT} as is_estimate +from approximation; +`.trim() + + return sql + } + } +} diff --git a/apps/studio/hooks/misc/useReportDateRange.ts b/apps/studio/hooks/misc/useReportDateRange.ts index c55756b40088f..a4744ada6e6a7 100644 --- a/apps/studio/hooks/misc/useReportDateRange.ts +++ b/apps/studio/hooks/misc/useReportDateRange.ts @@ -46,8 +46,7 @@ export const useReportDateRange = ( defaultHelper: | REPORT_DATERANGE_HELPER_LABELS | string - | ReportsDatetimeHelper = REPORT_DATERANGE_HELPER_LABELS.LAST_60_MINUTES, - useV2Granularity = false + | ReportsDatetimeHelper = REPORT_DATERANGE_HELPER_LABELS.LAST_60_MINUTES ) => { const { plan: orgPlan, isLoading: isOrgPlanLoading } = useCurrentOrgPlan() const [showUpgradePrompt, setShowUpgradePrompt] = useState(false) @@ -180,35 +179,11 @@ export const useReportDateRange = ( const diffInDays = dayjs(to).diff(from, 'day', true) const diffInHours = dayjs(to).diff(from, 'hour', true) - if (useV2Granularity) { - if (diffInHours <= 1) return '1m' - if (diffInHours <= 12) return '2m' - if (diffInHours <= 24) return '10m' - if (diffInDays <= 7) return '1h' - return '1d' - } - - const conditions = { - '1m': diffInHours < 1.1, // less than 1.1 hours - '5m': diffInHours < 3.1, // less than 3.1 hours - '10m': diffInHours < 6.1, // less than 6.1 hours - '30m': diffInHours < 25, // less than 25 hours - '1h': diffInDays < 10, // less than 10 days - '1d': diffInDays >= 10, // more than 10 days - } - - switch (true) { - case conditions['1m']: - return '1m' - case conditions['5m']: - return '5m' - case conditions['10m']: - return '10m' - case conditions['30m']: - return '30m' - default: - return '1h' - } + if (diffInHours <= 1) return '1m' + if (diffInHours <= 12) return '2m' + if (diffInHours <= 24) return '10m' + if (diffInDays <= 7) return '1h' + return '1d' } // Derive selectedDateRange from current values @@ -218,7 +193,7 @@ export const useReportDateRange = ( period_end: { date: timestampEnd, time_period: 'today' }, interval: handleIntervalGranularity(timestampStart, timestampEnd), }), - [timestampStart, timestampEnd, useV2Granularity] + [timestampStart, timestampEnd] ) const updateDateRange = useCallback( diff --git a/apps/studio/hooks/use-check-latest-deploy.tsx b/apps/studio/hooks/use-check-latest-deploy.tsx index 8cbbae1a84c89..fe19496d0356f 100644 --- a/apps/studio/hooks/use-check-latest-deploy.tsx +++ b/apps/studio/hooks/use-check-latest-deploy.tsx @@ -1,10 +1,9 @@ +import { IS_PLATFORM } from 'common' +import { useDeploymentCommitQuery } from 'data/utils/deployment-commit-query' import dayjs from 'dayjs' import { useRouter } from 'next/router' import { useEffect, useRef, useState } from 'react' import { toast } from 'sonner' - -import { IS_PLATFORM, useFlag } from 'common' -import { useDeploymentCommitQuery } from 'data/utils/deployment-commit-query' import { Button, StatusIcon } from 'ui' const DeployCheckToast = ({ id }: { id: string | number }) => { @@ -34,8 +33,6 @@ const DeployCheckToast = ({ id }: { id: string | number }) => { // there's a new version of Studio is available, and the user has been on the old dashboard (based on commit) for more than 24 hours. // [Joshen] K-Dog has a suggestion here to bring down the time period here by checking commits export function useCheckLatestDeploy() { - const showRefreshToast = useFlag('showRefreshToast') - const [currentCommitTime, setCurrentCommitTime] = useState('') const [isToastShown, setIsToastShown] = useState(false) @@ -59,7 +56,7 @@ export function useCheckLatestDeploy() { }, [commit]) useEffect(() => { - if (!showRefreshToast || !commit || commit.commitTime === 'unknown') { + if (!commit || commit.commitTime === 'unknown') { return } @@ -91,5 +88,5 @@ export function useCheckLatestDeploy() { position: 'bottom-right', }) setIsToastShown(true) - }, [commit, showRefreshToast, isToastShown, currentCommitTime]) + }, [commit, isToastShown, currentCommitTime]) } diff --git a/apps/studio/pages/api/integrations/stripe-sync.ts b/apps/studio/pages/api/integrations/stripe-sync.ts index 0c35530202751..3e43dd7de11be 100644 --- a/apps/studio/pages/api/integrations/stripe-sync.ts +++ b/apps/studio/pages/api/integrations/stripe-sync.ts @@ -4,8 +4,6 @@ import { VERSION } from 'stripe-experiment-sync' import { install, uninstall } from 'stripe-experiment-sync/supabase' import { z } from 'zod' -const ENABLE_FLAG_KEY = 'enableStripeSyncEngineIntegration' - const InstallBodySchema = z.object({ projectRef: z.string().min(1), stripeSecretKey: z.string().min(1), diff --git a/apps/studio/pages/project/[ref]/database/replication/index.tsx b/apps/studio/pages/project/[ref]/database/replication/index.tsx index 5d5c8699fd33b..46c71518f672b 100644 --- a/apps/studio/pages/project/[ref]/database/replication/index.tsx +++ b/apps/studio/pages/project/[ref]/database/replication/index.tsx @@ -1,11 +1,8 @@ -import { useFlag, useParams } from 'common' -import { ReplicationComingSoon } from 'components/interfaces/Database/Replication/ComingSoon' +import { useParams } from 'common' import { Destinations } from 'components/interfaces/Database/Replication/Destinations' -import { useIsETLPrivateAlpha } from 'components/interfaces/Database/Replication/useIsETLPrivateAlpha' import DatabaseLayout from 'components/layouts/DatabaseLayout/DatabaseLayout' import { DefaultLayout } from 'components/layouts/DefaultLayout' import { ScaffoldContainer, ScaffoldSection } from 'components/layouts/Scaffold' -import { FormHeader } from 'components/ui/Forms/FormHeader' import { UnknownInterface } from 'components/ui/UnknownInterface' import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled' import { PipelineRequestStatusProvider } from 'state/replication-pipeline-request-status' @@ -15,56 +12,36 @@ import { ReplicationDiagram } from '@/components/interfaces/Database/Replication const DatabaseReplicationPage: NextPageWithLayout = () => { const { ref } = useParams() - const enablePgReplicate = useIsETLPrivateAlpha() const showPgReplicate = useIsFeatureEnabled('database:replication') - const unifiedReplication = useFlag('unifiedReplication') if (!showPgReplicate) { return } return ( - <> - {unifiedReplication || enablePgReplicate ? ( - - - -
-
-

Replication

-
-

- {unifiedReplication - ? 'Deploy read replicas across multiple regions, or replicate database changes to external data warehouses and analytics platforms' - : 'Automatically replicate your database changes to external data warehouses and analytics platforms in real-time'} -

-
-
-
- - - - - - - - -
- ) : ( - <> - - - - - - - - )} - + + + +
+
+

Replication

+
+

+ Deploy read replicas across multiple regions, or replicate database changes to + external data warehouses and analytics platforms +

+
+
+
+ + + + + + + + +
) } diff --git a/apps/studio/pages/project/[ref]/functions/[functionSlug]/index.tsx b/apps/studio/pages/project/[ref]/functions/[functionSlug]/index.tsx index b2708a941938a..62863ee259340 100644 --- a/apps/studio/pages/project/[ref]/functions/[functionSlug]/index.tsx +++ b/apps/studio/pages/project/[ref]/functions/[functionSlug]/index.tsx @@ -1,5 +1,5 @@ import { PermissionAction } from '@supabase/shared-types/out/constants' -import { IS_PLATFORM, useFlag, useParams } from 'common' +import { IS_PLATFORM, useParams } from 'common' import { EdgeFunctionRecentInvocations } from 'components/interfaces/Functions/EdgeFunctionRecentInvocations' import ReportWidget from 'components/interfaces/Reports/ReportWidget' import DefaultLayout from 'components/layouts/DefaultLayout' @@ -19,7 +19,7 @@ import maxBy from 'lodash/maxBy' import meanBy from 'lodash/meanBy' import sumBy from 'lodash/sumBy' import { useRouter } from 'next/router' -import { useEffect, useMemo, useState } from 'react' +import { useMemo, useState } from 'react' import type { ChartIntervals, NextPageWithLayout } from 'types' import { Alert_Shadcn_, @@ -66,7 +66,6 @@ const PageLayout: NextPageWithLayout = () => { const router = useRouter() const { ref: projectRef, functionSlug } = useParams() - const newChartsEnabled = useFlag('newEdgeFunctionOverviewCharts') const [interval, setInterval] = useState('15min') const selectedInterval = CHART_INTERVALS.find((i) => i.key === interval) || CHART_INTERVALS[1] const { data: selectedFunction } = useEdgeFunctionQuery({ @@ -204,20 +203,18 @@ const PageLayout: NextPageWithLayout = () => { format="ms" highlightedValue={meanBy(props.data, 'avg_execution_time')} /> - {newChartsEnabled && ( - - )} +
) }} @@ -302,24 +299,22 @@ const PageLayout: NextPageWithLayout = () => { ) }} /> - {newChartsEnabled && ( - { - router.push( - `/project/${projectRef}/functions/${functionSlug}/logs?its=${startDate.toISOString()}` - ) - }} - /> - )} + { + router.push( + `/project/${projectRef}/functions/${functionSlug}/logs?its=${startDate.toISOString()}` + ) + }} + /> ) } @@ -351,20 +346,16 @@ const PageLayout: NextPageWithLayout = () => { format="ms" highlightedValue={meanBy(props.data, 'avg_cpu_time_used')} /> - {newChartsEnabled && ( - - )} + ) }} @@ -414,20 +405,18 @@ const PageLayout: NextPageWithLayout = () => { format="MB" highlightedValue={meanBy(props.data, 'avg_memory_used')} /> - {newChartsEnabled && ( - - )} + ) }} diff --git a/apps/studio/pages/project/[ref]/integrations/[id]/[pageId]/index.tsx b/apps/studio/pages/project/[ref]/integrations/[id]/[pageId]/index.tsx index a67fda5142d57..030eb5cf12639 100644 --- a/apps/studio/pages/project/[ref]/integrations/[id]/[pageId]/index.tsx +++ b/apps/studio/pages/project/[ref]/integrations/[id]/[pageId]/index.tsx @@ -1,4 +1,4 @@ -import { useFlag, useParams } from 'common' +import { useParams } from 'common' import { INTEGRATIONS } from 'components/interfaces/Integrations/Landing/Integrations.constants' import { useInstalledIntegrations } from 'components/interfaces/Integrations/Landing/useInstalledIntegrations' import { DefaultLayout } from 'components/layouts/DefaultLayout' @@ -41,7 +41,6 @@ const IntegrationPage: NextPageWithLayout = () => { const router = useRouter() const { ref, id, pageId, childId } = useParams() const { integrationsWrappers } = useIsFeatureEnabled(['integrations:wrappers']) - const stripeSyncEnabled = useFlag('enableStripeSyncEngineIntegration') const { installedIntegrations: installedIntegrations, isLoading: isIntegrationsLoading } = useInstalledIntegrations() @@ -140,10 +139,6 @@ const IntegrationPage: NextPageWithLayout = () => { return } - if (id === 'stripe_sync_engine' && !stripeSyncEnabled) { - return - } - if (!integrationsWrappers && id?.endsWith('_wrapper')) { return } diff --git a/apps/studio/pages/project/[ref]/integrations/index.tsx b/apps/studio/pages/project/[ref]/integrations/index.tsx index 4e77700840332..79e163acc97ce 100644 --- a/apps/studio/pages/project/[ref]/integrations/index.tsx +++ b/apps/studio/pages/project/[ref]/integrations/index.tsx @@ -1,7 +1,3 @@ -import { Search } from 'lucide-react' -import { parseAsString, useQueryState } from 'nuqs' -import { useMemo } from 'react' - import { IntegrationCard, IntegrationLoadingCard, @@ -13,6 +9,9 @@ import { AlertError } from 'components/ui/AlertError' import { DocsButton } from 'components/ui/DocsButton' import { NoSearchResults } from 'components/ui/NoSearchResults' import { DOCS_URL } from 'lib/constants' +import { Search } from 'lucide-react' +import { parseAsString, useQueryState } from 'nuqs' +import { useMemo } from 'react' import type { NextPageWithLayout } from 'types' import { Input } from 'ui-patterns/DataInputs/Input' import { PageContainer } from 'ui-patterns/PageContainer' @@ -25,9 +24,8 @@ import { PageHeaderTitle, } from 'ui-patterns/PageHeader' import { PageSection, PageSectionContent, PageSectionMeta } from 'ui-patterns/PageSection' -import { useFlag } from 'common' -const FEATURED_INTEGRATIONS = ['cron', 'queues'] // + either stripe_sync_engine or stripe_wrapper depending on feature flag +const FEATURED_INTEGRATIONS = ['cron', 'queues', 'stripe_sync_engine'] // Featured integration images const FEATURED_INTEGRATION_IMAGES: Record = { @@ -47,16 +45,6 @@ const IntegrationsPage: NextPageWithLayout = () => { parseAsString.withDefault('').withOptions({ clearOnDefault: true }) ) - const isStripeSyncEngineEnabled = useFlag('enableStripeSyncEngineIntegration') - - const featuredIntegrationIds = useMemo(() => { - if (isStripeSyncEngineEnabled) { - return FEATURED_INTEGRATIONS.concat(['stripe_sync_engine']) - } else { - return FEATURED_INTEGRATIONS.concat(['stripe_wrapper']) - } - }, [isStripeSyncEngineEnabled]) - const { availableIntegrations, installedIntegrations, error, isError, isLoading, isSuccess } = useInstalledIntegrations() @@ -117,7 +105,7 @@ const IntegrationsPage: NextPageWithLayout = () => { } const featured = filteredAndSortedIntegrations.filter((i) => - featuredIntegrationIds.includes(i.id) + FEATURED_INTEGRATIONS.includes(i.id) ) const allIntegrations = filteredAndSortedIntegrations // Include all integrations, including featured diff --git a/apps/studio/pages/project/[ref]/observability/database.tsx b/apps/studio/pages/project/[ref]/observability/database.tsx index cdbeac91ac105..da3f9b26c8232 100644 --- a/apps/studio/pages/project/[ref]/observability/database.tsx +++ b/apps/studio/pages/project/[ref]/observability/database.tsx @@ -1,12 +1,6 @@ import { PermissionAction } from '@supabase/shared-types/out/constants' import { useQueryClient } from '@tanstack/react-query' -import dayjs from 'dayjs' -import { ArrowRight, ExternalLink, RefreshCw } from 'lucide-react' -import Link from 'next/link' -import { useEffect, useRef, useState } from 'react' -import { toast } from 'sonner' - -import { useFlag, useParams } from 'common' +import { useParams } from 'common' import ReportHeader from 'components/interfaces/Reports/ReportHeader' import ReportPadding from 'components/interfaces/Reports/ReportPadding' import { REPORT_DATERANGE_HELPER_LABELS } from 'components/interfaces/Reports/Reports.constants' @@ -36,15 +30,20 @@ import { usePgbouncerConfigQuery } from 'data/database/pgbouncer-config-query' import { getReportAttributesV2 } from 'data/reports/database-charts' import { useDatabaseReport } from 'data/reports/database-report-query' import { useProjectAddonsQuery } from 'data/subscriptions/project-addons-query' +import dayjs from 'dayjs' import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions' import { useRefreshHandler, useReportDateRange } from 'hooks/misc/useReportDateRange' import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization' import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' import { DOCS_URL } from 'lib/constants' import { formatBytes } from 'lib/helpers' +import { ArrowRight, ExternalLink, RefreshCw } from 'lucide-react' +import Link from 'next/link' +import { useEffect, useRef, useState } from 'react' +import { toast } from 'sonner' import { useDatabaseSelectorStateSnapshot } from 'state/database-selector' import type { NextPageWithLayout } from 'types' -import { AlertDescription_Shadcn_, Alert_Shadcn_, Button } from 'ui' +import { Alert_Shadcn_, AlertDescription_Shadcn_, Button } from 'ui' const DatabaseReport: NextPageWithLayout = () => { return ( @@ -67,7 +66,6 @@ const DatabaseUsage = () => { const { db, chart, ref } = useParams() const { data: project } = useSelectedProjectQuery() const { data: org } = useSelectedOrganizationQuery() - const reportGranularityV2 = useFlag('reportGranularityV2') const { selectedDateRange, @@ -78,7 +76,7 @@ const DatabaseUsage = () => { showUpgradePrompt, setShowUpgradePrompt, handleDatePickerChange, - } = useReportDateRange(REPORT_DATERANGE_HELPER_LABELS.LAST_60_MINUTES, reportGranularityV2) + } = useReportDateRange(REPORT_DATERANGE_HELPER_LABELS.LAST_60_MINUTES) const state = useDatabaseSelectorStateSnapshot() const queryClient = useQueryClient() diff --git a/apps/studio/state/table-editor-table.tsx b/apps/studio/state/table-editor-table.tsx index 4641a5548abb8..b2d863355b5c6 100644 --- a/apps/studio/state/table-editor-table.tsx +++ b/apps/studio/state/table-editor-table.tsx @@ -1,4 +1,3 @@ -import { useFlag } from 'common' import { TableIndexAdvisorProvider } from 'components/grid/context/TableIndexAdvisorContext' import { loadTableEditorStateFromLocalStorage, @@ -196,7 +195,6 @@ export const TableEditorTableStateContextProvider = ({ table, ...props }: PropsWithChildren) => { - const showIndexAdvisor = useFlag('ShowIndexAdvisorOnTableEditor') const tableEditorSnap = useTableEditorStateSnapshot() const state = useRef( createTableEditorTableState({ @@ -246,7 +244,7 @@ export const TableEditorTableStateContextProvider = ({ return ( - {showIndexAdvisor && state.table.schema ? ( + {state.table.schema ? ( {children} diff --git a/apps/studio/styles/main.scss b/apps/studio/styles/main.scss index 76473f85a60b3..7229a55e252c6 100644 --- a/apps/studio/styles/main.scss +++ b/apps/studio/styles/main.scss @@ -282,3 +282,15 @@ div[data-radix-portal]:not(.portal--toast) { height: 6px !important; @apply border-strong dark:border-r-2 dark:border-b-2 dark:border-overlay #{!important}; } + +@keyframes typewriter { + from { + width: 0; + } +} + +@keyframes blink-caret { + 50% { + border-color: transparent; + } +} diff --git a/apps/studio/tailwind.config.js b/apps/studio/tailwind.config.js index ace71e440be9c..b5fdcf67abc2a 100644 --- a/apps/studio/tailwind.config.js +++ b/apps/studio/tailwind.config.js @@ -99,12 +99,6 @@ module.exports = config({ transform: 'rotate(10deg) scale(1.5) translateY(2rem)', }, }, - typewriter: { - from: { width: '0' }, - }, - 'blink-caret': { - '50%': { borderColor: 'transparent' }, - }, }, }, }, diff --git a/apps/www/_customers/brevo.mdx b/apps/www/_customers/brevo.mdx new file mode 100644 index 0000000000000..db64499c08a18 --- /dev/null +++ b/apps/www/_customers/brevo.mdx @@ -0,0 +1,180 @@ +--- +name: Brevo +title: How Brevo built AI-powered sales workflows on Supabase, without waiting for engineering +# Use meta_title to add a custom meta title. Otherwise it defaults to '{name} | Supabase Customer Stories': +# meta_title: +description: Brevo's Revenue Operations team built three production AI workflows connecting their CRM to Dust's AI agents via Supabase MCP—without a single engineering ticket. +# Use meta_description to add a custom meta description. Otherwise it defaults to {description}: +meta_description: How Brevo's RevOps team built AI-powered sales workflows with Supabase and Dust, connecting their CRM to AI agents in days—without engineering. +author: prashant +author_title: Prashant Sridharan +author_url: https://github.com/CoolAssPuppy +author_image_url: https://avatars.githubusercontent.com/u/914007?v=4 +logo: /images/customers/logos/brevo.svg +logo_inverse: /images/customers/logos/light/brevo.svg +tags: + - supabase +date: '2025-12-18' +company_url: https://www.brevo.com +misc: [{ label: 'Founded', text: 'France' }] +about: Paris-based Omnichannel Customer Engagement platform used by over 600,000 businesses worldwide. Email marketing, SMS, WhatsApp, CRM, marketing automation. Brevo surpassed $218M in ARR in 2025 and hit unicorn status with a $1B valuation. +# "healthcare" | "fintech" | "ecommerce" | "education" | "gaming" | "media" | "real-estate" | "saas" | "social" | "analytics" | "ai" | "developer-tools" +industry: ['saas', 'ai'] +# "startup" | "enterprise" | "indie_dev" +company_size: 'enterprise' +# "Asia" | "Europe" | "North America" | "South America" | "Africa" | "Oceania" +region: 'Europe' +# "database" | "auth" | "storage" | "realtime" | "functions" | "vector" +supabase_products: ['database'] +--- + + + Our AI agents are only as good as the data they can reach. Supabase gave them access to our entire + CRM, stored what they produced, and never got in the way. It is the quiet part of our stack that + makes everything else work. + + +[Brevo](https://www.brevo.com) is a Paris-based Omnichannel Customer Engagement platform used by over 600,000 businesses worldwide. Email marketing, SMS, WhatsApp, CRM, marketing automation. Brevo surpassed $218M in ARR in 2025 and hit unicorn status with a $1B valuation to take on HubSpot and Salesforce. + +## A CRM full of intelligence, locked away from AI + +Brevo's sales organization prospects across dozens of industries. E-commerce, retail, SaaS, financial services. For every prospect call, a rep needs context: which existing Brevo customers are in the same industry? What use cases worked? Has this prospect talked to Brevo before? How far did they get? + +All of that intelligence sits in the CRM. Contacts, Deals, Companies. Years of account history. + +Alexandre Le Goupil runs Revenue Systems and AI for Brevo's sales team. His group had adopted **[Dust](https://dust.tt), an AI agent platform**, and the agents were already good at research, reasoning, and writing. But the CRM was completely out of reach, and that data was what would make the agents' output truly actionable. + + + Salespeople would come to me and ask for a list of our best e-commerce customers before a call. Or they + would need to know if we had history with a prospect's company. That context was all in the CRM, + but our AI agents were completely blind to it. I needed to connect those two worlds. + + +Other teams at Brevo ran their analytics on BigQuery, Snowflake, and Databricks. None of those were built for what Alexandre needed: a database that AI agents could read from and write to in real time, through a standard protocol, without a custom integration for every workflow. + +## Why Supabase + +Alexandre found his answer in the [Supabase MCP server](/docs/guides/getting-started/mcp). MCP (Model Context Protocol) gives AI agents a structured way to interact with databases. Supabase ships one out of the box. That meant a direct connection between Dust's AI agents and a Postgres database, with read and write permissions controlled at the tool level. + + + Supabase shipping a remote MCP server means any Dust agent can connect to it instantly, with read + and write access, no custom integration needed. That is exactly the model we want to see from data + platforms: natively agent-ready, so teams can focus on building workflows instead of plumbing. + + +According to Dust's engineering team, Supabase was the first data platform where they enabled both read and write capabilities through natural language. Snowflake has since followed with its own MCP, and Databricks is next. But Supabase got there first, and for teams like Alexandre's that need to iterate fast with AI, that head start mattered. + + + BigQuery and Snowflake are great for analytics. But I needed something an AI agent could query live, + in the middle of a conversation. Supabase gave me Postgres with an MCP server ready to go. That was + what decided it. + + +Brevo actually started with a custom MCP connection before Dust launched its official Supabase integration in June 2025. When the official version shipped, they migrated. The fact that they went from a scrappy custom setup to the supported integration says something about commitment: this was not an experiment. + +The team is Revenue Operations, not database engineering. Speed mattered. Alexandre connected Supabase to Dust in days. He defined his tables, wrote descriptions of every field so the LLM would know what each one meant, and started testing. + + + Connecting Supabase was the easy part. The real work was writing good documentation for the AI, + telling it what each field means, which tables to query for which questions. Once we got that right, + everything clicked. + + +The Supabase MCP was well-documented and stable, and the integration was live on the platform level within minutes. Alexandre's investment in that documentation is what separates a good Dust agent from a great one. + +## Three workflows in production + +### Finding reference customers in seconds + +Brevo's sales reps now ask a Dust agent: "Find me the top three e-commerce customers we can reference for this prospect." The agent queries the CRM mirror in Supabase, pulls matching customers by industry, deal size, and product usage, and suggests a specific approach angle. + +Before, that request went to RevOps. Someone would pull a report, filter it, and send it back. Fifteen minutes per request, minimum. + + + That workflow alone changed how reps prepare for calls. They get reference customers, account + context, and a suggested angle in seconds. It freed up hours of my team's time every week. + + +### Personalized emails for every prospect + +This is the most ambitious workflow. BDRs select contacts to prospect for the week. That selection kicks off a Dust conversation, which pulls the prospect's full history from Supabase: prior contact, pipeline stage, products discussed, engagement with Brevo's content. + +The agent also grabs context from the web. LinkedIn profiles, firmographic data, company news. Then it routes to a specialized sub-agent based on the prospect type. Someone who downloaded a white paper goes to a "Gated Asset" agent. A cold e-commerce lead goes to an industry-specific agent. Each sub-agent writes three emails tailored to that person's role, seniority, and history. + +The emails come back as structured JSON and HTML. Dust writes them directly to Supabase. Brevo's CRM then pulls those emails into multi-channel sales sequences: email, phone, LinkedIn. + + + We used to send the same generic email to every e-commerce prospect. Now every email reflects who + this person is and what we know about them. Supabase holds the context going in and stores the + output coming out. It is the connective tissue between our CRM and our AI. + + +The result is an 80% reduction in time spent on email personalization, from thirty minutes of research and writing per prospect down to minutes. + +The team also built anti-hallucination guardrails into their prompts. A sales email with a fabricated customer name or made-up statistic destroys trust. By grounding every agent in structured data from Supabase, they reduced that risk. The prompts enforce strict rules: only reference data that exists in the database. + +### Personalized landing pages on demand + +Brevo's marketing team uses the same architecture for lead generation. A visitor enters their email and company name on a [landing page](https://www.brevo.com/tools/relationship-plan?utm_medium=web-external&utm_source=CTA_dust_blog&utm_campaign=en_supabase_blog_202602). The data goes into Supabase and triggers a Dust agent that generates a complete marketing plan for that company: channel recommendations, campaign ideas, timelines. The output lands back in Supabase and renders as a unique page for that visitor. + + + Someone fills out a form and gets a [custom marketing + plan](https://www.brevo.com/tools/relationship-plan?utm_medium=web-external&utm_source=CTA_dust_blog&utm_campaign=en_supabase_blog_202602) + in seconds. Data goes into Supabase, the AI builds the plan, the result comes back through + Supabase as a page. We kept the whole thing as simple as we could. + + +## Set it up, never touch it again + +The part of this story that stands out most is what happened after launch. Nothing. + +Alexandre's team connected Supabase, documented their schema, tested the workflows, and moved on. They have not had to troubleshoot, reconfigure, or debug the connection since. + + + We set it up, it worked, and we have not gone back. It just runs. That is exactly what you want from + infrastructure when you are a small ops team trying to ship fast. + + +Dust's data backs this up. Since the official integration launched in June 2025, Brevo has executed over 2,500 actions through the Supabase MCP. That includes parallel batch runs where dozens of AI conversations query and write to the database at the same time. + + + Brevo runs parallel batch conversations making Supabase queries, and it works smoothly. The MCP has + been rock-solid since deployment with no incidents. + + +Because Supabase is Postgres under the hood, extending it is simple. A new use case means a new table and an updated agent prompt. No re-architecture, no new integrations. + +## An ops team that ships like engineers + +Brevo's Revenue Operations team is not an engineering team. They do not write backend services or manage infrastructure. But with Supabase and [Dust](https://dust.tt), they built three production AI workflows that run daily across Sales and Marketing, without filing a single ticket with engineering. + +This is the pattern Supabase sees across enterprise innovation teams: when you give non-engineering builders a production-grade backend with AI-native tooling, they stop waiting and start shipping. + + + What makes Supabase particularly exciting is its agility. It is lighter and faster to iterate with + than traditional data platforms. For AI use cases, this speed matters: storing agent outputs, + syncing workflows, generating content that feeds directly into production systems. It is perfectly + suited for teams that need to experiment rapidly with AI. + + +## Supabase is the platform for building agentic systems + +Dust's engineering team points to three things that make Supabase work for agents. The remote MCP server is production-grade and easy to onboard. Read and write access closes the agentic loop, so agents produce durable outputs, not just answers. And non-technical teams own the entire data layer themselves, no engineering bottleneck. For agentic use cases where iteration speed is the advantage, that is a structural edge. + + + What teams like Brevo's gain is not just speed, it is focus. When agents handle the data pulling, + the personalization, the logging, the people can spend their time where it actually matters: + strategy, relationships, decisions. That is the version of AI we are building toward. + + +## What comes next + +Alexandre estimates that 30% or more of the internal support requests his team fields via Slack could be answered automatically. The data already exists across Notion, Slack history, and their Supabase-backed CRM mirror. The team is building a Slack assistant that handles first-level responses to internal sales support tickets. + +They are also scaling the email generation workflow to handle thousands of prospects in a single batch run. + + + We started with one use case. Now we have three in production and more on the way. Every time we + have a new idea, the first question is: what table do we need in Supabase? That is how fast we can + move now. + diff --git a/apps/www/_customers/hyper.mdx b/apps/www/_customers/hyper.mdx new file mode 100644 index 0000000000000..cd8c89fc3279b --- /dev/null +++ b/apps/www/_customers/hyper.mdx @@ -0,0 +1,141 @@ +--- +name: Hyper +title: Hyper builds AI marketing agents on Supabase +# Use meta_title to add a custom meta title. Otherwise it defaults to '{name} | Supabase Customer Stories': +# meta_title: +description: Hyper is an AI-native marketing platform with agents that operate across the entire marketing workflow. Supabase gives their three-person team the database platform to do it at enterprise scale. +# Use meta_description to add a custom meta description. Otherwise it defaults to {description}: +meta_description: How Hyper's three-person team built an AI marketing platform with agents that handle ads, SEO, and analytics — powered by Supabase at enterprise scale. +author: prashant +author_title: Prashant Sridharan +author_url: https://github.com/CoolAssPuppy +author_image_url: https://avatars.githubusercontent.com/u/914007?v=4 +logo: /images/customers/logos/hyper.svg +logo_inverse: /images/customers/logos/light/hyper.svg +tags: + - supabase +date: '2025-12-19' +company_url: https://www.hyperfx.ai +misc: + - { label: 'Company size', text: 'Pre-seed startup, 3 founders' } + - { label: 'Use case', text: 'Multi-tenant AI agent platform for marketing agencies and SMBs' } +about: AI-native marketing platform with agents that handle paid ads, SEO, analytics, and operations end to end. Connects to 80+ tools with built-in SEO and AI search data. Built for agencies managing hundreds of client accounts, SMBs running ads in-house, and founders launching their first campaign. +# "healthcare" | "fintech" | "ecommerce" | "education" | "gaming" | "media" | "real-estate" | "saas" | "social" | "analytics" | "ai" | "developer-tools" +industry: ['ai', 'saas'] +# "startup" | "enterprise" | "indie_dev" +company_size: 'startup' +# "Asia" | "Europe" | "North America" | "South America" | "Africa" | "Oceania" +region: 'North America' +# "database" | "auth" | "storage" | "realtime" | "functions" | "vector" +supabase_products: ['database', 'auth'] +--- + + + AI lowers the cost to start companies. Every company needs marketing. They'll all choose the best + tool, the one that does it for them. We believe the next decade will be won by entrepreneurs and + lean teams, and they'll use Hyper to do it. + + +[Hyper](https://www.hyperfx.ai) is an AI-native marketing platform with agents that handle paid ads, SEO, analytics, and operations, end to end. Campaigns across Meta, Google, TikTok, and LinkedIn. SEO and content strategy. Cross-platform reporting. The platform connects to 80+ tools and includes built-in capabilities most companies pay separately for: SEO and AI search data on par with SEMrush and Profound, managed databases per workspace, and a native file system where both users and agents can organize assets. + +Hyper is built for anyone who needs marketing — agencies managing hundreds of client accounts, SMBs running ads in-house, founders launching their first campaign. Founded by Elliot Fleck, Themba Mahlangu, and Jasper Shine, the company is building for a market they see as massive and inevitable. + +## The challenge + +Marketing is fragmented. Every platform — Meta, Google, Shopify, ESPs — has its own dashboard, its own metrics, its own API. Pulling that data into a single view is one of the biggest pain points in the industry — not just because it's tedious and fragile, but because without that context, you can't act correctly. Every decision depends on seeing the full picture. And it's getting harder. How people find products is changing — search to social feeds to AI assistants — tracking is noisier, and execution breaks down as complexity grows. + +Without a unified action system and data layer, problems go unnoticed. A broken campaign. A budget overspend. A drop in conversions that nobody catches for weeks. + + + Whether you're a first-time founder or an agency managing hundreds of accounts, your data is spread + across every platform — and no one knows if something is broken until weeks later. Agents on Hyper + consolidate all of it and catch problems immediately, like an expert watching everything 24/7. AI is + changing how work gets done — people want to say 'launch this' and 'run analysis and email me the + report,' not do it themselves. + + +## Why they chose Supabase + +Hyper needed a database platform that could handle multi-tenant data at scale, give both technical and non-technical team members direct visibility, and work well with AI agents. Supabase checked every box. + +The Supabase dashboard sits directly on top of the database. Elliot checks signup numbers by opening a table and sorting by date. Themba verifies a data sync by looking at the same table. No internal admin dashboards to build. No secondary tooling to maintain. + + + What sets Supabase apart is its UI. I can get in there and look at the database. Elliot, as the + non-technical co-founder, can also get in there and really dig deep without having to consult me + about anything. + + +Beyond the database, Supabase gives Hyper a full platform to grow into. Auth, Realtime, and Storage are all available without adding new vendors or stitching together separate services. + + + It's clear what Supabase is building for. They're building databases and features in the age of + super intelligence. Fantastic community, amazing developer documentation. If you're a startup looking + to build the next unicorn or just a lifestyle business, it's the easiest way to get started and + scale. + + +## The solution + +Hyper built a real-time data pipeline that automatically syncs cross-platform marketing data into Supabase — Meta, Google Ads, GA4, Search Console and more. Each customer gets their own managed Supabase database with only their data, and all they have to do is connect their account. No setup, no Supermetrics, no ETL, no warehouse configuration. It's the entire marketing data stack, simplified into one product that does all the heavy lifting. + +From there, agents run SQL to analyze marketing data, spin up customizable dashboards, and surface insights. No intermediate layer, no stale cache — agents query the real data directly. + + + Rather than going out in real time to each platform to get insights, agents write SQL to query the + data themselves. Agents are great at writing SQL. It's way more efficient. A literal 100x cost + reduction compared with if the agent were to go out and try to get that data. + + +Asking an agent to call APIs across five ad platforms in real time is slow, expensive, and often impossible at scale. But an agent can write a SQL query against a synced database and get the answer in seconds. The data stays close, structured, and queryable. Agents reason over it with SQL rather than wrestling with rate-limited APIs. + +When agents query Supabase, they hit the same tables that the founders and customers inspect in the dashboard. No ETL pipeline introducing drift. No caching layer serving stale results. The source of truth is the same for humans and agents. As the founders put it, "AI agents know Supabase like the back of their hand." + + + If you're getting the data from one place and visualizing it elsewhere, there's always going to be + a question mark. With Supabase, any user, whether they're technical or non-technical, can easily + jump in and see what's going on. + + +The result is a platform where agents operate like experts. Whether the user is a seasoned marketer or a first-time business owner, the agents generate reports, optimize campaigns, and flag issues automatically. + +## The results + +With Supabase as the system of record, Hyper gives agents a 360° marketing OS — unifying data, integrations, and intelligence into one product they can operate instantly, from analytics to real execution. Agents catch what's changing, diagnose opportunities and issues, and take omnichannel action immediately — across paid ads, SEO, reporting, and beyond. + +- 100x cost reduction in data retrieval by having agents query SQL instead of calling platform APIs in real time +- 80+ tool integrations connected through a single data pipeline +- Per-customer managed databases with isolated data for each client +- Continuous data sync across all connected ad platforms and data sources (real-time + scheduled) + +## What's next + +Hyper's next phase is built on Supabase for Platforms. The architecture creates two layers. + +The first layer handles the heavy internal workload: the pipeline that syncs ad platform data for agencies and powers the AI agents that analyze it. This runs on larger Supabase instances. + +The second layer changes the product. Each agency's end clients get their own isolated database through Supabase for Platforms. Today, agencies use Hyper to expose reporting dashboards for their clients. With Supabase for Platforms, they can expose full applications. + + + Supabase for Platforms opens up a path for our customers beyond just dashboards. They can expose + richer apps. We can take advantage of all the features that Supabase for Platforms offers, like + Storage, like rich authentication, for their end users. + + +Supabase for Platforms handles the backend infrastructure: per-customer databases, isolated storage, and authentication logic that would have taken at least two weeks to build, even with pre-built libraries. It also provides frontend components that plug directly into Hyper's app. That frees the team to focus on what sits on top: the agents, the dashboards, and the workflows their customers actually see. + +The vision goes further. If marketing agencies can spin up websites for their end clients through Hyper, all powered by Supabase for Platforms, that opens an entirely new competitive front. + + + With Supabase for Platforms, anyone can come into Hyper and launch a marketing agency from scratch. + Build a website, set up authentication and contact forms, create a funnel. In under 15 minutes you + have a live agency with AI agents that intake clients and run their marketing end to end. + + +That is what happens when you give a product team a platform that handles databases, auth, storage, and real-time out of the box. They stop building infrastructure and start building the thing they set out to build. + + + I will get on a podcast and talk about how much I love Supabase and the whole experience. With + Supabase we can move fast and build things that delight our customers without having to worry + about infrastructure. + diff --git a/apps/www/data/CustomerStories.ts b/apps/www/data/CustomerStories.ts index 448497752b0e0..85d30ee70726f 100644 --- a/apps/www/data/CustomerStories.ts +++ b/apps/www/data/CustomerStories.ts @@ -18,6 +18,31 @@ export type CustomerStoryType = { } export const data: CustomerStoryType[] = [ + { + type: 'Customer Story', + title: 'Hyper builds AI marketing agents on Supabase', + description: + 'Hyper is an AI-native marketing platform with agents that operate across the entire marketing workflow. Supabase gives their three-person team the database platform to do it at enterprise scale.', + organization: 'Hyper', + imgUrl: 'images/customers/logos/hyper.svg', + logo: '/images/customers/logos/hyper.svg', + logo_inverse: '/images/customers/logos/light/hyper.svg', + url: '/customers/hyper', + ctaText: 'View story', + }, + { + type: 'Customer Story', + title: + 'How Brevo built AI-powered sales workflows on Supabase, without waiting for engineering', + description: + "Brevo's Revenue Operations team built three production AI workflows connecting their CRM to Dust's AI agents via Supabase MCP—without a single engineering ticket.", + organization: 'Brevo', + imgUrl: 'images/customers/logos/brevo.svg', + logo: '/images/customers/logos/brevo.svg', + logo_inverse: '/images/customers/logos/light/brevo.svg', + url: '/customers/brevo', + ctaText: 'View story', + }, { type: 'Customer Story', title: diff --git a/apps/www/public/customers-rss.xml b/apps/www/public/customers-rss.xml index 5a0a092b4afe0..b8f0fe9eab44f 100644 --- a/apps/www/public/customers-rss.xml +++ b/apps/www/public/customers-rss.xml @@ -5,9 +5,23 @@ https://supabase.com Latest news from Supabase en - Wed, 17 Dec 2025 00:00:00 -0700 + Fri, 19 Dec 2025 00:00:00 -0700 + https://supabase.com/customers/hyper + Hyper builds AI marketing agents on Supabase + https://supabase.com/customers/hyper + Hyper is an AI-native marketing platform with agents that operate across the entire marketing workflow. Supabase gives their three-person team the database platform to do it at enterprise scale. + Fri, 19 Dec 2025 00:00:00 -0700 + + + https://supabase.com/customers/brevo + How Brevo built AI-powered sales workflows on Supabase, without waiting for engineering + https://supabase.com/customers/brevo + Brevo's Revenue Operations team built three production AI workflows connecting their CRM to Dust's AI agents via Supabase MCP—without a single engineering ticket. + Thu, 18 Dec 2025 00:00:00 -0700 + + https://supabase.com/customers/exprealty How eXp Realty Unlocked Enterprise Innovation and Cut SaaS Costs with Supabase https://supabase.com/customers/exprealty diff --git a/apps/www/public/images/avatars/alexandre-le-goupil-brevo.jpeg b/apps/www/public/images/avatars/alexandre-le-goupil-brevo.jpeg new file mode 100644 index 0000000000000..0a0175aa7ce14 Binary files /dev/null and b/apps/www/public/images/avatars/alexandre-le-goupil-brevo.jpeg differ diff --git a/apps/www/public/images/avatars/elliot-fleck-hyper.jpeg b/apps/www/public/images/avatars/elliot-fleck-hyper.jpeg new file mode 100644 index 0000000000000..0d073a37a81ab Binary files /dev/null and b/apps/www/public/images/avatars/elliot-fleck-hyper.jpeg differ diff --git a/apps/www/public/images/avatars/thembelani-mahlangu-fleck.jpeg b/apps/www/public/images/avatars/thembelani-mahlangu-fleck.jpeg new file mode 100644 index 0000000000000..cd69e9ab751d2 Binary files /dev/null and b/apps/www/public/images/avatars/thembelani-mahlangu-fleck.jpeg differ diff --git a/apps/www/public/images/blog/avatars/alexandre-le-goupil-brevo.jpeg b/apps/www/public/images/blog/avatars/alexandre-le-goupil-brevo.jpeg new file mode 100644 index 0000000000000..0a0175aa7ce14 Binary files /dev/null and b/apps/www/public/images/blog/avatars/alexandre-le-goupil-brevo.jpeg differ diff --git a/apps/www/public/images/blog/avatars/elliot-fleck-hyper.jpeg b/apps/www/public/images/blog/avatars/elliot-fleck-hyper.jpeg new file mode 100644 index 0000000000000..0d073a37a81ab Binary files /dev/null and b/apps/www/public/images/blog/avatars/elliot-fleck-hyper.jpeg differ diff --git a/apps/www/public/images/blog/avatars/themba-mahlangu-hyper.jpeg b/apps/www/public/images/blog/avatars/themba-mahlangu-hyper.jpeg new file mode 100644 index 0000000000000..cd69e9ab751d2 Binary files /dev/null and b/apps/www/public/images/blog/avatars/themba-mahlangu-hyper.jpeg differ diff --git a/apps/www/public/images/customers/logos/brevo.svg b/apps/www/public/images/customers/logos/brevo.svg new file mode 100644 index 0000000000000..d65fff180e40a --- /dev/null +++ b/apps/www/public/images/customers/logos/brevo.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/www/public/images/customers/logos/hyper.svg b/apps/www/public/images/customers/logos/hyper.svg new file mode 100644 index 0000000000000..9da486d9b4861 --- /dev/null +++ b/apps/www/public/images/customers/logos/hyper.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/www/public/images/customers/logos/light/brevo.svg b/apps/www/public/images/customers/logos/light/brevo.svg new file mode 100644 index 0000000000000..d369d572afd27 --- /dev/null +++ b/apps/www/public/images/customers/logos/light/brevo.svg @@ -0,0 +1,3 @@ + + + diff --git a/apps/www/public/images/customers/logos/light/hyper.svg b/apps/www/public/images/customers/logos/light/hyper.svg new file mode 100644 index 0000000000000..3455fa8dc535f --- /dev/null +++ b/apps/www/public/images/customers/logos/light/hyper.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/slack-clone/nextjs-slack-clone-dotenvx/package-lock.json b/examples/slack-clone/nextjs-slack-clone-dotenvx/package-lock.json index 063c37d93e6d0..3bdaceec6f262 100644 --- a/examples/slack-clone/nextjs-slack-clone-dotenvx/package-lock.json +++ b/examples/slack-clone/nextjs-slack-clone-dotenvx/package-lock.json @@ -13,7 +13,7 @@ "@supabase/auth-ui-shared": "^0.1.8", "@supabase/supabase-js": "^2.47.3", "jwt-decode": "^4.0.0", - "next": "latest", + "next": "^16.1.6", "react": "^18.2.0", "react-dom": "^18.2.0" }, @@ -115,6 +115,482 @@ "@noble/ciphers": "^1.0.0" } }, + "node_modules/@emnapi/runtime": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", + "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -201,47 +677,19 @@ "dev": true }, "node_modules/@next/env": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/env/-/env-12.1.5.tgz", - "integrity": "sha512-+34yUJslfJi7Lyx6ELuN8nWcOzi27izfYnZIC1Dqv7kmmfiBVxgzR3BXhlvEMTKC2IRJhXVs2FkMY+buQe3k7Q==" - }, - "node_modules/@next/swc-android-arm-eabi": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.1.5.tgz", - "integrity": "sha512-SKnGTdYcoN04Y2DvE0/Y7/MjkA+ltsmbuH/y/hR7Ob7tsj+8ZdOYuk+YvW1B8dY20nDPHP58XgDTSm2nA8BzzA==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-android-arm64": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.1.5.tgz", - "integrity": "sha512-YXiqgQ/9Rxg1dXp6brXbeQM1JDx9SwUY/36JiE+36FXqYEmDYbxld9qkX6GEzkc5rbwJ+RCitargnzEtwGW0mw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.6.tgz", + "integrity": "sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==", + "license": "MIT" }, "node_modules/@next/swc-darwin-arm64": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.5.tgz", - "integrity": "sha512-y8mhldb/WFZ6lFeowkGfi0cO/lBdiBqDk4T4LZLvCpoQp4Or/NzUN6P5NzBQZ5/b4oUHM/wQICEM+1wKA4qIVw==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.6.tgz", + "integrity": "sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -251,12 +699,13 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.5.tgz", - "integrity": "sha512-wqJ3X7WQdTwSGi0kIDEmzw34QHISRIQ5uvC+VXmsIlCPFcMA+zM5723uh8NfuKGquDMiEMS31a83QgkuHMYbwQ==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.6.tgz", + "integrity": "sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -265,28 +714,14 @@ "node": ">= 10" } }, - "node_modules/@next/swc-linux-arm-gnueabihf": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.5.tgz", - "integrity": "sha512-WnhdM5duONMvt2CncAl+9pim0wBxDS2lHoo7ub/o/i1bRbs11UTzosKzEXVaTDCUkCX2c32lIDi1WcN2ZPkcdw==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.5.tgz", - "integrity": "sha512-Jq2H68yQ4bLUhR/XQnbw3LDW0GMQn355qx6rU36BthDLeGue7YV7MqNPa8GKvrpPocEMW77nWx/1yI6w6J07gw==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.6.tgz", + "integrity": "sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -296,12 +731,13 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.5.tgz", - "integrity": "sha512-KgPjwdbhDqXI7ghNN8V/WAiLquc9Ebe8KBrNNEL0NQr+yd9CyKJ6KqjayVkmX+hbHzbyvbui/5wh/p3CZQ9xcQ==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.6.tgz", + "integrity": "sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -311,12 +747,13 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.5.tgz", - "integrity": "sha512-O2ErUTvCJ6DkNTSr9pbu1n3tcqykqE/ebty1rwClzIYdOgpB3T2MfEPP+K7GhUR87wmN/hlihO9ch7qpVFDGKw==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.6.tgz", + "integrity": "sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -326,12 +763,13 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.5.tgz", - "integrity": "sha512-1eIlZmlO/VRjxxzUBcVosf54AFU3ltAzHi+BJA+9U/lPxCYIsT+R4uO3QksRzRjKWhVQMRjEnlXyyq5SKJm7BA==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.6.tgz", + "integrity": "sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -341,27 +779,13 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.5.tgz", - "integrity": "sha512-oromsfokbEuVb0CBLLE7R9qX3KGXucZpsojLpzUh1QJjuy1QkrPJncwr8xmWQnwgtQ6ecMWXgXPB+qtvizT9Tw==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.6.tgz", + "integrity": "sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==", "cpu": [ "arm64" ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-ia32-msvc": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.5.tgz", - "integrity": "sha512-a/51L5KzBpeZSW9LbekMo3I3Cwul+V+QKwbEIMA+Qwb2qrlcn1L9h3lt8cHqNTFt2y72ce6aTwDTw1lyi5oIRA==", - "cpu": [ - "ia32" - ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -371,12 +795,13 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.5.tgz", - "integrity": "sha512-/SoXW1Ntpmpw3AXAzfDRaQidnd8kbZ2oSni8u5z0yw6t4RwJvmdZy1eOaAADRThWKV+2oU90++LSnXJIwBRWYQ==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.6.tgz", + "integrity": "sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -590,6 +1015,15 @@ "@supabase/storage-js": "2.7.1" } }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, "node_modules/@types/node": { "version": "22.10.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz", @@ -714,6 +1148,18 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", + "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/bin-links": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-5.0.0.tgz", @@ -804,9 +1250,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001509", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001509.tgz", - "integrity": "sha512-2uDDk+TRiTX5hMcUYT/7CSyzMZxjfGu0vAUjS2g0LSD8UoXOv0LtpH4LxGMemsiPq6LCVIUjNwVM0erkOkGCDA==", + "version": "1.0.30001776", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001776.tgz", + "integrity": "sha512-sg01JDPzZ9jGshqKSckOQthXnYwOEP50jeVFhaSFbZcOy05TiuuaffDOfcwtCisJ9kNQuLBFibYywv2Bgm9osw==", "funding": [ { "type": "opencollective", @@ -820,7 +1266,8 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/chokidar": { "version": "3.5.3", @@ -859,6 +1306,12 @@ "node": ">=18" } }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, "node_modules/cmd-shim": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-7.0.0.tgz", @@ -982,6 +1435,16 @@ } } }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -1630,47 +2093,51 @@ } }, "node_modules/next": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/next/-/next-12.1.5.tgz", - "integrity": "sha512-YGHDpyfgCfnT5GZObsKepmRnne7Kzp7nGrac07dikhutWQug7hHg85/+sPJ4ZW5Q2pDkb+n0FnmLkmd44htIJQ==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/next/-/next-16.1.6.tgz", + "integrity": "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==", + "license": "MIT", "dependencies": { - "@next/env": "12.1.5", - "caniuse-lite": "^1.0.30001283", - "postcss": "8.4.5", - "styled-jsx": "5.0.1" + "@next/env": "16.1.6", + "@swc/helpers": "0.5.15", + "baseline-browser-mapping": "^2.8.3", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" }, "bin": { "next": "dist/bin/next" }, "engines": { - "node": ">=12.22.0" + "node": ">=20.9.0" }, "optionalDependencies": { - "@next/swc-android-arm-eabi": "12.1.5", - "@next/swc-android-arm64": "12.1.5", - "@next/swc-darwin-arm64": "12.1.5", - "@next/swc-darwin-x64": "12.1.5", - "@next/swc-linux-arm-gnueabihf": "12.1.5", - "@next/swc-linux-arm64-gnu": "12.1.5", - "@next/swc-linux-arm64-musl": "12.1.5", - "@next/swc-linux-x64-gnu": "12.1.5", - "@next/swc-linux-x64-musl": "12.1.5", - "@next/swc-win32-arm64-msvc": "12.1.5", - "@next/swc-win32-ia32-msvc": "12.1.5", - "@next/swc-win32-x64-msvc": "12.1.5" + "@next/swc-darwin-arm64": "16.1.6", + "@next/swc-darwin-x64": "16.1.6", + "@next/swc-linux-arm64-gnu": "16.1.6", + "@next/swc-linux-arm64-musl": "16.1.6", + "@next/swc-linux-x64-gnu": "16.1.6", + "@next/swc-linux-x64-musl": "16.1.6", + "@next/swc-win32-arm64-msvc": "16.1.6", + "@next/swc-win32-x64-msvc": "16.1.6", + "sharp": "^0.34.4" }, "peerDependencies": { - "fibers": ">= 3.1.0", - "node-sass": "^6.0.0 || ^7.0.0", - "react": "^17.0.2 || ^18.0.0-0", - "react-dom": "^17.0.2 || ^18.0.0-0", + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.51.1", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "peerDependenciesMeta": { - "fibers": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { "optional": true }, - "node-sass": { + "babel-plugin-react-compiler": { "optional": true }, "sass": { @@ -1678,23 +2145,6 @@ } } }, - "node_modules/next/node_modules/postcss": { - "version": "8.4.5", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", - "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", - "dependencies": { - "nanoid": "^3.1.30", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, "node_modules/node-domexception": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", @@ -1918,10 +2368,9 @@ } }, "node_modules/postcss": { - "version": "8.4.24", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", - "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", - "dev": true, + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "funding": [ { "type": "opencollective", @@ -1936,6 +2385,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", @@ -2269,6 +2719,64 @@ "loose-envify": "^1.1.0" } }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -2422,14 +2930,18 @@ } }, "node_modules/styled-jsx": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.1.tgz", - "integrity": "sha512-+PIZ/6Uk40mphiQJJI1202b+/dYeTVd9ZnMPR80pgiWbjIwvN2zIp4r9et0BgqBuShh48I0gttPlAXA7WVvBxw==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, "engines": { "node": ">= 12.0.0" }, "peerDependencies": { - "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" }, "peerDependenciesMeta": { "@babel/core": { @@ -2626,6 +3138,12 @@ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", "dev": true }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, "node_modules/undici-types": { "version": "6.20.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", @@ -2934,6 +3452,198 @@ "dev": true, "requires": {} }, + "@emnapi/runtime": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", + "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", + "optional": true, + "requires": { + "tslib": "^2.4.0" + } + }, + "@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "optional": true + }, + "@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "optional": true, + "requires": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "optional": true, + "requires": { + "@img/sharp-libvips-darwin-x64": "1.2.4" + } + }, + "@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "optional": true + }, + "@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "optional": true + }, + "@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "optional": true + }, + "@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "optional": true + }, + "@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "optional": true + }, + "@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "optional": true + }, + "@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "optional": true + }, + "@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "optional": true + }, + "@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "optional": true + }, + "@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "optional": true + }, + "@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "optional": true, + "requires": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "optional": true, + "requires": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "optional": true, + "requires": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "optional": true, + "requires": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "optional": true, + "requires": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "optional": true, + "requires": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "optional": true, + "requires": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "optional": true, + "requires": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "optional": true, + "requires": { + "@emnapi/runtime": "^1.7.0" + } + }, + "@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "optional": true + }, + "@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "optional": true + }, + "@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "optional": true + }, "@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -3005,80 +3715,56 @@ } }, "@next/env": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/env/-/env-12.1.5.tgz", - "integrity": "sha512-+34yUJslfJi7Lyx6ELuN8nWcOzi27izfYnZIC1Dqv7kmmfiBVxgzR3BXhlvEMTKC2IRJhXVs2FkMY+buQe3k7Q==" - }, - "@next/swc-android-arm-eabi": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.1.5.tgz", - "integrity": "sha512-SKnGTdYcoN04Y2DvE0/Y7/MjkA+ltsmbuH/y/hR7Ob7tsj+8ZdOYuk+YvW1B8dY20nDPHP58XgDTSm2nA8BzzA==", - "optional": true - }, - "@next/swc-android-arm64": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.1.5.tgz", - "integrity": "sha512-YXiqgQ/9Rxg1dXp6brXbeQM1JDx9SwUY/36JiE+36FXqYEmDYbxld9qkX6GEzkc5rbwJ+RCitargnzEtwGW0mw==", - "optional": true + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.6.tgz", + "integrity": "sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==" }, "@next/swc-darwin-arm64": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.5.tgz", - "integrity": "sha512-y8mhldb/WFZ6lFeowkGfi0cO/lBdiBqDk4T4LZLvCpoQp4Or/NzUN6P5NzBQZ5/b4oUHM/wQICEM+1wKA4qIVw==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.6.tgz", + "integrity": "sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==", "optional": true }, "@next/swc-darwin-x64": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.5.tgz", - "integrity": "sha512-wqJ3X7WQdTwSGi0kIDEmzw34QHISRIQ5uvC+VXmsIlCPFcMA+zM5723uh8NfuKGquDMiEMS31a83QgkuHMYbwQ==", - "optional": true - }, - "@next/swc-linux-arm-gnueabihf": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.5.tgz", - "integrity": "sha512-WnhdM5duONMvt2CncAl+9pim0wBxDS2lHoo7ub/o/i1bRbs11UTzosKzEXVaTDCUkCX2c32lIDi1WcN2ZPkcdw==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.6.tgz", + "integrity": "sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==", "optional": true }, "@next/swc-linux-arm64-gnu": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.5.tgz", - "integrity": "sha512-Jq2H68yQ4bLUhR/XQnbw3LDW0GMQn355qx6rU36BthDLeGue7YV7MqNPa8GKvrpPocEMW77nWx/1yI6w6J07gw==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.6.tgz", + "integrity": "sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==", "optional": true }, "@next/swc-linux-arm64-musl": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.5.tgz", - "integrity": "sha512-KgPjwdbhDqXI7ghNN8V/WAiLquc9Ebe8KBrNNEL0NQr+yd9CyKJ6KqjayVkmX+hbHzbyvbui/5wh/p3CZQ9xcQ==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.6.tgz", + "integrity": "sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==", "optional": true }, "@next/swc-linux-x64-gnu": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.5.tgz", - "integrity": "sha512-O2ErUTvCJ6DkNTSr9pbu1n3tcqykqE/ebty1rwClzIYdOgpB3T2MfEPP+K7GhUR87wmN/hlihO9ch7qpVFDGKw==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.6.tgz", + "integrity": "sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==", "optional": true }, "@next/swc-linux-x64-musl": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.5.tgz", - "integrity": "sha512-1eIlZmlO/VRjxxzUBcVosf54AFU3ltAzHi+BJA+9U/lPxCYIsT+R4uO3QksRzRjKWhVQMRjEnlXyyq5SKJm7BA==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.6.tgz", + "integrity": "sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==", "optional": true }, "@next/swc-win32-arm64-msvc": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.5.tgz", - "integrity": "sha512-oromsfokbEuVb0CBLLE7R9qX3KGXucZpsojLpzUh1QJjuy1QkrPJncwr8xmWQnwgtQ6ecMWXgXPB+qtvizT9Tw==", - "optional": true - }, - "@next/swc-win32-ia32-msvc": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.5.tgz", - "integrity": "sha512-a/51L5KzBpeZSW9LbekMo3I3Cwul+V+QKwbEIMA+Qwb2qrlcn1L9h3lt8cHqNTFt2y72ce6aTwDTw1lyi5oIRA==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.6.tgz", + "integrity": "sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==", "optional": true }, "@next/swc-win32-x64-msvc": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.5.tgz", - "integrity": "sha512-/SoXW1Ntpmpw3AXAzfDRaQidnd8kbZ2oSni8u5z0yw6t4RwJvmdZy1eOaAADRThWKV+2oU90++LSnXJIwBRWYQ==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.6.tgz", + "integrity": "sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==", "optional": true }, "@noble/ciphers": { @@ -3230,6 +3916,14 @@ "@supabase/storage-js": "2.7.1" } }, + "@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "requires": { + "tslib": "^2.8.0" + } + }, "@types/node": { "version": "22.10.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz", @@ -3311,6 +4005,11 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "baseline-browser-mapping": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", + "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==" + }, "bin-links": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-5.0.0.tgz", @@ -3368,9 +4067,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001509", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001509.tgz", - "integrity": "sha512-2uDDk+TRiTX5hMcUYT/7CSyzMZxjfGu0vAUjS2g0LSD8UoXOv0LtpH4LxGMemsiPq6LCVIUjNwVM0erkOkGCDA==" + "version": "1.0.30001776", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001776.tgz", + "integrity": "sha512-sg01JDPzZ9jGshqKSckOQthXnYwOEP50jeVFhaSFbZcOy05TiuuaffDOfcwtCisJ9kNQuLBFibYywv2Bgm9osw==" }, "chokidar": { "version": "3.5.3", @@ -3394,6 +4093,11 @@ "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", "dev": true }, + "client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" + }, "cmd-shim": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-7.0.0.tgz", @@ -3476,6 +4180,12 @@ "ms": "^2.1.3" } }, + "detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "optional": true + }, "didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -3920,38 +4630,25 @@ "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==" }, "next": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/next/-/next-12.1.5.tgz", - "integrity": "sha512-YGHDpyfgCfnT5GZObsKepmRnne7Kzp7nGrac07dikhutWQug7hHg85/+sPJ4ZW5Q2pDkb+n0FnmLkmd44htIJQ==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/next/-/next-16.1.6.tgz", + "integrity": "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==", "requires": { - "@next/env": "12.1.5", - "@next/swc-android-arm-eabi": "12.1.5", - "@next/swc-android-arm64": "12.1.5", - "@next/swc-darwin-arm64": "12.1.5", - "@next/swc-darwin-x64": "12.1.5", - "@next/swc-linux-arm-gnueabihf": "12.1.5", - "@next/swc-linux-arm64-gnu": "12.1.5", - "@next/swc-linux-arm64-musl": "12.1.5", - "@next/swc-linux-x64-gnu": "12.1.5", - "@next/swc-linux-x64-musl": "12.1.5", - "@next/swc-win32-arm64-msvc": "12.1.5", - "@next/swc-win32-ia32-msvc": "12.1.5", - "@next/swc-win32-x64-msvc": "12.1.5", - "caniuse-lite": "^1.0.30001283", - "postcss": "8.4.5", - "styled-jsx": "5.0.1" - }, - "dependencies": { - "postcss": { - "version": "8.4.5", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", - "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", - "requires": { - "nanoid": "^3.1.30", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.1" - } - } + "@next/env": "16.1.6", + "@next/swc-darwin-arm64": "16.1.6", + "@next/swc-darwin-x64": "16.1.6", + "@next/swc-linux-arm64-gnu": "16.1.6", + "@next/swc-linux-arm64-musl": "16.1.6", + "@next/swc-linux-x64-gnu": "16.1.6", + "@next/swc-linux-x64-musl": "16.1.6", + "@next/swc-win32-arm64-msvc": "16.1.6", + "@next/swc-win32-x64-msvc": "16.1.6", + "@swc/helpers": "0.5.15", + "baseline-browser-mapping": "^2.8.3", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "sharp": "^0.34.4", + "styled-jsx": "5.1.6" } }, "node-domexception": { @@ -4097,10 +4794,9 @@ "dev": true }, "postcss": { - "version": "8.4.24", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", - "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", - "dev": true, + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "requires": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", @@ -4310,6 +5006,47 @@ "loose-envify": "^1.1.0" } }, + "semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "optional": true + }, + "sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "optional": true, + "requires": { + "@img/colour": "^1.0.0", + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + } + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -4414,10 +5151,12 @@ "dev": true }, "styled-jsx": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.1.tgz", - "integrity": "sha512-+PIZ/6Uk40mphiQJJI1202b+/dYeTVd9ZnMPR80pgiWbjIwvN2zIp4r9et0BgqBuShh48I0gttPlAXA7WVvBxw==", - "requires": {} + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "requires": { + "client-only": "0.0.1" + } }, "sucrase": { "version": "3.32.0", @@ -4555,6 +5294,11 @@ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", "dev": true }, + "tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + }, "undici-types": { "version": "6.20.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", diff --git a/examples/slack-clone/nextjs-slack-clone/package-lock.json b/examples/slack-clone/nextjs-slack-clone/package-lock.json index 2ac89187de94d..624ed4cb0693f 100644 --- a/examples/slack-clone/nextjs-slack-clone/package-lock.json +++ b/examples/slack-clone/nextjs-slack-clone/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@supabase/supabase-js": "^2.39.6", "jwt-decode": "^4.0.0", - "next": "latest", + "next": "^16.1.6", "react": "^18.2.0", "react-dom": "^18.2.0" }, @@ -33,6 +33,482 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@emnapi/runtime": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", + "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", @@ -88,47 +564,19 @@ "dev": true }, "node_modules/@next/env": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/env/-/env-12.1.5.tgz", - "integrity": "sha512-+34yUJslfJi7Lyx6ELuN8nWcOzi27izfYnZIC1Dqv7kmmfiBVxgzR3BXhlvEMTKC2IRJhXVs2FkMY+buQe3k7Q==" - }, - "node_modules/@next/swc-android-arm-eabi": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.1.5.tgz", - "integrity": "sha512-SKnGTdYcoN04Y2DvE0/Y7/MjkA+ltsmbuH/y/hR7Ob7tsj+8ZdOYuk+YvW1B8dY20nDPHP58XgDTSm2nA8BzzA==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-android-arm64": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.1.5.tgz", - "integrity": "sha512-YXiqgQ/9Rxg1dXp6brXbeQM1JDx9SwUY/36JiE+36FXqYEmDYbxld9qkX6GEzkc5rbwJ+RCitargnzEtwGW0mw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.6.tgz", + "integrity": "sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==", + "license": "MIT" }, "node_modules/@next/swc-darwin-arm64": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.5.tgz", - "integrity": "sha512-y8mhldb/WFZ6lFeowkGfi0cO/lBdiBqDk4T4LZLvCpoQp4Or/NzUN6P5NzBQZ5/b4oUHM/wQICEM+1wKA4qIVw==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.6.tgz", + "integrity": "sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -138,12 +586,13 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.5.tgz", - "integrity": "sha512-wqJ3X7WQdTwSGi0kIDEmzw34QHISRIQ5uvC+VXmsIlCPFcMA+zM5723uh8NfuKGquDMiEMS31a83QgkuHMYbwQ==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.6.tgz", + "integrity": "sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -152,28 +601,14 @@ "node": ">= 10" } }, - "node_modules/@next/swc-linux-arm-gnueabihf": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.5.tgz", - "integrity": "sha512-WnhdM5duONMvt2CncAl+9pim0wBxDS2lHoo7ub/o/i1bRbs11UTzosKzEXVaTDCUkCX2c32lIDi1WcN2ZPkcdw==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.5.tgz", - "integrity": "sha512-Jq2H68yQ4bLUhR/XQnbw3LDW0GMQn355qx6rU36BthDLeGue7YV7MqNPa8GKvrpPocEMW77nWx/1yI6w6J07gw==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.6.tgz", + "integrity": "sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -183,12 +618,13 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.5.tgz", - "integrity": "sha512-KgPjwdbhDqXI7ghNN8V/WAiLquc9Ebe8KBrNNEL0NQr+yd9CyKJ6KqjayVkmX+hbHzbyvbui/5wh/p3CZQ9xcQ==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.6.tgz", + "integrity": "sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -198,12 +634,13 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.5.tgz", - "integrity": "sha512-O2ErUTvCJ6DkNTSr9pbu1n3tcqykqE/ebty1rwClzIYdOgpB3T2MfEPP+K7GhUR87wmN/hlihO9ch7qpVFDGKw==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.6.tgz", + "integrity": "sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -213,12 +650,13 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.5.tgz", - "integrity": "sha512-1eIlZmlO/VRjxxzUBcVosf54AFU3ltAzHi+BJA+9U/lPxCYIsT+R4uO3QksRzRjKWhVQMRjEnlXyyq5SKJm7BA==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.6.tgz", + "integrity": "sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -228,27 +666,13 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.5.tgz", - "integrity": "sha512-oromsfokbEuVb0CBLLE7R9qX3KGXucZpsojLpzUh1QJjuy1QkrPJncwr8xmWQnwgtQ6ecMWXgXPB+qtvizT9Tw==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.6.tgz", + "integrity": "sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==", "cpu": [ "arm64" ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-ia32-msvc": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.5.tgz", - "integrity": "sha512-a/51L5KzBpeZSW9LbekMo3I3Cwul+V+QKwbEIMA+Qwb2qrlcn1L9h3lt8cHqNTFt2y72ce6aTwDTw1lyi5oIRA==", - "cpu": [ - "ia32" - ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -258,12 +682,13 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.5.tgz", - "integrity": "sha512-/SoXW1Ntpmpw3AXAzfDRaQidnd8kbZ2oSni8u5z0yw6t4RwJvmdZy1eOaAADRThWKV+2oU90++LSnXJIwBRWYQ==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.6.tgz", + "integrity": "sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -374,6 +799,15 @@ "@supabase/storage-js": "2.5.5" } }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, "node_modules/@types/node": { "version": "20.11.17", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.17.tgz", @@ -459,6 +893,18 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", + "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -532,9 +978,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001509", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001509.tgz", - "integrity": "sha512-2uDDk+TRiTX5hMcUYT/7CSyzMZxjfGu0vAUjS2g0LSD8UoXOv0LtpH4LxGMemsiPq6LCVIUjNwVM0erkOkGCDA==", + "version": "1.0.30001776", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001776.tgz", + "integrity": "sha512-sg01JDPzZ9jGshqKSckOQthXnYwOEP50jeVFhaSFbZcOy05TiuuaffDOfcwtCisJ9kNQuLBFibYywv2Bgm9osw==", "funding": [ { "type": "opencollective", @@ -548,7 +994,8 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/chokidar": { "version": "3.5.3", @@ -577,6 +1024,12 @@ "fsevents": "~2.3.2" } }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, "node_modules/commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", @@ -604,6 +1057,16 @@ "node": ">=4" } }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -939,47 +1402,51 @@ } }, "node_modules/next": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/next/-/next-12.1.5.tgz", - "integrity": "sha512-YGHDpyfgCfnT5GZObsKepmRnne7Kzp7nGrac07dikhutWQug7hHg85/+sPJ4ZW5Q2pDkb+n0FnmLkmd44htIJQ==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/next/-/next-16.1.6.tgz", + "integrity": "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==", + "license": "MIT", "dependencies": { - "@next/env": "12.1.5", - "caniuse-lite": "^1.0.30001283", - "postcss": "8.4.5", - "styled-jsx": "5.0.1" + "@next/env": "16.1.6", + "@swc/helpers": "0.5.15", + "baseline-browser-mapping": "^2.8.3", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" }, "bin": { "next": "dist/bin/next" }, "engines": { - "node": ">=12.22.0" + "node": ">=20.9.0" }, "optionalDependencies": { - "@next/swc-android-arm-eabi": "12.1.5", - "@next/swc-android-arm64": "12.1.5", - "@next/swc-darwin-arm64": "12.1.5", - "@next/swc-darwin-x64": "12.1.5", - "@next/swc-linux-arm-gnueabihf": "12.1.5", - "@next/swc-linux-arm64-gnu": "12.1.5", - "@next/swc-linux-arm64-musl": "12.1.5", - "@next/swc-linux-x64-gnu": "12.1.5", - "@next/swc-linux-x64-musl": "12.1.5", - "@next/swc-win32-arm64-msvc": "12.1.5", - "@next/swc-win32-ia32-msvc": "12.1.5", - "@next/swc-win32-x64-msvc": "12.1.5" + "@next/swc-darwin-arm64": "16.1.6", + "@next/swc-darwin-x64": "16.1.6", + "@next/swc-linux-arm64-gnu": "16.1.6", + "@next/swc-linux-arm64-musl": "16.1.6", + "@next/swc-linux-x64-gnu": "16.1.6", + "@next/swc-linux-x64-musl": "16.1.6", + "@next/swc-win32-arm64-msvc": "16.1.6", + "@next/swc-win32-x64-msvc": "16.1.6", + "sharp": "^0.34.4" }, "peerDependencies": { - "fibers": ">= 3.1.0", - "node-sass": "^6.0.0 || ^7.0.0", - "react": "^17.0.2 || ^18.0.0-0", - "react-dom": "^17.0.2 || ^18.0.0-0", + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.51.1", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "peerDependenciesMeta": { - "fibers": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { "optional": true }, - "node-sass": { + "babel-plugin-react-compiler": { "optional": true }, "sass": { @@ -987,23 +1454,6 @@ } } }, - "node_modules/next/node_modules/postcss": { - "version": "8.4.5", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", - "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", - "dependencies": { - "nanoid": "^3.1.30", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, "node_modules/node-releases": { "version": "2.0.12", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", @@ -1106,10 +1556,9 @@ } }, "node_modules/postcss": { - "version": "8.4.24", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", - "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", - "dev": true, + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "funding": [ { "type": "opencollective", @@ -1124,6 +1573,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", @@ -1357,6 +1807,64 @@ "loose-envify": "^1.1.0" } }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } + }, "node_modules/source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", @@ -1366,14 +1874,18 @@ } }, "node_modules/styled-jsx": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.1.tgz", - "integrity": "sha512-+PIZ/6Uk40mphiQJJI1202b+/dYeTVd9ZnMPR80pgiWbjIwvN2zIp4r9et0BgqBuShh48I0gttPlAXA7WVvBxw==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, "engines": { "node": ">= 12.0.0" }, "peerDependencies": { - "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" }, "peerDependenciesMeta": { "@babel/core": { @@ -1531,6 +2043,12 @@ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", "dev": true }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", @@ -1629,6 +2147,198 @@ "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", "dev": true }, + "@emnapi/runtime": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", + "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", + "optional": true, + "requires": { + "tslib": "^2.4.0" + } + }, + "@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "optional": true + }, + "@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "optional": true, + "requires": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "optional": true, + "requires": { + "@img/sharp-libvips-darwin-x64": "1.2.4" + } + }, + "@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "optional": true + }, + "@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "optional": true + }, + "@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "optional": true + }, + "@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "optional": true + }, + "@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "optional": true + }, + "@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "optional": true + }, + "@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "optional": true + }, + "@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "optional": true + }, + "@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "optional": true + }, + "@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "optional": true + }, + "@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "optional": true, + "requires": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "optional": true, + "requires": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "optional": true, + "requires": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "optional": true, + "requires": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "optional": true, + "requires": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "optional": true, + "requires": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "optional": true, + "requires": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "optional": true, + "requires": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "optional": true, + "requires": { + "@emnapi/runtime": "^1.7.0" + } + }, + "@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "optional": true + }, + "@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "optional": true + }, + "@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "optional": true + }, "@jridgewell/gen-mapping": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", @@ -1677,80 +2387,56 @@ } }, "@next/env": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/env/-/env-12.1.5.tgz", - "integrity": "sha512-+34yUJslfJi7Lyx6ELuN8nWcOzi27izfYnZIC1Dqv7kmmfiBVxgzR3BXhlvEMTKC2IRJhXVs2FkMY+buQe3k7Q==" - }, - "@next/swc-android-arm-eabi": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.1.5.tgz", - "integrity": "sha512-SKnGTdYcoN04Y2DvE0/Y7/MjkA+ltsmbuH/y/hR7Ob7tsj+8ZdOYuk+YvW1B8dY20nDPHP58XgDTSm2nA8BzzA==", - "optional": true - }, - "@next/swc-android-arm64": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.1.5.tgz", - "integrity": "sha512-YXiqgQ/9Rxg1dXp6brXbeQM1JDx9SwUY/36JiE+36FXqYEmDYbxld9qkX6GEzkc5rbwJ+RCitargnzEtwGW0mw==", - "optional": true + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.6.tgz", + "integrity": "sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==" }, "@next/swc-darwin-arm64": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.5.tgz", - "integrity": "sha512-y8mhldb/WFZ6lFeowkGfi0cO/lBdiBqDk4T4LZLvCpoQp4Or/NzUN6P5NzBQZ5/b4oUHM/wQICEM+1wKA4qIVw==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.6.tgz", + "integrity": "sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==", "optional": true }, "@next/swc-darwin-x64": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.5.tgz", - "integrity": "sha512-wqJ3X7WQdTwSGi0kIDEmzw34QHISRIQ5uvC+VXmsIlCPFcMA+zM5723uh8NfuKGquDMiEMS31a83QgkuHMYbwQ==", - "optional": true - }, - "@next/swc-linux-arm-gnueabihf": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.5.tgz", - "integrity": "sha512-WnhdM5duONMvt2CncAl+9pim0wBxDS2lHoo7ub/o/i1bRbs11UTzosKzEXVaTDCUkCX2c32lIDi1WcN2ZPkcdw==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.6.tgz", + "integrity": "sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==", "optional": true }, "@next/swc-linux-arm64-gnu": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.5.tgz", - "integrity": "sha512-Jq2H68yQ4bLUhR/XQnbw3LDW0GMQn355qx6rU36BthDLeGue7YV7MqNPa8GKvrpPocEMW77nWx/1yI6w6J07gw==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.6.tgz", + "integrity": "sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==", "optional": true }, "@next/swc-linux-arm64-musl": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.5.tgz", - "integrity": "sha512-KgPjwdbhDqXI7ghNN8V/WAiLquc9Ebe8KBrNNEL0NQr+yd9CyKJ6KqjayVkmX+hbHzbyvbui/5wh/p3CZQ9xcQ==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.6.tgz", + "integrity": "sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==", "optional": true }, "@next/swc-linux-x64-gnu": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.5.tgz", - "integrity": "sha512-O2ErUTvCJ6DkNTSr9pbu1n3tcqykqE/ebty1rwClzIYdOgpB3T2MfEPP+K7GhUR87wmN/hlihO9ch7qpVFDGKw==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.6.tgz", + "integrity": "sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==", "optional": true }, "@next/swc-linux-x64-musl": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.5.tgz", - "integrity": "sha512-1eIlZmlO/VRjxxzUBcVosf54AFU3ltAzHi+BJA+9U/lPxCYIsT+R4uO3QksRzRjKWhVQMRjEnlXyyq5SKJm7BA==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.6.tgz", + "integrity": "sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==", "optional": true }, "@next/swc-win32-arm64-msvc": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.5.tgz", - "integrity": "sha512-oromsfokbEuVb0CBLLE7R9qX3KGXucZpsojLpzUh1QJjuy1QkrPJncwr8xmWQnwgtQ6ecMWXgXPB+qtvizT9Tw==", - "optional": true - }, - "@next/swc-win32-ia32-msvc": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.5.tgz", - "integrity": "sha512-a/51L5KzBpeZSW9LbekMo3I3Cwul+V+QKwbEIMA+Qwb2qrlcn1L9h3lt8cHqNTFt2y72ce6aTwDTw1lyi5oIRA==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.6.tgz", + "integrity": "sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==", "optional": true }, "@next/swc-win32-x64-msvc": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.5.tgz", - "integrity": "sha512-/SoXW1Ntpmpw3AXAzfDRaQidnd8kbZ2oSni8u5z0yw6t4RwJvmdZy1eOaAADRThWKV+2oU90++LSnXJIwBRWYQ==", + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.6.tgz", + "integrity": "sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==", "optional": true }, "@nodelib/fs.scandir": { @@ -1843,6 +2529,14 @@ "@supabase/storage-js": "2.5.5" } }, + "@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "requires": { + "tslib": "^2.8.0" + } + }, "@types/node": { "version": "20.11.17", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.17.tgz", @@ -1906,6 +2600,11 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "baseline-browser-mapping": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", + "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==" + }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -1950,9 +2649,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001509", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001509.tgz", - "integrity": "sha512-2uDDk+TRiTX5hMcUYT/7CSyzMZxjfGu0vAUjS2g0LSD8UoXOv0LtpH4LxGMemsiPq6LCVIUjNwVM0erkOkGCDA==" + "version": "1.0.30001776", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001776.tgz", + "integrity": "sha512-sg01JDPzZ9jGshqKSckOQthXnYwOEP50jeVFhaSFbZcOy05TiuuaffDOfcwtCisJ9kNQuLBFibYywv2Bgm9osw==" }, "chokidar": { "version": "3.5.3", @@ -1970,6 +2669,11 @@ "readdirp": "~3.6.0" } }, + "client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" + }, "commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", @@ -1988,6 +2692,12 @@ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true }, + "detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "optional": true + }, "didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -2240,38 +2950,25 @@ "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==" }, "next": { - "version": "12.1.5", - "resolved": "https://registry.npmjs.org/next/-/next-12.1.5.tgz", - "integrity": "sha512-YGHDpyfgCfnT5GZObsKepmRnne7Kzp7nGrac07dikhutWQug7hHg85/+sPJ4ZW5Q2pDkb+n0FnmLkmd44htIJQ==", - "requires": { - "@next/env": "12.1.5", - "@next/swc-android-arm-eabi": "12.1.5", - "@next/swc-android-arm64": "12.1.5", - "@next/swc-darwin-arm64": "12.1.5", - "@next/swc-darwin-x64": "12.1.5", - "@next/swc-linux-arm-gnueabihf": "12.1.5", - "@next/swc-linux-arm64-gnu": "12.1.5", - "@next/swc-linux-arm64-musl": "12.1.5", - "@next/swc-linux-x64-gnu": "12.1.5", - "@next/swc-linux-x64-musl": "12.1.5", - "@next/swc-win32-arm64-msvc": "12.1.5", - "@next/swc-win32-ia32-msvc": "12.1.5", - "@next/swc-win32-x64-msvc": "12.1.5", - "caniuse-lite": "^1.0.30001283", - "postcss": "8.4.5", - "styled-jsx": "5.0.1" - }, - "dependencies": { - "postcss": { - "version": "8.4.5", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", - "integrity": "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==", - "requires": { - "nanoid": "^3.1.30", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.1" - } - } + "version": "16.1.6", + "resolved": "https://registry.npmjs.org/next/-/next-16.1.6.tgz", + "integrity": "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==", + "requires": { + "@next/env": "16.1.6", + "@next/swc-darwin-arm64": "16.1.6", + "@next/swc-darwin-x64": "16.1.6", + "@next/swc-linux-arm64-gnu": "16.1.6", + "@next/swc-linux-arm64-musl": "16.1.6", + "@next/swc-linux-x64-gnu": "16.1.6", + "@next/swc-linux-x64-musl": "16.1.6", + "@next/swc-win32-arm64-msvc": "16.1.6", + "@next/swc-win32-x64-msvc": "16.1.6", + "@swc/helpers": "0.5.15", + "baseline-browser-mapping": "^2.8.3", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "sharp": "^0.34.4", + "styled-jsx": "5.1.6" } }, "node-releases": { @@ -2349,10 +3046,9 @@ "dev": true }, "postcss": { - "version": "8.4.24", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", - "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", - "dev": true, + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "requires": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", @@ -2492,16 +3188,59 @@ "loose-envify": "^1.1.0" } }, + "semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "optional": true + }, + "sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "optional": true, + "requires": { + "@img/colour": "^1.0.0", + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + } + }, "source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" }, "styled-jsx": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.1.tgz", - "integrity": "sha512-+PIZ/6Uk40mphiQJJI1202b+/dYeTVd9ZnMPR80pgiWbjIwvN2zIp4r9et0BgqBuShh48I0gttPlAXA7WVvBxw==", - "requires": {} + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "requires": { + "client-only": "0.0.1" + } }, "sucrase": { "version": "3.32.0", @@ -2613,6 +3352,11 @@ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", "dev": true }, + "tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + }, "undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",