diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts
new file mode 100644
index 00000000000..38ef02e1244
--- /dev/null
+++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts
@@ -0,0 +1,435 @@
+// import SupabaseJsV1Nav from 'data/nav/supabase-js/v1'
+// import SupabaseJsV2Nav from 'data/nav/supabase-js/v2'
+// import SupabaseDartV0Nav from 'data/nav/supabase-dart/v0'
+// import SupabaseDartV1Nav from 'data/nav/supabase-dart/v1'
+// import SupabaseCLINav from 'data/nav/supabase-cli'
+// import SupabaseAPINav from 'data/nav/supabase-api'
+// import AuthServerNav from 'data/nav/auth-server'
+// import StorageServerNav from 'data/nav/storage-server'
+
+import { NavMenu, References } from '../Navigation.types'
+
+export const REFERENCES: References = {
+ javascript: {
+ name: 'supabase-js',
+ library: 'supabase-js',
+ versions: ['v2', 'v1'],
+ icon: '/docs/img/libraries/javascript-icon.svg',
+ },
+ dart: {
+ name: 'Flutter',
+ library: 'supabase-dart',
+ versions: ['v1', 'v0'],
+ icon: '/docs/img/libraries/flutter-icon.svg',
+ },
+ cli: {
+ name: 'CLI',
+ library: undefined,
+ versions: [],
+ icon: '/docs/img/icons/cli-icon.svg',
+ },
+ api: {
+ name: 'API',
+ library: undefined,
+ versions: [],
+ icon: '/docs/img/icons/api-icon.svg',
+ },
+}
+
+export const gettingstarted = {
+ label: 'Overview',
+ items: [
+ { name: 'Introduction', url: '/', items: [] },
+ { name: 'Features', url: '/features', items: [] },
+ { name: 'Architecture', url: '/architecture', items: [] },
+ ],
+}
+
+export const tutorials = {
+ label: 'Quickstarts',
+ items: [
+ { name: 'Angular', url: '/guides/with-angular', items: [] },
+ { name: 'Expo', url: '/guides/with-expo', items: [] },
+ { name: 'Flutter', url: '/guides/with-flutter', items: [] },
+ { name: 'Ionic Angular', url: '/guides/with-ionic-angular', items: [] },
+ { name: 'Ionic React', url: '/guides/with-ionic-react', items: [] },
+ { name: 'Ionic Vue', url: '/guides/with-ionic-vue', items: [] },
+ { name: 'Next.js', url: '/guides/with-nextjs', items: [] },
+ { name: 'Nuxt 3', url: '/guides/with-nuxt-3', items: [] },
+ { name: 'React', url: '/guides/with-react', items: [] },
+ { name: 'RedwoodJS', url: '/guides/with-redwoodjs', items: [] },
+ { name: 'SolidJS', url: '/guides/with-solidjs', items: [] },
+ { name: 'Svelte', url: '/guides/with-svelte', items: [] },
+ { name: 'SvelteKit', url: '/guides/with-sveltekit', items: [] },
+ { name: 'Vue 3', url: '/guides/with-vue-3', items: [] },
+ ],
+}
+export const cli = {
+ label: 'CLI',
+ items: [
+ { name: 'Overview', url: '/guides/cli', items: [] },
+ { name: 'Local Development', url: '/guides/cli/local-development', items: [] },
+ { name: 'Managing Environments', url: '/guides/cli/managing-environments', items: [] },
+ ],
+}
+
+export const auth = {
+ label: 'Auth',
+ extras: [
+ { name: 'API Reference', level: 'integrations', items: [] },
+ { name: 'Integrations', level: 'reference', items: [] },
+ ],
+ items: [
+ {
+ name: 'Authentication',
+ url: undefined,
+ items: [
+ { name: 'Login with Email', url: '/guides/auth/auth-email', items: [] },
+ { name: 'Login with Magic Link', url: '/guides/auth/auth-magic-link', items: [] },
+ { name: 'Login with Apple', url: '/guides/auth/auth-apple', items: [] },
+ { name: 'Login with Azure', url: '/guides/auth/auth-azure', items: [] },
+ { name: 'Login with Bitbucket', url: '/guides/auth/auth-bitbucket', items: [] },
+ { name: 'Login with Discord', url: '/guides/auth/auth-discord', items: [] },
+ { name: 'Login with Facebook', url: '/guides/auth/auth-facebook', items: [] },
+ { name: 'Login with Github', url: '/guides/auth/auth-github', items: [] },
+ { name: 'Login with Gitlab', url: '/guides/auth/auth-gitlab', items: [] },
+ { name: 'Login with Google', url: '/guides/auth/auth-google', items: [] },
+ { name: 'Login with Keycloak', url: '/guides/auth/auth-keycloak', items: [] },
+ { name: 'Login with LinkedIn', url: '/guides/auth/auth-linkedin', items: [] },
+ { name: 'Login with Notion', url: '/guides/auth/auth-notion', items: [] },
+ { name: 'Login with Slack', url: '/guides/auth/auth-slack', items: [] },
+ { name: 'Login with Spotify', url: '/guides/auth/auth-spotify', items: [] },
+ { name: 'Login with Twitch', url: '/guides/auth/auth-twitch', items: [] },
+ { name: 'Login with Twitter', url: '/guides/auth/auth-twitter', items: [] },
+ { name: 'Login with WorkOS', url: '/guides/auth/auth-workos', items: [] },
+ { name: 'Phone Auth with Twilio', url: '/guides/auth/auth-twilio', items: [] },
+ { name: 'Phone Auth with Vonage', url: '/guides/auth/auth-vonage', items: [] },
+ {
+ name: 'Phone Auth with MessageBird',
+ url: '/guides/auth/auth-messagebird',
+ items: [],
+ },
+ ],
+ },
+ {
+ name: 'Authorization',
+ url: undefined,
+ items: [
+ { name: 'Row Level Security', url: '/guides/auth/row-level-security', items: [] },
+ { name: 'Managing User Data', url: '/guides/auth/managing-user-data', items: [] },
+ { name: 'Enable Captcha Protection', url: '/guides/auth/auth-captcha', items: [] },
+ { name: 'Server-side Rendering', url: '/guides/auth/server-side-rendering', items: [] },
+ { name: 'Multi-Factor Authentication', url: '/guides/auth/auth-mfa', items: [] },
+ ],
+ },
+ {
+ name: 'Auth Helpers',
+ url: undefined,
+ items: [
+ { name: 'Overview', url: '/guides/auth/auth-helpers', items: [] },
+ { name: 'Auth UI', url: '/guides/auth/auth-helpers/auth-ui', items: [] },
+ { name: 'Next.js', url: '/guides/auth/auth-helpers/nextjs', items: [] },
+ { name: 'SvelteKit', url: '/guides/auth/auth-helpers/sveltekit', items: [] },
+ { name: 'Remix', url: '/guides/auth/auth-helpers/remix', items: [] },
+ ],
+ },
+ {
+ name: 'Deep Dive',
+ url: undefined,
+ items: [
+ {
+ name: 'Part One: JWTs',
+ url: '/learn/auth-deep-dive/auth-deep-dive-jwts',
+ items: [],
+ },
+ {
+ name: 'Part Two: Row Level Security',
+ url: '/learn/auth-deep-dive/auth-row-level-security',
+ items: [],
+ },
+ { name: 'Part Three: Policies', url: '/learn/auth-deep-dive/auth-policies', items: [] },
+ { name: 'Part Four: GoTrue', url: '/learn/auth-deep-dive/auth-gotrue', items: [] },
+ {
+ name: 'Part Five: Google OAuth',
+ url: '/learn/auth-deep-dive/auth-google-oauth',
+ items: [],
+ },
+ ],
+ },
+ ],
+}
+
+export const database = {
+ label: 'Database',
+ items: [
+ { name: 'Overview', url: '/guides/database', items: [] },
+ { name: 'Database Connections', url: '/guides/database/connecting-to-postgres', items: [] },
+ { name: 'Tables and Data', url: '/guides/database/tables', items: [] },
+ { name: 'Database Functions', url: '/guides/database/functions', items: [] },
+ { name: 'Database Webhooks', url: '/guides/database/database-webhooks', items: [] },
+ { name: 'Full Text Search', url: '/guides/database/full-text-search', items: [] },
+ { name: 'Database Testing', url: '/guides/database/testing', items: [] },
+ {
+ name: 'Serverless APIs',
+ url: undefined,
+ items: [
+ { name: 'Overview', url: '/guides/api', items: [] },
+ { name: 'Generating Types', url: '/guides/api/generating-types', items: [] },
+ ],
+ },
+ {
+ name: 'Extensions',
+ url: undefined,
+ items: [
+ { name: 'Overview', url: '/guides/database/extensions', items: [] },
+ {
+ name: 'plv8: Javascript Language',
+ url: '/guides/database/extensions/plv8',
+ items: [],
+ },
+ { name: 'http: RESTful Client', url: '/guides/database/extensions/http', items: [] },
+ {
+ name: 'pg_cron: Job Scheduling',
+ url: '/guides/database/extensions/pgcron',
+ items: [],
+ },
+ {
+ name: 'pg_net: Async Networking',
+ url: '/guides/database/extensions/pgnet',
+ items: [],
+ },
+ { name: 'pgTAP: Unit Testing', url: '/guides/database/extensions/pgtap', items: [] },
+ {
+ name: 'uuid-ossp: Unique Identifiers',
+ url: '/guides/database/extensions/uuid-ossp',
+ items: [],
+ },
+ ],
+ },
+ {
+ name: 'Configuration',
+ url: undefined,
+ items: [
+ { name: 'Timeouts', url: '/guides/database/timeouts', items: [] },
+ { name: 'Replication', url: '/guides/database/replication', items: [] },
+ { name: 'Passwords', url: '/guides/database/managing-passwords', items: [] },
+ { name: 'Timezones', url: '/guides/database/managing-timezones', items: [] },
+ ],
+ },
+ ],
+}
+
+export const functions = {
+ label: 'Edge Functions',
+ items: [
+ { name: 'Overview', url: '/guides/functions', items: [] },
+ { name: 'Auth', url: '/guides/functions/auth', items: [] },
+ { name: 'Examples', url: '/guides/functions/examples', items: [] },
+ { name: 'CI/CD Workflow', url: '/guides/functions/cicd-workflow', items: [] },
+ ],
+}
+
+export const realtime = {
+ label: 'Realtime',
+ items: [
+ { name: 'Overview', url: '/guides/realtime', items: [] },
+ { name: 'Quickstart', url: '/guides/realtime/quickstart', items: [] },
+ { name: 'Postgres CDC', url: '/guides/realtime/postgres-cdc', items: [] },
+ { name: 'Rate Limits', url: '/guides/realtime/rate-limits', items: [] },
+ ],
+}
+
+export const storage = {
+ label: 'Storage',
+ items: [
+ { name: 'Overview', url: '/guides/storage', items: [] },
+ { name: 'CDN', url: '/guides/storage-cdn', items: [] },
+ ],
+}
+
+export const platform = {
+ label: 'Platform',
+ items: [
+ { name: 'Overview', url: '/guides/hosting/platform', items: [] },
+ { name: 'Custom Domains', url: '/guides/platform/custom-domains', items: [] },
+ { name: 'Database Usage', url: '/guides/platform/database-usage', items: [] },
+ { name: 'Logging', url: '/guides/platform/logs', items: [] },
+ { name: 'Metrics', url: '/guides/platform/metrics', items: [] },
+ {
+ name: 'Migrating and upgrading',
+ url: '/guides/platform/migrating-and-upgrading-projects',
+ items: [],
+ },
+ { name: 'Performance Tuning', url: '/guides/platform/performance', items: [] },
+ { name: 'Permissions', url: '/guides/platform/permissions', items: [] },
+ { name: 'Production Readiness', url: '/guides/platform/going-into-prod', items: [] },
+ ],
+}
+
+export const selfHosting = {
+ label: 'Self Hosting',
+ items: [
+ { name: 'Overview', url: '/guides/hosting/overview', items: [] },
+ { name: 'Docker', url: '/guides/hosting/docker', items: [] },
+ ],
+}
+
+export const migrate = {
+ label: 'Migrate to Supabase',
+ items: [
+ { name: 'Firebase Auth', url: '/guides/migrations/firebase-auth', items: [] },
+ { name: 'Firestore Data', url: '/guides/migrations/firestore-data', items: [] },
+ { name: 'Firebase Storage', url: '/guides/migrations/firebase-storage', items: [] },
+ { name: 'Heroku', url: '/guides/migrations/heroku', items: [] },
+ ],
+}
+
+export const integrations = {
+ label: 'Integrations',
+ items: [
+ { name: 'Supabase Marketplace', url: '/guides/integrations/integrations', items: [] },
+ {
+ name: 'Auth',
+ url: undefined,
+ items: [
+ { name: 'Auth0', url: '/guides/integrations/auth0', items: [] },
+ { name: 'Authsignal', url: '/guides/integrations/authsignal', items: [] },
+ { name: 'Clerk', url: '/guides/integrations/clerk', items: [] },
+ { name: 'keyri', url: '/guides/integrations/keyri', items: [] },
+ { name: 'Stytch', url: '/guides/integrations/stytch', items: [] },
+ { name: 'SuperTokens', url: '/guides/integrations/supertokens', items: [] },
+ ],
+ },
+ {
+ name: 'Caching / Offline-first',
+ url: undefined,
+ items: [{ name: 'Polyscale', url: '/guides/integrations/polyscale', items: [] }],
+ },
+ {
+ name: 'Developer Tools',
+ url: undefined,
+ items: [
+ { name: 'pgMustard', url: '/guides/integrations/pgmustard', items: [] },
+ { name: 'Prisma', url: '/guides/integrations/prisma', items: [] },
+ { name: 'Sequin', url: '/guides/integrations/sequin', items: [] },
+ { name: 'Snaplet', url: '/guides/integrations/snaplet', items: [] },
+ { name: 'Vercel', url: '/guides/integrations/vercel', items: [] },
+ ],
+ },
+ {
+ name: 'Low-code',
+ url: undefined,
+ items: [
+ { name: 'Appsmith', url: '/guides/integrations/appsmith', items: [] },
+ { name: 'Dashibase', url: '/guides/integrations/dashibase', items: [] },
+ { name: 'DhiWise', url: '/guides/integrations/dhiwise', items: [] },
+ { name: 'Directus', url: '/guides/integrations/directus', items: [] },
+ { name: 'Draftbit', url: '/guides/integrations/draftbit', items: [] },
+ { name: 'Plasmic', url: '/guides/integrations/plasmic', items: [] },
+ ],
+ },
+ ],
+}
+
+export const reference = {
+ items: [
+ {
+ name: 'Client libraries',
+ items: [
+ {
+ name: 'supabase-js',
+ href: '/reference/javascript/start',
+ level: 'reference_javascript',
+ items: [],
+ icon: '/img/icons/javascript.svg',
+ },
+ {
+ name: 'supabase-dart',
+ href: '/reference/dart/start',
+ level: 'reference_dart',
+ items: [],
+ icon: '/img/icons/javascript.svg',
+ },
+ {
+ name: 'supbase-python',
+ href: '/reference/python/start',
+ level: 'reference_python',
+ items: [],
+ icon: '/img/icons/javascript.svg',
+ },
+ ],
+ },
+ {
+ name: 'Other tools',
+ items: [
+ {
+ name: 'Supabase CLI',
+ href: '/reference/cli',
+ items: [],
+ icon: '/img/icons/javascript.svg',
+ },
+ {
+ name: 'Management API',
+ href: '/reference/javascript',
+ items: [],
+ icon: '/img/icons/javascript.svg',
+ },
+ ],
+ },
+ ],
+}
+
+export const reference_javascript = {
+ icon: '/img/icons/javascript-icon.svg',
+ title: 'javascript-js',
+ parent: '/reference',
+ items: [
+ {
+ name: 'Getting Started',
+ items: [
+ {
+ name: 'fake link',
+ href: '/reference/javascript/start',
+ level: 'reference_javascript',
+ items: [],
+ icon: '/img/icons/javascript.svg',
+ },
+ ],
+ },
+ ],
+}
+
+// export const reference: [
+// {
+// label: 'Official'
+// items: [
+// { name: 'Reference Documentation'; url: '/reference'; items: [] },
+// { name: 'Supabase JavaScript Library'; url: '/reference/javascript'; items: [] },
+// { name: 'Supabase Flutter Library'; url: '/reference/dart'; items: [] },
+// { name: 'Supabase CLI'; url: '/reference/cli'; items: [] },
+// { name: 'Management API'; url: '/reference/api'; items: [] }
+// ]
+// },
+// {
+// label: 'Self-hosting'
+// items: [
+// { name: 'Auth Server'; url: '/reference/auth'; items: [] },
+// { name: 'Storage Server'; url: '/reference/storage'; items: [] }
+// ]
+// }
+// {
+// label: 'Clients',
+// items: [
+// { name: 'Auth Server', url: '/reference/auth', items: [] },
+// { name: 'Storage Server', url: '/reference/storage', items: [] },
+// ],
+// },
+// 'reference/javascript': SupabaseJsV2Nav,
+// 'reference/javascript/v1': SupabaseJsV1Nav,
+// 'reference/dart': SupabaseDartV1Nav,
+// 'reference/dart/v0': SupabaseDartV0Nav,
+// 'reference/cli': SupabaseCLINav,
+// 'reference/api': SupabaseAPINav,
+// 'reference/auth': AuthServerNav,
+// 'reference/storage': StorageServerNav,
+// ]
diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.tsx b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.tsx
new file mode 100644
index 00000000000..3914684bdeb
--- /dev/null
+++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.tsx
@@ -0,0 +1,382 @@
+import { useRouter } from 'next/router'
+import { useState, useEffect } from 'react'
+import { IconChevronLeft } from '~/../../packages/ui'
+import * as NavItems from './NavigationMenu.constants'
+import NavigationMenuGuideList from './NavigationMenuGuideList'
+
+const SideNav = () => {
+ console.log('sidebar rerendered')
+ const router = useRouter()
+
+ const [level, setLevel] = useState('home')
+
+ const tempBasePath = '/new'
+
+ useEffect(() => {
+ function handleRouteChange(url: string) {
+ console.log('path changed')
+ console.log(url)
+ switch (url) {
+ case `/docs${tempBasePath}`:
+ setLevel('home')
+ break
+ case `/docs${tempBasePath}/database`:
+ setLevel('database')
+ break
+ case `/docs${tempBasePath}/auth`:
+ setLevel('auth')
+ break
+ case `/docs${tempBasePath}/storage`:
+ setLevel('storage')
+ break
+ case `/docs${tempBasePath}/realtime`:
+ setLevel('realtime')
+ break
+ case `/docs${tempBasePath}/edge-functions`:
+ setLevel('functions')
+ break
+ case `/docs${tempBasePath}/reference`:
+ setLevel('reference')
+ break
+ case `/docs${tempBasePath}/integrations`:
+ setLevel('integrations')
+ break
+ case `/docs${tempBasePath}/platform`:
+ setLevel('platform')
+ break
+ case url.includes(`/docs${tempBasePath}/reference/javascript/`) && url:
+ setLevel('reference_javascript')
+ break
+
+ default:
+ break
+ }
+ }
+
+ // Listen for page changes after a navigation or when the query changes
+ router.events.on('routeChangeComplete', handleRouteChange)
+ return () => {
+ router.events.off('routeChangeComplete', handleRouteChange)
+ }
+ }, [router.events])
+
+ const home = [
+ [
+ {
+ label: 'Home',
+ icon: 'home.svg',
+ href: '',
+ level: 'home',
+ },
+ {
+ label: 'Getting started',
+ icon: 'gettingstarted.svg',
+ href: '/getting-started',
+ level: 'gettingstarted',
+ },
+ {
+ label: 'Tutorials',
+ icon: 'tutorials.svg',
+ href: '/tutorials',
+ level: 'tutorials',
+ },
+ ],
+ [
+ {
+ label: 'Database',
+ icon: 'database.svg',
+ href: '/database',
+ level: 'database',
+ },
+ {
+ label: 'Auth',
+ icon: 'auth.svg',
+ href: '/auth',
+ level: 'auth',
+ },
+ {
+ label: 'Storage',
+ icon: 'storage.svg',
+ href: '/storage',
+ level: 'storage',
+ },
+ {
+ label: 'Realtime',
+ icon: 'realtime.svg',
+ href: '/realtime',
+ level: 'realtime',
+ },
+ {
+ label: 'Edge Functions',
+ icon: 'functions.svg',
+ href: '/edge-functions',
+ level: 'functions',
+ },
+ ],
+ [
+ {
+ label: 'API Reference',
+ icon: 'reference.svg',
+ href: '/reference',
+ level: 'reference',
+ },
+ {
+ label: 'Integrations',
+ icon: 'integrations.svg',
+ href: '/integrations',
+ level: 'integrations',
+ },
+ {
+ label: 'Platform',
+ icon: 'platform.svg',
+ href: '/platform',
+ level: 'platform',
+ },
+ ],
+ ]
+
+ const auth = [
+ {
+ label: 'back',
+ icon: 'home.svg',
+ href: '',
+ level: 'home',
+ },
+ ]
+
+ const ref = [
+ {
+ label: 'back',
+ icon: 'home.svg',
+ href: '',
+ level: 'home',
+ },
+ {
+ label: 'supabase-js v2',
+ icon: 'home.svg',
+ href: '/reference/javascript/start',
+ level: 'ref_js',
+ },
+ {
+ label: 'supabase-js v1',
+ icon: 'home.svg',
+ href: '/reference/javascript/v1/start',
+ level: 'ref_js',
+ },
+ {
+ label: 'supabase-dart v1',
+ icon: 'home.svg',
+ href: '/reference/dart/start',
+ level: 'ref_dart',
+ },
+ ]
+
+ const ref_js = [
+ {
+ label: 'back to ref',
+ icon: 'home.svg',
+ href: '/reference',
+ level: 'ref',
+ },
+ ]
+
+ return (
+
+ {/* // main menu */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* reference level */}
+
+
+ {/* // ref menu */}
+ {/*
+
+ {ref.map((link) => {
+ return (
+ - {
+ setLevel(link.level)
+ router.push(tempBasePath + link.href)
+ }}
+ className={[
+ 'flex items-center gap-3',
+ 'text-base transition-all duration-200 text-scale-1200 hover:text-brand-900 hover:cursor-pointer ',
+ ].join(' ')}
+ >
+
+ {link.label}
+
+ )
+ })}
+
+
*/}
+
+ {/* // JS menu */}
+ {/*
+
+ {ref_js.map((link) => {
+ return (
+ - {
+ setLevel(link.level)
+ router.push(tempBasePath + link.href)
+ }}
+ className={[
+ 'flex items-center gap-3',
+ 'text-base transition-all duration-200 text-scale-1200 hover:text-brand-900 hover:cursor-pointer ',
+ ].join(' ')}
+ >
+
+ {link.label}
+
+ )
+ })}
+
+
*/}
+
+ {/* // Dart menu */}
+ {/*
+
+ {ref_js.map((link) => {
+ return (
+ - {
+ setLevel(link.level)
+ router.push(tempBasePath + link.href)
+ }}
+ className={[
+ 'flex items-center gap-3',
+ 'text-base transition-all duration-200 text-scale-1200 hover:text-brand-900 hover:cursor-pointer ',
+ ].join(' ')}
+ >
+
+ {link.label}
+
+ )
+ })}
+
+
*/}
+
+ )
+}
+
+export default SideNav
diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuGuideList.tsx b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuGuideList.tsx
new file mode 100644
index 00000000000..553b3a71999
--- /dev/null
+++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuGuideList.tsx
@@ -0,0 +1,117 @@
+import { useRouter } from 'next/router'
+import rehypeFilter from 'react-markdown/lib/rehype-filter'
+import { IconChevronLeft } from '~/../../packages/ui'
+import * as NavItems from './NavigationMenu.constants'
+
+const NavigationMenuGuideList = ({ currentLevel, setLevel, tempBasePath, id }) => {
+ const router = useRouter()
+
+ const menu = NavItems[id]
+
+ return (
+
+
+ - {
+ router.push(`${tempBasePath}${menu.parent ?? ''}`)
+ // setLevel(menu.parent && 'home')
+ }}
+ className={[
+ 'flex items-center gap-1 text-xs group mb-3',
+ 'text-base transition-all duration-200 text-scale-1200 hover:text-brand-900 hover:cursor-pointer ',
+ ].join(' ')}
+ >
+
+ back
+
+
+
+ {/*
*/}
+

+ {/*
*/}
+
+ {menu.title ?? currentLevel}
+
+
+
+ {menu.items.map((x, index) => {
+ return (
+
+ )
+ })}
+ {menu.extras && }
+ {menu.extras?.map((x) => {
+ return (
+
+
+ {x.name}
+
+ {x.items.map((x) => {
+ return (
+
-
+ {x.name}
+
+ )
+ })}
+
+ )
+ })}
+
+
+ )
+}
+
+export default NavigationMenuGuideList
diff --git a/apps/docs/components/NavigationMenu/index.tsx b/apps/docs/components/NavigationMenu/index.tsx
deleted file mode 100644
index 6dfc16fd784..00000000000
--- a/apps/docs/components/NavigationMenu/index.tsx
+++ /dev/null
@@ -1,216 +0,0 @@
-import { useRouter } from 'next/router'
-import { useState } from 'react'
-
-const SideNav = () => {
- console.log('sidebar rerendered')
- const router = useRouter()
-
- const [level, setLevel] = useState('home')
-
- const tempBasePath = '/new'
-
- const home = [
- {
- label: 'Home',
- icon: 'home.svg',
- href: '',
- level: 'home',
- },
- {
- label: 'Getting started',
- icon: 'getting-started.svg',
- level: 'getting-started',
- },
- {
- label: 'Tutorials',
- icon: 'tutorials.svg',
- level: 'tutorials',
- },
- {
- label: 'Database',
- icon: 'database.svg',
- level: 'database',
- },
- {
- label: 'Auth',
- icon: 'auth.svg',
- href: '/auth',
- level: 'auth',
- },
- {
- label: 'Storage',
- icon: 'storage.svg',
- level: 'storage',
- },
- {
- label: 'API Reference',
- icon: 'api.svg',
- href: '/ref',
- level: 'ref',
- },
- {
- label: 'Integrations',
- icon: 'integrations.svg',
- level: 'integrations',
- },
- {
- label: 'Platform',
- icon: 'platform.svg',
- level: 'platform',
- },
- ]
-
- const auth = [
- {
- label: 'back',
- icon: 'home.svg',
- href: '',
- level: 'home',
- },
- ]
-
- const ref = [
- {
- label: 'back',
- icon: 'home.svg',
- href: '',
- level: 'home',
- },
- {
- label: 'supabsae-js',
- icon: 'home.svg',
- href: '/ref/js/start',
- level: 'ref_js',
- },
- ]
-
- const ref_js = [
- {
- label: 'back to ref',
- icon: 'home.svg',
- href: '/ref',
- level: 'ref',
- },
- ]
-
- return (
-
- {/* // main menu */}
-
-
- {/* // auth menu */}
-
-
- {auth.map((link) => {
- return (
- - {
- setLevel(link.level)
- router.push(tempBasePath + link.href)
- }}
- className={[
- 'flex items-center gap-3',
- 'text-base transition-all duration-200 text-scale-1200 hover:text-brand-900 hover:cursor-pointer ',
- ].join(' ')}
- >
-
- {link.label}
-
- )
- })}
-
-
-
- {/* // ref menu */}
-
-
- {ref.map((link) => {
- return (
- - {
- setLevel(link.level)
- router.push(tempBasePath + link.href)
- }}
- className={[
- 'flex items-center gap-3',
- 'text-base transition-all duration-200 text-scale-1200 hover:text-brand-900 hover:cursor-pointer ',
- ].join(' ')}
- >
-
- {link.label}
-
- )
- })}
-
-
-
- {/* // JS menu */}
-
-
- {ref_js.map((link) => {
- return (
- - {
- setLevel(link.level)
- router.push(tempBasePath + link.href)
- }}
- className={[
- 'flex items-center gap-3',
- 'text-base transition-all duration-200 text-scale-1200 hover:text-brand-900 hover:cursor-pointer ',
- ].join(' ')}
- >
-
- {link.label}
-
- )
- })}
-
-
-
- )
-}
-
-export default SideNav
diff --git a/apps/docs/layouts/SiteLayout.tsx b/apps/docs/layouts/SiteLayout.tsx
index f47a65e37c0..aaff2611a13 100644
--- a/apps/docs/layouts/SiteLayout.tsx
+++ b/apps/docs/layouts/SiteLayout.tsx
@@ -1,11 +1,17 @@
+import { useRouter } from 'next/router'
import Footer from '~/components/Footer'
import NavBar from '~/components/Navigation/NavBar'
-import NavigationMenu from '~/components/NavigationMenu'
+import NavigationMenu from '~/components/Navigation/NavigationMenu/NavigationMenu'
const Layout = ({ children }) => {
+ const router = useRouter()
return (
<>
+
diff --git a/apps/docs/pages/new/reference/dart/[...slug].tsx b/apps/docs/pages/new/reference/dart/[...slug].tsx
new file mode 100644
index 00000000000..23c4092bc51
--- /dev/null
+++ b/apps/docs/pages/new/reference/dart/[...slug].tsx
@@ -0,0 +1,381 @@
+import {
+ useEffect,
+ // useRef,
+ useState,
+} from 'react'
+// pages/index.js
+
+import fs from 'fs'
+
+import matter from 'gray-matter'
+import { MDXRemote } from 'next-mdx-remote'
+import { serialize } from 'next-mdx-remote/serialize'
+import remarkGfm from 'remark-gfm'
+import components from '~/components/index'
+import { getAllDocs } from '~/lib/docs'
+
+import ReactMarkdown from 'react-markdown'
+
+// @ts-ignore
+import jsTypeSpec from '~/../../spec/enrichments/tsdoc_v2/combined.json'
+// @ts-ignore
+import examples from '~/../../spec/examples/examples.yml' assert { type: 'yml' }
+// @ts-expect-error
+import jsSpec from '~/../../spec/supabase_dart_v1_temp_new_shape.yml' assert { type: 'yml' }
+
+import { IconDatabase, Tabs } from 'ui'
+import CodeBlock from '~/components/CodeBlock/CodeBlock'
+
+import { useRouter } from 'next/router'
+import { extractTsDocNode, generateParameters } from '~/lib/refGenerator/helpers'
+
+const marginTop = 256
+export default function Ref(props) {
+ // const myRef = useRef(null)
+
+ console.log('props', props)
+
+ const [offsetY, setOffsetY] = useState(0)
+ const [sections, setSections] = useState([])
+
+ // useEffect(() => {
+ // window.scrollTo(0, 0)
+ // setOffsetY(0)
+ // }, [])
+
+ useEffect(() => {
+ const els: HTMLElement[] = Array.from(document.querySelectorAll('div.ref-container'))
+
+ const allSections = els.map((el: HTMLElement, index: number) => {
+ const { top: boundingTop } = el.getBoundingClientRect()
+
+ return {
+ topic: el.getAttribute('id')!,
+ boundingTop,
+ isActive: index === 0,
+ }
+ })
+
+ // console.log('allSections', allSections)
+ setSections(allSections)
+ }, [])
+
+ // useEffect(() => {
+ // if (sections.length <= 1) return
+
+ // const onScroll = () => {
+ // console.log('SCROLL EVENT')
+ // setOffsetY(window.pageYOffset)
+ // }
+ // window.addEventListener('scroll', debounce(onScroll, 500))
+
+ // return () => window.removeEventListener('scroll', onScroll)
+ // }, [sections])
+
+ // useEffect(() => {
+ // if (sections.length === 0) return
+
+ // if (sections.length === 1) {
+ // sections[0].isActive = true
+ // return
+ // }
+
+ // sections.forEach((section, index) => {
+ // if (index === 0) {
+ // section.isActive = sections[index + 1].boundingTop > offsetY + marginTop
+ // } else {
+ // if (sections[index + 1]) {
+ // section.isActive =
+ // sections[index + 1].boundingTop > offsetY + marginTop &&
+ // sections[index].boundingTop <= offsetY + marginTop
+ // } else {
+ // section.isActive = sections[index].boundingTop <= offsetY + marginTop
+ // }
+ // }
+ // })
+ // }, [sections, offsetY])
+
+ // useEffect(() => {
+ // const observer = new IntersectionObserver((entries) => {
+ // // console.log('entries', entries)
+ // const entry = entries[0]
+ // // console.log('entry', entry)
+ // })
+ // // console.log('myRef', myRef.current)
+ // observer.observe(myRef.current)
+ // }, [])
+
+ const router = useRouter()
+
+ function updateUrl(key) {
+ // router.replace(
+ // {
+ // pathname: `/ref/js/${key}`,
+ // // query: { sortBy: 'price' },
+ // }
+ // // undefined,
+ // // { shallow: true }
+ // )
+ router.replace(
+ {
+ pathname: `/ref/js/${key}`,
+ // query: { sortBy: 'price' },
+ },
+ undefined,
+ { scroll: false }
+ )
+ }
+
+ return (
+
+
+
+
+
+
+ {jsSpec.functions.map((item, itemIndex) => {
+ // if (item.id !== 'select()') return
hidden section
+ // const sectionRef = useRef(null)
+
+ // console.log('x', x)
+ const hasTsRef = item['$ref'] || null
+ // console.log('hasTsRef', hasTsRef)
+ // console.log('jsTypeSpec', jsTypeSpec)
+ const tsDefinition = hasTsRef && extractTsDocNode(hasTsRef, jsTypeSpec)
+ // console.log('tsDefinition', tsDefinition)
+ // console.log(`tsDefinition for ${item.title ?? item.id}`, tsDefinition)
+
+ // useEffect(() => {
+ // const observer = new IntersectionObserver((entries) => {
+ // // console.log('entries', entries)
+ // const entry = entries[0]
+
+ // // console.log(
+ // // x.id,
+ // // 'intersectiong',
+ // // entry.isIntersecting,
+ // // 'visible',
+ // // entry.isVisible
+ // // )
+ // })
+ // // console.log('myRef', myRef.current)
+ // observer.observe(sectionRef.current)
+ // }, [])
+
+ const parameters = hasTsRef ? generateParameters(tsDefinition) : ''
+
+ // @ts-ignore
+ // const [serialFunctionMarkdownContent, setSerialFunctionMarkdownContent] =
+ // useState(null)
+
+ const functionMarkdownContent = props?.docs[itemIndex]?.content
+
+ // useEffect(() => {
+ // async function makeContent() {
+ // setSerialFunctionMarkdownContent(
+ // await serialize(functionMarkdownContent, {
+ // mdxOptions: {
+ // remarkPlugins: [remarkGfm],
+ // format: 'mdx',
+ // },
+ // })
+ // )
+ // }
+ // makeContent()
+ // }, [])
+
+ // console.log('serialFunctionMarkdownContent', serialFunctionMarkdownContent)
+
+ return (
+ <>
+
+ updateUrl(item.id)}>
+ {examples.functions[itemIndex].title ??
+ examples.functions[itemIndex].id ??
+ item.name ??
+ item.id}
+
+
+
+
+
+ {examples.functions[itemIndex].description}
+
+
+
+ {functionMarkdownContent && (
+
+ )}
+
+ {item.notes && (
+
+ {item.notes}
+
+ )}
+
+ {/* // parameters */}
+ {parameters &&
}
+
+
+
+ {item.examples && (
+
+ {item.examples &&
+ item.examples.map((example, exampleIndex) => {
+ const exampleString = `
+import { createClient } from '@supabase/supabase-js'
+
+// Create a single supabase client for interacting with your database
+const supabase = createClient('https://xyzcompany.supabase.co', 'public-anon-key')
+`
+ const currentExampleId = example.id
+ // const staticExample =
+ // examples.functions[itemIndex].examples[exampleIndex]
+
+ // const response = staticExample.response
+ // const sql = staticExample?.data?.sql
+ // const tables = staticExample?.data?.tables
+
+ return (
+
+
+ {exampleString +
+ (example.code &&
+ example.code
+ .replace('```', '')
+ .replace('js', '')
+ .replace('```', ''))}
+
+
+ )
+ })}
+
+ )}
+
+
+
+ >
+ )
+ })}
+
+
+
+
+ )
+}
+
+export async function getStaticProps({ params }: { params: { slug: string[] } }) {
+ /**
+ * This is our collection of human readable titles and IDs
+ */
+ let markdownDocs = [
+ {
+ title: 'Inserting data',
+ id: 'select()',
+ },
+ { title: 'Deleting data', id: 'delete()' },
+ ]
+
+ const pages = jsSpec.functions.map((x) => x.id)
+ console.log('pages', pages)
+
+ /**
+ * Read all the markdown files that might have
+ * - custom text
+ * - call outs
+ * - important notes regarding implementation
+ */
+ const allMarkdownDocs = await Promise.all(
+ pages.map(async (x, i) => {
+ // const doc = getDocsBySlug(`docs/ref/database/${x}`)
+
+ // if (i >= 5) return null
+
+ const pathName = `docs/ref/js/${x}.mdx`
+
+ function checkFileExists(x) {
+ // console.log('checking this ', x)
+ if (fs.existsSync(x)) {
+ return true
+ } else {
+ return false
+ }
+ }
+
+ const markdownExists = checkFileExists(pathName)
+
+ console.log(x, 'markdownExists', markdownExists)
+
+ const fileContents = markdownExists ? fs.readFileSync(pathName, 'utf8') : ''
+ const { data, content } = matter(fileContents)
+ // console.log('docBySlug', content)
+ // console.log()
+
+ if (content) console.log(content)
+ return {
+ id: x,
+ title: x,
+ // ...content,
+ meta: data,
+ content: content ? await serialize(content || '') : null,
+ }
+ })
+ )
+
+ // console.log('allMarkdownDocs', allMarkdownDocs)
+
+ return {
+ props: {
+ docs: allMarkdownDocs,
+ },
+ }
+}
+
+export function getStaticPaths() {
+ let docs = getAllDocs()
+
+ return {
+ paths: docs.map(() => {
+ return {
+ params: {
+ slug: docs.map((d) => d.slug),
+ },
+ }
+ }),
+ fallback: 'blocking',
+ }
+}
diff --git a/apps/docs/pages/new/ref/index.mdx b/apps/docs/pages/new/reference/index.mdx
similarity index 100%
rename from apps/docs/pages/new/ref/index.mdx
rename to apps/docs/pages/new/reference/index.mdx
diff --git a/apps/docs/pages/new/ref/js/[...slug].tsx b/apps/docs/pages/new/reference/javascript/[...slug].tsx
similarity index 100%
rename from apps/docs/pages/new/ref/js/[...slug].tsx
rename to apps/docs/pages/new/reference/javascript/[...slug].tsx
diff --git a/apps/docs/pages/new/reference/javascript/v1/[...slug].tsx b/apps/docs/pages/new/reference/javascript/v1/[...slug].tsx
new file mode 100644
index 00000000000..e07b7a69cfb
--- /dev/null
+++ b/apps/docs/pages/new/reference/javascript/v1/[...slug].tsx
@@ -0,0 +1,442 @@
+import {
+ useEffect,
+ // useRef,
+ useState,
+} from 'react'
+// pages/index.js
+
+import fs from 'fs'
+
+import matter from 'gray-matter'
+import { MDXRemote } from 'next-mdx-remote'
+import { serialize } from 'next-mdx-remote/serialize'
+import remarkGfm from 'remark-gfm'
+import components from '~/components/index'
+import { getAllDocs } from '~/lib/docs'
+
+import ReactMarkdown from 'react-markdown'
+
+// @ts-ignore
+import jsTypeSpec from '~/../../spec/enrichments/tsdoc_v1/combined.json'
+// @ts-ignore
+import examples from '~/../../spec/examples/examples.yml' assert { type: 'yml' }
+// @ts-expect-error
+import jsSpec from '~/../../spec/supabase_js_v1_temp_new_shape.yml' assert { type: 'yml' }
+
+import { IconDatabase, Tabs } from 'ui'
+import CodeBlock from '~/components/CodeBlock/CodeBlock'
+
+import { useRouter } from 'next/router'
+import { extractTsDocNode, generateParameters } from '~/lib/refGenerator/helpers'
+
+const marginTop = 256
+export default function Ref(props) {
+ // const myRef = useRef(null)
+
+ console.log('props', props)
+
+ const [offsetY, setOffsetY] = useState(0)
+ const [sections, setSections] = useState([])
+
+ // useEffect(() => {
+ // window.scrollTo(0, 0)
+ // setOffsetY(0)
+ // }, [])
+
+ useEffect(() => {
+ const els: HTMLElement[] = Array.from(document.querySelectorAll('div.ref-container'))
+
+ const allSections = els.map((el: HTMLElement, index: number) => {
+ const { top: boundingTop } = el.getBoundingClientRect()
+
+ return {
+ topic: el.getAttribute('id')!,
+ boundingTop,
+ isActive: index === 0,
+ }
+ })
+
+ // console.log('allSections', allSections)
+ setSections(allSections)
+ }, [])
+
+ // useEffect(() => {
+ // if (sections.length <= 1) return
+
+ // const onScroll = () => {
+ // console.log('SCROLL EVENT')
+ // setOffsetY(window.pageYOffset)
+ // }
+ // window.addEventListener('scroll', debounce(onScroll, 500))
+
+ // return () => window.removeEventListener('scroll', onScroll)
+ // }, [sections])
+
+ // useEffect(() => {
+ // if (sections.length === 0) return
+
+ // if (sections.length === 1) {
+ // sections[0].isActive = true
+ // return
+ // }
+
+ // sections.forEach((section, index) => {
+ // if (index === 0) {
+ // section.isActive = sections[index + 1].boundingTop > offsetY + marginTop
+ // } else {
+ // if (sections[index + 1]) {
+ // section.isActive =
+ // sections[index + 1].boundingTop > offsetY + marginTop &&
+ // sections[index].boundingTop <= offsetY + marginTop
+ // } else {
+ // section.isActive = sections[index].boundingTop <= offsetY + marginTop
+ // }
+ // }
+ // })
+ // }, [sections, offsetY])
+
+ // useEffect(() => {
+ // const observer = new IntersectionObserver((entries) => {
+ // // console.log('entries', entries)
+ // const entry = entries[0]
+ // // console.log('entry', entry)
+ // })
+ // // console.log('myRef', myRef.current)
+ // observer.observe(myRef.current)
+ // }, [])
+
+ const router = useRouter()
+
+ function updateUrl(key) {
+ // router.replace(
+ // {
+ // pathname: `/ref/js/${key}`,
+ // // query: { sortBy: 'price' },
+ // }
+ // // undefined,
+ // // { shallow: true }
+ // )
+ router.replace(
+ {
+ pathname: `/ref/js/${key}`,
+ // query: { sortBy: 'price' },
+ },
+ undefined,
+ { scroll: false }
+ )
+ }
+
+ return (
+
+
+
+
+
+
+ {jsSpec.functions.map((item, itemIndex) => {
+ // if (item.id !== 'select()') return
hidden section
+ // const sectionRef = useRef(null)
+
+ // console.log('x', x)
+ const hasTsRef = item['$ref'] || null
+ // console.log('hasTsRef', hasTsRef)
+ // console.log('jsTypeSpec', jsTypeSpec)
+ const tsDefinition = hasTsRef && extractTsDocNode(hasTsRef, jsTypeSpec)
+ // console.log('tsDefinition', tsDefinition)
+ // console.log(`tsDefinition for ${item.title ?? item.id}`, tsDefinition)
+
+ // useEffect(() => {
+ // const observer = new IntersectionObserver((entries) => {
+ // // console.log('entries', entries)
+ // const entry = entries[0]
+
+ // // console.log(
+ // // x.id,
+ // // 'intersectiong',
+ // // entry.isIntersecting,
+ // // 'visible',
+ // // entry.isVisible
+ // // )
+ // })
+ // // console.log('myRef', myRef.current)
+ // observer.observe(sectionRef.current)
+ // }, [])
+
+ const parameters = hasTsRef ? generateParameters(tsDefinition) : ''
+
+ // @ts-ignore
+ // const [serialFunctionMarkdownContent, setSerialFunctionMarkdownContent] =
+ // useState(null)
+
+ const functionMarkdownContent = props?.docs[itemIndex]?.content
+
+ // useEffect(() => {
+ // async function makeContent() {
+ // setSerialFunctionMarkdownContent(
+ // await serialize(functionMarkdownContent, {
+ // mdxOptions: {
+ // remarkPlugins: [remarkGfm],
+ // format: 'mdx',
+ // },
+ // })
+ // )
+ // }
+ // makeContent()
+ // }, [])
+
+ // console.log('serialFunctionMarkdownContent', serialFunctionMarkdownContent)
+
+ return (
+ <>
+
+ updateUrl(item.id)}>
+ {examples.functions[itemIndex].title ??
+ examples.functions[itemIndex].id ??
+ item.name ??
+ item.id}
+
+
+
+
+
+ {examples.functions[itemIndex].description}
+
+
+
+ {functionMarkdownContent && (
+
+ )}
+
+ {item.notes && (
+
+ {item.notes}
+
+ )}
+
+ {/* // parameters */}
+ {parameters &&
}
+
+
+
+ {item.examples && (
+
+ {item.examples &&
+ item.examples.map((example, exampleIndex) => {
+ const exampleString = `
+import { createClient } from '@supabase/supabase-js'
+
+// Create a single supabase client for interacting with your database
+const supabase = createClient('https://xyzcompany.supabase.co', 'public-anon-key')
+`
+ const currentExampleId = example.id
+
+ const staticExample =
+ examples?.functions[itemIndex]?.examples &&
+ examples?.functions[itemIndex]?.examples[exampleIndex]
+
+ const response = staticExample?.response
+ const sql = staticExample?.data?.sql
+ const tables = staticExample?.data?.tables
+
+ return (
+
+ {tables &&
+ tables.length > 0 &&
+ tables.map((table) => {
+ console.log(table)
+
+ // @ts-ignore
+ // const [content, setContent] = useState(null)
+
+ // // @ts-ignore
+ // useEffect(() => {
+ // async function makeContent() {
+ // setContent(
+ // await serialize(table.content, {
+ // mdxOptions: {
+ // remarkPlugins: [remarkGfm],
+ // format: 'mdx',
+ // },
+ // })
+ // )
+ // }
+ // makeContent()
+ // }, [])
+
+ return (
+
+
+
+
+
+
+
+ {table.name}
+
+
+
+
+ {/*
{table.content} */}
+ {/* {content &&
} */}
+
+ )
+ })}
+ {sql && (
+
+ {sql}
+
+ )}
+
+ {exampleString +
+ (example.code &&
+ example.code
+ .replace('```', '')
+ .replace('js', '')
+ .replace('```', ''))}
+
+ {response && (
+
+ {response}
+
+ )}
+
+ )
+ })}
+
+ )}
+
+
+
+ >
+ )
+ })}
+
+
+
+
+ )
+}
+
+export async function getStaticProps({ params }: { params: { slug: string[] } }) {
+ /**
+ * This is our collection of human readable titles and IDs
+ */
+ let markdownDocs = [
+ {
+ title: 'Inserting data',
+ id: 'select()',
+ },
+ { title: 'Deleting data', id: 'delete()' },
+ ]
+
+ const pages = jsSpec.functions.map((x) => x.id)
+ console.log('pages', pages)
+
+ /**
+ * Read all the markdown files that might have
+ * - custom text
+ * - call outs
+ * - important notes regarding implementation
+ */
+ const allMarkdownDocs = await Promise.all(
+ pages.map(async (x, i) => {
+ // const doc = getDocsBySlug(`docs/ref/database/${x}`)
+
+ // if (i >= 5) return null
+
+ const pathName = `docs/ref/js/${x}.mdx`
+
+ function checkFileExists(x) {
+ // console.log('checking this ', x)
+ if (fs.existsSync(x)) {
+ return true
+ } else {
+ return false
+ }
+ }
+
+ const markdownExists = checkFileExists(pathName)
+
+ console.log(x, 'markdownExists', markdownExists)
+
+ const fileContents = markdownExists ? fs.readFileSync(pathName, 'utf8') : ''
+ const { data, content } = matter(fileContents)
+ // console.log('docBySlug', content)
+ // console.log()
+
+ if (content) console.log(content)
+ return {
+ id: x,
+ title: x,
+ // ...content,
+ meta: data,
+ content: content ? await serialize(content || '') : null,
+ }
+ })
+ )
+
+ // console.log('allMarkdownDocs', allMarkdownDocs)
+
+ return {
+ props: {
+ docs: allMarkdownDocs,
+ },
+ }
+}
+
+export function getStaticPaths() {
+ let docs = getAllDocs()
+
+ return {
+ paths: docs.map(() => {
+ return {
+ params: {
+ slug: docs.map((d) => d.slug),
+ },
+ }
+ }),
+ fallback: 'blocking',
+ }
+}
diff --git a/apps/docs/public/img/gradient-bg.png b/apps/docs/public/img/gradient-bg.png
new file mode 100644
index 00000000000..ff11607e143
Binary files /dev/null and b/apps/docs/public/img/gradient-bg.png differ
diff --git a/apps/docs/public/img/icons/menu/edge-functions.svg b/apps/docs/public/img/icons/menu/functions.svg
similarity index 100%
rename from apps/docs/public/img/icons/menu/edge-functions.svg
rename to apps/docs/public/img/icons/menu/functions.svg
diff --git a/apps/docs/public/img/icons/menu/getting-started.svg b/apps/docs/public/img/icons/menu/gettingstarted.svg
similarity index 100%
rename from apps/docs/public/img/icons/menu/getting-started.svg
rename to apps/docs/public/img/icons/menu/gettingstarted.svg
diff --git a/apps/docs/public/img/icons/menu/api.svg b/apps/docs/public/img/icons/menu/reference.svg
similarity index 100%
rename from apps/docs/public/img/icons/menu/api.svg
rename to apps/docs/public/img/icons/menu/reference.svg
diff --git a/spec/supabase_dart_v1_temp_new_shape.yml b/spec/supabase_dart_v1_temp_new_shape.yml
new file mode 100644
index 00000000000..04997e1ff5b
--- /dev/null
+++ b/spec/supabase_dart_v1_temp_new_shape.yml
@@ -0,0 +1,2438 @@
+openref: 0.1
+
+info:
+ id: reference/dart
+ title: Getting started
+ description: |
+
+ Supabase Dart.
+
+ definition: ../../spec/enrichments/tsdoc_v2/combined.json
+ slugPrefix: '/'
+ specUrl: https://github.com/supabase/supabase/edit/master/spec/supabase_dart_v1.yml
+ libraries:
+ - name: 'Dart'
+ id: 'dart'
+ version: '0.0.1'
+
+functions:
+ - id: auth.signUp()
+ title: 'signUp()'
+ description: |
+ Creates a new user.
+ notes: |
+ - By default, the user needs to verify their email address before logging in. To turn this off, disable **Confirm email** in [your project](https://app.supabase.com/project/_/auth/settings).
+ - **Confirm email** determines if users need to confirm their email address after signing up.
+ - If **Confirm email** is enabled, a `user` is returned but `session` is null.
+ - If **Confirm email** is disabled, both a `user` and a `session` are returned.
+ - When the user confirms their email address, they are redirected to the [`SITE_URL`](https://supabase.com/docs/reference/auth/config#site_url) by default. You can modify your `SITE_URL` or add additional redirect URLs in [your project](https://app.supabase.com/project/_/auth/settings).
+ - If signUp() is called for an existing confirmed user:
+ - If **Confirm email** is enabled in [your project](https://app.supabase.com/project/_/auth/settings), an obfuscated/fake user object is returned.
+ - If **Confirm email** is disabled, the error message, `User already registered` is returned.
+ examples:
+ - id: sign-up.
+ name: Sign up.
+ isSpotlight: true
+ code: |
+ ```dart
+ final AuthResponse res = await supabase.auth.signUp(
+ email: 'example@email.com',
+ password: 'example-password',
+ );
+ final Session? session = res.session;
+ final User? user = res.user;
+ ```
+ - id: sign-up-with-third-party-providers.
+ name: Sign up with third-party providers.
+ hideCodeBlock: true
+ description: |
+ If you are using Flutter, you can sign up with OAuth providers using the [`signInWithOAuth()`](/docs/reference/dart/auth-signinwithoauth) method available on `supabase_flutter`.
+
+ - id: auth.signInWithPassword()
+ title: 'signInWithPassword()'
+ description: |
+ Log in an existing user using email or phone number with password.
+ notes: |
+ - Requires either an email and password or a phone number and password.
+ examples:
+ - id: sign-in-with-email-and-password
+ name: Sign in with email and password
+ isSpotlight: true
+ code: |
+ ```dart
+ final AuthResponse res = await supabase.auth.signInWithPassword(
+ email: 'example@email.com',
+ password: 'example-password',
+ );
+ final Session? session = res.session;
+ final User? user = res.user;
+ ```
+ - id: sign-in-with-phone-and-password
+ name: Sign in with phone and password
+ code: |
+ ```dart
+ final AuthResponse res = await supabase.auth.signInWithPassword(
+ phone: '+13334445555',
+ password: 'example-password',
+ );
+ final Session? session = res.session;
+ final User? user = res.user;
+ ```
+ - id: auth.signInWithOtp()
+ title: 'signInWithOtp()'
+ notes: |
+ - Requires either an email or phone number.
+ - This method is used for passwordless sign-ins where a OTP is sent to the user's email or phone number.
+ - If you're using an email, you can configure whether you want the user to receive a magiclink or a OTP.
+ - If you're using phone, you can configure whether you want the user to receive a OTP.
+ - The magic link's destination URL is determined by the [`SITE_URL`](https://supabase.com/docs/reference/auth/config#site_url). You can modify the `SITE_URL` or add additional redirect urls in [your project](https://app.supabase.com/project/_/auth/settings).
+ examples:
+ - id: sign-in-with-email.
+ name: Sign in with email.
+ isSpotlight: true
+ description: |
+ The user will be sent an email which contains either a magiclink or a OTP or both. By default, a given user can only request a OTP once every 60 seconds.
+ You can pass `emailRedirectTo` with dynamic link to bring the users back to your app after they click on the magic link.
+ code: |
+ ```dart
+ await supabase.auth.signInWithOtp(
+ email: 'example@email.com',
+ emailRedirectTo: kIsWeb ? null : 'io.supabase.flutter://signin-callback/',
+ );
+ ```
+ - id: sign-in-with-sms-otp.
+ name: Sign in with SMS OTP.
+ description: The user will be sent a SMS which contains a OTP. By default, a given user can only request a OTP once every 60 seconds.
+ code: |
+ ```dart
+ await supabase.auth.signInWithOtp(
+ phone: '+13334445555',
+ );
+ ```
+ - id: auth.signInWithOAuth()
+ title: 'signInWithOAuth()'
+ description: |
+ Signs the user in using third party OAuth providers.
+ notes: |
+ - This method is used for signing in using a third-party provider.
+ - Supabase supports many different [third-party providers](https://supabase.com/docs/guides/auth#providers).
+ examples:
+ - id: sign-in-using-a-third-party-provider
+ name: Sign in using a third-party provider
+ isSpotlight: true
+ code: |
+ ```dart
+ await supabase.auth.signInWithOAuth(Provider.github);
+ ```
+ - id: with`redirectto`
+ name: With `redirectTo`
+ description: |
+ Specify the redirect link to bring back the user via deeplink.
+ Note that `redirectTo` should be null for Flutter Web.
+ code: |
+ ```dart
+ await supabase.auth.signInWithOAuth(
+ Provider.github,
+ redirectTo: kIsWeb ? null : 'io.supabase.flutter://reset-callback/',
+ );
+ ```
+ - id: with-scopes
+ name: With scopes
+ description: |
+ If you need additional data from an OAuth provider, you can include a space-separated list of scopes in your request to get back an OAuth provider token.
+ You may also need to specify the scopes in the provider's OAuth app settings, depending on the provider.
+ code: |
+ ```dart
+ await supabase.auth.signInWithOAuth(
+ Provider.github,
+ scopes: 'repo gist notifications'
+ );
+ ...
+ // after user comes back from signin flow
+
+ final Session? session = supabase.auth.currentSession;
+ final String? oAuthToken = session?.providerToken;
+ ```
+ - id: auth.signOut()
+ title: 'signOut()'
+ description: |
+ Signs out the current user, if there is a logged in user.
+ notes: |
+ - In order to use the `signOut()` method, the user needs to be signed in first.
+ examples:
+ - id: sign-out
+ name: Sign out
+ isSpotlight: true
+ code: |
+ ```dart
+ await supabase.auth.signOut();
+ ```
+ - id: auth.verifyOtp()
+ title: 'verifyOtp()'
+ notes: |
+ - The `verifyOtp` method takes in different verification types. If a phone number is used, the type can either be `sms` or `phone_change`. If an email address is used, the type can be one of the following: `signup`, `magiclink`, `recovery`, `invite` or `email_change`.
+ - The verification type used should be determined based on the corresponding auth method called before `verifyOtp` to sign up / sign-in a user.
+ examples:
+ - id: verify-sms-one-time-password(otp)
+ name: Verify Sms One-Time Password (OTP)
+ isSpotlight: true
+ code: |
+ ```dart
+ final AuthResponse res = await supabase.auth.verifyOTP(
+ type: OtpType.sms,
+ token: '111111',
+ phone: '+13334445555',
+ );
+ final Session? session = res.session;
+ final User? user = res.user;
+ ```
+ - id: verify-signup-one-time-password(otp)
+ name: Verify Signup One-Time Password (OTP)
+ isSpotlight: false
+ code: |
+ ```dart
+ final AuthResponse res = await supabase.auth.verifyOTP(
+ type: OtpType.signup,
+ token: token,
+ phone: '+13334445555',
+ );
+ final Session? session = res.session;
+ final User? user = res.user;
+ ```
+ - id: auth.currentSession
+ title: 'currentSession'
+ description: |
+ Returns the session data, if there is an active session.
+ examples:
+ - id: get-the-session-data
+ name: Get the session data
+ isSpotlight: true
+ code: |
+ ```dart
+ final Session? session = supabase.auth.currentSession;
+ ```
+ - id: auth.currentUser
+ title: 'currentUser'
+ description: |
+ Returns the user data, if there is a logged in user.
+ examples:
+ - id: get-the-logged-in-user
+ name: Get the logged in user
+ isSpotlight: true
+ code: |
+ ```dart
+ final User? user = supabase.auth.currentUser;
+ ```
+ - id: auth.updateUser()
+ title: 'updateUser()'
+ description: |
+ Updates user data, if there is a logged in user.
+ notes: |
+ - In order to use the `updateUser()` method, the user needs to be signed in first.
+ - By Default, email updates sends a confirmation link to both the user's current and new email.
+ To only send a confirmation link to the user's new email, disable **Secure email change** in your project's [email auth provider settings](https://app.supabase.com/project/_/auth/settings).
+ examples:
+ - id: update-the-email-for-an-authenticated-user
+ name: Update the email for an authenticated user
+ description: Sends a "Confirm Email Change" email to the new email address.
+ isSpotlight: true
+ code: |
+ ```dart
+ final UserResponse res = await supabase.auth.updateUser(
+ UserAttributes(
+ email: 'example@email.com',
+ ),
+ );
+ final User? updatedUser = res.user;
+ ```
+ - id: update-the-password-for-an-authenticated-user
+ name: Update the password for an authenticated user
+ isSpotlight: false
+ code: |
+ ```dart
+ final UserResponse res = await supabase.auth.updateUser(
+ UserAttributes(
+ password: 'new password',
+ ),
+ );
+ final User? updatedUser = res.user;
+ ```
+ - id: update-the-user's-metadata
+ name: Update the user's metadata
+ isSpotlight: true
+ code: |
+ ```dart
+ final UserResponse res = await supabase.auth.updateUser(
+ UserAttributes(
+ data: { 'hello': 'world' },
+ ),
+ );
+ final User? updatedUser = res.user;
+ ```
+ - id: auth.onAuthStateChange()
+ title: 'onAuthStateChange()'
+ description: |
+ Receive a notification every time an auth event happens.
+ notes: |
+ - Types of auth events: `AuthChangeEvent.passwordRecovery`, `AuthChangeEvent.signedIn`, `AuthChangeEvent.signedOut`, `AuthChangeEvent.tokenRefreshed`, `AuthChangeEvent.userUpdated`and `AuthChangeEvent.userDeleted`
+ examples:
+ - id: listen-to-auth-changes
+ name: Listen to auth changes
+ isSpotlight: true
+ code: |
+ ```dart
+ final authSubscription = supabase.auth.onAuthStateChange.listen((data) {
+ final AuthChangeEvent event = data.event;
+ final Session? session = data.session;
+ });
+ ```
+ - id: listen-to-a-specific-event
+ name: Listen to a specific event
+ code: |
+ ```dart
+ final authSubscription = supabase.auth.onAuthStateChange.listen((data) {
+ final AuthChangeEvent event = data.event;
+ if (event == AuthChangeEvent.signedIn) {
+ // handle signIn
+ }
+ });
+ ```
+ - id: unsubscribe-from-auth-subscription
+ name: Unsubscribe from auth subscription
+ code: |
+ ```dart
+ final authSubscription = supabase.auth.onAuthStateChange((event, session) {});
+
+ authSubscription.cancel();
+ ```
+ - id: auth.resetPasswordForEmail
+ title: 'resetPasswordForEmail()'
+ description: |
+ Sends a reset request to an email address.
+ notes: |
+ Sends a password reset request to an email address. When the user clicks the reset link in the email they are redirected back to your application. Prompt the user for a new password and call auth.updateUser():
+
+ ```dart
+ await supabase.auth.resetPasswordForEmail(
+ 'sample@email.com',
+ redirectTo: kIsWeb ? null : 'io.supabase.flutter://reset-callback/',
+ );
+ ```
+ examples:
+ - id: reset-password-for-flutter
+ name: Reset password for Flutter
+ isSpotlight: true
+ code: |
+ `redirectTo` is used to open the app via deeplink when user opens the password reset email.
+ ```dart
+ await supabase.auth.resetPasswordForEmail(
+ 'sample@email.com',
+ redirectTo: kIsWeb ? null : 'io.supabase.flutter://reset-callback/',
+ );
+ ```
+ - id: invoke()
+ title: 'invoke()'
+ description: |
+ Invokes a Supabase Function. See the [guide](/docs/guides/functions) for details on writing Functions.
+ notes: |
+ - Requires an Authorization header.
+ - Invoke params generally match the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) spec.
+ examples:
+ - id: basic-invocation.
+ name: Basic invocation.
+ isSpotlight: true
+ code: |
+ ```dart
+ final res = await supabase.functions.invoke('hello', body: {'foo': 'baa'});
+ final data = res.data;
+ ```
+ - id: specifying-response-type.
+ name: Specifying response type.
+ description: |
+ By default, `invoke()` will parse the response as JSON. You can parse the response in the following formats: `json`, `blob`, `text`, and `arrayBuffer`.
+ isSpotlight: true
+ code: |
+ ```dart
+ final res = await supabase.functions.invoke(
+ 'hello',
+ body: {'foo': 'baa'},
+ responseType: ResponseType.text,
+ );
+ final data = res.data;
+ ```
+ - id: parsing-custom-headers.
+ name: Parsing custom headers.
+ description: |
+ Any `headers` will be passed through to the function. A common pattern is to pass a logged-in user's JWT token as an Authorization header.
+ isSpotlight: true
+ code: |
+ ```dart
+ final res = await supabase.functions.invoke(
+ 'hello',
+ body: {'foo': 'baa'},
+ headers: {
+ 'Authorization': 'Bearer ${supabase.auth.currentSession?.accessToken}'
+ },
+ );
+ ```
+ - id: select()
+ description: |
+ Performs vertical filtering with SELECT.
+ title: 'Fetch data: select()'
+ notes: |
+ - By default, Supabase projects will return a maximum of 1,000 rows. This setting can be changed in Project API Settings. It's recommended that you keep it low to limit the payload size of accidental or malicious requests. You can use `range()` queries to paginate through your data.
+ - `select()` can be combined with [Modifiers](/docs/reference/dart/using-modifiers)
+ - `select()` can be combined with [Filters](/docs/reference/dart/using-filters)
+ - If using the Supabase hosted platform `apikey` is technically a reserved keyword, since the API gateway will pluck it out for authentication. [It should be avoided as a column name](https://github.com/supabase/supabase/issues/5465).
+ examples:
+ - id: getting-your-data
+ name: Getting your data
+ isSpotlight: true
+ code: |
+ ```dart
+ final data = await supabase
+ .from('cities')
+ .select('name');
+ ```
+ - id: selecting-specific-columns
+ name: Selecting specific columns
+ description: You can select specific fields from your tables.
+ code: |
+ ```dart
+ final data = await supabase
+ .from('countries')
+ .select('''
+ name,
+ cities (
+ name
+ )
+ ''');
+ ```
+ - id: query-foreign-tables
+ name: Query foreign tables
+ description: If your database has relationships, you can query related tables too.
+ code: |
+ ```dart
+ final data = await supabase
+ .from('products')
+ .select('''
+ id,
+ supplier:supplier_id ( name ),
+ purchaser:purchaser_id ( name )
+ ''');
+ ```
+ - id: query-the-same-foreign-table-multiple-times
+ name: Query the same foreign table multiple times
+ description: |
+ Sometimes you will need to query the same foreign table twice.
+ In this case, you can use the name of the joined column to identify
+ which join you intend to use. For convenience, you can also give an
+ alias for each column. For example, if we had a shop of products,
+ and we wanted to get the supplier and the purchaser at the same time
+ (both in the users) table:
+ code: |
+ ```dart
+ final data = await supabase
+ .from('messages')
+ .select('*, users!inner(*)')
+ .eq('users.username', 'Jane');
+ ```
+ - id: filtering-with-inner-joins
+ name: Filtering with inner joins
+ description: |
+ If you want to filter a table based on a child table's values you can use the `!inner()` function. For example, if you wanted
+ to select all rows in a `message` table which belong to a user with the `username` "Jane":
+ code: |
+ ```dart
+ final data = await supabase
+ .from('messages')
+ .select('*, users!inner(*)')
+ .eq('users.username', 'Jane');
+ ```
+ - id: querying-with-count-option
+ name: Querying with count option
+ description: |
+ You can get the number of rows by using the count option.
+ Allowed values for count option are [exact](https://postgrest.org/en/stable/api.html#exact-count), [planned](https://postgrest.org/en/stable/api.html#planned-count) and [estimated](https://postgrest.org/en/stable/api.html#estimated-count).
+ code: |
+ ```dart
+ final res = await supabase.from('cities').select(
+ 'name',
+ const FetchOptions(
+ count: CountOption.exact,
+ ),
+ );
+
+ final count = res.count;
+ ```
+ - id: querying-json-data
+ name: Querying JSON data
+ description: |
+ If you have data inside of a JSONB column, you can apply select
+ and query filters to the data values. Postgres offers a
+ [number of operators](https://www.postgresql.org/docs/current/functions-json.html)
+ for querying JSON data. Also see
+ [PostgREST docs](http://postgrest.org/en/v7.0.0/api.html#json-columns) for more details.
+ code: |
+ ```dart
+ final data = await supabase
+ .from('users')
+ .select('''
+ id, name,
+ address->street
+ ''')
+ .eq('address->postcode', 90210);
+ ```
+ - id: return-data-as-csv
+ name: Return data as CSV
+ description: |
+ By default the data is returned in JSON format, however you can also request for it to be returned as Comma Separated Values.
+ code: |
+ ```dart
+ final data = await supabase
+ .from('users')
+ .select()
+ .csv();
+ ```
+
+ - id: insert()
+ description: |
+ Performs an INSERT into the table.
+ title: 'Create data: insert()'
+ examples:
+ - id: create-a-record
+ name: Create a record
+ isSpotlight: true
+ code: |
+ ```dart
+ final data = await supabase
+ .from('cities')
+ .insert({'name': 'The Shire', 'country_id': 554});
+ ```
+ - id: bulk-create
+ name: Bulk create
+ code: |
+ ```dart
+ final res = await supabase.from('cities').insert([
+ {'name': 'The Shire', 'country_id': 554},
+ {'name': 'Rohan', 'country_id': 555},
+ ]);
+ ```
+
+ - id: update()
+ description: |
+ Performs an UPDATE on the table.
+ title: 'Modify data: update()'
+ notes: |
+ - `update()` should always be combined with [Filters](/docs/reference/dart/using-filters) to target the item(s) you wish to update.
+ examples:
+ - id: updating-your-data
+ name: Updating your data
+ isSpotlight: true
+ code: |
+ ```dart
+ final data = await supabase
+ .from('cities')
+ .update({ 'name': 'Middle Earth' })
+ .match({ 'name': 'Auckland' });
+ ```
+ - id: updating-json-data
+ name: Updating JSON data
+ description: |
+ Postgres offers a
+ [number of operators](https://www.postgresql.org/docs/current/functions-json.html)
+ for working with JSON data. Right now it is only possible to update an entire JSON document,
+ but we are [working on ideas](https://github.com/PostgREST/postgrest/issues/465) for updating individual keys.
+ code: |
+ ```dart
+ final data = await supabase
+ .from('users')
+ .update({
+ 'address': {
+ 'street': 'Melrose Place',
+ 'postcode': 90210
+ }
+ })
+ .eq('address->postcode', 90210);
+ ```
+
+ - id: upsert()
+ description: |
+ Performs an UPSERT into the table.
+ title: 'Upsert data: upsert()'
+ notes: |
+ - Primary keys should be included in the data payload in order for an update to work correctly.
+ - Primary keys must be natural, not surrogate. There are however, [workarounds](https://github.com/PostgREST/postgrest/issues/1118) for surrogate primary keys.
+ examples:
+ - id: upsert-your-data
+ name: Upsert your data
+ isSpotlight: true
+ code: |
+ ```dart
+ final data = await supabase
+ .from('messages')
+ .upsert({ 'id': 3, 'message': 'foo', 'username': 'supabot' });
+ ```
+ - id: upserting-into-tables-with-constraints
+ name: Upserting into tables with constraints
+ description: |
+ Running the following will cause supabase to upsert data into the `users` table.
+ If the username 'supabot' already exists, the `onConflict` argument tells supabase to overwrite that row
+ based on the column passed into `onConflict`.
+ isSpotlight: true
+ code: |
+ ```dart
+ final data = await supabase
+ .from('users')
+ .upsert({ 'username': 'supabot' }, { 'onConflict': 'username' });
+ ```
+ - id: return-the-exact-number-of-rows
+ name: Return the exact number of rows
+ description: |
+ Allowed values for count option are `exact`, `planned` and `estimated`.
+ code: |
+ ```dart
+ final res = await supabase.from('users').upsert(
+ {'id': 3, 'message': 'foo', 'username': 'supabot'},
+ options: const FetchOptions(count: CountOption.exact),
+ );
+
+ final data = res.data;
+ final count = res.count;
+ ```
+
+ - id: delete()
+ description: |
+ Performs a DELETE on the table.
+ title: 'Delete data: delete()'
+ notes: |
+ - `delete()` should always be combined with [Filters](/docs/reference/dart/using-filters) to target the item(s) you wish to delete.
+ examples:
+ - id: delete-records
+ name: Delete records
+ isSpotlight: true
+ code: |
+ ```dart
+ final data = await supabase
+ .from('cities')
+ .delete()
+ .match({ 'id': 666 });
+ ```
+
+ - id: rpc()
+ title: 'Stored Procedures: rpc()'
+ description: |
+ You can call stored procedures as a "Remote Procedure Call".
+
+ That's a fancy way of saying that you can put some logic into your database then call it from anywhere.
+ It's especially useful when the logic rarely changes - like password resets and updates.
+ examples:
+ - id: call-a-stored-procedure
+ name: Call a stored procedure
+ isSpotlight: true
+ description: This is an example invoking a stored procedure.
+ code: |
+ ```dart
+ final data = await supabase
+ .rpc('hello_world');
+ ```
+ - id: with-parameters
+ name: With Parameters
+ code: |
+ ```dart
+ final data = await supabase
+ .rpc('echo_city', params: { 'name': 'The Shire' });
+ ```
+
+ - id: subscribe()
+ description: |
+ Subscribe to realtime changes in your database.
+ title: 'on().subscribe()'
+ notes: |
+ - Realtime is disabled by default for new Projects for better database performance and security. You can turn it on by [managing replication](/docs/guides/api#managing-realtime).
+ - If you want to receive the "previous" data for updates and deletes, you will need to set `REPLICA IDENTITY` to `FULL`, like this: `ALTER TABLE your_table REPLICA IDENTITY FULL;`
+ examples:
+ - id: listen-to-all-database-changes
+ name: Listen to all database changes
+ isSpotlight: true
+ code: |
+ ```dart
+ supabase.channel('*').on(
+ RealtimeListenTypes.postgresChanges,
+ ChannelFilter(event: '*', schema: '*'),
+ (payload, [ref]) {
+ print('Change received: ${payload.toString()}');
+ },
+ ).subscribe();
+ ```
+ - id: listening-to-a-specific-table
+ name: Listening to a specific table
+ code: |
+ ```dart
+ supabase.channel('public:countries').on(
+ RealtimeListenTypes.postgresChanges,
+ ChannelFilter(event: '*', schema: 'public', table: 'countries'),
+ (payload, [ref]) {
+ print('Change received: ${payload.toString()}');
+ },
+ ).subscribe();
+ ```
+ - id: listening-to-inserts
+ name: Listening to inserts
+ code: |
+ ```dart
+ supabase.channel('public:countries').on(
+ RealtimeListenTypes.postgresChanges,
+ ChannelFilter(event: 'INSERT', schema: 'public', table: 'countries'),
+ (payload, [ref]) {
+ print('Change received: ${payload.toString()}');
+ },
+ ).subscribe();
+ ```
+ - id: listening-to-updates
+ name: Listening to updates
+ description: |
+ By default, Supabase will send only the updated record. If you want to receive the previous values as well you can
+ enable full replication for the table you are listening too:
+
+ ```sql
+ alter table "your_table" replica identity full;
+ ```
+ code: |
+ ```dart
+ supabase.channel('public:countries').on(
+ RealtimeListenTypes.postgresChanges,
+ ChannelFilter(event: 'UPDATE', schema: 'public', table: 'countries'),
+ (payload, [ref]) {
+ print('Change received: ${payload.toString()}');
+ },
+ ).subscribe();
+ ```
+ - id: listening-to-deletes
+ name: Listening to deletes
+ description: |
+ By default, Supabase does not send deleted records. If you want to receive the deleted record you can
+ enable full replication for the table you are listening too:
+
+ ```sql
+ alter table "your_table" replica identity full;
+ ```
+ code: |
+ ```dart
+ supabase.channel('public:countries').on(
+ RealtimeListenTypes.postgresChanges,
+ ChannelFilter(event: 'DELETE', schema: 'public', table: 'countries'),
+ (payload, [ref]) {
+ print('Change received: ${payload.toString()}');
+ },
+ ).subscribe();
+ ```
+ - id: listening-to-multiple-events
+ name: Listening to multiple events
+ description: You can chain listeners if you want to listen to multiple events for each table.
+ code: |
+ ```dart
+ supabase.channel('public:countries').on(RealtimeListenTypes.postgresChanges,
+ ChannelFilter(event: 'INSERT', schema: 'public', table: 'countries'),
+ (payload, [ref]) {
+ print('Change received: ${payload.toString()}');
+ }).on(RealtimeListenTypes.postgresChanges,
+ ChannelFilter(event: 'DELETE', schema: 'public', table: 'countries'),
+ (payload, [ref]) {
+ print('Change received: ${payload.toString()}');
+ }).subscribe();
+ ```
+ - id: listening-to-row-level-changes
+ name: Listening to row level changes
+ description: You can listen to individual rows using the format `{table}:{col}=eq.{val}` - where `{col}` is the column name, and `{val}` is the value which you want to match.
+ code: |
+ ```dart
+ supabase.channel('public:countries:id=eq.200').on(
+ RealtimeListenTypes.postgresChanges,
+ ChannelFilter(
+ event: 'UPDATE',
+ schema: 'public',
+ table: 'countries',
+ filter: 'id=eq.200',
+ ), (payload, [ref]) {
+ print('Change received: ${payload.toString()}');
+ }).subscribe();
+ ```
+
+ - id: removeChannel()
+ description: |
+ Unsubscribes and removes Realtime channel from Realtime client.
+ title: 'removeChannel()'
+ notes: |
+ - Removing a channel is a great way to maintain the performance of your project's Realtime service as well as your database if you're listening to Postgres changes. Supabase will automatically handle cleanup 30 seconds after a client is disconnected, but unused channels may cause degradation as more clients are simultaneously subscribed.
+ examples:
+ - id: remove-a-channel
+ name: Remove a channel
+ isSpotlight: true
+ code: |
+ ```dart
+ final status = await supabase.removeChannel(channel);
+ ```
+
+ - id: removeAllChannels()
+ description: |
+ Unsubscribes and removes all Realtime channels from Realtime client.
+ title: 'removeAllChannels()'
+ notes: |
+ - Removing channels is a great way to maintain the performance of your project's Realtime service as well as your database if you're listening to Postgres changes. Supabase will automatically handle cleanup 30 seconds after a client is disconnected, but unused channels may cause degradation as more clients are simultaneously subscribed.
+ examples:
+ - id: remove-all-channels
+ name: Remove all channels
+ isSpotlight: true
+ code: |
+ ```dart
+ final statuses = await supabase.removeAllChannels();
+ ```
+
+ - id: getChannels()
+ description: |
+ Returns all Realtime channels.
+ title: 'getChannels()'
+ examples:
+ - id: get-all-channels
+ name: Get all channels
+ isSpotlight: true
+ code: |
+ ```dart
+ final channels = supabase.getChannels();
+ ```
+
+ - id: stream()
+ description: |
+ Notifies of data at the queried table.
+ title: 'stream()'
+ notes: |
+ - `stream()` will emit the initial data as well as any further change on the database as `Stream` of `List