diff --git a/apps/docs/components/DocSearch.tsx b/apps/docs/components/DocSearch.tsx index 52fc0956ecd..d8bde374580 100644 --- a/apps/docs/components/DocSearch.tsx +++ b/apps/docs/components/DocSearch.tsx @@ -74,11 +74,14 @@ export function SearchProvider({ children }: any) { appId={APP_ID} // @ts-ignore navigator={{ - navigate({ suggestionUrl }) { + navigate({ itemUrl }) { setIsOpen(false) - router.push(suggestionUrl) + router.push(itemUrl) }, }} + getMissingResultsUrl={({ query }) => { + return `https://github.com/supabase/supabase/issues/new?title=Unable+to+search+docs+with+query:+${query}` + }} hitComponent={Hit} transformItems={(items) => { return items.map((item, index) => { diff --git a/apps/docs/components/Navigation/Navigation.constants.ts b/apps/docs/components/Navigation/Navigation.constants.ts index 47c2bee3335..5bfb8aa40df 100644 --- a/apps/docs/components/Navigation/Navigation.constants.ts +++ b/apps/docs/components/Navigation/Navigation.constants.ts @@ -226,8 +226,9 @@ export const menuItems: NavMenu = { label: 'Edge Functions', items: [ { name: 'Overview', url: '/guides/functions', items: [] }, + { name: 'Quickstart', url: '/guides/functions/quickstart', items: [] }, { name: 'Auth', url: '/guides/functions/auth', items: [] }, - { name: 'Examples', url: '/guides/functions/examples', items: [] }, + { name: 'Best Practices', url: '/guides/functions/best-practices', items: [] }, { name: 'CI/CD Workflow', url: '/guides/functions/cicd-workflow', items: [] }, ], }, @@ -313,6 +314,7 @@ export const menuItems: NavMenu = { { name: 'Sequin', url: '/guides/integrations/sequin', items: [] }, { name: 'Snaplet', url: '/guides/integrations/snaplet', items: [] }, { name: 'Vercel', url: '/guides/integrations/vercel', items: [] }, + { name: 'Zuplo', url: '/guides/integrations/zuplo', items: [] }, ], }, { diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts index 004ce383c5d..b6c61adcf19 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts @@ -453,21 +453,21 @@ export const reference = { items: [ { name: 'supabase-js', - url: '/new/reference/javascript/start', + url: '/reference/javascript/start', level: 'reference_javascript', items: [], icon: '/img/icons/javascript.svg', }, { name: 'supabase-dart', - url: '/new/reference/dart/start', + url: '/reference/dart/start', level: 'reference_dart', items: [], icon: '/img/icons/javascript.svg', }, { name: 'supbase-python', - url: '/new/reference/python/start', + url: '/reference/python/start', level: 'reference_python', items: [], icon: '/img/icons/javascript.svg', @@ -479,13 +479,13 @@ export const reference = { items: [ { name: 'Supabase CLI', - url: '/new/reference/cli/start', + url: '/reference/cli/start', items: [], icon: '/img/icons/cli.svg', }, { name: 'Management API', - url: '/new/reference/javascript', + url: '/reference/javascript', items: [], icon: '/img/icons/javascript.svg', }, @@ -598,20 +598,20 @@ export const references = [ versions: ['v2', 'v1'], description: 'something about the reference', icon: '/docs/img/icons/javascript-icon.svg', - url: '/new/reference/javascript/start', + url: '/reference/javascript/start', }, { label: 'supabase-py', description: 'something about the reference', icon: '/docs/img/icons/python-icon.svg', - url: '/new/reference/python/start', + url: '/reference/python/start', }, { label: 'supabase-dart', versions: ['v1', 'v0'], description: 'something about the reference', icon: '/docs/img/icons/dart-icon.svg', - url: '/new/reference/dart/start', + url: '/reference/dart/start', }, ], }, @@ -622,13 +622,13 @@ export const references = [ label: 'CLI', description: 'something about the reference', icon: '/docs/img/icons/cli-icon.svg', - url: '/new/reference/cli/start', + url: '/reference/cli/start', }, { label: 'Management API', description: 'something about the reference', icon: '/docs/img/icons/api-icon.svg', - url: '/new/reference/management-api/start', + url: '/reference/management-api/start', }, ], }, diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.tsx b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.tsx index 1b50f85b9ed..dcb16381bd8 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.tsx +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.tsx @@ -1,13 +1,11 @@ -import Link from 'next/link' -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' -import NavigationMenuRefList from './NavigationMenuRefList' -import NavigationMenuCliList from './NavigationMenuCliList' import { useTheme } from 'common/Providers' import Image from 'next/image' +import Link from 'next/link' +import { useRouter } from 'next/router' +import { useEffect, useState } from 'react' +import NavigationMenuCliList from './NavigationMenuCliList' +import NavigationMenuGuideList from './NavigationMenuGuideList' +import NavigationMenuRefList from './NavigationMenuRefList' const SideNav = () => { const router = useRouter() @@ -40,9 +38,6 @@ const SideNav = () => { case url.includes(`/docs/guides/functions`) && url: setLevel('functions') break - case url.includes(`/docs/reference`) && url: - setLevel('reference') - break case url.includes(`/docs/guides/integrations`) && url: setLevel('integrations') break @@ -50,13 +45,13 @@ const SideNav = () => { (url.includes(`/docs/guides/hosting/platform`) && url): setLevel('platform') break - case url.includes(`/docs/new/reference/javascript/`) && url: + case url.includes(`/docs/reference/javascript`) && url: setLevel('reference_javascript') break - case url.includes(`/docs/new/reference/dart/`) && url: + case url.includes(`/docs/reference/dart`) && url: setLevel('reference_dart') break - case url.includes(`/docs/new/reference/cli/`) && url: + case url.includes(`/docs/reference/cli`) && url: setLevel('reference_cli') break @@ -155,21 +150,21 @@ const SideNav = () => { label: 'JavaScript Client', icon: '/img/icons/javascript-icon', hasLightIcon: false, - href: '/new/reference/javascript/start', - level: 'reference_javascript', - }, - { - label: 'Python Client Library', - icon: '/img/icons/python-icon', - hasLightIcon: false, - href: '/new/reference/javascript/start', + href: '/reference/javascript/start', level: 'reference_javascript', }, + // { + // label: 'Python Client Library', + // icon: '/img/icons/python-icon', + // hasLightIcon: false, + // href: '/reference/javascript/start', + // level: 'reference_javascript', + // }, { label: 'Dart Client Library', icon: '/img/icons/dart-icon', hasLightIcon: false, - href: '/new/reference/dart/start', + href: '/reference/dart/start', level: 'reference_dart', }, { @@ -179,20 +174,20 @@ const SideNav = () => { label: 'Mangement API', icon: '/img/icons/api-icon', hasLightIcon: false, - href: '/new/reference/javascript/start', + href: '/reference/javascript/start', level: 'reference_javascript', }, { label: 'CLI', icon: '/img/icons/cli-icon', hasLightIcon: false, - href: '/new/reference/cli/start', + href: '/reference/cli/start', level: 'reference_javascript', }, { label: 'Self hosting server', icon: '/img/icons/menu/platform', - href: '/new/reference/javascript/start', + href: '/reference/javascript/start', level: 'reference_javascript', }, ], @@ -279,90 +274,6 @@ const SideNav = () => { - - {/* // 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} -
  • - ) - })} -
