├── supabase ├── seed.sql ├── .gitignore ├── functions │ ├── deno.json │ ├── .env.example │ └── certificate │ │ ├── env.ts │ │ └── README.md └── migrations │ ├── 20240810203851_remove_waitlist_delete_policy.sql │ ├── 20240909160000_pg_cron.sql │ ├── 20240807150202_rename_publish_waitlist.sql │ ├── 20241115093122_enable_rls_deployment_providers.sql │ ├── 20240909155000_expose_functions_certificate_secrets.sql │ └── 20240806202109_publish_waitlist.sql ├── apps ├── browser-proxy │ ├── .gitignore │ ├── src │ │ ├── pg-dump-middleware │ │ │ ├── constants.ts │ │ │ └── utils.ts │ │ ├── debug.ts │ │ ├── findhit-proxywrap.types.d.ts │ │ ├── extract-ip.ts │ │ ├── servername.ts │ │ ├── protocol.ts │ │ ├── index.ts │ │ ├── tls.ts │ │ ├── telemetry.ts │ │ ├── create-message.ts │ │ └── connection-manager.ts │ ├── Dockerfile │ ├── tsconfig.json │ ├── .env.example │ ├── package.json │ └── README.md ├── web │ ├── .gitignore │ ├── components │ │ ├── ai-icon-animation │ │ │ ├── index.tsx │ │ │ └── ai-icon-animation.tsx │ │ ├── framer-features.ts │ │ ├── ui │ │ │ ├── skeleton.tsx │ │ │ ├── textarea.tsx │ │ │ ├── label.tsx │ │ │ ├── separator.tsx │ │ │ ├── progress.tsx │ │ │ ├── input.tsx │ │ │ ├── switch.tsx │ │ │ ├── badge.tsx │ │ │ ├── tooltip.tsx │ │ │ ├── avatar.tsx │ │ │ ├── popover.tsx │ │ │ ├── button.tsx │ │ │ ├── tabs.tsx │ │ │ ├── accordion.tsx │ │ │ └── breadcrumb.tsx │ │ ├── theme-provider.tsx │ │ ├── schema │ │ │ ├── graph.tsx │ │ │ └── legend.tsx │ │ ├── layout │ │ │ └── header │ │ │ │ ├── menu-button.tsx │ │ │ │ ├── bring-your-own-llm-button.tsx │ │ │ │ ├── create-database-button.tsx │ │ │ │ ├── deploy-button │ │ │ │ ├── connect-supabase-tab.tsx │ │ │ │ ├── redeploy-supabase-tab.tsx │ │ │ │ └── deploy-supabase-tab.tsx │ │ │ │ ├── live-share-button.tsx │ │ │ │ ├── header.tsx │ │ │ │ ├── toggle-theme-button.tsx │ │ │ │ ├── extra-database-actions-button.tsx │ │ │ │ └── user.tsx │ │ ├── sign-in-button.tsx │ │ ├── deploy │ │ │ ├── deploy-failure-dialog.tsx │ │ │ ├── deploy-success-dialog.tsx │ │ │ ├── integration-dialog.tsx │ │ │ ├── schema-overlap-warning.tsx │ │ │ ├── deploy-info-dialog.tsx │ │ │ ├── redeploy-dialog.tsx │ │ │ └── deploy-info.tsx │ │ ├── tools │ │ │ ├── csv-import.tsx │ │ │ ├── sql-import.tsx │ │ │ ├── generated-embedding.tsx │ │ │ ├── conversation-rename.tsx │ │ │ ├── generated-chart.tsx │ │ │ ├── index.tsx │ │ │ ├── csv-export.tsx │ │ │ └── executed-sql.tsx │ │ ├── live-share-icon.tsx │ │ ├── model-provider │ │ │ └── use-model-provider.ts │ │ ├── providers.tsx │ │ ├── byo-llm-button.tsx │ │ ├── theme-dropdown.tsx │ │ ├── sidebar │ │ │ ├── database-menu-item.tsx │ │ │ ├── sign-in-dialog.tsx │ │ │ └── set-external-model-provider-button.tsx │ │ ├── copyable-field.tsx │ │ ├── supabase-icon.tsx │ │ ├── markdown-accordion.tsx │ │ ├── code-accordion.tsx │ │ ├── layout.tsx │ │ └── lines.tsx │ ├── app │ │ ├── favicon.ico │ │ ├── apple-icon.png │ │ ├── opengraph-image.png │ │ ├── (main) │ │ │ ├── layout.tsx │ │ │ └── db │ │ │ │ └── [id] │ │ │ │ └── page.tsx │ │ └── layout.tsx │ ├── public │ │ ├── images │ │ │ └── empty.png │ │ └── fonts │ │ │ ├── custom │ │ │ ├── CustomFont-Bold.woff │ │ │ ├── CustomFont-Book.woff │ │ │ ├── CustomFont-Black.woff │ │ │ ├── CustomFont-Black.woff2 │ │ │ ├── CustomFont-Bold.woff2 │ │ │ ├── CustomFont-Book.woff2 │ │ │ ├── CustomFont-Medium.woff │ │ │ ├── CustomFont-Medium.woff2 │ │ │ ├── CustomFont-BlackItalic.woff │ │ │ ├── CustomFont-BlackItalic.woff2 │ │ │ ├── CustomFont-BoldItalic.woff │ │ │ ├── CustomFont-BoldItalic.woff2 │ │ │ ├── CustomFont-BookItalic.woff │ │ │ └── CustomFont-BookItalic.woff2 │ │ │ └── source-code-pro │ │ │ ├── SourceCodePro-Regular.eot │ │ │ ├── SourceCodePro-Regular.ttf │ │ │ ├── SourceCodePro-Regular.woff │ │ │ └── SourceCodePro-Regular.woff2 │ ├── types │ │ └── highlightjs-curl.d.ts │ ├── lib │ │ ├── utils.ts │ │ ├── embed │ │ │ ├── worker.ts │ │ │ └── index.ts │ │ ├── llm-provider.ts │ │ ├── websocket-protocol.ts │ │ ├── use-breakpoint.ts │ │ ├── files.ts │ │ ├── db │ │ │ └── worker.ts │ │ ├── system-prompt.ts │ │ └── schema.ts │ ├── postcss.config.mjs │ ├── global.d.ts │ ├── docker-compose.yml │ ├── utils │ │ ├── supabase │ │ │ ├── client.ts │ │ │ ├── admin.ts │ │ │ ├── server.ts │ │ │ └── middleware.ts │ │ └── telemetry.ts │ ├── middleware.ts │ ├── components.json │ ├── vite.config.mts │ ├── hooks │ │ └── use-mobile.tsx │ ├── data │ │ ├── databases │ │ │ ├── databases-query.ts │ │ │ ├── database-query.ts │ │ │ ├── database-create-mutation.ts │ │ │ ├── database-delete-mutation.ts │ │ │ └── database-update-mutation.ts │ │ ├── messages │ │ │ ├── messages-query.ts │ │ │ └── message-create-mutation.ts │ │ ├── merged-databases │ │ │ ├── merged-databases.ts │ │ │ └── merged-database.ts │ │ ├── deploy-waitlist │ │ │ ├── deploy-waitlist-create-mutation.ts │ │ │ └── deploy-waitlist-query.ts │ │ ├── deployed-databases │ │ │ └── deployed-databases-query.ts │ │ ├── integrations │ │ │ └── integration-query.ts │ │ └── tables │ │ │ └── tables-query.ts │ ├── tsconfig.json │ ├── .env.example │ ├── assets │ │ └── github-icon.tsx │ ├── next.config.mjs │ ├── sw.ts │ ├── README.md │ ├── polyfills │ │ └── readable-stream.ts │ └── config │ │ └── default-colors.js └── deploy-worker │ ├── tsconfig.json │ ├── README.md │ ├── .env.example │ ├── .gitignore │ ├── Dockerfile │ ├── package.json │ └── src │ └── index.ts ├── .npmrc ├── packages └── deploy │ ├── src │ ├── index.ts │ ├── error.ts │ └── supabase │ │ ├── schemas.ts │ │ ├── index.ts │ │ ├── generate-password.ts │ │ ├── management-api │ │ └── client.ts │ │ ├── revoke-integration.ts │ │ ├── get-database-url.ts │ │ ├── types.ts │ │ └── get-access-token.ts │ ├── tsconfig.json │ ├── tsup.config.ts │ └── package.json ├── .eslintrc.json ├── .dockerignore ├── vercel.json ├── .vscode ├── extensions.json └── settings.json ├── .env.example ├── package.json ├── fly.deploy-worker.toml ├── .prettierrc ├── fly.browser-proxy.toml ├── .gitignore ├── .github └── workflows │ └── run-migrations.yml └── turbo.json /supabase/seed.sql: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/browser-proxy/.gitignore: -------------------------------------------------------------------------------- 1 | tls -------------------------------------------------------------------------------- /apps/web/.gitignore: -------------------------------------------------------------------------------- 1 | public/sw.mjs -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | @jsr:registry=https://npm.jsr.io 2 | -------------------------------------------------------------------------------- /packages/deploy/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './error.js' 2 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /supabase/.gitignore: -------------------------------------------------------------------------------- 1 | # Supabase 2 | .branches 3 | .temp 4 | .env 5 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | **/.next 3 | **/.turbo 4 | **/.env* 5 | -------------------------------------------------------------------------------- /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "buildCommand": "DO_NOT_TRACK=1 turbo build" 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["denoland.vscode-deno"] 3 | } 4 | -------------------------------------------------------------------------------- /apps/web/components/ai-icon-animation/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './ai-icon-animation' 2 | -------------------------------------------------------------------------------- /supabase/functions/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@database-build/supabase-functions" 3 | } 4 | -------------------------------------------------------------------------------- /apps/web/components/framer-features.ts: -------------------------------------------------------------------------------- 1 | import { domMax } from 'framer-motion' 2 | export default domMax 3 | -------------------------------------------------------------------------------- /apps/web/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supabase-community/database-build/HEAD/apps/web/app/favicon.ico -------------------------------------------------------------------------------- /apps/web/app/apple-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supabase-community/database-build/HEAD/apps/web/app/apple-icon.png -------------------------------------------------------------------------------- /apps/browser-proxy/src/pg-dump-middleware/constants.ts: -------------------------------------------------------------------------------- 1 | export const VECTOR_OID = 99999 2 | export const FIRST_NORMAL_OID = 16384 3 | -------------------------------------------------------------------------------- /apps/web/app/opengraph-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supabase-community/database-build/HEAD/apps/web/app/opengraph-image.png -------------------------------------------------------------------------------- /apps/web/public/images/empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supabase-community/database-build/HEAD/apps/web/public/images/empty.png -------------------------------------------------------------------------------- /apps/web/types/highlightjs-curl.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'highlightjs-curl' { 2 | const languageFunc: any 3 | export = languageFunc 4 | } 5 | -------------------------------------------------------------------------------- /apps/web/public/fonts/custom/CustomFont-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supabase-community/database-build/HEAD/apps/web/public/fonts/custom/CustomFont-Bold.woff -------------------------------------------------------------------------------- /apps/web/public/fonts/custom/CustomFont-Book.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supabase-community/database-build/HEAD/apps/web/public/fonts/custom/CustomFont-Book.woff -------------------------------------------------------------------------------- /supabase/migrations/20240810203851_remove_waitlist_delete_policy.sql: -------------------------------------------------------------------------------- 1 | drop policy if exists "Users can only delete their own waitlist record." on public.deploy_waitlist; -------------------------------------------------------------------------------- /apps/web/public/fonts/custom/CustomFont-Black.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supabase-community/database-build/HEAD/apps/web/public/fonts/custom/CustomFont-Black.woff -------------------------------------------------------------------------------- /apps/web/public/fonts/custom/CustomFont-Black.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supabase-community/database-build/HEAD/apps/web/public/fonts/custom/CustomFont-Black.woff2 -------------------------------------------------------------------------------- /apps/web/public/fonts/custom/CustomFont-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supabase-community/database-build/HEAD/apps/web/public/fonts/custom/CustomFont-Bold.woff2 -------------------------------------------------------------------------------- /apps/web/public/fonts/custom/CustomFont-Book.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supabase-community/database-build/HEAD/apps/web/public/fonts/custom/CustomFont-Book.woff2 -------------------------------------------------------------------------------- /apps/web/public/fonts/custom/CustomFont-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supabase-community/database-build/HEAD/apps/web/public/fonts/custom/CustomFont-Medium.woff -------------------------------------------------------------------------------- /apps/web/public/fonts/custom/CustomFont-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supabase-community/database-build/HEAD/apps/web/public/fonts/custom/CustomFont-Medium.woff2 -------------------------------------------------------------------------------- /apps/browser-proxy/src/debug.ts: -------------------------------------------------------------------------------- 1 | import createDebug from 'debug' 2 | 3 | createDebug.formatters.e = (fn) => fn() 4 | 5 | export const debug = createDebug('browser-proxy') 6 | -------------------------------------------------------------------------------- /apps/web/public/fonts/custom/CustomFont-BlackItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supabase-community/database-build/HEAD/apps/web/public/fonts/custom/CustomFont-BlackItalic.woff -------------------------------------------------------------------------------- /apps/web/public/fonts/custom/CustomFont-BlackItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supabase-community/database-build/HEAD/apps/web/public/fonts/custom/CustomFont-BlackItalic.woff2 -------------------------------------------------------------------------------- /apps/web/public/fonts/custom/CustomFont-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supabase-community/database-build/HEAD/apps/web/public/fonts/custom/CustomFont-BoldItalic.woff -------------------------------------------------------------------------------- /apps/web/public/fonts/custom/CustomFont-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supabase-community/database-build/HEAD/apps/web/public/fonts/custom/CustomFont-BoldItalic.woff2 -------------------------------------------------------------------------------- /apps/web/public/fonts/custom/CustomFont-BookItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supabase-community/database-build/HEAD/apps/web/public/fonts/custom/CustomFont-BookItalic.woff -------------------------------------------------------------------------------- /apps/web/public/fonts/custom/CustomFont-BookItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supabase-community/database-build/HEAD/apps/web/public/fonts/custom/CustomFont-BookItalic.woff2 -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | SUPABASE_AUTH_GITHUB_CLIENT_ID=github-client-id 2 | SUPABASE_AUTH_GITHUB_SECRET=github-secret 3 | SUPABASE_AUTH_GITHUB_REDIRECT_URI=http://localhost:54321/auth/v1/callback 4 | -------------------------------------------------------------------------------- /apps/web/public/fonts/source-code-pro/SourceCodePro-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supabase-community/database-build/HEAD/apps/web/public/fonts/source-code-pro/SourceCodePro-Regular.eot -------------------------------------------------------------------------------- /apps/web/public/fonts/source-code-pro/SourceCodePro-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supabase-community/database-build/HEAD/apps/web/public/fonts/source-code-pro/SourceCodePro-Regular.ttf -------------------------------------------------------------------------------- /apps/web/public/fonts/source-code-pro/SourceCodePro-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supabase-community/database-build/HEAD/apps/web/public/fonts/source-code-pro/SourceCodePro-Regular.woff -------------------------------------------------------------------------------- /apps/web/public/fonts/source-code-pro/SourceCodePro-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supabase-community/database-build/HEAD/apps/web/public/fonts/source-code-pro/SourceCodePro-Regular.woff2 -------------------------------------------------------------------------------- /supabase/migrations/20240909160000_pg_cron.sql: -------------------------------------------------------------------------------- 1 | create extension pg_cron with schema extensions; 2 | grant usage on schema cron to postgres; 3 | grant all privileges on all tables in schema cron to postgres; -------------------------------------------------------------------------------- /apps/browser-proxy/src/findhit-proxywrap.types.d.ts: -------------------------------------------------------------------------------- 1 | module 'findhit-proxywrap' { 2 | const module = { 3 | proxy: (net: typeof import('node:net')) => typeof net, 4 | } 5 | export default module 6 | } 7 | -------------------------------------------------------------------------------- /apps/web/lib/utils.ts: -------------------------------------------------------------------------------- 1 | import { type ClassValue, clsx } from "clsx" 2 | import { twMerge } from "tailwind-merge" 3 | 4 | export function cn(...inputs: ClassValue[]) { 5 | return twMerge(clsx(inputs)) 6 | } 7 | -------------------------------------------------------------------------------- /packages/deploy/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@total-typescript/tsconfig/tsc/no-dom/app", 3 | "include": ["src/**/*.ts"], 4 | "compilerOptions": { 5 | "noEmit": true, 6 | "outDir": "dist" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /apps/web/postcss.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('postcss-load-config').Config} */ 2 | const config = { 3 | plugins: { 4 | tailwindcss: {}, 5 | autoprefixer: {}, 6 | }, 7 | } 8 | 9 | export default config 10 | -------------------------------------------------------------------------------- /supabase/migrations/20240807150202_rename_publish_waitlist.sql: -------------------------------------------------------------------------------- 1 | alter table public.publish_waitlist 2 | rename to deploy_waitlist; 3 | 4 | alter table public.deploy_waitlist rename constraint publish_waitlist_user_id_fkey to deploy_waitlist_user_id_fkey; -------------------------------------------------------------------------------- /apps/web/app/(main)/layout.tsx: -------------------------------------------------------------------------------- 1 | import Layout from '~/components/layout' 2 | 3 | export default function MainLayout({ 4 | children, 5 | }: Readonly<{ 6 | children: React.ReactNode 7 | }>) { 8 | return {children} 9 | } 10 | -------------------------------------------------------------------------------- /apps/web/global.d.ts: -------------------------------------------------------------------------------- 1 | declare interface ReadableStream extends AsyncIterable { 2 | values(options?: ReadableStreamIteratorOptions): AsyncIterator 3 | [Symbol.asyncIterator](options?: ReadableStreamIteratorOptions): AsyncIterator 4 | } 5 | -------------------------------------------------------------------------------- /apps/browser-proxy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:22-alpine 2 | 3 | WORKDIR /app 4 | 5 | COPY --link package.json ./ 6 | COPY --link src/ ./src/ 7 | 8 | RUN npm install 9 | 10 | EXPOSE 443 11 | EXPOSE 5432 12 | 13 | CMD ["node", "--experimental-strip-types", "src/index.ts"] -------------------------------------------------------------------------------- /apps/browser-proxy/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@total-typescript/tsconfig/tsc/no-dom/app", 3 | "include": ["src/**/*.ts"], 4 | "compilerOptions": { 5 | "noEmit": true, 6 | "allowImportingTsExtensions": true, 7 | "outDir": "dist" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /apps/deploy-worker/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@total-typescript/tsconfig/tsc/no-dom/app", 3 | "include": ["src/**/*.ts"], 4 | "compilerOptions": { 5 | "allowImportingTsExtensions": true, 6 | "noEmit": true, 7 | "outDir": "dist" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /apps/deploy-worker/README.md: -------------------------------------------------------------------------------- 1 | ## Development 2 | 3 | Copy the `.env.example` file to `.env` and set the correct environment variables. 4 | 5 | Run the dev server from the monorepo root. See [Development](../../README.md#development). 6 | 7 | The deploy worker will be listening on port `4000` (HTTP). 8 | -------------------------------------------------------------------------------- /apps/web/docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | redis: 3 | image: redis 4 | local-vercel-kv: 5 | image: hiett/serverless-redis-http:latest 6 | ports: 7 | - 8080:80 8 | environment: 9 | SRH_MODE: env 10 | SRH_TOKEN: local_token 11 | SRH_CONNECTION_STRING: redis://redis:6379 12 | -------------------------------------------------------------------------------- /apps/web/utils/supabase/client.ts: -------------------------------------------------------------------------------- 1 | import { createBrowserClient } from '@supabase/ssr' 2 | import { Database } from './db-types' 3 | 4 | export function createClient() { 5 | return createBrowserClient( 6 | process.env.NEXT_PUBLIC_SUPABASE_URL!, 7 | process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! 8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /packages/deploy/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup' 2 | 3 | export default defineConfig([ 4 | { 5 | entry: ['src/index.ts', 'src/supabase/index.ts'], 6 | format: ['cjs', 'esm'], 7 | outDir: 'dist', 8 | sourcemap: true, 9 | dts: true, 10 | minify: true, 11 | splitting: true, 12 | }, 13 | ]) 14 | -------------------------------------------------------------------------------- /apps/web/utils/supabase/admin.ts: -------------------------------------------------------------------------------- 1 | import { createClient as createSupabaseClient } from '@supabase/supabase-js' 2 | import { Database } from './db-types' 3 | 4 | export function createClient() { 5 | return createSupabaseClient( 6 | process.env.NEXT_PUBLIC_SUPABASE_URL!, 7 | process.env.SUPABASE_SERVICE_ROLE_KEY! 8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /apps/web/components/ui/skeleton.tsx: -------------------------------------------------------------------------------- 1 | import { cn } from "~/lib/utils" 2 | 3 | function Skeleton({ 4 | className, 5 | ...props 6 | }: React.HTMLAttributes) { 7 | return ( 8 |
12 | ) 13 | } 14 | 15 | export { Skeleton } 16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@database.build/root", 3 | "private": true, 4 | "packageManager": "npm@10.8.3", 5 | "scripts": { 6 | "dev": "turbo watch dev", 7 | "build": "turbo run build" 8 | }, 9 | "workspaces": ["apps/*", "packages/*"], 10 | "devDependencies": { 11 | "supabase": "^2.0.0", 12 | "turbo": "^2.3.2" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /fly.deploy-worker.toml: -------------------------------------------------------------------------------- 1 | primary_region = 'iad' 2 | 3 | [build] 4 | dockerfile = "./apps/deploy-worker/Dockerfile" 5 | 6 | [http_service] 7 | internal_port = 4000 8 | force_https = true 9 | auto_stop_machines = "suspend" 10 | auto_start_machines = true 11 | min_machines_running = 0 12 | 13 | [[vm]] 14 | memory = '512mb' 15 | cpu_kind = 'shared' 16 | cpus = 1 17 | -------------------------------------------------------------------------------- /supabase/functions/.env.example: -------------------------------------------------------------------------------- 1 | ACME_DIRECTORY_URL=https://acme-staging-v02.api.letsencrypt.org/directory 2 | ACME_EMAIL="" 3 | AWS_ACCESS_KEY_ID="" 4 | AWS_ENDPOINT_URL_S3=http://172.17.0.1:54321/storage/v1/s3 5 | AWS_S3_BUCKET=storage 6 | AWS_SECRET_ACCESS_KEY="" 7 | AWS_REGION=local 8 | CLOUDFLARE_API_TOKEN="" -------------------------------------------------------------------------------- /supabase/migrations/20241115093122_enable_rls_deployment_providers.sql: -------------------------------------------------------------------------------- 1 | -- Enable RLS on deployment_providers to dismiss security warnings 2 | alter table deployment_providers enable row level security; 3 | 4 | -- RLS allow all policy for deployment_providers 5 | create policy "Allow all operations on deployment_providers" 6 | on deployment_providers 7 | for all 8 | using (true); 9 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "tabWidth": 2, 4 | "semi": false, 5 | "singleQuote": true, 6 | "printWidth": 100, 7 | "endOfLine": "lf", 8 | "sqlKeywordCase": "lower", 9 | "pluginSearchDirs": false, 10 | "overrides": [ 11 | { 12 | "files": "**/*.json", 13 | "options": { 14 | "parser": "json" 15 | } 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /apps/web/components/theme-provider.tsx: -------------------------------------------------------------------------------- 1 | 'use client' 2 | 3 | import * as React from 'react' 4 | import { ThemeProvider as NextThemesProvider } from 'next-themes' 5 | import { type ThemeProviderProps } from 'next-themes/dist/types' 6 | 7 | export function ThemeProvider({ children, ...props }: ThemeProviderProps) { 8 | return {children} 9 | } 10 | -------------------------------------------------------------------------------- /apps/web/middleware.ts: -------------------------------------------------------------------------------- 1 | import { NextRequest } from 'next/server' 2 | import { updateSession } from '~/utils/supabase/middleware' 3 | 4 | export async function middleware(request: NextRequest) { 5 | return await updateSession(request) 6 | } 7 | 8 | export const config = { 9 | matcher: [ 10 | /* 11 | * Middleware only runs on API routes. 12 | */ 13 | '/api/:path*', 14 | ], 15 | } 16 | -------------------------------------------------------------------------------- /apps/deploy-worker/.env.example: -------------------------------------------------------------------------------- 1 | SUPABASE_ANON_KEY="" 2 | SUPABASE_OAUTH_CLIENT_ID="" 3 | SUPABASE_OAUTH_SECRET="" 4 | SUPABASE_SERVICE_ROLE_KEY="" 5 | SUPABASE_URL="" 6 | SUPABASE_PLATFORM_URL="https://supabase.com" 7 | SUPABASE_PLATFORM_API_URL="https://api.supabase.com" 8 | SUPABASE_PLATFORM_DEPLOY_REGION="us-east-1" 9 | -------------------------------------------------------------------------------- /apps/web/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": true, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.ts", 8 | "css": "app/globals.css", 9 | "baseColor": "neutral", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "~/components", 15 | "utils": "~/lib/utils" 16 | } 17 | } -------------------------------------------------------------------------------- /apps/browser-proxy/src/extract-ip.ts: -------------------------------------------------------------------------------- 1 | import { isIPv4 } from 'node:net' 2 | 3 | export function extractIP(address: string): string { 4 | if (isIPv4(address)) { 5 | return address 6 | } 7 | 8 | // Check if it's an IPv4-mapped IPv6 address 9 | const ipv4 = address.match(/::ffff:(\d+\.\d+\.\d+\.\d+)/) 10 | if (ipv4) { 11 | return ipv4[1]! 12 | } 13 | 14 | // We assume it's an IPv6 address 15 | return address 16 | } 17 | -------------------------------------------------------------------------------- /apps/browser-proxy/.env.example: -------------------------------------------------------------------------------- 1 | AWS_ACCESS_KEY_ID="" 2 | AWS_ENDPOINT_URL_S3="" 3 | AWS_S3_BUCKET=storage 4 | AWS_SECRET_ACCESS_KEY="" 5 | AWS_REGION=us-east-1 6 | LOGFLARE_SOURCE_URL="" 7 | # enable PROXY protocol support 8 | #PROXIED=true 9 | SUPABASE_URL="" 10 | SUPABASE_ANON_KEY="" 11 | WILDCARD_DOMAIN=browser.staging.db.build 12 | -------------------------------------------------------------------------------- /apps/deploy-worker/.gitignore: -------------------------------------------------------------------------------- 1 | # dev 2 | .yarn/ 3 | !.yarn/releases 4 | .vscode/* 5 | !.vscode/launch.json 6 | !.vscode/*.code-snippets 7 | .idea/workspace.xml 8 | .idea/usage.statistics.xml 9 | .idea/shelf 10 | 11 | # deps 12 | node_modules/ 13 | 14 | # env 15 | .env 16 | .env.production 17 | 18 | # logs 19 | logs/ 20 | *.log 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | pnpm-debug.log* 25 | lerna-debug.log* 26 | 27 | # misc 28 | .DS_Store 29 | -------------------------------------------------------------------------------- /packages/deploy/src/error.ts: -------------------------------------------------------------------------------- 1 | export class DeployError extends Error { 2 | constructor(message: string, options?: ErrorOptions) { 3 | super(message, options) 4 | } 5 | } 6 | 7 | export class IntegrationRevokedError extends Error { 8 | constructor(options?: ErrorOptions) { 9 | super( 10 | 'Your Supabase integration has been revoked. Please retry to restore your integration.', 11 | options 12 | ) 13 | this.name = 'IntegrationRevokedError' 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/deploy/src/supabase/schemas.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Supabase built-in schemas that will be excluded from the 3 | * deployment if they exist in the source database. 4 | */ 5 | export const SUPABASE_SCHEMAS = [ 6 | 'auth', 7 | 'cron', 8 | 'extensions', 9 | 'graphql', 10 | 'graphql_public', 11 | 'net', 12 | 'pgbouncer', 13 | 'pgsodium', 14 | 'pgsodium_masks', 15 | 'realtime', 16 | 'storage', 17 | 'supabase_functions', 18 | 'supabase_migrations', 19 | 'vault', 20 | ] 21 | -------------------------------------------------------------------------------- /packages/deploy/src/supabase/index.ts: -------------------------------------------------------------------------------- 1 | export * from './create-deployed-database.js' 2 | export * from './generate-password.js' 3 | export * from './get-access-token.js' 4 | export * from './get-database-url.js' 5 | export * from './revoke-integration.js' 6 | export * from './wait-for-health.js' 7 | export * from './database-types.js' 8 | export * from './schemas.js' 9 | export * from './types.js' 10 | 11 | export * from './management-api/client.js' 12 | export * from './management-api/types.js' 13 | -------------------------------------------------------------------------------- /fly.browser-proxy.toml: -------------------------------------------------------------------------------- 1 | primary_region = 'iad' 2 | 3 | [build] 4 | dockerfile = "./apps/browser-proxy/Dockerfile" 5 | 6 | [[services]] 7 | internal_port = 5432 8 | protocol = "tcp" 9 | [[services.ports]] 10 | handlers = ["proxy_proto"] 11 | port = 5432 12 | 13 | [[services]] 14 | internal_port = 443 15 | protocol = "tcp" 16 | [[services.ports]] 17 | port = 443 18 | 19 | [[restart]] 20 | policy = "always" 21 | retries = 10 22 | 23 | [[vm]] 24 | memory = '512mb' 25 | cpu_kind = 'shared' 26 | cpus = 1 27 | -------------------------------------------------------------------------------- /packages/deploy/src/supabase/generate-password.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Generate a random password with a length of 16 characters. 3 | */ 4 | export function generatePassword(): string { 5 | const charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' 6 | const length = 16 7 | const randomValues = new Uint8Array(length) 8 | crypto.getRandomValues(randomValues) 9 | 10 | return Array.from(randomValues) 11 | .map((value) => charset[value % charset.length]) 12 | .join('') 13 | } 14 | -------------------------------------------------------------------------------- /apps/web/components/schema/graph.tsx: -------------------------------------------------------------------------------- 1 | import { ReactFlowProvider } from 'reactflow' 2 | import 'reactflow/dist/style.css' 3 | 4 | import TablesGraph from './table-graph' 5 | 6 | export type SchemaGraphProps = { 7 | databaseId: string 8 | schemas: string[] 9 | } 10 | 11 | export default function SchemaGraph({ databaseId, schemas }: SchemaGraphProps) { 12 | return ( 13 | 14 | 15 | 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /apps/web/components/layout/header/menu-button.tsx: -------------------------------------------------------------------------------- 1 | import { MenuIcon } from 'lucide-react' 2 | import { useApp } from '~/components/app-provider' 3 | import Sidebar from '~/components/sidebar' 4 | import { Button } from '~/components/ui/button' 5 | 6 | export function MenuButton() { 7 | const { showSidebar, setShowSidebar } = useApp() 8 | 9 | return ( 10 | <> 11 | 14 | 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /apps/web/lib/embed/worker.ts: -------------------------------------------------------------------------------- 1 | import { FeatureExtractionPipelineOptions, pipeline } from '@xenova/transformers' 2 | import * as Comlink from 'comlink' 3 | 4 | const embedPromise = pipeline('feature-extraction', 'supabase/gte-small', { 5 | quantized: true, 6 | }) 7 | 8 | export async function embed( 9 | texts: string[], 10 | options?: FeatureExtractionPipelineOptions 11 | ): Promise { 12 | const embedFn = await embedPromise 13 | const tensor = await embedFn(texts, options) 14 | return tensor.tolist() 15 | } 16 | 17 | Comlink.expose(embed) 18 | -------------------------------------------------------------------------------- /apps/web/components/sign-in-button.tsx: -------------------------------------------------------------------------------- 1 | import GitHubIcon from '~/assets/github-icon' 2 | import { useApp } from './app-provider' 3 | import { Button } from './ui/button' 4 | 5 | export default function SignInButton() { 6 | const { signIn } = useApp() 7 | return ( 8 | 17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /supabase/functions/certificate/env.ts: -------------------------------------------------------------------------------- 1 | import { z } from 'https://deno.land/x/zod@v3.23.8/mod.ts' 2 | 3 | export const env = z 4 | .object({ 5 | ACME_DIRECTORY_URL: z.string(), 6 | ACME_EMAIL: z.string(), 7 | AWS_ACCESS_KEY_ID: z.string(), 8 | AWS_ENDPOINT_URL_S3: z.string(), 9 | AWS_S3_BUCKET: z.string(), 10 | AWS_SECRET_ACCESS_KEY: z.string(), 11 | AWS_REGION: z.string(), 12 | CLOUDFLARE_API_TOKEN: z.string(), 13 | SUPABASE_SERVICE_ROLE_KEY: z.string(), 14 | SUPABASE_URL: z.string(), 15 | }) 16 | .parse(Deno.env.toObject()) 17 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "deno.enablePaths": ["supabase/functions"], 3 | "deno.lint": true, 4 | "deno.unstable": true, 5 | "[javascript]": { 6 | "editor.defaultFormatter": "esbenp.prettier-vscode" 7 | }, 8 | "[json]": { 9 | "editor.defaultFormatter": "esbenp.prettier-vscode" 10 | }, 11 | "[jsonc]": { 12 | "editor.defaultFormatter": "esbenp.prettier-vscode" 13 | }, 14 | "[typescript]": { 15 | "editor.defaultFormatter": "esbenp.prettier-vscode" 16 | }, 17 | "[typescriptreact]": { 18 | "editor.defaultFormatter": "esbenp.prettier-vscode" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /apps/web/components/layout/header/bring-your-own-llm-button.tsx: -------------------------------------------------------------------------------- 1 | import { BrainIcon } from 'lucide-react' 2 | import { useApp } from '~/components/app-provider' 3 | import { Button } from '~/components/ui/button' 4 | 5 | export function BringYourOwnLLMButton() { 6 | const { modelProvider } = useApp() 7 | 8 | const modelName = modelProvider.state?.model.split('/').at(-1) 9 | const text = modelProvider.state?.enabled ? modelName : 'Bring your own LLM' 10 | 11 | return ( 12 | 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /apps/web/vite.config.mts: -------------------------------------------------------------------------------- 1 | import { fileURLToPath } from 'node:url' 2 | import { defineConfig } from 'vite' 3 | 4 | export default defineConfig({ 5 | define: { 6 | 'process.env': {}, 7 | }, 8 | resolve: { 9 | alias: { 10 | '~': fileURLToPath(new URL('.', import.meta.url)), 11 | }, 12 | }, 13 | build: { 14 | lib: { 15 | entry: fileURLToPath(new URL('sw.ts', import.meta.url)), 16 | fileName: 'sw', 17 | formats: ['es'], 18 | }, 19 | outDir: fileURLToPath(new URL('public', import.meta.url)), 20 | emptyOutDir: false, 21 | copyPublicDir: false, 22 | }, 23 | }) 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | node_modules 5 | .pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | coverage 11 | 12 | # next.js 13 | .next/ 14 | out/ 15 | 16 | # production 17 | build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | *.srl 23 | 24 | # debug 25 | npm-debug.log* 26 | yarn-debug.log* 27 | yarn-error.log* 28 | 29 | # local env files 30 | .env*.local 31 | 32 | # vercel 33 | .vercel 34 | 35 | # typescript 36 | *.tsbuildinfo 37 | next-env.d.ts 38 | 39 | dbs/ 40 | tls/ 41 | dist/ 42 | 43 | .env 44 | .turbo 45 | -------------------------------------------------------------------------------- /apps/browser-proxy/src/servername.ts: -------------------------------------------------------------------------------- 1 | const WILDCARD_DOMAIN = process.env.WILDCARD_DOMAIN ?? 'browser.db.build' 2 | 3 | // Escape any dots in the domain since dots are special characters in regex 4 | const escapedDomain = WILDCARD_DOMAIN.replace(/\./g, '\\.') 5 | 6 | // Create the regex pattern dynamically 7 | const regexPattern = new RegExp(`^([^.]+)\\.${escapedDomain}$`) 8 | 9 | export function extractDatabaseId(servername: string): string { 10 | const match = servername.match(regexPattern) 11 | return match![1]! 12 | } 13 | 14 | export function isValidServername(servername: string): boolean { 15 | return regexPattern.test(servername) 16 | } 17 | -------------------------------------------------------------------------------- /apps/web/hooks/use-mobile.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | const MOBILE_BREAKPOINT = 768 4 | 5 | export function useIsMobile() { 6 | const [isMobile, setIsMobile] = React.useState(undefined) 7 | 8 | React.useEffect(() => { 9 | const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`) 10 | const onChange = () => { 11 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) 12 | } 13 | mql.addEventListener("change", onChange) 14 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT) 15 | return () => mql.removeEventListener("change", onChange) 16 | }, []) 17 | 18 | return !!isMobile 19 | } 20 | -------------------------------------------------------------------------------- /apps/web/components/layout/header/create-database-button.tsx: -------------------------------------------------------------------------------- 1 | import { PackagePlusIcon } from 'lucide-react' 2 | import Link from 'next/link' 3 | import { Button } from '~/components/ui/button' 4 | import { Tooltip, TooltipContent, TooltipTrigger } from '~/components/ui/tooltip' 5 | 6 | export function CreateDatabaseButton() { 7 | return ( 8 | 9 | 10 | 15 | 16 | New database 17 | 18 | ) 19 | } 20 | -------------------------------------------------------------------------------- /supabase/migrations/20240909155000_expose_functions_certificate_secrets.sql: -------------------------------------------------------------------------------- 1 | create function supabase_url() 2 | returns text 3 | language plpgsql 4 | security definer 5 | as $$ 6 | declare 7 | secret_value text; 8 | begin 9 | select decrypted_secret into secret_value from vault.decrypted_secrets where name = 'supabase_url'; 10 | return secret_value; 11 | end; 12 | $$; 13 | 14 | create function supabase_functions_certificate_secret() 15 | returns text 16 | language plpgsql 17 | security definer 18 | as $$ 19 | declare 20 | secret_value text; 21 | begin 22 | select decrypted_secret into secret_value from vault.decrypted_secrets where name = 'supabase_functions_certificate_secret'; 23 | return secret_value; 24 | end; 25 | $$; -------------------------------------------------------------------------------- /apps/web/data/databases/databases-query.ts: -------------------------------------------------------------------------------- 1 | import { UseQueryOptions, useQuery } from '@tanstack/react-query' 2 | import { useApp } from '~/components/app-provider' 3 | import { Database } from '~/lib/db' 4 | 5 | export const useDatabasesQuery = ( 6 | options: Omit, 'queryKey' | 'queryFn'> = {} 7 | ) => { 8 | const { dbManager } = useApp() 9 | 10 | return useQuery({ 11 | ...options, 12 | queryKey: getDatabasesQueryKey(), 13 | queryFn: async () => { 14 | if (!dbManager) { 15 | throw new Error('dbManager is not available') 16 | } 17 | return await dbManager.getDatabases() 18 | }, 19 | staleTime: Infinity, 20 | }) 21 | } 22 | 23 | export const getDatabasesQueryKey = () => ['databases'] 24 | -------------------------------------------------------------------------------- /apps/web/lib/llm-provider.ts: -------------------------------------------------------------------------------- 1 | const providerUrlMap = new Map([ 2 | ['openai', 'https://api.openai.com/v1'], 3 | ['x-ai', 'https://api.x.ai/v1'], 4 | ['openrouter', 'https://openrouter.ai/api/v1'], 5 | ] as const) 6 | 7 | type MapKeys = T extends Map ? K : never 8 | 9 | export type Provider = MapKeys 10 | 11 | export function getProviderUrl(provider: Provider) { 12 | const url = providerUrlMap.get(provider) 13 | 14 | if (!url) { 15 | throw new Error(`unknown provider: ${provider}`) 16 | } 17 | 18 | return url 19 | } 20 | 21 | export function getProviderId(apiUrl: string): Provider | undefined { 22 | for (const [key, value] of providerUrlMap.entries()) { 23 | if (value === apiUrl) { 24 | return key 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /apps/web/components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react" 2 | 3 | import { cn } from "~/lib/utils" 4 | 5 | const Textarea = React.forwardRef< 6 | HTMLTextAreaElement, 7 | React.ComponentProps<"textarea"> 8 | >(({ className, ...props }, ref) => { 9 | return ( 10 |