diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 32b4390a497..201d1b6dc87 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -14,7 +14,7 @@ /docker/ @supabase/cli @supabase/self-hosted -/apps/studio/csp.js @supabase/security +/apps/studio/csp.ts @supabase/security /apps/studio/components/interfaces/Billing/Payment @supabase/security /apps/studio/components/interfaces/Organization/Documents/ @supabase/security /apps/studio/pages/new/index.tsx @supabase/security diff --git a/apps/studio/components/ui/AIAssistantPanel/MessageMarkdown.tsx b/apps/studio/components/ui/AIAssistantPanel/MessageMarkdown.tsx index b8370650bde..8376cc22684 100644 --- a/apps/studio/components/ui/AIAssistantPanel/MessageMarkdown.tsx +++ b/apps/studio/components/ui/AIAssistantPanel/MessageMarkdown.tsx @@ -40,7 +40,7 @@ const Streamdown = dynamic( // Streamdown splits ordered lists with complex content (e.g. code blocks) into // separate
    elements. The `start` attribute preserves semantics for screen // readers, while `counterReset` is what actually fixes the visible numbering — -// the prose config (tailwind.config.js) uses a custom CSS counter named "item" +// the prose config (tailwind.config.ts) uses a custom CSS counter named "item" // with `listStyleType: 'none'`, so the `start` attribute alone has no visual effect. export const OrderedList = memo(({ children, start }: { children?: ReactNode; start?: number }) => (
      { diff --git a/apps/studio/csp.js b/apps/studio/csp.ts similarity index 99% rename from apps/studio/csp.js rename to apps/studio/csp.ts index 610cc22d161..c3dd416efc7 100644 --- a/apps/studio/csp.js +++ b/apps/studio/csp.ts @@ -80,7 +80,7 @@ const PUSHER_URL_WS = 'wss://*.pusher.com' const GOOGLE_MAPS_API_URL = 'https://maps.googleapis.com' -module.exports.getCSP = function getCSP() { +export function getCSP() { const DEFAULT_SRC_URLS = [ API_URL, SUPABASE_URL, diff --git a/apps/studio/eslint-rules/require-safe-sql-fragment.js b/apps/studio/eslint-rules/require-safe-sql-fragment.cjs similarity index 100% rename from apps/studio/eslint-rules/require-safe-sql-fragment.js rename to apps/studio/eslint-rules/require-safe-sql-fragment.cjs diff --git a/apps/studio/eslint.type-checks.config.cjs b/apps/studio/eslint.type-checks.config.cjs index e5bb7209a47..fe7a4570e2a 100644 --- a/apps/studio/eslint.type-checks.config.cjs +++ b/apps/studio/eslint.type-checks.config.cjs @@ -9,7 +9,7 @@ const { defineConfig } = require('eslint/config') const tsparser = require('@typescript-eslint/parser') -const requireSafeSqlFragment = require('./eslint-rules/require-safe-sql-fragment') +const requireSafeSqlFragment = require('./eslint-rules/require-safe-sql-fragment.cjs') const studioPlugin = { rules: { diff --git a/apps/studio/instrumentation-client.ts b/apps/studio/instrumentation-client.ts index 300a361c859..b9b26d37d26 100644 --- a/apps/studio/instrumentation-client.ts +++ b/apps/studio/instrumentation-client.ts @@ -105,7 +105,7 @@ Sentry.init({ // Tag errors whose stack trace only contains third-party frames (browser extensions, // injected scripts, etc.). This uses build-time code annotation via the applicationKey - // in next.config.js to reliably distinguish our code from third-party code. + // in next.config.ts to reliably distinguish our code from third-party code. // We use 'apply-tag' instead of 'drop' so that beforeSend can exempt error boundary // crashes — these may originate in third-party code but are caused by first-party bugs. return [ diff --git a/apps/studio/next.config.js b/apps/studio/next.config.ts similarity index 90% rename from apps/studio/next.config.js rename to apps/studio/next.config.ts index 7b865278390..513ca4c3128 100644 --- a/apps/studio/next.config.js +++ b/apps/studio/next.config.ts @@ -1,11 +1,14 @@ -const { withSentryConfig } = require('@sentry/nextjs') -const withBundleAnalyzer = require('@next/bundle-analyzer')({ +/* eslint-disable no-restricted-exports */ + +import bundleAnalyzer from '@next/bundle-analyzer' +import { withSentryConfig } from '@sentry/nextjs' +import type { NextConfig } from 'next' + +import { getCSP } from './csp' + +const withBundleAnalyzer = bundleAnalyzer({ enabled: process.env.ANALYZE === 'true', }) -const { getCSP } = require('./csp') - -// Required for nextjs standalone build -const path = require('path') function getAssetPrefix() { // If not force enabled, but not production env, disable CDN @@ -23,13 +26,10 @@ function getAssetPrefix() { ? 'https://frontend-assets.supabase.green' : 'https://frontend-assets.supabase.com' - return `${SUPABASE_ASSETS_URL}/${process.env.SITE_NAME}/${process.env.VERCEL_GIT_COMMIT_SHA.substring(0, 12)}` + return `${SUPABASE_ASSETS_URL}/${process.env.SITE_NAME}/${process.env.VERCEL_GIT_COMMIT_SHA?.substring(0, 12) ?? 'unknown'}` } -/** - * @type {import('next').NextConfig} - */ -const nextConfig = { +const nextConfig: NextConfig = { basePath: process.env.NEXT_PUBLIC_BASE_PATH, assetPrefix: getAssetPrefix(), output: 'standalone', @@ -53,7 +53,7 @@ const nextConfig = { source: '/', has: [ { - type: 'query', + type: 'query' as const, key: 'next', value: 'new-project', }, @@ -468,7 +468,7 @@ const nextConfig = { { source: '/', destination: process.env.NEXT_PUBLIC_BASE_PATH, - basePath: false, + basePath: false as const, permanent: false, }, ] @@ -616,38 +616,34 @@ const nextConfig = { const platformConfig = process.env.NEXT_PUBLIC_IS_PLATFORM === 'true' ? withBundleAnalyzer(nextConfig) : nextConfig -module.exports = - process.env.NEXT_PUBLIC_IS_PLATFORM === 'true' && process.env.VERCEL === '1' - ? withSentryConfig(platformConfig, { - silent: true, +export default process.env.NEXT_PUBLIC_IS_PLATFORM === 'true' && process.env.VERCEL === '1' + ? withSentryConfig(platformConfig, { + silent: true, - // For all available options, see: - // https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/ + // For all available options, see: + // https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/ - // Upload a larger set of source maps for prettier stack traces (increases build time) - widenClientFileUpload: true, + // Upload a larger set of source maps for prettier stack traces (increases build time) + widenClientFileUpload: true, - // Automatically annotate React components to show their full name in breadcrumbs and session replay - reactComponentAnnotation: { - enabled: true, - }, + // Automatically annotate React components to show their full name in breadcrumbs and session replay + reactComponentAnnotation: { + enabled: true, + }, - // Hides source maps from generated client bundles - hideSourceMaps: true, + // Automatically tree-shake Sentry logger statements to reduce bundle size + disableLogger: true, - // Automatically tree-shake Sentry logger statements to reduce bundle size - disableLogger: true, + // Enables automatic instrumentation of Vercel Cron Monitors. (Does not yet work with App Router route handlers.) + // See the following for more information: + // https://docs.sentry.io/product/crons/ + // https://vercel.com/docs/cron-jobs + automaticVercelMonitors: true, - // Enables automatic instrumentation of Vercel Cron Monitors. (Does not yet work with App Router route handlers.) - // See the following for more information: - // https://docs.sentry.io/product/crons/ - // https://vercel.com/docs/cron-jobs - automaticVercelMonitors: true, - - // Annotate bundles at build time so thirdPartyErrorFilterIntegration can - // distinguish our code from browser extensions / injected scripts at runtime. - unstable_sentryWebpackPluginOptions: { - applicationKey: 'supabase-studio', - }, - }) - : platformConfig + // Annotate bundles at build time so thirdPartyErrorFilterIntegration can + // distinguish our code from browser extensions / injected scripts at runtime. + unstable_sentryWebpackPluginOptions: { + applicationKey: 'supabase-studio', + }, + }) + : platformConfig diff --git a/apps/studio/package.json b/apps/studio/package.json index f2fadd709f4..d734050b20d 100644 --- a/apps/studio/package.json +++ b/apps/studio/package.json @@ -2,6 +2,7 @@ "name": "studio", "version": "0.0.9", "private": true, + "type": "module", "scripts": { "preinstall": "npx only-allow pnpm", "dev": "next dev -p ${STUDIO_PORT:-8082}", diff --git a/apps/studio/postcss.config.js b/apps/studio/postcss.config.js index 08a01d4d167..2259daa8a9d 100644 --- a/apps/studio/postcss.config.js +++ b/apps/studio/postcss.config.js @@ -1,4 +1,7 @@ -module.exports = { +/* eslint-disable no-restricted-exports */ +/* eslint-disable import/no-anonymous-default-export */ + +export default { plugins: { tailwindcss: {}, }, diff --git a/apps/studio/tailwind.config.js b/apps/studio/tailwind.config.ts similarity index 94% rename from apps/studio/tailwind.config.js rename to apps/studio/tailwind.config.ts index 8d57ee1f28b..b0f9e40fc1d 100644 --- a/apps/studio/tailwind.config.js +++ b/apps/studio/tailwind.config.ts @@ -1,6 +1,9 @@ -const config = require('config/tailwind.config') +/* eslint-disable no-restricted-exports */ -module.exports = config({ +import containerQueries from '@tailwindcss/container-queries' +import tailwindConfig from 'config/tailwind.config' + +export default tailwindConfig({ content: [ './pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}', @@ -8,7 +11,7 @@ module.exports = config({ './../../packages/ui/src/**/*.{tsx,ts,js}', './../../packages/ui-patterns/src/**/*.{tsx,ts,js}', ], - plugins: [require('@tailwindcss/container-queries')], + plugins: [containerQueries], theme: { extend: { fontSize: { diff --git a/apps/studio/types/config.d.ts b/apps/studio/types/config.d.ts new file mode 100644 index 00000000000..c8ce1d21d56 --- /dev/null +++ b/apps/studio/types/config.d.ts @@ -0,0 +1,6 @@ +declare module 'config/tailwind.config' { + import type { Config } from 'tailwindcss' + const wrapper: (tailwindConfig: Partial) => Config + // eslint-disable-next-line no-restricted-exports + export default wrapper +}