-
*/} ) } diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuRefList.tsx b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuRefList.tsx index 87a18b11847..9f370952ab1 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuRefList.tsx +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuRefList.tsx @@ -43,7 +43,7 @@ const NavigationMenuRefList = ({ currentLevel, setLevel, id }) => { }) => { return (
  • - + {icon && } {title} diff --git a/apps/docs/components/Navigation/NavigationMenu/TopNavBarRef.tsx b/apps/docs/components/Navigation/NavigationMenu/TopNavBarRef.tsx index 94fd02a817c..0f790090caf 100644 --- a/apps/docs/components/Navigation/NavigationMenu/TopNavBarRef.tsx +++ b/apps/docs/components/Navigation/NavigationMenu/TopNavBarRef.tsx @@ -92,7 +92,7 @@ const TopNavBarRef: FC = () => { DOCS - {/* {router.asPath.includes('/new/reference/') && } */} + {/* {router.asPath.includes('/reference/') && } */}
    diff --git a/apps/docs/components/Options.tsx b/apps/docs/components/Options.tsx index 269bca93077..34f29821b07 100644 --- a/apps/docs/components/Options.tsx +++ b/apps/docs/components/Options.tsx @@ -1,6 +1,6 @@ import { FC, useState } from 'react' import { IconXCircle } from '~/../../packages/ui' -import { AcceptedValue } from '~/pages/new/reference/cli/[...slug]' +import { AcceptedValue } from '~/pages/reference/cli/[...slug]' interface IOptions { name?: string diff --git a/apps/docs/components/Params.tsx b/apps/docs/components/Params.tsx index 7475d4ab2de..32118482069 100644 --- a/apps/docs/components/Params.tsx +++ b/apps/docs/components/Params.tsx @@ -1,5 +1,5 @@ import { FC } from 'react' -import { Flag } from '~/pages/new/reference/cli/[...slug]' +import { Flag } from '~/pages/reference/cli/[...slug]' type IParamProps = Flag | any diff --git a/apps/docs/data/nav/supabase-dart/v1.ts b/apps/docs/data/nav/supabase-dart/v1.ts index fb1491e2555..8fe2fad4791 100644 --- a/apps/docs/data/nav/supabase-dart/v1.ts +++ b/apps/docs/data/nav/supabase-dart/v1.ts @@ -118,6 +118,11 @@ const Nav = [ url: '/reference/dart/storage-from-createsignedurl', items: [], }, + { + name: 'from.createSignedUrls()', + url: '/reference/dart/storage-from-createsignedurls', + items: [], + }, { name: 'from.getPublicUrl()', url: '/reference/dart/storage-from-getpublicurl', diff --git a/apps/docs/docs/reference/dart/initializing.mdx b/apps/docs/docs/reference/dart/initializing.mdx index 00a69bbf1f3..7d914d71efd 100644 --- a/apps/docs/docs/reference/dart/initializing.mdx +++ b/apps/docs/docs/reference/dart/initializing.mdx @@ -28,6 +28,33 @@ Once you initialize Supabase in your `main()` method, you can access the `Supaba final supabase = Supabase.instance.client; ``` +### Call `initialize()` with custom headers + +You can pass `headers` to initialize your Supabase client with customer headers. +Here is an example of passing a custom auth header to Supabase client. +```dart title=main.dart +Future main() async { + await Supabase.initialize( + url: 'https://xyzcompany.supabase.co', + anonKey: 'public-anon-key', + headers: { + 'Authorization': 'Bearer $accessToken', + }, + ); + runApp(const MyApp()); +} +``` + +### Call `initialize()`multiple times + +You can initialize Supabase multiple times in your app. When doing so, call `dispose()` each time before you initialize again. + +```dart +Supabase.instance.dispose(); + +await Supabase.initialize(url: 'https://xyzcompany.supabase.co', anonKey: 'public-anon-key'); +``` + ## Other Dart Projects You can initialize a new Supabase client using the `SupabaseClient()` method. diff --git a/apps/docs/docs/reference/javascript/v1/initializing.mdx b/apps/docs/docs/reference/javascript/v1/initializing.mdx index d18f8017b3e..7ea5f5cf164 100644 --- a/apps/docs/docs/reference/javascript/v1/initializing.mdx +++ b/apps/docs/docs/reference/javascript/v1/initializing.mdx @@ -117,7 +117,7 @@ const supabase = createClient('https://xyzcompany.supabase.co', 'public-anon-key ``` By default the API server points to the `public` schema. You can enable other database schemas within the Dashboard. -Go to `Settings > API > Schema` and add the schema which you want to expose to the API. +Go to `Settings > API > Schema` and add the schema which you want to expose to the API. You also need to grant `USAGE` on your new schema with the grants you desire, such as `SELECT, INSERT, UPDATE, DELETE`. Note: each client connection can only access a single schema, so the code above can access the `other_schema` schema but cannot access the `public` schema. diff --git a/apps/docs/layouts/SiteRefLayout.tsx b/apps/docs/layouts/SiteRefLayout.tsx index f9a2b8179d1..dc4ae3a8c69 100644 --- a/apps/docs/layouts/SiteRefLayout.tsx +++ b/apps/docs/layouts/SiteRefLayout.tsx @@ -21,10 +21,10 @@ const SiteRefLayout = ({ children }) => { return ( <>
    - + /> */}
    { DOCS - {/* {router.asPath.includes('/new/reference/') && } */} + {/* {router.asPath.includes('/reference/') && } */}
    diff --git a/apps/docs/layouts/ref/RefSubLayout.tsx b/apps/docs/layouts/ref/RefSubLayout.tsx index f280172be7b..7f32aa99a3c 100644 --- a/apps/docs/layouts/ref/RefSubLayout.tsx +++ b/apps/docs/layouts/ref/RefSubLayout.tsx @@ -1,22 +1,22 @@ import { useInView } from 'react-intersection-observer' import { FC } from 'react' -interface ISectionContainer extends FC { +interface ISectionContainer { id: string title?: string monoFont?: boolean } type RefSubLayoutSubComponents = { - Section: ISectionContainer - Details: ISectionDetails - Examples: ISectionExamples + Section: FC + Details: FC + Examples: FC } type StickyHeader = { id: string - title: string - monoFont: boolean + title?: string + monoFont?: boolean } type RefSubLayoutType = {} @@ -31,16 +31,16 @@ const RefSubLayout: FC & RefSubLayoutSubComponents = (props) = ) } -const Section: FC = ({ id, title, monoFont, children }) => { +const Section: FC = (props) => { return ( -
    - -
    {children}
    +
    + +
    {props.children}
    ) } -const StickyHeader: FC = ({ id, title, monoFont }) => { +const StickyHeader: FC = (props) => { const { ref } = useInView({ threshold: 1, rootMargin: '30% 0% -35% 0px', @@ -52,21 +52,23 @@ const StickyHeader: FC = ({ id, title, monoFont }) => { return (

    - {title} + {props.title && {props.title}}

    ) } -interface ISectionDetails extends FC {} +interface ISectionDetails {} -const Details: FC = (props: any) => { - return
    {props.children}
    +const Details: FC = (props) => { + return
    {props.children}
    } -interface ISectionExamples extends FC {} +interface ISectionExamples {} const Examples: FC = (props) => { return ( @@ -76,7 +78,6 @@ const Examples: FC = (props) => { ) } -// @ts-ignore // needs typing with FC type RefSubLayout.Section = Section RefSubLayout.Details = Details RefSubLayout.Examples = Examples diff --git a/apps/docs/lib/refGenerator/helpers.ts b/apps/docs/lib/refGenerator/helpers.ts index e0e3d1f49b6..b87098f22c8 100644 --- a/apps/docs/lib/refGenerator/helpers.ts +++ b/apps/docs/lib/refGenerator/helpers.ts @@ -150,19 +150,20 @@ function extractParamTypeAsString(paramDefinition) { } else if (paramDefinition.type?.type === 'union') { // only do this for literal/primitive types - for complex objects we just return 'object' if (paramDefinition.type.types.every(({ type }) => ['literal', 'intrinsic'].includes(type))) { - return paramDefinition.type.types.map((x) => { - if (x.type === 'literal') { - if (typeof x.value === 'string') { - return `"${x.value}"` + return paramDefinition.type.types + .map((x) => { + if (x.type === 'literal') { + if (typeof x.value === 'string') { + return `"${x.value}"` + } + return `${x.value}` + } else if (x.type === 'intrinsic') { + if (x.name === 'unknown') { + return 'any' + } + return x.name } - return `${x.value}` - } else if (x.type === 'intrinsic') { - if (x.name === 'unknown') { - return 'any' - } - return x.name - } - }) + }) .join(' | ') } } else if (paramDefinition.type?.type === 'array') { @@ -231,6 +232,7 @@ export function gen_v3(spec: OpenAPIV3.Document, dest: string, { apiUrl }: { api responseList: toArrayWithKey(operation.responses!, 'responseCode') || [], } + // @ts-expect-error // missing 'responses', see OpenAPIV3.OperationObject.responses operations.push(enriched) }) }) diff --git a/apps/docs/next.config.mjs b/apps/docs/next.config.mjs index e6c750eb710..eaa58ed0fec 100644 --- a/apps/docs/next.config.mjs +++ b/apps/docs/next.config.mjs @@ -52,7 +52,7 @@ const nextConfig = { async headers() { return [ { - source: '/(.*)', + source: '/:path*', headers: [ { key: 'Strict-Transport-Security', diff --git a/apps/docs/package.json b/apps/docs/package.json index 1740ab5b95a..e5b93c4dfb8 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -37,10 +37,10 @@ "@algolia/autocomplete-plugin-recent-searches": "^1.7.2", "@apollo/client": "^3.6.6", "@code-hike/mdx": "^0.7.4", - "@docsearch/react": "1.0.0-alpha.27", - "@mdx-js/loader": "^2.1.5", - "@mdx-js/react": "^2.1.5", - "@next/mdx": "^12.3.2", + "@docsearch/react": "^3.3.0", + "@mdx-js/loader": "^1.6.22", + "@mdx-js/react": "^1.6.22", + "@next/mdx": "^12.0.4", "@radix-ui/react-accordion": "^1.0.1", "@tailwindcss/typography": "^0.4.1", "algoliasearch": "^4.14.2", diff --git a/apps/docs/pages/404.tsx b/apps/docs/pages/404.tsx index 94f4db764e3..71b9bb5f6f5 100644 --- a/apps/docs/pages/404.tsx +++ b/apps/docs/pages/404.tsx @@ -33,9 +33,9 @@ export default function Custom404() { }`} >
    -

    Looking for something? πŸ”

    +

    Looking for something?

    - We couldn't find the page that you're looking for! + We could not find the page that you are looking for!

    diff --git a/apps/docs/pages/_middleware.ts b/apps/docs/pages/_middleware.ts index c7bb67a3023..7b7ed1f968b 100644 --- a/apps/docs/pages/_middleware.ts +++ b/apps/docs/pages/_middleware.ts @@ -11,5 +11,5 @@ export function middleware(request: NextRequest) { // See "Matching Paths" below to learn more export const config = { - matcher: '/about/:path*', + //matcher: '/about/:path*', } diff --git a/apps/docs/pages/guides/auth.mdx b/apps/docs/pages/guides/auth.mdx index 9b2d55fcb77..85b1fdc96da 100644 --- a/apps/docs/pages/guides/auth.mdx +++ b/apps/docs/pages/guides/auth.mdx @@ -57,31 +57,43 @@ You can enable third-party providers with the click of a button by navigating to When using third-party providers, the [Supabase client library](/docs/reference/javascript/auth-signinwithoauth#sign-in-using-a-third-party-provider-with-redirect) redirects the user to the provider. When the third-party provider successfully authenticates the user, the provider redirects the user to the Supabase Auth callback URL where they are further redirected to the URL specified in the `redirectTo` parameter. This parameter defaults to the [`SITE_URL`](/docs/reference/auth/config#site_url). You can modify the `SITE_URL` or [add additional redirect URLs](https://app.supabase.com/project/_/auth/settings). -You can use wildcard match patterns to support preview URLs from providers like Netlify and Vercel. See the [full list of supported patterns](https://pkg.go.dev/github.com/gobwas/glob#Compile). +You can use wildcard match patterns to support preview URLs from providers like Netlify and Vercel. See the [full list of supported patterns](https://pkg.go.dev/github.com/gobwas/glob#Compile). Use [this tool](https://www.digitalocean.com/community/tools/glob?comments=true&glob=http%3A%2F%2Flocalhost%3A3000%2F%2A%2A&matches=false&tests=http%3A%2F%2Flocalhost%3A3000&tests=http%3A%2F%2Flocalhost%3A3000%2F&tests=http%3A%2F%2Flocalhost%3A3000%2F%3Ftest%3Dtest&tests=http%3A%2F%2Flocalhost%3A3000%2Ftest-test%3Ftest%3Dtest&tests=http%3A%2F%2Flocalhost%3A3000%2Ftest%2Ftest%3Ftest%3Dtest) to test your patterns. + +> ⚠️ WARNING: While the "globstar" (`**`) is useful for local development and preview URLs, we recommend setting the exact redirect URL path for your site URL in production. #### Netlify preview URLs For deployments with Netlify, set the `SITE_URL` to your official site URL. Add the following additional redirect URLs for local development and deployment previews: -- `http://localhost:3000/*/*` -- `https://**--my_org.netlify.app/*` +- `http://localhost:3000/**` +- `https://**--my_org.netlify.app/**` #### Vercel preview URLs For deployments with Vercel, set the `SITE_URL` to your official site URL. Add the following additional redirect URLs for local development and deployment previews: -- `http://localhost:3000/*/*` -- `https://**vercel.app/*/*` +- `http://localhost:3000/**` +- `https://*-username.vercel.app/**` Vercel provides an environment variable for the URL of the deployment called `NEXT_PUBLIC_VERCEL_URL`. See the [Vercel docs](https://vercel.com/docs/concepts/projects/environment-variables#system-environment-variables) for more details. You can use this variable to dynamically redirect depending on the environment: ```js +const getURL = () => { + let url = + process?.env?.NEXT_PUBLIC_SITE_URL ?? // Set this to your site URL in production env. + process?.env?.NEXT_PUBLIC_VERCEL_URL ?? // Automatically set by Vercel. + 'http://localhost:3000/'; + // Make sure to include `https://` when not localhost. + url = url.includes('http') ? url : `https://${url}`; + // Make sure to including trailing `/`. + url = url.charAt(url.length - 1) === '/' ? url : `${url}/`; + return url; +}; + const { data, error } = await supabase.auth.signInWithOAuth({ provider: 'github' options: { - redirectTo: process.env.NEXT_PUBLIC_VERCEL_URL - ? `https://${process.env.NEXT_PUBLIC_VERCEL_URL}` - : "http://localhost:3000" + redirectTo: getURL() } } ``` diff --git a/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx b/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx index 08dbb12a001..c38f8f3b284 100644 --- a/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx +++ b/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx @@ -365,7 +365,7 @@ export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { -## Server-side data fetching to OAuth APIs using `provider token` {#oauth-provider-token} +## Server-side data fetching to OAuth APIs using `provider token` {`#oauth-provider-token`} When using third-party auth providers, sessions are initiated with an additional `provider_token` field which is persisted in the auth cookie and can be accessed within the session object. The `provider_token` can be used to make API requests to the OAuth provider's API endpoints on behalf of the logged-in user. diff --git a/apps/docs/pages/guides/auth/overview.mdx b/apps/docs/pages/guides/auth/overview.mdx index 2f798039bb9..5e9e4639ea8 100644 --- a/apps/docs/pages/guides/auth/overview.mdx +++ b/apps/docs/pages/guides/auth/overview.mdx @@ -1,6 +1,8 @@ import Layout from '~/layouts/DefaultGuideLayout' import OldContent from '~/pages/guides/auth.mdx' +export const meta = {} + export const Page = ({ children }) => { if (process.env.NEXT_PUBLIC_NEW_DOCS === 'true') { return OldContent() diff --git a/apps/docs/pages/guides/database.mdx b/apps/docs/pages/guides/database.mdx index 3dd7df57aa3..90a72a9bacf 100644 --- a/apps/docs/pages/guides/database.mdx +++ b/apps/docs/pages/guides/database.mdx @@ -87,7 +87,7 @@ Read about resetting your database password [here](/docs/guides/database/managin ## Next steps -- Read more about [Postgres](/docs/postgres/server/about) +- Read more about [Postgres](https://www.postgresql.org/about/) - Sign in: [app.supabase.com](https://app.supabase.com) export const Page = ({ children }) => { diff --git a/apps/docs/pages/guides/functions.mdx b/apps/docs/pages/guides/functions.mdx index dc9d680ec67..9822760ab50 100644 --- a/apps/docs/pages/guides/functions.mdx +++ b/apps/docs/pages/guides/functions.mdx @@ -1,280 +1,31 @@ import Layout from '~/layouts/DefaultGuideLayout' +import {Button} from 'ui' export const meta = { id: 'functions', title: 'Edge Functions', description: 'Globally distributed TypeScript functions.', sidebar_label: 'Overview', + hide_table_of_contents: true, } -Edge Functions are server-side TypeScript functions, distributed globally at the edgeβ€”close to your users. They can be used for listening to webhooks or integrating your Supabase project with third-parties [like Stripe](https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/stripe-webhooks). - -Edge Functions are developed using [Deno](https://deno.com), which offers a few benefits to you as a developer: +Edge Functions are server-side TypeScript functions, distributed globally at the edgeβ€”close to your users. They can be used for listening to webhooks or integrating your Supabase project with third-parties [like Stripe](https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/stripe-webhooks). Edge Functions are developed using [Deno](https://deno.com), which offers a few benefits to you as a developer: - It is open source. - It is portable. Supabase Edge Functions run locally, and on any other Deno-compatible platform (including self-hosted infrastructure). - It is TypeScript first and supports WASM. - Edge Functions are globally distributed for low-latency. -## Quickstart + -Learn how to develop Edge Functions in less than 7 minutes: +## Examples -
    - +Check out the [Edge Function Examples](https://github.com/supabase/supabase/tree/master/examples/edge-functions) in our GitHub repository. + +
    +
    -## Prerequisites - -Follow the steps to prepare your Supabase project on your local machine. - -- Install the Supabase CLI. [Docs](/docs/guides/cli). -- Login to the CLI using the command: `supabase login`. [Docs](/docs/reference/cli/usage#supabase-login). -- Initialize Supabase inside your project using the command: `supabase init`. [Docs](/docs/guides/cli/local-development#getting-started). -- Link to your Remote Project using the command `supabase link --project-ref your-project-ref`. [Docs](/docs/reference/cli/usage#supabase-link). -- Optional: Setup your environment: Follow [this setup guide](https://deno.land/manual/getting_started/setup_your_environment) to integrate the Deno language server with your editor. - -## Getting Started - -Let's build an Edge Function locally, then deploy it to the Supabase Platform. - -### Creating a function - -Let's create a new Edge Function called `hello-world` inside your project: - -```bash -supabase functions new hello-world -``` - -This creates a function stub in your `supabase` folder at `./functions/hello-world/index.ts`. - -### Deploy to production - -```bash -supabase functions deploy hello-world -``` - -This command bundles your Edge Function from `./functions/hello-world/index.ts` and deploys it to the Supabase platform. -The command outputs a URL to the Supabase Dashboard which you can open to find view more details. Let's open the link to find the execution command. - - - -By default, Edge Functions require a valid JWT in the authorization header. This header is automatically set when invoking your function via a Supabase client library. - -If you want to use Edge Functions to handle webhooks (e.g. [Stripe payment webhooks](https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/stripe-webhooks) etc.), you need to pass the `--no-verify-jwt` flag when deploying your function. - - - -### Executing Remote Functions - -You can execute Edge Functions using curl. Copy the curl command from the Dashboard. It should look like this: - -```bash -curl --request POST 'https://.functions.supabase.co/hello-world' \ - --header 'Authorization: Bearer ANON_KEY' \ - --header 'Content-Type: application/json' \ - --data '{ "name":"Functions" }' -``` - -If you receive an error `Invalid JWT`, find the `ANON_KEY` of your project in the Dashboard under `Settings > API`. - -After invoking your Edge Function you should see the response `{ "message":"Hello Functions!" }`. - -## Debugging your Functions - -You can debug your deployed Edge Functions using the "Functions" section of the Dashboard. There are two types debugging tools available: - -- Invocations: shows the Request and Response for each execution. -- Logs: shows any platform events, including deployments and errors. - -![Function invocations.](/docs/img/guides/functions/function-logs.png) - -## Developing locally - -You can run your Edge Function locally using [`supabase functions serve`](/docs/reference/cli/usage#supabase-functions-serve): - -```bash -supabase start # start the supabase stack -supabase functions serve hello-world # start the Function watcher -``` - -The `functions serve` command has hot-reloading capabilities. It will watch for any changes to your files and restart the Deno server. - -### Invoking Functions locally - -While serving your local Function, you can execute it using curl: - -```bash -curl --request POST 'http://localhost:54321/functions/v1/hello-world' \ - --header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24ifQ.625_WdcF3KHqz5amU0x2X5WWHP-OEs_4qj0ssLNHzTs' \ - --header 'Content-Type: application/json' \ - --data '{ "name":"Functions" }' -``` - -You should see the response `{ "message":"Hello Functions!" }`. - -
    -Implementation details - -- All Edge Functions are `POST` requests. -- The `Authorization` header is required. You can use either the `ANON` key, the `SERVICE_ROLE` key, or a logged-in user's JWT. -- The Function is proxied through the local API (`http://localhost:54321`) - -
    -
    - -If you execute Function with a different payload the response will change.
    -Modify the `--data '{"name":"Functions"}'` line to `--data '{"name":"World"}'` and try invoking the command again! - -## Secrets and Environment Variables - -It's common that you will need to use sensitive information or environment-specific variables inside your Edge Functions. You can access these using Deno's built-in handler - -```js -Deno.env.get(MY_SECRET_NAME) -``` - -### Default secrets - -By default, Edge Functions have access to these secrets: - -- `SUPABASE_URL`: The API gateway for your Supabase project. -- `SUPABASE_ANON_KEY`: The `anon` key for your Supabase API. This is safe to use in a browser when you have [Row Level Security](/docs/guides/auth/row-level-security) enabled. -- `SUPABASE_SERVICE_ROLE_KEY`: The `service_role` key for your Supabase API. This is safe to use in Edge Functions, but it should NEVER be used in a browser. This key will bypass [Row Level Security](/docs/guides/auth/row-level-security). -- `SUPABASE_DB_URL`: The URL for your [PostgreSQL database](/docs/guides/database). You can use this to connect directly to your database. - -### Local secrets - -Let's create a local file for storing our secrets, and inside it we can store a secret `MY_NAME`: - -```jsx -echo "MY_NAME=Yoda" >> ./supabase/.env.local -``` - -This creates a new file `./supabase/.env.local` for storing your local development secrets. - - - -Never check your .env files into Git! - - - -Now let's access this environment variable `MY_NAME` inside our Function. Anywhere in your function, add this line: - -```jsx -console.log(Deno.env.get('MY_NAME')) -``` - -Now we can invoke our function locally, by serving it with our new `.env.local` file: - -```bash -supabase functions serve hello-world --env-file ./supabase/.env.local -``` - -When the function starts you should see the name β€œYoda” output to the terminal. - -### Production secrets - -Let's create a `.env` for production. In this case we'll just use the same as our local secrets: - -```bash -cp ./supabase/.env.local ./supabase/.env -``` - -This creates a new file `./supabase/.env` for storing your production secrets. - - - -Never check your `.env` files into Git! - - - -Let's push all the secrets from the `.env` file to our remote project using [`supabase secrets set`](/docs/reference/cli/usage#supabase-secrets-set): - -```bash -supabase secrets set --env-file ./supabase/.env - -# You can also set secrets individually using: -supabase secrets set MY_NAME=Chewbacca -``` - -You don't need to re-deploy after setting your secrets. - -To see all the secrets which you have set remotely, use [`supabase secrets list`](/docs/reference/cli/usage#supabase-secrets-list): - -```bash -supabase secrets list -``` - -## Suggestions - -### Database Functions vs Edge Functions - -For data-intensive operations we recommend using [Database Functions](/docs/guides/database/functions), which are executed within your database -and can be called remotely using the [REST and GraphQL API](/docs/guides/api). - -For use-cases which require low-latency we recommend [Edge Functions](/docs/guides/functions), which are globally-distributed and can be written in TypeScript. - -### Organizing your Edge Functions - -We recommend developing β€œfat functions”. This means that you should develop few large functions, rather than many small functions. One common pattern when developing Functions is that you need to share code between two or more Functions. To do this, you can store any shared code in a folder prefixed with an underscore (`_`). We recommend this folder structure: - -```bash -└── supabase - β”œβ”€β”€ functions - β”‚ β”œβ”€β”€ _shared - β”‚ | β”œβ”€β”€ supabaseAdmin.ts # Supabase client with SERVICE_ROLE key - β”‚ β”‚ └── supabaseClient.ts # Supabase client with ANON key - β”‚ β”œβ”€β”€ function-one # use hyphens to name functions - β”‚ β”‚ └── index.ts - β”‚ └── function-two - β”‚ └── index.ts - β”œβ”€β”€ migrations - └── config.toml -``` - -### Naming Edge Functions - -We recommend using hyphens to name functions because hyphens are the most URL-friendly of all the naming conventions (snake_case, camelCase, PascalCase). - -### CORS (Cross-Origin Resource Sharing) - -We recommend adding a check to handle [CORS Preflight](https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request) requests in your edge function to be able to invoke the function from browsers. - -See the [example on GitHub](https://github.com/supabase/supabase/blob/master/examples/edge-functions/supabase/functions/browser-with-cors/index.ts). - -```ts -export const corsHeaders = { - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey', -} - -serve(async (req) => { - if (req.method === 'OPTIONS') { - return new Response('ok', { headers: corsHeaders }) - } - ... -}) -``` - -### Using HTTP Methods - -Edge Functions supports `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, and `OPTIONS`. A function can be designed to perform different actions based on a request's HTTP method. See the [example on building a RESTful service](https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/restful-tasks) to learn how to handle different HTTP methods in your function. - -## Limitations - -- Deno Deploy limitations - - Deno does not support outgoing connections to ports `25`, `465`, and `587`. - - Cannot write to File System -- Edge Functions - - Local development - only one function at a time - - Serving of HTML content is not supported (`GET` requests that return `text/html` will be rewritten to `text/plain`). - export const Page = ({ children }) => export default Page diff --git a/apps/docs/pages/guides/functions/best-practices.mdx b/apps/docs/pages/guides/functions/best-practices.mdx new file mode 100644 index 00000000000..b670cd73a05 --- /dev/null +++ b/apps/docs/pages/guides/functions/best-practices.mdx @@ -0,0 +1,64 @@ +import Layout from '~/layouts/DefaultGuideLayout' + +export const meta = { + id: 'functions-best-practices', + title: 'Edge Functions Best Practices', + description: 'Globally distributed TypeScript functions.', +} + +## Database Functions vs Edge Functions + +For data-intensive operations we recommend using [Database Functions](/docs/guides/database/functions), which are executed within your database +and can be called remotely using the [REST and GraphQL API](/docs/guides/api). + +For use-cases which require low-latency we recommend [Edge Functions](/docs/guides/functions), which are globally-distributed and can be written in TypeScript. + +## Organizing your Edge Functions + +We recommend developing β€œfat functions”. This means that you should develop few large functions, rather than many small functions. One common pattern when developing Functions is that you need to share code between two or more Functions. To do this, you can store any shared code in a folder prefixed with an underscore (`_`). We recommend this folder structure: + +```bash +└── supabase + β”œβ”€β”€ functions + β”‚ β”œβ”€β”€ _shared + β”‚ | β”œβ”€β”€ supabaseAdmin.ts # Supabase client with SERVICE_ROLE key + β”‚ β”‚ └── supabaseClient.ts # Supabase client with ANON key + β”‚ β”œβ”€β”€ function-one # use hyphens to name functions + β”‚ β”‚ └── index.ts + β”‚ └── function-two + β”‚ └── index.ts + β”œβ”€β”€ migrations + └── config.toml +``` + +## Naming Edge Functions + +We recommend using hyphens to name functions because hyphens are the most URL-friendly of all the naming conventions (snake_case, camelCase, PascalCase). + +## CORS (Cross-Origin Resource Sharing) + +We recommend adding a check to handle [CORS Preflight](https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request) requests in your edge function to be able to invoke the function from browsers. + +See the [example on GitHub](https://github.com/supabase/supabase/blob/master/examples/edge-functions/supabase/functions/browser-with-cors/index.ts). + +```ts +export const corsHeaders = { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey', +} + +serve(async (req) => { + if (req.method === 'OPTIONS') { + return new Response('ok', { headers: corsHeaders }) + } + ... +}) +``` + +## Using HTTP Methods + +Edge Functions supports `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, and `OPTIONS`. A function can be designed to perform different actions based on a request's HTTP method. See the [example on building a RESTful service](https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/restful-tasks) to learn how to handle different HTTP methods in your function. + +export const Page = ({ children }) => + +export default Page diff --git a/apps/docs/pages/guides/functions/quickstart.mdx b/apps/docs/pages/guides/functions/quickstart.mdx new file mode 100644 index 00000000000..963305181a3 --- /dev/null +++ b/apps/docs/pages/guides/functions/quickstart.mdx @@ -0,0 +1,210 @@ +import Layout from '~/layouts/DefaultGuideLayout' + +export const meta = { + id: 'functions-quickstart', + title: 'Edge Functions Quickstart', + description: 'Globally distributed TypeScript functions.', + sidebar_label: 'Quickstart', +} + +Learn how to build an Edge Function locally and deploy it to the Supabase Platform in less than 7 minutes. + +
    + +
    + +## Prerequisites + +Follow the steps to prepare your Supabase project on your local machine. + +- Install the Supabase CLI. [Docs](/docs/guides/cli). +- Login to the CLI using the command: `supabase login`. [Docs](/docs/reference/cli/usage#supabase-login). +- Initialize Supabase inside your project using the command: `supabase init`. [Docs](/docs/guides/cli/local-development#getting-started). +- Link to your Remote Project using the command `supabase link --project-ref your-project-ref`. [Docs](/docs/reference/cli/usage#supabase-link). +- Optional: Setup your environment: Follow [this setup guide](https://deno.land/manual/getting_started/setup_your_environment) to integrate the Deno language server with your editor. + +## Create a function + +Let's create a new Edge Function called `hello-world` inside your project: + +```bash +supabase functions new hello-world +``` + +This creates a function stub in your `supabase` folder at `./functions/hello-world/index.ts`. + +## Deploy to production + +```bash +supabase functions deploy hello-world +``` + +This command bundles your Edge Function from `./functions/hello-world/index.ts` and deploys it to the Supabase platform. +The command outputs a URL to the Supabase Dashboard which you can open to find view more details. Let's open the link to find the execution command. + + + +By default, Edge Functions require a valid JWT in the authorization header. This header is automatically set when invoking your function via a Supabase client library. + +If you want to use Edge Functions to handle webhooks (e.g. [Stripe payment webhooks](https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/stripe-webhooks) etc.), you need to pass the `--no-verify-jwt` flag when deploying your function. + + + +## Execute remote functions + +You can execute Edge Functions using curl. Copy the curl command from the Dashboard. It should look like this: + +```bash +curl --request POST 'https://.functions.supabase.co/hello-world' \ + --header 'Authorization: Bearer ANON_KEY' \ + --header 'Content-Type: application/json' \ + --data '{ "name":"Functions" }' +``` + +If you receive an error `Invalid JWT`, find the `ANON_KEY` of your project in the Dashboard under `Settings > API`. + +After invoking your Edge Function you should see the response `{ "message":"Hello Functions!" }`. + +## Debug functions + +You can debug your deployed Edge Functions using the "Functions" section of the Dashboard. There are two types debugging tools available: + +- Invocations: shows the Request and Response for each execution. +- Logs: shows any platform events, including deployments and errors. + +![Function invocations.](/docs/img/guides/functions/function-logs.png) + +## Develop locally + +You can run your Edge Function locally using [`supabase functions serve`](/docs/reference/cli/usage#supabase-functions-serve): + +```bash +supabase start # start the supabase stack +supabase functions serve hello-world # start the Function watcher +``` + +The `functions serve` command has hot-reloading capabilities. It will watch for any changes to your files and restart the Deno server. + +### Invoke functions locally + +While serving your local Function, you can execute it using curl: + +```bash +curl --request POST 'http://localhost:54321/functions/v1/hello-world' \ + --header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24ifQ.625_WdcF3KHqz5amU0x2X5WWHP-OEs_4qj0ssLNHzTs' \ + --header 'Content-Type: application/json' \ + --data '{ "name":"Functions" }' +``` + +You should see the response `{ "message":"Hello Functions!" }`. + +
    +Implementation details + +- All Edge Functions are `POST` requests. +- The `Authorization` header is required. You can use either the `ANON` key, the `SERVICE_ROLE` key, or a logged-in user's JWT. +- The Function is proxied through the local API (`http://localhost:54321`) + +
    +
    + +If you execute Function with a different payload the response will change.
    +Modify the `--data '{"name":"Functions"}'` line to `--data '{"name":"World"}'` and try invoking the command again! + +## Secrets and Environment Variables + +It's common that you will need to use sensitive information or environment-specific variables inside your Edge Functions. You can access these using Deno's built-in handler + +```js +Deno.env.get(MY_SECRET_NAME) +``` + +### Default secrets + +By default, Edge Functions have access to these secrets: + +- `SUPABASE_URL`: The API gateway for your Supabase project. +- `SUPABASE_ANON_KEY`: The `anon` key for your Supabase API. This is safe to use in a browser when you have [Row Level Security](/docs/guides/auth/row-level-security) enabled. +- `SUPABASE_SERVICE_ROLE_KEY`: The `service_role` key for your Supabase API. This is safe to use in Edge Functions, but it should NEVER be used in a browser. This key will bypass [Row Level Security](/docs/guides/auth/row-level-security). +- `SUPABASE_DB_URL`: The URL for your [PostgreSQL database](/docs/guides/database). You can use this to connect directly to your database. + +### Local secrets + +Let's create a local file for storing our secrets, and inside it we can store a secret `MY_NAME`: + +```jsx +echo "MY_NAME=Yoda" >> ./supabase/.env.local +``` + +This creates a new file `./supabase/.env.local` for storing your local development secrets. + + + +Never check your .env files into Git! + + + +Now let's access this environment variable `MY_NAME` inside our Function. Anywhere in your function, add this line: + +```jsx +console.log(Deno.env.get('MY_NAME')) +``` + +Now we can invoke our function locally, by serving it with our new `.env.local` file: + +```bash +supabase functions serve hello-world --env-file ./supabase/.env.local +``` + +When the function starts you should see the name β€œYoda” output to the terminal. + +### Production secrets + +Let's create a `.env` for production. In this case we'll just use the same as our local secrets: + +```bash +cp ./supabase/.env.local ./supabase/.env +``` + +This creates a new file `./supabase/.env` for storing your production secrets. + + + +Never check your `.env` files into Git! + + + +Let's push all the secrets from the `.env` file to our remote project using [`supabase secrets set`](/docs/reference/cli/usage#supabase-secrets-set): + +```bash +supabase secrets set --env-file ./supabase/.env + +# You can also set secrets individually using: +supabase secrets set MY_NAME=Chewbacca +``` + +You don't need to re-deploy after setting your secrets. + +To see all the secrets which you have set remotely, use [`supabase secrets list`](/docs/reference/cli/usage#supabase-secrets-list): + +```bash +supabase secrets list +``` + +## Limitations + +- Deno Deploy limitations + - Deno does not support outgoing connections to ports `25`, `465`, and `587`. + - Cannot write to File System +- Edge Functions + - Local development - only one function at a time + - Serving of HTML content is not supported (`GET` requests that return `text/html` will be rewritten to `text/plain`). + +export const Page = ({ children }) => + +export default Page diff --git a/apps/docs/pages/guides/hosting/overview.mdx b/apps/docs/pages/guides/hosting/overview.mdx index cf50195723c..51e618c4d31 100644 --- a/apps/docs/pages/guides/hosting/overview.mdx +++ b/apps/docs/pages/guides/hosting/overview.mdx @@ -39,7 +39,7 @@ Each system has a number of configuration options which can be found in the rele - [Realtime](https://github.com/supabase/realtime#server) - [GoTrue](https://github.com/supabase/gotrue) - [Storage](https://github.com/supabase/storage-api) -- [Kong](https://docs.konghq.com/install/docker/) +- [Kong](https://docs.konghq.com/gateway/latest/install/docker/) ## Managing your database diff --git a/apps/docs/pages/guides/integrations.mdx b/apps/docs/pages/guides/integrations.mdx index 9a47a5bcdcf..465770b0ac5 100644 --- a/apps/docs/pages/guides/integrations.mdx +++ b/apps/docs/pages/guides/integrations.mdx @@ -19,7 +19,7 @@ export const meta = {

    {item.name}

    {item.items.map((integration) => ( - + **API** as shown below: + +![secret_role jwt](/docs/img/guides/integrations/zuplo/secret-role.png) + +Once you've got your service_role JWT, click **Add Policy** again on the **Request** pipeline and choose the **Add/Set Headers Policy** and configure it as follows: + +```json +{ + "export": "SetHeadersInboundPolicy", + "module": "$import(@zuplo/runtime)", + "options": { + "headers": [ + { + "name": "apikey", + "value": "$env(SUPABASE_API_KEY)", + "overwrite": true + }, + { + "name": "authorization", + "value": "$env(SUPABASE_AUTHZ_HEADER)", + "overwrite": true + } + ] + } +} +``` + +Save your changes. + +Next, create two secret [environment variables](https://zuplo.com/docs/deployments/environment-variables) as follows: + +- SUPABASE_API_KEY: `"YOUR_SUPABASE_SECRET_ROLE_JWT"` +- SUPABASE_AUTHZ_HEADER: `"Bearer YOUR_SUPABASE_SECRET_ROLE_JWT"` + +Obviously, in both instances replace `YOUR_SUPABASE_SECRET_ROLE_JWT` with your service_role JWT from Supabase. + +You are now ready to invoke your API gateway and see data flow through from your Supabase backend! + +Click on the **open in browser** button shown below and you should see the JSON, flowing from Supabase in your browser πŸ‘. + +![open in browser](/docs/img/guides/integrations/zuplo/open-in-browser.png) + +## Adding authentication + +At this point, that route is wide open to the world so we need to secure it. We'll do this using API keys. You can follow this guide [Add API key Authentication](https://zuplo.com/docs/quickstarts/add-api-key-auth). Be sure to drag the API Key authentication policy to the very top of your **Request** pipeline. Come back here when you're done. + +Welcome back! You've now learned how to secure your API with API-Keys. + +## Adding a Create route + +Next we'll add a route that allows somebody to create a review. Add another route with the following settings + +- method: `POST` +- path: `/reviews` +- summary: `Create a new review` +- version: `v1` +- CORS: `Anything goes` + +And the request handler as follows: + +- URL Rewrite: `https://YOUR_SUPABASE_URL.supabase.co/rest/v1/ski-reviews` +- Forward Search: `unchecked` + +Expand the policies section and add the same policies (note you can reuse policies by picking from the existing policies at the top of the library) + +![existing policies](/docs/img/guides/integrations/zuplo/existing-policies.png) + +- api-key-auth-inbound +- clear-headers-inbound +- set-headers-inbound + +Now your **create** route is secured and will automatically set the right headers before calling Supabase. That was easy. + +You can test this out by using the **API Test Console** to invoke your new endpoint. Go to the **API Test Console** and create a new test called `create-review.json`. + +- Method: `POST` +- Path: `/v1/reviews` +- Headers: + - `content-type`: `application/json` + - `authorization`: `Bearer YOUR_ZUPLO_API_KEY` +- Body: + +```json +{ + "make": "Rossignol", + "model": "Soul HD7", + "rating": 5, + "year": 2019 +} +``` + +![Test console](/docs/img/guides/integrations/zuplo/test-console.png) + +If you invoke your API by clicking `Test` you should see that you get a **201 Created** - congratulations! + +## Add validation to your post + +To make your API more usable and more secure it is good practice to validate incoming requests. In this case we will add a JSON Schema document and use it to validate the incoming body to our POST. + +Create a new schema document called `new-review.json`. + +![new schema](/docs/img/guides/integrations/zuplo/new-schema.png) + +This example fits the ski-reviews table we described above + +```json +{ + "$id": "http://example.com/example.json", + "type": "object", + "default": {}, + "title": "Root Schema", + "required": ["make", "model", "rating", "year"], + "additionalProperties": false, + "properties": { + "make": { + "type": "string", + "default": "", + "title": "The make Schema", + "examples": ["DPS"] + }, + "model": { + "type": "string", + "default": "", + "title": "The model Schema", + "examples": ["Pagoda"] + }, + "rating": { + "type": "integer", + "default": 0, + "title": "The rating Schema", + "examples": [5] + }, + "year": { + "type": "integer", + "default": 0, + "title": "The year Schema", + "examples": [2018] + } + }, + "examples": [ + { + "make": "DPS", + "model": "Pagoda", + "rating": 5, + "year": 2018, + "author": "Josh" + } + ] +} +``` + +Now add a new policy to **request** pipeline for your `Create new review` route. Choose the **JSON Body Validation** policy and configure it to use your newly created JSON schema document: + +```json +{ + "export": "ValidateJsonSchemaInbound", + "module": "$import(@zuplo/runtime)", + "options": { + "validator": "$import(./schemas/new-review.json)" + } +} +``` + +This policy can be dragged to the first position in your pipeline. + +Now to test this is working, go back to your API test console and change the body of your `create-review.json` test to be invalid (add a new property for example). You should find that you get a `400 Bad Request` response. + +![400 Bad Request](/docs/img/guides/integrations/zuplo/400-bad.png) + +Finally, lean back and marvel at your beautiful Developer Portal that took almost zero effort to get this far, wow! Hopefully you already found the link for this when adding API key support :) + +![Developer Portal](/docs/img/guides/integrations/zuplo/dev-portal.png) + +Zuplo can also be used to handle Supabase JWT tokens for any API, learn more at [API Authentication with Supabase JWT Tokens](https://zuplo.com/blog/2022/11/15/api-authentication-with-supabase-jwt) + +export const Page = ({ children }) => + +export default Page diff --git a/apps/docs/pages/guides/platform/logs.mdx b/apps/docs/pages/guides/platform/logs.mdx index 60944eacd99..0754840cd7d 100644 --- a/apps/docs/pages/guides/platform/logs.mdx +++ b/apps/docs/pages/guides/platform/logs.mdx @@ -38,31 +38,6 @@ Supabase provides a logging interface specific to each product. You can use simp [Postgres logs](https://app.supabase.com/project/_/logs/postgres-logs) show queries and activity for your [database](../../guides/database). -By default, query logs are disabled for all new Supabase projects, as they can reveal metadata about the contents of your database (e.g. table and column names). If you'd like to enable query logs, you can enable and configure the [pgAudit extension](https://www.pgaudit.org/): - -- [Enable the pgAudit extension for your project](https://app.supabase.com/project/_/database/extensions) -- [Reboot the DB](https://app.supabase.com/project/_/settings/general); a "Fast database reboot" is sufficient, and faster than a full project restart -- Configure `pgaudit.log` to the [appropriate value](https://github.com/pgaudit/pgaudit/blob/master/README.md#pgauditlog) -- You should be able to view query logs in your [log explorer](https://app.supabase.com/project/_/logs/explorer) now - -As an example, if you wanted to enable logs for writes and DDL statements for a single session, you could execute within the session: - -```sql -set pgaudit.log = 'write, ddl'; -``` - -To _permanently_ enable logs for all statements that relate to roles and privileges, you could execute (followed by a db reboot): - -```sql -alter system set pgaudit.log to 'role'; -``` - -To remove a system-wide setting, you can use (followed by a db reboot): - -```sql -alter system reset pgaudit.log -``` - ![Postgres Logs](/docs/img/guides/platform/logs/logs-database.png) @@ -106,6 +81,50 @@ The Logs tab displays logs emitted during function execution. +--- + +## Logging Postgres Queries + +By default, query logs are disabled for new Supabase projects, as they can reveal metadata about the contents of your database (such as table and column names). + +To enable query logs: + +1. [Enable the pgAudit extension](https://app.supabase.com/project/_/database/extensions). +2. [Restart your project](https://app.supabase.com/project/_/settings/general) using the **Fast database reboot** option. +3. Configure `pgaudit.log` (see below). Perform a fast reboot if needed. +4. View your query logs under [Logs > Postgres Logs](https://app.supabase.com/project/_/logs/postgres-logs). + +### Configuring `pgaudit.log` + +The stored value under `pgaudit.log` determines the classes of statements that are logged by [pgAudit extension](https://www.pgaudit.org/). Refer to the pgAudit documentation for the [full list of values](https://github.com/pgaudit/pgaudit/blob/master/README.md#pgauditlog). + +To enable logging for function calls/do blocks, writes, and DDL statements for a single session, execute the following within the session: + +```sql +-- temporary single-session config update +set pgaudit.log = 'function, write, ddl'; +``` + +To _permanently_ set a logging configuration (beyond a single session), execute the following, then perform a fast reboot: + +```sql +-- equivalent permanent config update. +alter role postgres set pgaudit.log to 'function, write, ddl'; +``` + +To reset system-wide settings, execute the following, then perform a fast reboot: + +```sql +-- resets stored config. +alter role postgres reset pgaudit.log +``` + + + +If any permission errors are encountered when executing `alter role postgres ...`, it is likely that your project has yet to receive the patch to the latest version of [supautils](https://github.com/supabase/supautils), which is currently being rolled out. + + + ## Logs Explorer The [Logs Explorer](https://app.supabase.com/project/_/logs-explorer) exposes logs from each part of the Supabase stack as a separate table that can be queried and joined using SQL. diff --git a/apps/docs/pages/guides/realtime.mdx b/apps/docs/pages/guides/realtime.mdx index f2142bc69dd..acf13a0f57b 100644 --- a/apps/docs/pages/guides/realtime.mdx +++ b/apps/docs/pages/guides/realtime.mdx @@ -10,7 +10,7 @@ export const meta = { Supabase provides a globally distributed cluster of [Realtime](https://github.com/supabase/realtime) servers that enable the following functionality: - [Broadcast](#broadcast): Send ephemeral messages from client to clients with low latency. -- [Presence](#presence): Track and synchrononize shared state between clients. +- [Presence](#presence): Track and synchronize shared state between clients. - [Postgres CDC](#postgres-cdc): Listen to Postgres database changes and send them to authorized clients. A [channel](https://hexdocs.pm/phoenix/channels.html) is the basic building block of Realtime and narrows the scope of data flow to subscribed clients. You can think of a channel as a chatroom where participants are able to see who's online and send and receive messages; similar to a Discord or Slack channel. diff --git a/apps/docs/pages/guides/tutorials.mdx b/apps/docs/pages/guides/tutorials.mdx index d4681aa2977..3b5c36f7231 100644 --- a/apps/docs/pages/guides/tutorials.mdx +++ b/apps/docs/pages/guides/tutorials.mdx @@ -14,7 +14,7 @@ export const meta = { {topArticles.map((item) => { return ( diff --git a/apps/docs/pages/guides/tutorials/with-angular.mdx b/apps/docs/pages/guides/tutorials/with-angular.mdx index b1479a50e9a..15bfa56dead 100644 --- a/apps/docs/pages/guides/tutorials/with-angular.mdx +++ b/apps/docs/pages/guides/tutorials/with-angular.mdx @@ -1,6 +1,8 @@ import Layout from '~/layouts/DefaultGuideLayout' import oldContent from '~/pages/guides/with-angular.mdx' +export const meta = {} + export const Page = ({ children }) => { if (process.env.NEXT_PUBLIC_NEW_DOCS === 'true') { return oldContent() diff --git a/apps/docs/pages/guides/tutorials/with-expo.mdx b/apps/docs/pages/guides/tutorials/with-expo.mdx index 657aba26325..7efd769243b 100644 --- a/apps/docs/pages/guides/tutorials/with-expo.mdx +++ b/apps/docs/pages/guides/tutorials/with-expo.mdx @@ -1,6 +1,8 @@ import Layout from '~/layouts/DefaultGuideLayout' import oldContent from '~/pages/guides/with-expo.mdx' +export const meta = {} + export const Page = ({ children }) => { if (process.env.NEXT_PUBLIC_NEW_DOCS === 'true') { return oldContent() diff --git a/apps/docs/pages/guides/tutorials/with-flutter.mdx b/apps/docs/pages/guides/tutorials/with-flutter.mdx index 2039cb1d051..67305a95e3b 100644 --- a/apps/docs/pages/guides/tutorials/with-flutter.mdx +++ b/apps/docs/pages/guides/tutorials/with-flutter.mdx @@ -1,6 +1,8 @@ import Layout from '~/layouts/DefaultGuideLayout' import oldContent from '~/pages/guides/with-flutter.mdx' +export const meta = {} + export const Page = ({ children }) => { if (process.env.NEXT_PUBLIC_NEW_DOCS === 'true') { return oldContent() diff --git a/apps/docs/pages/guides/tutorials/with-ionic-angular.mdx b/apps/docs/pages/guides/tutorials/with-ionic-angular.mdx index 4736d7e664a..c3b8a3b7a4b 100644 --- a/apps/docs/pages/guides/tutorials/with-ionic-angular.mdx +++ b/apps/docs/pages/guides/tutorials/with-ionic-angular.mdx @@ -1,6 +1,8 @@ import Layout from '~/layouts/DefaultGuideLayout' import oldContent from '~/pages/guides/with-ionic-angular.mdx' +export const meta = {} + export const Page = ({ children }) => { if (process.env.NEXT_PUBLIC_NEW_DOCS === 'true') { return oldContent() diff --git a/apps/docs/pages/guides/tutorials/with-ionic-react.mdx b/apps/docs/pages/guides/tutorials/with-ionic-react.mdx index 1e73208baf1..6f0222be4ab 100644 --- a/apps/docs/pages/guides/tutorials/with-ionic-react.mdx +++ b/apps/docs/pages/guides/tutorials/with-ionic-react.mdx @@ -1,6 +1,8 @@ import Layout from '~/layouts/DefaultGuideLayout' import oldContent from '~/pages/guides/with-ionic-react.mdx' +export const meta = {} + export const Page = ({ children }) => { if (process.env.NEXT_PUBLIC_NEW_DOCS === 'true') { return oldContent() diff --git a/apps/docs/pages/guides/tutorials/with-ionic-vue.mdx b/apps/docs/pages/guides/tutorials/with-ionic-vue.mdx index 3df41e07fca..0ce735328ef 100644 --- a/apps/docs/pages/guides/tutorials/with-ionic-vue.mdx +++ b/apps/docs/pages/guides/tutorials/with-ionic-vue.mdx @@ -1,6 +1,8 @@ import Layout from '~/layouts/DefaultGuideLayout' import oldContent from '~/pages/guides/with-ionic-vue.mdx' +export const meta = {} + export const Page = ({ children }) => { if (process.env.NEXT_PUBLIC_NEW_DOCS === 'true') { return oldContent() diff --git a/apps/docs/pages/guides/tutorials/with-nextjs.mdx b/apps/docs/pages/guides/tutorials/with-nextjs.mdx index 4f74ea1e24d..cae82cc840a 100644 --- a/apps/docs/pages/guides/tutorials/with-nextjs.mdx +++ b/apps/docs/pages/guides/tutorials/with-nextjs.mdx @@ -1,6 +1,8 @@ import Layout from '~/layouts/DefaultGuideLayout' import OldContent from '~/pages/guides/with-nextjs.mdx' +export const meta = {} + export const Page = ({ children }) => { if (process.env.NEXT_PUBLIC_NEW_DOCS === 'true') { return OldContent() diff --git a/apps/docs/pages/guides/tutorials/with-nuxt-3.mdx b/apps/docs/pages/guides/tutorials/with-nuxt-3.mdx index fe91855561b..042b287789f 100644 --- a/apps/docs/pages/guides/tutorials/with-nuxt-3.mdx +++ b/apps/docs/pages/guides/tutorials/with-nuxt-3.mdx @@ -1,6 +1,8 @@ import Layout from '~/layouts/DefaultGuideLayout' import oldContent from '~/pages/guides/with-nuxt-3.mdx' +export const meta = {} + export const Page = ({ children }) => { if (process.env.NEXT_PUBLIC_NEW_DOCS === 'true') { return oldContent() diff --git a/apps/docs/pages/guides/tutorials/with-react.mdx b/apps/docs/pages/guides/tutorials/with-react.mdx index 29f8eaee132..fcab9102b61 100644 --- a/apps/docs/pages/guides/tutorials/with-react.mdx +++ b/apps/docs/pages/guides/tutorials/with-react.mdx @@ -1,6 +1,8 @@ import Layout from '~/layouts/DefaultGuideLayout' import oldContent from '~/pages/guides/with-react.mdx' +export const meta = {} + export const Page = ({ children }) => { if (process.env.NEXT_PUBLIC_NEW_DOCS === 'true') { return oldContent() diff --git a/apps/docs/pages/guides/tutorials/with-redwoodjs.mdx b/apps/docs/pages/guides/tutorials/with-redwoodjs.mdx index 086c34786d7..c2f01c38501 100644 --- a/apps/docs/pages/guides/tutorials/with-redwoodjs.mdx +++ b/apps/docs/pages/guides/tutorials/with-redwoodjs.mdx @@ -1,6 +1,8 @@ import Layout from '~/layouts/DefaultGuideLayout' import oldContent from '~/pages/guides/with-redwoodjs.mdx' +export const meta = {} + export const Page = ({ children }) => { if (process.env.NEXT_PUBLIC_NEW_DOCS === 'true') { return oldContent() diff --git a/apps/docs/pages/guides/tutorials/with-solidjs.mdx b/apps/docs/pages/guides/tutorials/with-solidjs.mdx index 2a8518fc3dc..186dc073f30 100644 --- a/apps/docs/pages/guides/tutorials/with-solidjs.mdx +++ b/apps/docs/pages/guides/tutorials/with-solidjs.mdx @@ -1,6 +1,8 @@ import Layout from '~/layouts/DefaultGuideLayout' import oldContent from '~/pages/guides/with-solidjs.mdx' +export const meta = {} + export const Page = ({ children }) => { if (process.env.NEXT_PUBLIC_NEW_DOCS === 'true') { return oldContent() diff --git a/apps/docs/pages/guides/tutorials/with-svelte.mdx b/apps/docs/pages/guides/tutorials/with-svelte.mdx index a7d0c6e967f..f6d8ed2a9fa 100644 --- a/apps/docs/pages/guides/tutorials/with-svelte.mdx +++ b/apps/docs/pages/guides/tutorials/with-svelte.mdx @@ -1,6 +1,8 @@ import Layout from '~/layouts/DefaultGuideLayout' import oldContent from '~/pages/guides/with-svelte.mdx' +export const meta = {} + export const Page = ({ children }) => { if (process.env.NEXT_PUBLIC_NEW_DOCS === 'true') { return oldContent() diff --git a/apps/docs/pages/guides/tutorials/with-sveltekit.mdx b/apps/docs/pages/guides/tutorials/with-sveltekit.mdx index 7bd8cf0761e..0c495eebced 100644 --- a/apps/docs/pages/guides/tutorials/with-sveltekit.mdx +++ b/apps/docs/pages/guides/tutorials/with-sveltekit.mdx @@ -1,6 +1,8 @@ import Layout from '~/layouts/DefaultGuideLayout' import oldContent from '~/pages/guides/with-sveltekit.mdx' +export const meta = {} + export const Page = ({ children }) => { if (process.env.NEXT_PUBLIC_NEW_DOCS === 'true') { return oldContent() diff --git a/apps/docs/pages/guides/tutorials/with-vue-3.mdx b/apps/docs/pages/guides/tutorials/with-vue-3.mdx index b41828aef0d..65f5c5527c8 100644 --- a/apps/docs/pages/guides/tutorials/with-vue-3.mdx +++ b/apps/docs/pages/guides/tutorials/with-vue-3.mdx @@ -1,6 +1,8 @@ import Layout from '~/layouts/DefaultGuideLayout' import oldContent from '~/pages/guides/with-vue-3.mdx' +export const meta = {} + export const Page = ({ children }) => { if (process.env.NEXT_PUBLIC_NEW_DOCS === 'true') { return oldContent() diff --git a/apps/docs/pages/new/auth.mdx b/apps/docs/pages/new/auth.mdx index 9a8ce71bb04..fddd0644efd 100644 --- a/apps/docs/pages/new/auth.mdx +++ b/apps/docs/pages/new/auth.mdx @@ -17,7 +17,7 @@ export const meta = { {topArticles.map((item) => { return ( diff --git a/apps/docs/pages/new/reference/index.mdx b/apps/docs/pages/new/reference/index.mdx deleted file mode 100644 index 6d74a1c57ff..00000000000 --- a/apps/docs/pages/new/reference/index.mdx +++ /dev/null @@ -1,11 +0,0 @@ -import Layout from '~/layouts/DefaultLayout' - -export const meta = { - title: 'Ref', -} - -## REF REF - -export const Page = ({ children }) => - -export default Page diff --git a/apps/docs/pages/new/reference/api/[...slug].tsx b/apps/docs/pages/reference/api/[...slug].tsx similarity index 100% rename from apps/docs/pages/new/reference/api/[...slug].tsx rename to apps/docs/pages/reference/api/[...slug].tsx diff --git a/apps/docs/pages/new/reference/auth/[...slug].tsx b/apps/docs/pages/reference/auth/[...slug].tsx similarity index 100% rename from apps/docs/pages/new/reference/auth/[...slug].tsx rename to apps/docs/pages/reference/auth/[...slug].tsx diff --git a/apps/docs/pages/new/reference/auth/config.tsx b/apps/docs/pages/reference/auth/config.tsx similarity index 100% rename from apps/docs/pages/new/reference/auth/config.tsx rename to apps/docs/pages/reference/auth/config.tsx diff --git a/apps/docs/pages/new/reference/cli/[...slug].tsx b/apps/docs/pages/reference/cli/[...slug].tsx similarity index 78% rename from apps/docs/pages/new/reference/cli/[...slug].tsx rename to apps/docs/pages/reference/cli/[...slug].tsx index f779cbc5fa4..9ddb60b923f 100644 --- a/apps/docs/pages/new/reference/cli/[...slug].tsx +++ b/apps/docs/pages/reference/cli/[...slug].tsx @@ -4,6 +4,14 @@ import CodeBlock from '~/components/CodeBlock/CodeBlock' import Options from '~/components/Options' import Param from '~/components/Params' import RefSubLayout from '~/layouts/ref/RefSubLayout' +import { getAllDocs, getDocsBySlug } from '~/lib/docs' + +import toc from 'markdown-toc' +import { serialize } from 'next-mdx-remote/serialize' + +import components from '~/components/index' +import { MDXRemote } from 'next-mdx-remote' +import OldLayout from '~/layouts/Default' export type AcceptedValue = { id: string @@ -32,7 +40,19 @@ export type Command = { usage?: string } -export default function Config() { +export default function Config(props) { + /* + * handle old ref pages + */ + if (process.env.NEXT_PUBLIC_NEW_DOCS === 'false') { + return ( + // @ts-ignore + + + + ) + } + return (
    @@ -123,3 +143,38 @@ export default function Config() { ) } + +export async function getStaticProps({ params }: { params: { slug: string[] } }) { + let slug + if (params.slug.length > 1) { + slug = `docs/${params.slug.join('/')}` + } else { + slug = `docs/${params.slug[0]}` + } + + let doc = getDocsBySlug(slug) + const content = await serialize(doc.content || '') + + return { + props: { + ...doc, + content, + toc: toc(doc.content, { maxdepth: 1, firsth1: false }), + }, + } +} + +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/reference/cli/config.tsx b/apps/docs/pages/reference/cli/config.tsx similarity index 100% rename from apps/docs/pages/new/reference/cli/config.tsx rename to apps/docs/pages/reference/cli/config.tsx diff --git a/apps/docs/pages/new/reference/dart/[...slug].tsx b/apps/docs/pages/reference/dart/[...slug].tsx similarity index 89% rename from apps/docs/pages/new/reference/dart/[...slug].tsx rename to apps/docs/pages/reference/dart/[...slug].tsx index eec26f08ed5..94a75b32e35 100644 --- a/apps/docs/pages/new/reference/dart/[...slug].tsx +++ b/apps/docs/pages/reference/dart/[...slug].tsx @@ -1,12 +1,13 @@ import { useEffect } from 'react' import fs from 'fs' +import toc from 'markdown-toc' import matter from 'gray-matter' import { MDXRemote } from 'next-mdx-remote' import { serialize } from 'next-mdx-remote/serialize' import components from '~/components/index' -import { getAllDocs } from '~/lib/docs' +import { getAllDocs, getDocsBySlug } from '~/lib/docs' import ReactMarkdown from 'react-markdown' @@ -27,6 +28,8 @@ import Param from '~/components/Params' import Options from '~/components/Options' import RefSubLayout from '~/layouts/ref/RefSubLayout' +import OldLayout from '~/layouts/Default' + export default function DartReference(props) { const router = useRouter() const slug = router.query.slug[0] @@ -38,6 +41,18 @@ export default function DartReference(props) { } }) + /* + * handle old ref pages + */ + if (process.env.NEXT_PUBLIC_NEW_DOCS === 'false') { + return ( + // @ts-ignore + + + + ) + } + return ( {dartSpec.functions.map((item, itemIndex) => { @@ -251,10 +266,41 @@ export async function getStaticProps({ params }: { params: { slug: string[] } }) }) ) - return { - props: { - docs: allMarkdownDocs, - }, + /* + * old content generation + * this is for grabbing to old markdown files + */ + + let slug + if (params.slug.length > 1) { + slug = `docs/reference/dart/${params.slug.join('/')}` + } else { + slug = `docs/reference/dart/${params.slug[0]}` + } + + let doc = getDocsBySlug(slug) + const content = await serialize(doc.content || '') + + /* + * handle old ref pages + */ + if (process.env.NEXT_PUBLIC_NEW_DOCS === 'false') { + return { + props: { + /* + * old reference docs are below + */ + ...doc, + content, + toc: toc(doc.content, { maxdepth: 1, firsth1: false }), + }, + } + } else { + return { + props: { + docs: allMarkdownDocs, + }, + } } } diff --git a/apps/docs/pages/reference.mdx b/apps/docs/pages/reference/index.mdx similarity index 100% rename from apps/docs/pages/reference.mdx rename to apps/docs/pages/reference/index.mdx diff --git a/apps/docs/pages/new/reference/javascript/[...slug].tsx b/apps/docs/pages/reference/javascript/[...slug].tsx similarity index 88% rename from apps/docs/pages/new/reference/javascript/[...slug].tsx rename to apps/docs/pages/reference/javascript/[...slug].tsx index 5f1a06e90a6..8c7314fb580 100644 --- a/apps/docs/pages/new/reference/javascript/[...slug].tsx +++ b/apps/docs/pages/reference/javascript/[...slug].tsx @@ -1,12 +1,13 @@ import { useEffect } from 'react' import fs from 'fs' +import toc from 'markdown-toc' import matter from 'gray-matter' import { MDXRemote } from 'next-mdx-remote' import { serialize } from 'next-mdx-remote/serialize' import components from '~/components/index' -import { getAllDocs } from '~/lib/docs' +import { getAllDocs, getDocsBySlug } from '~/lib/docs' import ReactMarkdown from 'react-markdown' @@ -27,11 +28,14 @@ import Param from '~/components/Params' import Options from '~/components/Options' import RefSubLayout from '~/layouts/ref/RefSubLayout' +import OldLayout from '~/layouts/Default' + export default function JSReference(props) { const router = useRouter() + const slug = router.query.slug[0] - // When user lands on a url like http://supabase.com/docs/new/reference/javascript/sign-up + // When user lands on a url like http://supabase.com/docs/reference/javascript/sign-up // find the #sign-up element and scroll to that useEffect(() => { if (document && slug !== 'start') { @@ -39,6 +43,18 @@ export default function JSReference(props) { } }) + /* + * handle old ref pages + */ + if (process.env.NEXT_PUBLIC_NEW_DOCS === 'false') { + return ( + // @ts-ignore + + + + ) + } + return ( {jsSpec.functions.map((item, itemIndex) => { @@ -92,7 +108,7 @@ export default function JSReference(props) { {/* // parameters */} {parameters && (
    -
    Parameters
    +
    Parameters