feat: new docs ia (#29364)
New Docs IA, mainly splitting up the miscellaneous bucket that is Platform into multiple sections
This commit is contained in:
@@ -12,7 +12,7 @@ export default async function ContributingPage() {
|
||||
const content = await readFile(contentFile, 'utf-8')
|
||||
|
||||
return (
|
||||
<SidebarSkeleton>
|
||||
<SidebarSkeleton hideSideNav>
|
||||
<div className="px-8 py-16">
|
||||
<article className="prose mx-auto">
|
||||
<MDXProviderGuides>
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import matter from 'gray-matter'
|
||||
import { type Heading } from 'mdast'
|
||||
import { fromMarkdown } from 'mdast-util-from-markdown'
|
||||
import { toMarkdown } from 'mdast-util-to-markdown'
|
||||
import { type SerializeOptions } from 'next-mdx-remote/dist/types'
|
||||
import { readFile } from 'node:fs/promises'
|
||||
import { join, relative } from 'node:path'
|
||||
import rehypeSlug from 'rehype-slug'
|
||||
import emoji from 'remark-emoji'
|
||||
|
||||
import { genGuideMeta, genGuidesStaticParams } from '~/features/docs/GuidesMdx.utils'
|
||||
import {
|
||||
genGuideMeta,
|
||||
genGuidesStaticParams,
|
||||
removeRedundantH1,
|
||||
} from '~/features/docs/GuidesMdx.utils'
|
||||
import { GuideTemplate, newEditLink } from '~/features/docs/GuidesMdx.template'
|
||||
import { fetchRevalidatePerDay } from '~/features/helpers.fetch'
|
||||
import { GUIDES_DIRECTORY, isValidGuideFrontmatter } from '~/lib/docs'
|
||||
@@ -16,7 +17,6 @@ import { UrlTransformFunction, linkTransform } from '~/lib/mdx/plugins/rehypeLin
|
||||
import remarkMkDocsAdmonition from '~/lib/mdx/plugins/remarkAdmonition'
|
||||
import { removeTitle } from '~/lib/mdx/plugins/remarkRemoveTitle'
|
||||
import remarkPyMdownTabs from '~/lib/mdx/plugins/remarkTabs'
|
||||
import remarkGfm from 'remark-gfm'
|
||||
|
||||
// We fetch these docs at build time from an external repo
|
||||
const org = 'supabase'
|
||||
@@ -184,22 +184,7 @@ const getContent = async (params: Params) => {
|
||||
const rawContent = await response.text()
|
||||
|
||||
const { content: contentWithoutFrontmatter } = matter(rawContent)
|
||||
|
||||
// This is the more robust way of doing it, but problems with the rewritten
|
||||
// Markdown and handling of tables this way, so saving it for later.
|
||||
//
|
||||
// const mdxTree = fromMarkdown(contentWithoutFrontmatter)
|
||||
// const maybeH1 = mdxTree.children[0]
|
||||
// if (maybeH1 && maybeH1.type === 'heading' && (maybeH1 as Heading).depth === 1) {
|
||||
// mdxTree.children.shift()
|
||||
// }
|
||||
// content = toMarkdown(mdxTree)
|
||||
|
||||
content = contentWithoutFrontmatter
|
||||
if (meta.title) {
|
||||
const h1Regex = new RegExp(`(?:^|\n)# ${meta.title}\n+`)
|
||||
content = content.replace(h1Regex, '')
|
||||
}
|
||||
content = removeRedundantH1(contentWithoutFrontmatter)
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { notFound } from 'next/navigation'
|
||||
import { relative } from 'node:path'
|
||||
import rehypeSlug from 'rehype-slug'
|
||||
|
||||
import { genGuideMeta } from '~/features/docs/GuidesMdx.utils'
|
||||
import { genGuideMeta, removeRedundantH1 } from '~/features/docs/GuidesMdx.utils'
|
||||
import { GuideTemplate, newEditLink } from '~/features/docs/GuidesMdx.template'
|
||||
import { fetchRevalidatePerDay } from '~/features/helpers.fetch'
|
||||
import { UrlTransformFunction, linkTransform } from '~/lib/mdx/plugins/rehypeLinkTransform'
|
||||
@@ -83,7 +83,7 @@ const getContent = async ({ slug }: Params) => {
|
||||
`https://raw.githubusercontent.com/${org}/${repo}/${branch}/${docsDir}/${remoteFile}`
|
||||
)
|
||||
|
||||
const content = await response.text()
|
||||
const content = removeRedundantH1(await response.text())
|
||||
|
||||
return {
|
||||
pathname: `/guides/cli/github-action/${slug}` satisfies `/${string}`,
|
||||
@@ -0,0 +1,146 @@
|
||||
import matter from 'gray-matter'
|
||||
import { type SerializeOptions } from 'next-mdx-remote/dist/types'
|
||||
import { notFound } from 'next/navigation'
|
||||
import rehypeSlug from 'rehype-slug'
|
||||
|
||||
import { genGuideMeta, removeRedundantH1 } from '~/features/docs/GuidesMdx.utils'
|
||||
import { GuideTemplate, newEditLink } from '~/features/docs/GuidesMdx.template'
|
||||
import { fetchRevalidatePerDay } from '~/features/helpers.fetch'
|
||||
import { isValidGuideFrontmatter } from '~/lib/docs'
|
||||
import { UrlTransformFunction, linkTransform } from '~/lib/mdx/plugins/rehypeLinkTransform'
|
||||
import remarkMkDocsAdmonition from '~/lib/mdx/plugins/remarkAdmonition'
|
||||
import { removeTitle } from '~/lib/mdx/plugins/remarkRemoveTitle'
|
||||
import remarkPyMdownTabs from '~/lib/mdx/plugins/remarkTabs'
|
||||
import {
|
||||
terraformDocsBranch,
|
||||
terraformDocsDocsDir,
|
||||
terraformDocsOrg,
|
||||
terraformDocsRepo,
|
||||
} from '../terraformConstants'
|
||||
|
||||
// Each external docs page is mapped to a local page
|
||||
const pageMap = [
|
||||
{
|
||||
remoteFile: 'README.md',
|
||||
meta: {
|
||||
title: 'Terraform Provider',
|
||||
},
|
||||
useRoot: true,
|
||||
},
|
||||
{
|
||||
slug: 'tutorial',
|
||||
remoteFile: 'tutorial.md',
|
||||
meta: {
|
||||
title: 'Using the Supabase Terraform Provider',
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
interface Params {
|
||||
slug?: string[]
|
||||
}
|
||||
|
||||
const TerraformDocs = async ({ params }: { params: Params }) => {
|
||||
const { meta, ...data } = await getContent(params)
|
||||
|
||||
const options = {
|
||||
mdxOptions: {
|
||||
remarkPlugins: [remarkMkDocsAdmonition, remarkPyMdownTabs, [removeTitle, meta.title]],
|
||||
rehypePlugins: [[linkTransform, urlTransform], rehypeSlug],
|
||||
},
|
||||
} as SerializeOptions
|
||||
|
||||
return <GuideTemplate mdxOptions={options} meta={meta} {...data} />
|
||||
}
|
||||
|
||||
/**
|
||||
* The GitHub repo uses relative links, which don't lead to the right locations
|
||||
* in docs.
|
||||
*
|
||||
* @param url The original link, as written in the Markdown file
|
||||
* @returns The rewritten link
|
||||
*/
|
||||
const urlTransform: UrlTransformFunction = (url: string) => {
|
||||
try {
|
||||
const placeholderHostname = 'placeholder'
|
||||
const { hostname, pathname, hash } = new URL(url, `http://${placeholderHostname}`)
|
||||
|
||||
// Don't modify a url with a FQDN or a url that's only a hash
|
||||
if (hostname !== placeholderHostname || pathname === '/') {
|
||||
return url
|
||||
}
|
||||
|
||||
const getBasename = (pathname: string) =>
|
||||
pathname.endsWith('.md') ? pathname.replace(/\.md$/, '') : pathname
|
||||
const stripLeadingPrefix = (pathname: string) => pathname.replace(/^\//, '')
|
||||
const stripLeadingDocs = (pathname: string) => pathname.replace(/^docs\//, '')
|
||||
|
||||
const relativePath = stripLeadingPrefix(getBasename(pathname))
|
||||
|
||||
const page = pageMap.find(
|
||||
({ remoteFile, useRoot }) =>
|
||||
(useRoot && `${relativePath}.md` === remoteFile) ||
|
||||
(!useRoot && `${stripLeadingDocs(relativePath)}.md` === remoteFile)
|
||||
)
|
||||
|
||||
if (page) {
|
||||
return 'terraform' + `/${page.slug}` + hash
|
||||
}
|
||||
|
||||
// If we don't have this page in our docs, link to GitHub repo
|
||||
return `https://github.com/${terraformDocsOrg}/${terraformDocsRepo}/blob/${terraformDocsBranch}${pathname}${hash}`
|
||||
} catch (err) {
|
||||
console.error('Error transforming markdown URL', err)
|
||||
return url
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch markdown from external repo
|
||||
*/
|
||||
const getContent = async ({ slug }: Params) => {
|
||||
const [requestedSlug] = slug ?? []
|
||||
const page = pageMap.find((page) => page.slug === requestedSlug)
|
||||
|
||||
if (!page) {
|
||||
notFound()
|
||||
}
|
||||
|
||||
const { meta, remoteFile, useRoot } = page
|
||||
|
||||
const editLink = newEditLink(
|
||||
`${terraformDocsOrg}/${terraformDocsRepo}/blob/${terraformDocsBranch}/${useRoot ? '' : `${terraformDocsDocsDir}/`}${remoteFile}`
|
||||
)
|
||||
|
||||
let response = await fetchRevalidatePerDay(
|
||||
`https://raw.githubusercontent.com/${terraformDocsOrg}/${terraformDocsRepo}/${terraformDocsBranch}/${useRoot ? '' : `${terraformDocsDocsDir}/`}${remoteFile}`
|
||||
)
|
||||
|
||||
let rawContent = await response.text()
|
||||
// Strip out HTML comments
|
||||
rawContent = rawContent.replace(/<!--.*?-->/, '')
|
||||
let { content, data } = matter(rawContent)
|
||||
|
||||
// Remove the title from the content so it isn't duplicated in the final display
|
||||
content = removeRedundantH1(content)
|
||||
|
||||
Object.assign(meta, data)
|
||||
|
||||
if (!isValidGuideFrontmatter(meta)) {
|
||||
throw Error('Guide frontmatter is invalid.')
|
||||
}
|
||||
|
||||
return {
|
||||
pathname:
|
||||
`/guides/platform/terraform${slug?.length ? `/${slug.join('/')}` : ''}` satisfies `/${string}`,
|
||||
meta,
|
||||
content,
|
||||
editLink,
|
||||
}
|
||||
}
|
||||
|
||||
const generateStaticParams = async () => pageMap.map(({ slug }) => ({ slug: slug ? [slug] : [] }))
|
||||
const generateMetadata = genGuideMeta(getContent)
|
||||
|
||||
export default TerraformDocs
|
||||
export { generateStaticParams, generateMetadata }
|
||||
@@ -0,0 +1,410 @@
|
||||
import { codeBlock } from 'common-tags'
|
||||
import { Check, PlusCircle } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import ReactMarkdown from 'react-markdown'
|
||||
|
||||
import {
|
||||
CodeBlock,
|
||||
Heading,
|
||||
PopoverContent_Shadcn_,
|
||||
PopoverTrigger_Shadcn_,
|
||||
Popover_Shadcn_,
|
||||
} from 'ui'
|
||||
|
||||
import { genGuideMeta } from '~/features/docs/GuidesMdx.utils'
|
||||
import { GuideTemplate, newEditLink } from '~/features/docs/GuidesMdx.template'
|
||||
import { fetchRevalidatePerDay } from '~/features/helpers.fetch'
|
||||
import { TabPanel, Tabs } from '~/features/ui/Tabs'
|
||||
import {
|
||||
terraformDocsBranch,
|
||||
terraformDocsDocsDir,
|
||||
terraformDocsOrg,
|
||||
terraformDocsRepo,
|
||||
} from '../terraformConstants'
|
||||
|
||||
const meta = {
|
||||
title: 'Terraform Provider reference',
|
||||
subtitle: 'Resources and data sources available through the Terraform Provider',
|
||||
}
|
||||
|
||||
const generateMetadata = genGuideMeta(() => ({
|
||||
pathname: '/guides/platform/terraform/reference',
|
||||
meta,
|
||||
}))
|
||||
|
||||
function ProviderSettings({ schema }: { schema: any }) {
|
||||
const attributes = schema.block.attributes
|
||||
|
||||
const example = codeBlock`
|
||||
provider "supabase" {
|
||||
${Object.keys(attributes).map(
|
||||
(attribute) =>
|
||||
`${attribute} = ${attributes[attribute].type === 'string' ? `""` : '<value>'}`
|
||||
)}
|
||||
}
|
||||
`
|
||||
|
||||
return (
|
||||
<section aria-labelledby="provider-settings" className="prose max-w-none">
|
||||
<Heading tag="h2">Provider settings</Heading>
|
||||
<p>
|
||||
Use these settings to configure your Supabase provider and authenticate to your Supabase
|
||||
project.
|
||||
</p>
|
||||
<Heading tag="h3">Example usage</Heading>
|
||||
<CodeBlock className="not-prose">{example}</CodeBlock>
|
||||
<Heading tag="h3">Details</Heading>
|
||||
{/* extra div because width restriction doesn't work on table itself */}
|
||||
<div className="w-full overflow-auto">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Attribute</th>
|
||||
<th>Description</th>
|
||||
<th>Type</th>
|
||||
<th>Optional</th>
|
||||
<th>Sensitive</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{Object.keys(schema.block.attributes).map((attribute) => (
|
||||
<tr key={attribute}>
|
||||
<td>{attribute}</td>
|
||||
<td>
|
||||
<ReactMarkdown>{attributes[attribute].description}</ReactMarkdown>
|
||||
</td>
|
||||
<td>{attributes[attribute].type}</td>
|
||||
<td className="align-middle">
|
||||
{attributes[attribute].optional && (
|
||||
<>
|
||||
<Check className="ml-[2.5ch]" />
|
||||
<span className="sr-only">true</span>
|
||||
</>
|
||||
)}
|
||||
</td>
|
||||
<td className="align-middle">
|
||||
{attributes[attribute].sensitive && (
|
||||
<>
|
||||
<Check className="ml-[2.5ch]" />
|
||||
<span className="sr-only">true</span>
|
||||
</>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
function Resources({ schema }: { schema: any }) {
|
||||
return (
|
||||
<section aria-labelledby="resources" className="prose max-w-none">
|
||||
<Heading tag="h2">Resources</Heading>
|
||||
<p>You can configure these resources using the Supabase Terraform provider:</p>
|
||||
<Tabs>
|
||||
{Object.keys(schema).map((resource) => (
|
||||
<TabPanel id={resource} label={resource}>
|
||||
<Heading tag="h4">Example usage</Heading>
|
||||
<CodeBlock className="not-prose">{codeBlock`
|
||||
resource "${resource}" "<label>" {
|
||||
${Object.keys(schema[resource].block.attributes)
|
||||
.filter((attribute) => !schema[resource].block.attributes[attribute].computed)
|
||||
.map(
|
||||
(attribute) =>
|
||||
`${attribute} = ${
|
||||
schema[resource].block.attributes[attribute].type === 'string'
|
||||
? `""`
|
||||
: '<value>'
|
||||
}`
|
||||
)}
|
||||
}
|
||||
`}</CodeBlock>
|
||||
<Heading tag="h4">Details</Heading>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Attribute</th>
|
||||
<th>Description</th>
|
||||
<th>Type</th>
|
||||
<th>Required</th>
|
||||
<th>Optional</th>
|
||||
<th>Read-only</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{Object.keys(schema[resource].block.attributes).map((attribute) => (
|
||||
<tr key={attribute}>
|
||||
<td>
|
||||
<code>{attribute}</code>
|
||||
</td>
|
||||
<td>
|
||||
<ReactMarkdown>
|
||||
{schema[resource].block.attributes[attribute].description}
|
||||
</ReactMarkdown>
|
||||
</td>
|
||||
<td>
|
||||
{schema[resource].block.attributes[attribute].type ?? (
|
||||
<Popover_Shadcn_>
|
||||
<PopoverTrigger_Shadcn_ asChild>
|
||||
<button className="flex items-center justify-between gap-2">
|
||||
Nested type
|
||||
<PlusCircle size={14} className="shrink-0" />
|
||||
</button>
|
||||
</PopoverTrigger_Shadcn_>
|
||||
<PopoverContent_Shadcn_ className="max-h-[50vh] overflow-auto">
|
||||
<ul>
|
||||
{Object.keys(
|
||||
schema[resource].block.attributes[attribute].nested_type.attributes
|
||||
).map((nestedAttribute) => (
|
||||
<li key={nestedAttribute}>
|
||||
{nestedAttribute}
|
||||
<ul>
|
||||
<li>
|
||||
<ReactMarkdown className="*:!m-0">
|
||||
{
|
||||
schema[resource].block.attributes[attribute].nested_type
|
||||
.attributes[nestedAttribute].description
|
||||
}
|
||||
</ReactMarkdown>
|
||||
</li>
|
||||
<li>
|
||||
{schema[resource].block.attributes[attribute].nested_type
|
||||
.attributes[nestedAttribute].type ?? 'nested type'}
|
||||
</li>
|
||||
{schema[resource].block.attributes[attribute].nested_type
|
||||
.attributes[nestedAttribute].required && <li>Required</li>}
|
||||
{schema[resource].block.attributes[attribute].nested_type
|
||||
.attributes[nestedAttribute].optional && <li>Optional</li>}
|
||||
{schema[resource].block.attributes[attribute].nested_type
|
||||
.attributes[nestedAttribute].computed && <li>Read-only</li>}
|
||||
</ul>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</PopoverContent_Shadcn_>
|
||||
</Popover_Shadcn_>
|
||||
)}
|
||||
</td>
|
||||
<td className="align-middle">
|
||||
{schema[resource].block.attributes[attribute].required && (
|
||||
<>
|
||||
<Check className="ml-[2.5ch]" />
|
||||
<span className="sr-only">true</span>
|
||||
</>
|
||||
)}
|
||||
</td>
|
||||
<td className="align-middle">
|
||||
{schema[resource].block.attributes[attribute].optional && (
|
||||
<>
|
||||
<Check className="ml-[2.5ch]" />
|
||||
<span className="sr-only">true</span>
|
||||
</>
|
||||
)}
|
||||
</td>
|
||||
<td className="align-middle">
|
||||
{schema[resource].block.attributes[attribute].computed && (
|
||||
<>
|
||||
<Check className="ml-[2.5ch]" />
|
||||
<span className="sr-only">true</span>
|
||||
</>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</TabPanel>
|
||||
))}
|
||||
</Tabs>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
function DataSources({ schema }: { schema: any }) {
|
||||
return (
|
||||
<section aria-labelledby="data-sources" className="prose max-w-none">
|
||||
<Heading tag="h2">Data sources</Heading>
|
||||
<p>You can read these resources using the Supabase Terraform provider:</p>
|
||||
<Tabs>
|
||||
{Object.keys(schema).map((dataSource) => (
|
||||
<TabPanel id={dataSource} label={dataSource}>
|
||||
<Heading tag="h4">Example usage</Heading>
|
||||
<CodeBlock className="not-prose">{codeBlock`
|
||||
resource "${dataSource}" "all" {
|
||||
${Object.keys(schema[dataSource].block.attributes)
|
||||
.filter(
|
||||
(attribute) => !schema[dataSource].block.attributes[attribute].computed
|
||||
)
|
||||
.map(
|
||||
(attribute) =>
|
||||
`${attribute} = ${
|
||||
schema[dataSource].block.attributes[attribute].type === 'string'
|
||||
? `""`
|
||||
: '<value>'
|
||||
}`
|
||||
)}
|
||||
}
|
||||
`}</CodeBlock>
|
||||
<Heading tag="h4">Details</Heading>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Attribute</th>
|
||||
<th>Description</th>
|
||||
<th>Type</th>
|
||||
<th>Required</th>
|
||||
<th>Optional</th>
|
||||
<th>Read-only</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{Object.keys(schema[dataSource].block.attributes).map((attribute) => (
|
||||
<tr key={attribute}>
|
||||
<td>
|
||||
<code>{attribute}</code>
|
||||
</td>
|
||||
<td>
|
||||
<ReactMarkdown>
|
||||
{schema[dataSource].block.attributes[attribute].description}
|
||||
</ReactMarkdown>
|
||||
</td>
|
||||
<td>
|
||||
{schema[dataSource].block.attributes[attribute].type ?? (
|
||||
<Popover_Shadcn_>
|
||||
<PopoverTrigger_Shadcn_ asChild>
|
||||
<button className="flex items-center justify-between gap-2">
|
||||
Nested type
|
||||
<PlusCircle size={14} />
|
||||
</button>
|
||||
</PopoverTrigger_Shadcn_>
|
||||
<PopoverContent_Shadcn_ className="max-h-[50vh] overflow-auto">
|
||||
{schema[dataSource].block.attributes[attribute].nested_type
|
||||
.nesting_mode === 'set' && 'Array of:'}
|
||||
<ul>
|
||||
{Object.keys(
|
||||
schema[dataSource].block.attributes[attribute].nested_type
|
||||
.attributes
|
||||
).map((nestedAttribute) => (
|
||||
<li key={nestedAttribute}>
|
||||
{nestedAttribute}
|
||||
<ul>
|
||||
<li>
|
||||
<ReactMarkdown className="*:!m-0">
|
||||
{
|
||||
schema[dataSource].block.attributes[attribute].nested_type
|
||||
.attributes[nestedAttribute].description
|
||||
}
|
||||
</ReactMarkdown>
|
||||
</li>
|
||||
<li>
|
||||
{schema[dataSource].block.attributes[attribute].nested_type
|
||||
.attributes[nestedAttribute].type ?? 'nested type'}
|
||||
</li>
|
||||
{schema[dataSource].block.attributes[attribute].nested_type
|
||||
.attributes[nestedAttribute].required && <li>Required</li>}
|
||||
{schema[dataSource].block.attributes[attribute].nested_type
|
||||
.attributes[nestedAttribute].optional && <li>Optional</li>}
|
||||
{schema[dataSource].block.attributes[attribute].nested_type
|
||||
.attributes[nestedAttribute].computed && <li>Read-only</li>}
|
||||
</ul>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</PopoverContent_Shadcn_>
|
||||
</Popover_Shadcn_>
|
||||
)}
|
||||
</td>
|
||||
<td className="align-middle">
|
||||
{schema[dataSource].block.attributes[attribute].required && (
|
||||
<>
|
||||
<Check className="ml-[2.5ch]" />
|
||||
<span className="sr-only">true</span>
|
||||
</>
|
||||
)}
|
||||
</td>
|
||||
<td className="align-middle">
|
||||
{schema[dataSource].block.attributes[attribute].optional && (
|
||||
<>
|
||||
<Check className="ml-[2.5ch]" />
|
||||
<span className="sr-only">true</span>
|
||||
</>
|
||||
)}
|
||||
</td>
|
||||
<td className="align-middle">
|
||||
{schema[dataSource].block.attributes[attribute].computed && (
|
||||
<>
|
||||
<Check className="ml-[2.5ch]" />
|
||||
<span className="sr-only">true</span>
|
||||
</>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</TabPanel>
|
||||
))}
|
||||
</Tabs>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
const TerraformReferencePage = async () => {
|
||||
const { schema } = await getSchema()
|
||||
|
||||
const editLink = newEditLink('supabase/terraform-provider-supabase')
|
||||
|
||||
return (
|
||||
<GuideTemplate meta={meta} editLink={editLink}>
|
||||
The Terraform Provider provices access to{' '}
|
||||
<Link
|
||||
href="https://developer.hashicorp.com/terraform/language/resources"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
resources
|
||||
</Link>{' '}
|
||||
and{' '}
|
||||
<Link
|
||||
href="https://developer.hashicorp.com/terraform/language/data-sources"
|
||||
rel="noreferrer noopener"
|
||||
>
|
||||
data sources
|
||||
</Link>
|
||||
. Resources are infrastructure objects, such as a Supabase project, that you can declaratively
|
||||
configure. Data sources are sources of information about your Supabase instances.
|
||||
<ProviderSettings
|
||||
schema={schema.provider_schemas['registry.terraform.io/supabase/supabase'].provider}
|
||||
/>
|
||||
<Resources
|
||||
schema={schema.provider_schemas['registry.terraform.io/supabase/supabase'].resource_schemas}
|
||||
/>
|
||||
<DataSources
|
||||
schema={
|
||||
schema.provider_schemas['registry.terraform.io/supabase/supabase'].data_source_schemas
|
||||
}
|
||||
/>
|
||||
</GuideTemplate>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch JSON schema from external repo
|
||||
*/
|
||||
const getSchema = async () => {
|
||||
let response = await fetchRevalidatePerDay(
|
||||
`https://raw.githubusercontent.com/${terraformDocsOrg}/${terraformDocsRepo}/${terraformDocsBranch}/${terraformDocsDocsDir}/schema.json`
|
||||
)
|
||||
if (!response.ok) throw Error('Failed to fetch Terraform JSON schema from GitHub')
|
||||
|
||||
const schema = await response.json()
|
||||
|
||||
return {
|
||||
schema,
|
||||
}
|
||||
}
|
||||
|
||||
export default TerraformReferencePage
|
||||
export { generateMetadata }
|
||||
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Information on where to fetch docs content
|
||||
*/
|
||||
const terraformDocsOrg = 'supabase'
|
||||
const terraformDocsRepo = 'terraform-provider-supabase'
|
||||
const terraformDocsBranch = 'v1.1.3'
|
||||
const terraformDocsDocsDir = 'docs'
|
||||
|
||||
export { terraformDocsOrg, terraformDocsRepo, terraformDocsBranch, terraformDocsDocsDir }
|
||||
@@ -1,16 +1,29 @@
|
||||
'use client'
|
||||
|
||||
import { usePathname } from 'next/navigation'
|
||||
import { type PropsWithChildren } from 'react'
|
||||
|
||||
import { getMenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu.utils'
|
||||
import { supabaseMisc } from '~/lib/supabaseMisc'
|
||||
import Layout from '~/layouts/guides'
|
||||
|
||||
const GuidesLayout = ({ children }: PropsWithChildren) => {
|
||||
const pathname = usePathname()
|
||||
const menuId = getMenuId(pathname)
|
||||
const GuidesLayout = async ({ children }: PropsWithChildren) => {
|
||||
const partners = await getPartners()
|
||||
const partnerNavItems = partners.map((partner) => ({
|
||||
name: partner.title,
|
||||
url: `https://supabase.com/partners/integrations/${partner.slug}` as `https://${string}`,
|
||||
}))
|
||||
|
||||
return <Layout menuId={menuId}>{children}</Layout>
|
||||
return <Layout additionalNavItems={partnerNavItems}>{children}</Layout>
|
||||
}
|
||||
|
||||
async function getPartners() {
|
||||
const { data, error } = await supabaseMisc()
|
||||
.from('partners')
|
||||
.select('slug, title')
|
||||
.eq('type', 'technology')
|
||||
.order('title')
|
||||
if (error) {
|
||||
console.error(new Error('Error fetching partners', { cause: error }))
|
||||
}
|
||||
|
||||
return data ?? []
|
||||
}
|
||||
|
||||
export default GuidesLayout
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
import ReactMarkdown from 'react-markdown'
|
||||
import { CodeBlock } from 'ui'
|
||||
import { Heading } from 'ui/src/components/CustomHTMLElements'
|
||||
import { type TOCHeader } from '~/components/GuidesTableOfContents'
|
||||
import { genGuideMeta } from '~/features/docs/GuidesMdx.utils'
|
||||
import { GuideTemplate, newEditLink } from '~/features/docs/GuidesMdx.template'
|
||||
import type { Parameter } from '~/lib/refGenerator/refTypes'
|
||||
import specFile from '~/spec/cli_v1_config.yaml' assert { type: 'yml' }
|
||||
|
||||
const meta = {
|
||||
title: 'Supabase CLI config',
|
||||
}
|
||||
|
||||
const generateMetadata = genGuideMeta(() => ({
|
||||
pathname: '/guides/cli/config',
|
||||
meta,
|
||||
}))
|
||||
|
||||
const tocList: TOCHeader[] = []
|
||||
const content = specFile.info.tags.map((tag: { id: string; title: string }, id: number) => {
|
||||
tocList.push({ id: `${id}`, text: tag.title, link: `${tag.id}-config`, level: 2 })
|
||||
return (
|
||||
<div>
|
||||
<Heading tag="h2">{tag.title} Config</Heading>
|
||||
{specFile.parameters
|
||||
.filter((param: Parameter) => param.tags && param.tags[0] === tag.id)
|
||||
.map((parameter: Parameter, id: number) => {
|
||||
tocList.push({ id: `${id}`, text: parameter.id, link: `#${parameter.id}`, level: 3 })
|
||||
return <Info parameter={parameter} />
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
const Config = () => {
|
||||
const editLink = newEditLink('supabase/supabase/blob/master/apps/docs/spec/cli_v1_config.yaml')
|
||||
|
||||
return (
|
||||
<GuideTemplate meta={meta} editLink={editLink}>
|
||||
<ReactMarkdown>{specFile.info.description}</ReactMarkdown>
|
||||
<div>{content}</div>
|
||||
</GuideTemplate>
|
||||
)
|
||||
}
|
||||
|
||||
function Info({ parameter }: { parameter: Parameter }) {
|
||||
return (
|
||||
<div className="mt-8">
|
||||
<div>
|
||||
<Heading tag="h3" parseAnchors={false} customAnchor={parameter.id}>
|
||||
<code>{parameter.title}</code>
|
||||
</Heading>
|
||||
|
||||
<div className="border-b pb-8" key={parameter.id}>
|
||||
<div className=" mb-16">
|
||||
<div>
|
||||
<table className="table-auto">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="text-left">Name</th>
|
||||
<th className="text-left">Default</th>
|
||||
<th className="text-left">Required</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{parameter.id}</td>
|
||||
<td>{parameter.default ? parameter.default.toString() : 'None'}</td>
|
||||
<td>{parameter.required !== undefined && parameter.required.toString()}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className="mb-4 scroll-mt-16 mt-0 ">
|
||||
<p className="text-sm font-bold uppercase">Description</p>
|
||||
<ReactMarkdown>{parameter.description}</ReactMarkdown>
|
||||
</div>
|
||||
{parameter.usage && (
|
||||
<div className="mb-4 scroll-mt-16 mt-0 ">
|
||||
<p className="text-sm font-bold uppercase">Usage</p>
|
||||
<CodeBlock className="useless-code-block-class" language="py">
|
||||
{parameter.usage}
|
||||
</CodeBlock>
|
||||
</div>
|
||||
)}
|
||||
{parameter.links && (
|
||||
<div>
|
||||
<p className="text-sm font-bold uppercase">See also</p>
|
||||
<ul>
|
||||
{parameter.links.map((link) => (
|
||||
<li key={link.link}>
|
||||
<a href={link.link}>{link.name}</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Config
|
||||
export { generateMetadata }
|
||||
@@ -3,7 +3,7 @@ import { type SerializeOptions } from 'next-mdx-remote/dist/types'
|
||||
import { notFound } from 'next/navigation'
|
||||
import rehypeSlug from 'rehype-slug'
|
||||
|
||||
import { genGuideMeta } from '~/features/docs/GuidesMdx.utils'
|
||||
import { genGuideMeta, removeRedundantH1 } from '~/features/docs/GuidesMdx.utils'
|
||||
import { GuideTemplate, newEditLink } from '~/features/docs/GuidesMdx.template'
|
||||
import { fetchRevalidatePerDay } from '~/features/helpers.fetch'
|
||||
import { isValidGuideFrontmatter } from '~/lib/docs'
|
||||
@@ -119,7 +119,11 @@ const getContent = async ({ slug }: Params) => {
|
||||
let rawContent = await response.text()
|
||||
// Strip out HTML comments
|
||||
rawContent = rawContent.replace(/<!--.*?-->/, '')
|
||||
const { content, data } = matter(rawContent)
|
||||
let { content, data } = matter(rawContent)
|
||||
|
||||
// Remove the title from the content so it isn't duplicated in the final display
|
||||
content = removeRedundantH1(content)
|
||||
|
||||
Object.assign(meta, data)
|
||||
|
||||
if (!isValidGuideFrontmatter(meta)) {
|
||||
|
||||
@@ -4,12 +4,13 @@ import '../styles/main.scss'
|
||||
import '../styles/new-docs.scss'
|
||||
import '../styles/prism-okaidia.scss'
|
||||
|
||||
import { genFaviconData } from 'common/MetaFavicons/app-router'
|
||||
import { type Metadata, type Viewport } from 'next'
|
||||
|
||||
import { BASE_PATH, IS_PRODUCTION } from '~/lib/constants'
|
||||
import { genFaviconData } from 'common/MetaFavicons/app-router'
|
||||
|
||||
import { GlobalProviders } from '~/features/app.providers'
|
||||
import { TopNavSkeleton } from '~/layouts/MainSkeleton'
|
||||
import { BASE_PATH, IS_PRODUCTION } from '~/lib/constants'
|
||||
|
||||
const metadata: Metadata = {
|
||||
applicationName: 'Supabase Docs',
|
||||
|
||||
@@ -9,7 +9,7 @@ export interface NavMenuGroup {
|
||||
|
||||
export interface NavMenuSection {
|
||||
name: string
|
||||
url?: `/${string}`
|
||||
url?: `/${string}` | `https://${string}`
|
||||
items: Partial<NavMenuSection>[]
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { Heart, Server } from 'lucide-react'
|
||||
|
||||
import {
|
||||
IconBranching,
|
||||
IconGitHub,
|
||||
@@ -85,8 +87,12 @@ function getMenuIcon(menuKey: string, width: number = 16, height: number = 16, c
|
||||
return <IconGitHub width={width} height={height} className={className} />
|
||||
case 'support':
|
||||
return <IconSupport width={width} height={height} className={className} />
|
||||
case 'contributing':
|
||||
case 'troubleshooting':
|
||||
return <IconTroubleshooting width={width} height={height} className={className} />
|
||||
case 'contributing':
|
||||
return <Heart width={width} height={height} className={className} />
|
||||
case 'deployment':
|
||||
return <Server width={width} height={height} className={className} />
|
||||
default:
|
||||
return <IconMenuPlatform width={width} height={height} className={className} />
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { GlobalMenuItems, NavMenuConstant } from '../Navigation.types'
|
||||
import type { GlobalMenuItems, NavMenuConstant, NavMenuSection } from '../Navigation.types'
|
||||
|
||||
export const GLOBAL_MENU_ITEMS: GlobalMenuItems = [
|
||||
[
|
||||
@@ -60,16 +60,10 @@ export const GLOBAL_MENU_ITEMS: GlobalMenuItems = [
|
||||
menuItems: [
|
||||
[
|
||||
{
|
||||
label: 'Local Dev / CLI',
|
||||
label: 'Local Development & CLI',
|
||||
icon: 'dev-cli',
|
||||
href: '/guides/cli',
|
||||
level: 'reference_javascript',
|
||||
},
|
||||
{
|
||||
label: 'Platform',
|
||||
icon: 'platform',
|
||||
href: '/guides/platform',
|
||||
level: 'platform',
|
||||
href: '/guides/local-development',
|
||||
level: 'local_development',
|
||||
},
|
||||
{
|
||||
label: 'Self-Hosting',
|
||||
@@ -81,9 +75,36 @@ export const GLOBAL_MENU_ITEMS: GlobalMenuItems = [
|
||||
label: 'Integrations',
|
||||
icon: 'integrations',
|
||||
hasLightIcon: true,
|
||||
href: 'https://supabase.com/partners/integrations',
|
||||
href: '/guides/integrations',
|
||||
level: 'integrations',
|
||||
},
|
||||
{
|
||||
label: 'Deployment',
|
||||
icon: 'deployment',
|
||||
href: '/guides/deployment',
|
||||
level: 'deployment',
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
label: 'Manage',
|
||||
menuItems: [
|
||||
[
|
||||
{
|
||||
label: 'Platform Management',
|
||||
icon: 'platform',
|
||||
href: '/guides/platform',
|
||||
level: 'platform',
|
||||
},
|
||||
{
|
||||
label: 'Monitoring & Troubleshooting',
|
||||
icon: 'troubleshooting',
|
||||
href: '/guides/monitoring-troubleshooting',
|
||||
level: 'troubleshooting',
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
@@ -178,9 +199,9 @@ export const GLOBAL_MENU_ITEMS: GlobalMenuItems = [
|
||||
href: '/guides/troubleshooting',
|
||||
}, */
|
||||
{
|
||||
label: 'Migration guides',
|
||||
label: 'Glossary',
|
||||
icon: 'resources',
|
||||
href: '/guides/resources',
|
||||
href: '/guides/resources/glossary',
|
||||
level: 'resources',
|
||||
},
|
||||
{
|
||||
@@ -1751,68 +1772,62 @@ export const ai = {
|
||||
],
|
||||
}
|
||||
|
||||
export const supabase_cli: NavMenuConstant = {
|
||||
export const local_development: NavMenuConstant = {
|
||||
icon: 'dev-cli',
|
||||
title: 'Local Dev / CLI',
|
||||
url: '/guides/cli',
|
||||
url: '/guides/local-development',
|
||||
items: [
|
||||
{ name: 'Overview', url: '/guides/cli' },
|
||||
{ name: 'Overview', url: '/guides/local-development' },
|
||||
{
|
||||
name: 'Using the CLI',
|
||||
name: 'CLI',
|
||||
url: undefined,
|
||||
items: [
|
||||
{ name: 'Getting started', url: '/guides/cli/getting-started' },
|
||||
{ name: 'CLI Configuration', url: '/guides/cli/config' },
|
||||
{ name: 'Getting started', url: '/guides/local-development/cli/getting-started' },
|
||||
{ name: 'Configuration', url: '/guides/local-development/cli/config' },
|
||||
{ name: 'CLI commands', url: '/reference/cli' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Developing with Supabase',
|
||||
name: 'Local development',
|
||||
url: undefined,
|
||||
items: [
|
||||
{ name: 'Local Development', url: '/guides/cli/local-development' },
|
||||
{
|
||||
name: 'Managing environments',
|
||||
url: '/guides/cli/managing-environments',
|
||||
},
|
||||
{ name: 'Getting started', url: '/guides/local-development/overview' },
|
||||
{
|
||||
name: 'Managing config and secrets',
|
||||
url: '/guides/cli/managing-config',
|
||||
url: '/guides/local-development/managing-config',
|
||||
},
|
||||
{
|
||||
name: 'Seeding your database',
|
||||
url: '/guides/cli/seeding-your-database',
|
||||
},
|
||||
{
|
||||
name: 'Testing and linting',
|
||||
url: '/guides/cli/testing-and-linting',
|
||||
url: '/guides/local-development/seeding-your-database',
|
||||
},
|
||||
{
|
||||
name: 'Customizing email templates',
|
||||
url: '/guides/cli/customizing-email-templates',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'GitHub Action',
|
||||
url: undefined,
|
||||
items: [
|
||||
{
|
||||
name: 'Generate types from your database',
|
||||
url: '/guides/cli/github-action/generating-types',
|
||||
},
|
||||
{
|
||||
name: 'Automated testing',
|
||||
url: '/guides/cli/github-action/testing',
|
||||
},
|
||||
{
|
||||
name: 'Backup your database',
|
||||
url: '/guides/cli/github-action/backups',
|
||||
url: '/guides/local-development/customizing-email-templates',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export const MIGRATION_PAGES: Partial<NavMenuSection>[] = [
|
||||
{ name: 'Amazon RDS', url: '/guides/platform/migrating-to-supabase/amazon-rds' },
|
||||
{ name: 'Auth0', url: '/guides/platform/migrating-to-supabase/auth0' },
|
||||
{ name: 'Firebase Auth', url: '/guides/platform/migrating-to-supabase/firebase-auth' },
|
||||
{
|
||||
name: 'Firebase Firestore',
|
||||
url: '/guides/platform/migrating-to-supabase/firestore-data',
|
||||
},
|
||||
{
|
||||
name: 'Firebase Storage',
|
||||
url: '/guides/platform/migrating-to-supabase/firebase-storage',
|
||||
},
|
||||
{ name: 'Heroku Postgres', url: '/guides/platform/migrating-to-supabase/heroku' },
|
||||
{ name: 'MySQL', url: '/guides/platform/migrating-to-supabase/mysql' },
|
||||
{ name: 'MSSQL', url: '/guides/platform/migrating-to-supabase/mssql' },
|
||||
{ name: 'Postgres', url: '/guides/platform/migrating-to-supabase/postgres' },
|
||||
{ name: 'Render', url: '/guides/platform/migrating-to-supabase/render' },
|
||||
]
|
||||
|
||||
export const platform: NavMenuConstant = {
|
||||
icon: 'platform',
|
||||
title: 'Platform',
|
||||
@@ -1830,31 +1845,28 @@ export const platform: NavMenuConstant = {
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Logging and observability',
|
||||
name: 'Upgrades & Migrations',
|
||||
url: undefined,
|
||||
items: [
|
||||
{ name: 'Logging', url: '/guides/platform/logs' },
|
||||
{ name: 'Advanced Log Filtering', url: '/guides/platform/advanced-log-filtering' },
|
||||
{ name: 'Log Drains', url: '/guides/platform/log-drains' },
|
||||
{ name: 'Metrics', url: '/guides/platform/metrics' },
|
||||
{ name: 'Monitoring with Sentry', url: '/guides/platform/sentry-monitoring' },
|
||||
{ name: 'Upgrading', url: '/guides/platform/upgrading' },
|
||||
{
|
||||
name: 'Migrating within Supabase',
|
||||
url: '/guides/platform/migrating-within-supabase',
|
||||
},
|
||||
{
|
||||
name: 'Migrating to Supabase',
|
||||
url: '/guides/platform/migrating-to-supabase',
|
||||
items: MIGRATION_PAGES,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Platform Management',
|
||||
name: 'Project & Account Management',
|
||||
url: undefined,
|
||||
items: [
|
||||
{ name: 'Regions', url: '/guides/platform/regions' },
|
||||
{ name: 'Database Size', url: '/guides/platform/database-size' },
|
||||
{ name: 'Fly Postgres', url: '/guides/platform/fly-postgres' },
|
||||
{ name: 'Vercel Marketplace', url: '/guides/platform/vercel-marketplace' },
|
||||
{
|
||||
name: 'HTTP Status Codes',
|
||||
url: '/guides/platform/http-status-codes',
|
||||
},
|
||||
{
|
||||
name: 'Migrating and Upgrading',
|
||||
url: '/guides/platform/migrating-and-upgrading-projects',
|
||||
name: 'Access Control',
|
||||
url: '/guides/platform/access-control',
|
||||
},
|
||||
{
|
||||
name: 'Multi-factor Authentication',
|
||||
@@ -1864,21 +1876,34 @@ export const platform: NavMenuConstant = {
|
||||
name: 'Transfer Project',
|
||||
url: '/guides/platform/project-transfer',
|
||||
},
|
||||
{
|
||||
name: 'Single Sign-On',
|
||||
url: '/guides/platform/sso',
|
||||
items: [
|
||||
{ name: 'SSO with Azure AD', url: '/guides/platform/sso/azure' },
|
||||
{
|
||||
name: 'SSO with Google Workspace',
|
||||
url: '/guides/platform/sso/gsuite',
|
||||
},
|
||||
{ name: 'SSO with Okta', url: '/guides/platform/sso/okta' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Platform Configuration',
|
||||
url: undefined,
|
||||
items: [
|
||||
{ name: 'Regions', url: '/guides/platform/regions' },
|
||||
{ name: 'Database Size', url: '/guides/platform/database-size' },
|
||||
{ name: 'Fly Postgres', url: '/guides/platform/fly-postgres' },
|
||||
{
|
||||
name: 'Network Restrictions',
|
||||
url: '/guides/platform/network-restrictions',
|
||||
},
|
||||
{ name: 'Performance Tuning', url: '/guides/platform/performance' },
|
||||
{ name: 'Branching', url: '/guides/platform/branching' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Security',
|
||||
url: undefined,
|
||||
items: [
|
||||
{ name: 'Access Control', url: '/guides/platform/access-control' },
|
||||
{ name: 'SSL Enforcement', url: '/guides/platform/ssl-enforcement' },
|
||||
{ name: 'Platform-required Permissions', url: '/guides/platform/permissions' },
|
||||
{ name: 'Default Platform Permissions', url: '/guides/platform/permissions' },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -1899,73 +1924,38 @@ export const platform: NavMenuConstant = {
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export const monitoring_troubleshooting: NavMenuConstant = {
|
||||
icon: 'troubleshooting',
|
||||
title: 'Monitor & Fix',
|
||||
url: '/guides/monitoring-troubleshooting',
|
||||
items: [
|
||||
{ name: 'Overview', url: '/guides/monitoring-troubleshooting' },
|
||||
{
|
||||
name: 'Single sign-on',
|
||||
name: 'Logging & observability',
|
||||
url: undefined,
|
||||
items: [
|
||||
{
|
||||
name: 'Enable SSO for your organization',
|
||||
url: '/guides/platform/sso',
|
||||
},
|
||||
{ name: 'SSO with Azure AD', url: '/guides/platform/sso/azure' },
|
||||
{
|
||||
name: 'SSO with Google Workspace',
|
||||
url: '/guides/platform/sso/gsuite',
|
||||
},
|
||||
{ name: 'SSO with Okta', url: '/guides/platform/sso/okta' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Terraform',
|
||||
url: undefined,
|
||||
items: [
|
||||
{
|
||||
name: 'Terraform Provider',
|
||||
url: '/guides/platform/terraform',
|
||||
name: 'Logging',
|
||||
url: '/guides/monitoring-troubleshooting/logs',
|
||||
},
|
||||
{
|
||||
name: 'Terraform Tutorial',
|
||||
url: '/guides/platform/terraform/tutorial',
|
||||
name: 'Advanced log filtering',
|
||||
url: '/guides/monitoring-troubleshooting/advanced-log-filtering',
|
||||
},
|
||||
{
|
||||
name: 'Reference',
|
||||
url: '/guides/platform/terraform/reference',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Production Readiness',
|
||||
url: undefined,
|
||||
items: [
|
||||
{
|
||||
name: 'Shared Responsibility Model',
|
||||
url: '/guides/platform/shared-responsibility-model',
|
||||
name: 'Log drains',
|
||||
url: '/guides/monitoring-troubleshooting/log-drains',
|
||||
},
|
||||
{
|
||||
name: 'Maturity Model',
|
||||
url: '/guides/platform/maturity-model',
|
||||
name: 'Metrics',
|
||||
url: '/guides/monitoring-troubleshooting/metrics',
|
||||
},
|
||||
{
|
||||
name: 'Production Checklist',
|
||||
url: '/guides/platform/going-into-prod',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Integrations',
|
||||
url: undefined,
|
||||
items: [
|
||||
{
|
||||
name: 'Integrations Marketplace',
|
||||
url: '/guides/platform/marketplace',
|
||||
},
|
||||
{
|
||||
name: 'Build a Supabase Integration',
|
||||
url: '/guides/platform/oauth-apps/build-a-supabase-integration',
|
||||
},
|
||||
{
|
||||
name: 'OAuth Scopes',
|
||||
url: '/guides/platform/oauth-apps/oauth-scopes',
|
||||
name: 'Sentry integration',
|
||||
url: '/guides/monitoring-troubleshooting/sentry-monitoring',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -1974,24 +1964,34 @@ export const platform: NavMenuConstant = {
|
||||
url: undefined,
|
||||
items: [
|
||||
{
|
||||
name: 'HTTP and Project Issues',
|
||||
url: '/guides/platform/troubleshooting',
|
||||
name: 'HTTP and project issues',
|
||||
url: '/guides/monitoring-troubleshooting/troubleshooting',
|
||||
},
|
||||
{
|
||||
name: 'High Disk IO Consumption',
|
||||
url: '/guides/platform/exhaust-disk-io',
|
||||
name: 'High disk IO consumption',
|
||||
url: '/guides/monitoring-troubleshooting/exhaust-disk-io',
|
||||
},
|
||||
{
|
||||
name: 'High CPU Usage',
|
||||
url: '/guides/platform/exhaust-cpu',
|
||||
name: 'High CPU usage',
|
||||
url: '/guides/monitoring-troubleshooting/exhaust-cpu',
|
||||
},
|
||||
{
|
||||
name: 'High RAM Usage',
|
||||
url: '/guides/platform/exhaust-ram',
|
||||
name: 'High RAM usage',
|
||||
url: '/guides/monitoring-troubleshooting/exhaust-ram',
|
||||
},
|
||||
{
|
||||
name: 'High Swap Usage',
|
||||
url: '/guides/platform/exhaust-swap',
|
||||
name: 'High swap usage',
|
||||
url: '/guides/monitoring-troubleshooting/exhaust-swap',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Status codes',
|
||||
url: undefined,
|
||||
items: [
|
||||
{
|
||||
name: 'HTTP status codes',
|
||||
url: '/guides/monitoring-troubleshooting/http-status-codes',
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -2002,60 +2002,7 @@ export const resources: NavMenuConstant = {
|
||||
icon: 'resources',
|
||||
title: 'Resources',
|
||||
url: '/guides/resources',
|
||||
items: [
|
||||
{ name: 'Examples', url: '/guides/resources/examples' },
|
||||
{ name: 'Glossary', url: '/guides/resources/glossary' },
|
||||
{
|
||||
name: 'Migrate to Supabase',
|
||||
url: '/guides/resources/migrating-to-supabase',
|
||||
items: [
|
||||
{
|
||||
name: 'Amazon RDS',
|
||||
url: '/guides/resources/migrating-to-supabase/amazon-rds',
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
name: 'Auth0',
|
||||
url: '/guides/resources/migrating-to-supabase/auth0',
|
||||
},
|
||||
{
|
||||
name: 'Firebase Auth',
|
||||
url: '/guides/resources/migrating-to-supabase/firebase-auth',
|
||||
},
|
||||
{
|
||||
name: 'Firebase Firestore',
|
||||
url: '/guides/resources/migrating-to-supabase/firestore-data',
|
||||
},
|
||||
{
|
||||
name: 'Firebase Storage',
|
||||
url: '/guides/resources/migrating-to-supabase/firebase-storage',
|
||||
},
|
||||
{
|
||||
name: 'Heroku Postgres',
|
||||
url: '/guides/resources/migrating-to-supabase/heroku',
|
||||
},
|
||||
{
|
||||
name: 'MySQL',
|
||||
url: '/guides/resources/migrating-to-supabase/mysql',
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
name: 'MSSQL',
|
||||
url: '/guides/resources/migrating-to-supabase/mssql',
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
name: 'Postgres',
|
||||
url: '/guides/resources/migrating-to-supabase/postgres',
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
name: 'Render',
|
||||
url: '/guides/resources/migrating-to-supabase/render',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
items: [{ name: 'Glossary', url: '/guides/resources/glossary' }],
|
||||
}
|
||||
|
||||
export const self_hosting: NavMenuConstant = {
|
||||
@@ -2120,16 +2067,86 @@ export const self_hosting: NavMenuConstant = {
|
||||
],
|
||||
}
|
||||
|
||||
export const migrate = {
|
||||
title: 'Migrate to Supabase',
|
||||
url: '/guides/migrate',
|
||||
export const deployment: NavMenuConstant = {
|
||||
title: 'Deployment',
|
||||
url: '/guides/deployment',
|
||||
icon: 'deployment',
|
||||
items: [
|
||||
{ name: 'Firebase Auth', url: '/guides/migrations/firebase-auth' },
|
||||
{ name: 'Firestore Data', url: '/guides/migrations/firestore-data' },
|
||||
{ name: 'Firebase Storage', url: '/guides/migrations/firebase-storage' },
|
||||
{ name: 'Heroku', url: '/guides/migrations/heroku' },
|
||||
{ name: 'Render', url: '/guides/migrations/render' },
|
||||
{ name: 'Amazon RDS', url: '/guides/migrations/amazon-rds' },
|
||||
{ name: 'Overview', url: '/guides/deployment' },
|
||||
{
|
||||
name: 'Environments',
|
||||
items: [
|
||||
{ name: 'Managing environments', url: '/guides/deployment/managing-environments' },
|
||||
{ name: 'Branching', url: '/guides/deployment/branching' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Terraform',
|
||||
items: [
|
||||
{ name: 'Terraform provider', url: '/guides/deployment/terraform' },
|
||||
{ name: 'Terraform tutorial', url: '/guides/deployment/terraform/tutorial' },
|
||||
{ name: 'Terraform reference', url: '/guides/deployment/terraform/reference' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Production readiness',
|
||||
items: [
|
||||
{
|
||||
name: 'Shared responsibility model',
|
||||
url: '/guides/deployment/shared-responsibility-model',
|
||||
},
|
||||
{ name: 'Maturity model', url: '/guides/deployment/maturity-model' },
|
||||
{ name: 'Production checklist', url: '/guides/deployment/going-into-prod' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'CI/CD',
|
||||
items: [
|
||||
{
|
||||
name: 'Generate types from your database',
|
||||
url: '/guides/deployment/ci/generating-types',
|
||||
},
|
||||
{ name: 'Automated testing', url: '/guides/deployment/ci/testing' },
|
||||
{ name: 'Back up your database', url: '/guides/deployment/ci/backups' },
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export const integrations: NavMenuConstant = {
|
||||
title: 'Integrations',
|
||||
icon: 'integrations',
|
||||
url: '/guides/integrations',
|
||||
items: [
|
||||
{
|
||||
name: 'Overview',
|
||||
url: '/guides/integrations',
|
||||
},
|
||||
{
|
||||
name: 'Vercel Marketplace',
|
||||
url: '/guides/integrations/vercel-marketplace',
|
||||
},
|
||||
{
|
||||
name: 'Supabase Marketplace',
|
||||
url: '/guides/integrations/supabase-marketplace',
|
||||
},
|
||||
{
|
||||
name: 'Build Your Own',
|
||||
url: undefined,
|
||||
items: [
|
||||
{
|
||||
name: 'Build a Supabase integration',
|
||||
url: '/guides/integrations/build-a-supabase-integration',
|
||||
items: [
|
||||
{
|
||||
name: 'OAuth scopes',
|
||||
url: '/guides/integrations/build-a-supabase-integration/oauth-scopes',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{ name: 'Integrations', url: undefined, items: [] },
|
||||
],
|
||||
}
|
||||
|
||||
@@ -2472,6 +2489,7 @@ export const references = [
|
||||
]
|
||||
|
||||
export const navDataForMdx = {
|
||||
migrationPages: MIGRATION_PAGES,
|
||||
nativeMobileLoginItems: NativeMobileLoginItems,
|
||||
phoneLoginsItems: PhoneLoginsItems,
|
||||
socialLoginItems: SocialLoginItems,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { memo } from 'react'
|
||||
|
||||
import type { NavMenuSection } from '../Navigation.types'
|
||||
import NavigationMenuGuideList from './NavigationMenuGuideList'
|
||||
import NavigationMenuRefList from './NavigationMenuRefList'
|
||||
import { useCloseMenuOnRouteChange } from './NavigationMenu.utils'
|
||||
@@ -15,10 +16,12 @@ enum MenuId {
|
||||
Storage = 'storage',
|
||||
Ai = 'ai',
|
||||
Platform = 'platform',
|
||||
Deployment = 'deployment',
|
||||
MonitoringTroubleshooting = 'monitoring_troubleshooting',
|
||||
Resources = 'resources',
|
||||
SelfHosting = 'self_hosting',
|
||||
Integrations = 'integrations',
|
||||
Cli = 'supabase_cli',
|
||||
LocalDevelopment = 'local_development',
|
||||
RefJavaScriptV1 = 'reference_javascript_v1',
|
||||
RefJavaScriptV2 = 'reference_javascript_v2',
|
||||
RefDartV1 = 'reference_dart_v1',
|
||||
@@ -82,6 +85,10 @@ const menus: Menu[] = [
|
||||
id: MenuId.Functions,
|
||||
type: 'guide',
|
||||
},
|
||||
{
|
||||
id: MenuId.MonitoringTroubleshooting,
|
||||
type: 'guide',
|
||||
},
|
||||
{
|
||||
id: MenuId.Realtime,
|
||||
type: 'guide',
|
||||
@@ -111,7 +118,11 @@ const menus: Menu[] = [
|
||||
type: 'guide',
|
||||
},
|
||||
{
|
||||
id: MenuId.Cli,
|
||||
id: MenuId.LocalDevelopment,
|
||||
type: 'guide',
|
||||
},
|
||||
{
|
||||
id: MenuId.Deployment,
|
||||
type: 'guide',
|
||||
},
|
||||
{
|
||||
@@ -222,11 +233,11 @@ function getMenuById(id: MenuId) {
|
||||
return menus.find((menu) => menu.id === id)
|
||||
}
|
||||
|
||||
function getMenuElement(menu: Menu | undefined) {
|
||||
function getMenuElement(menu: Menu | undefined, props?: any) {
|
||||
const menuType = menu?.type
|
||||
switch (menuType) {
|
||||
case 'guide':
|
||||
return <NavigationMenuGuideList id={menu.id} />
|
||||
return <NavigationMenuGuideList id={menu.id} {...props} />
|
||||
case 'reference':
|
||||
return (
|
||||
<NavigationMenuRefList
|
||||
@@ -240,13 +251,19 @@ function getMenuElement(menu: Menu | undefined) {
|
||||
}
|
||||
}
|
||||
|
||||
const NavigationMenu = ({ menuId }: { menuId: MenuId }) => {
|
||||
const NavigationMenu = ({
|
||||
menuId,
|
||||
additionalNavItems,
|
||||
}: {
|
||||
menuId: MenuId
|
||||
additionalNavItems?: Partial<NavMenuSection>[]
|
||||
}) => {
|
||||
const level = menuId
|
||||
const menu = getMenuById(level)
|
||||
|
||||
useCloseMenuOnRouteChange()
|
||||
|
||||
return getMenuElement(menu)
|
||||
return getMenuElement(menu, { additionalNavItems })
|
||||
}
|
||||
|
||||
export { MenuId, getMenuById }
|
||||
|
||||
@@ -109,16 +109,22 @@ export const getMenuId = (pathname: string | null) => {
|
||||
return MenuId.Api
|
||||
case pathname.startsWith('auth'):
|
||||
return MenuId.Auth
|
||||
case pathname.startsWith('cli'):
|
||||
return MenuId.Cli
|
||||
case pathname.startsWith('local-development'):
|
||||
return MenuId.LocalDevelopment
|
||||
case pathname.startsWith('database'):
|
||||
return MenuId.Database
|
||||
case pathname.startsWith('deployment'):
|
||||
return MenuId.Deployment
|
||||
case pathname.startsWith('functions'):
|
||||
return MenuId.Functions
|
||||
case pathname.startsWith('getting-started'):
|
||||
return MenuId.GettingStarted
|
||||
case pathname.startsWith('graphql'):
|
||||
return MenuId.Graphql
|
||||
case pathname.startsWith('integrations'):
|
||||
return MenuId.Integrations
|
||||
case pathname.startsWith('monitoring-troubleshooting'):
|
||||
return MenuId.MonitoringTroubleshooting
|
||||
case pathname.startsWith('platform'):
|
||||
return MenuId.Platform
|
||||
case pathname.startsWith('realtime'):
|
||||
|
||||
@@ -2,15 +2,39 @@
|
||||
|
||||
import * as Accordion from '@radix-ui/react-accordion'
|
||||
|
||||
import { type NavMenuSection } from '../Navigation.types'
|
||||
import * as NavItems from './NavigationMenu.constants'
|
||||
import NavigationMenuGuideListItems from './NavigationMenuGuideListItems'
|
||||
import { usePathname } from 'next/navigation'
|
||||
|
||||
const NavigationMenuGuideList = ({ id }: { id: string }) => {
|
||||
const NavigationMenuGuideList = ({
|
||||
id,
|
||||
additionalNavItems,
|
||||
}: {
|
||||
id: string
|
||||
additionalNavItems?: Partial<NavMenuSection>[]
|
||||
}) => {
|
||||
const pathname = usePathname()
|
||||
const firstLevelRoute = pathname?.split('/')?.slice(0, 4)?.join('/')
|
||||
|
||||
const menu = NavItems[id]
|
||||
let menu = NavItems[id]
|
||||
|
||||
if (id === 'integrations' && additionalNavItems) {
|
||||
const integrationsListIndex = menu.items.findIndex((item) => item.name === 'Integrations')
|
||||
if (integrationsListIndex !== -1) {
|
||||
menu = {
|
||||
...menu,
|
||||
items: [
|
||||
...menu.items.slice(0, integrationsListIndex),
|
||||
{
|
||||
...menu.items[integrationsListIndex],
|
||||
items: [...menu.items[integrationsListIndex].items, ...additionalNavItems],
|
||||
},
|
||||
...menu.items.slice(integrationsListIndex + 1),
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Accordion.Root
|
||||
|
||||
@@ -34,8 +34,15 @@ const ContentAccordionLink = React.memo(function ContentAccordionLink(props: any
|
||||
const activeItemRef = useRef<HTMLLIElement>(null)
|
||||
|
||||
const LinkContainer = (props) => {
|
||||
const isExternal = props.url.startsWith('https://')
|
||||
|
||||
return (
|
||||
<Link href={props.url} className={props.className}>
|
||||
<Link
|
||||
href={props.url}
|
||||
className={props.className}
|
||||
target={isExternal ? '_blank' : undefined}
|
||||
rel={isExternal ? 'noopener noreferrer' : undefined}
|
||||
>
|
||||
{props.children}
|
||||
</Link>
|
||||
)
|
||||
|
||||
29
apps/docs/content/guides/deployment.mdx
Normal file
29
apps/docs/content/guides/deployment.mdx
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
title: Deployment
|
||||
---
|
||||
|
||||
Deploying your app makes it live and accessible to users. Usually, you will deploy an app to at least two environments: a production environment for users and (one or multiple) staging or preview environments for developers.
|
||||
|
||||
Supabase provides several options for environment management and deployment.
|
||||
|
||||
## Environment management
|
||||
|
||||
You can maintain separate development, staging, and production environments for Supabase:
|
||||
|
||||
- **Development**: Develop with a local Supabase stack using the [Supabase CLI](/docs/guides/local-development).
|
||||
- **Staging**: Use [branching](/docs/guides/deployment/branching) to create staging or preview environments. You can use persistent branches for a long-lived staging setup, or ephemeral branches for short-lived previews (which are often tied to a pull request).
|
||||
- **Production**: If you have branching enabled, you can use the Supabase GitHub integration to automatically push your migration files when you merge a pull request. Alternatively, you can set up your own continuous deployment pipeline using the Supabase CLI.
|
||||
|
||||
<Admonition type="tip" title="Self-hosting">
|
||||
|
||||
See the [self-hosting guides](/docs/guides/self-hosting) for instructions on hosting your own Supabase stack.
|
||||
|
||||
</Admonition>
|
||||
|
||||
## Deployment
|
||||
|
||||
You can automate deployments using:
|
||||
|
||||
- The [Supabase GitHub integration](/dashboard/project/_/settings/integrations) (with branching enabled)
|
||||
- The [Supabase CLI](/docs/local-development/cli) in your own continuous deployment pipeline
|
||||
- The [Supabase Terraform provider](/docs/guides/deployment/terraform)
|
||||
13
apps/docs/content/guides/integrations.mdx
Normal file
13
apps/docs/content/guides/integrations.mdx
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
title: Integrations
|
||||
---
|
||||
|
||||
Supabase integrates with many of your favorite third-party services.
|
||||
|
||||
## Vercel Marketplace
|
||||
|
||||
Create and manage your Supabase projects directly through Vercel. [Get started with Vercel](/docs/guides/integrations/vercel-marketplace).
|
||||
|
||||
## Supabase Marketplace
|
||||
|
||||
Browse tools for extending your Supabase project. [Browse the Supabase Marketplace](/partners/integrations).
|
||||
126
apps/docs/content/guides/local-development.mdx
Normal file
126
apps/docs/content/guides/local-development.mdx
Normal file
@@ -0,0 +1,126 @@
|
||||
---
|
||||
title: Local Development & CLI
|
||||
subtitle: Learn how to develop locally and use the Supabase CLI
|
||||
---
|
||||
|
||||
Develop locally while running the Supabase stack on your machine.
|
||||
|
||||
## Quickstart
|
||||
|
||||
1. Install the Supabase CLI:
|
||||
|
||||
<Tabs scrollable size="small" type="underlined" defaultActiveId="npm" queryGroup="package-manager"><TabPanel id="npm" label="npm">
|
||||
|
||||
```sh
|
||||
npm install supabase --save-dev
|
||||
```
|
||||
|
||||
</TabPanel><TabPanel id="yarn" label="yarn">
|
||||
|
||||
```sh
|
||||
yarn add supabase --dev
|
||||
```
|
||||
|
||||
</TabPanel><TabPanel id="pnpm" label="pnpm">
|
||||
|
||||
```sh
|
||||
pnpm add supabase --save-dev
|
||||
```
|
||||
|
||||
</TabPanel><TabPanel id="brew" label="brew">
|
||||
|
||||
```sh
|
||||
brew install supabase/tap/supabase
|
||||
```
|
||||
|
||||
</TabPanel></Tabs>
|
||||
|
||||
2. In your repo, initialize the Supabase project:
|
||||
|
||||
<Tabs scrollable size="small" type="underlined" defaultActiveId="npm" queryGroup="package-manager"><TabPanel id="npm" label="npm">
|
||||
|
||||
```sh
|
||||
npx supabase init
|
||||
```
|
||||
|
||||
</TabPanel><TabPanel id="yarn" label="yarn">
|
||||
|
||||
```sh
|
||||
yarn supabase init
|
||||
```
|
||||
|
||||
</TabPanel><TabPanel id="pnpm" label="pnpm">
|
||||
|
||||
```sh
|
||||
pnpm supabase init
|
||||
```
|
||||
|
||||
</TabPanel><TabPanel id="brew" label="brew">
|
||||
|
||||
```sh
|
||||
supabase init
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
|
||||
</Tabs>
|
||||
|
||||
3. Start the Supabase stack:
|
||||
|
||||
<Tabs scrollable size="small" type="underlined" defaultActiveId="npm" queryGroup="package-manager"><TabPanel id="npm" label="npm">
|
||||
|
||||
```sh
|
||||
npx supabase start
|
||||
```
|
||||
|
||||
</TabPanel><TabPanel id="yarn" label="yarn">
|
||||
|
||||
```sh
|
||||
yarn supabase start
|
||||
```
|
||||
|
||||
</TabPanel><TabPanel id="pnpm" label="pnpm">
|
||||
|
||||
```sh
|
||||
pnpm supabase start
|
||||
```
|
||||
|
||||
</TabPanel><TabPanel id="brew" label="brew">
|
||||
|
||||
```sh
|
||||
supabase start
|
||||
```
|
||||
|
||||
</TabPanel>
|
||||
|
||||
</Tabs>
|
||||
|
||||
4. View your local Supabase instance at [http://localhost:54323](http://localhost:54323).
|
||||
|
||||
## Local Development
|
||||
|
||||
Local development with Supabase allows you to work on your projects in a self-contained environment on your local machine. Working locally has several advantages:
|
||||
|
||||
1. Faster development: You can make changes and see results instantly without waiting for remote deployments.
|
||||
2. Offline work: You can continue development even without an internet connection.
|
||||
3. Cost-effective: Local development is free and doesn't consume your project's quota.
|
||||
4. Enhanced privacy: Sensitive data remains on your local machine during development.
|
||||
5. Easy testing: You can experiment with different configurations and features without affecting your production environment.
|
||||
|
||||
To get started with local development, you'll need to install the [Supabase CLI](#cli) and Docker. The Supabase CLI allows you to start and manage your local Supabase stack, while Docker is used to run the necessary services.
|
||||
|
||||
Once set up, you can initialize a new Supabase project, start the local stack, and begin developing your application using local Supabase services. This includes access to a local PostgreSQL database, Auth, Storage, and other Supabase features.
|
||||
|
||||
## CLI
|
||||
|
||||
The Supabase CLI is a powerful tool that enables developers to manage their Supabase projects directly from the terminal. It provides a suite of commands for various tasks, including:
|
||||
|
||||
- Setting up and managing local development environments
|
||||
- Generating TypeScript types for your database schema
|
||||
- Handling database migrations
|
||||
- Managing environment variables and secrets
|
||||
- Deploying your project to the Supabase platform
|
||||
|
||||
With the CLI, you can streamline your development workflow, automate repetitive tasks, and maintain consistency across different environments. It's an essential tool for both local development and CI/CD pipelines.
|
||||
|
||||
See the [CLI Getting Started guide](/docs/guides/local-development/cli/getting-started) for more information.
|
||||
@@ -1,12 +1,13 @@
|
||||
---
|
||||
title: 'Supabase CLI'
|
||||
description: 'The Supabase CLI provides tools to develop your project locally and deploy to the Supabase Platform.'
|
||||
subtitle: 'The Supabase CLI provides tools to develop your project locally and deploy to the Supabase Platform.'
|
||||
description: 'The Supabase CLI provides tools to develop your project locally, deploy to the Supabase Platform, and set up CI/CD workflows.'
|
||||
subtitle: 'Develop locally, deploy to the Supabase Platform, and set up CI/CD workflows'
|
||||
---
|
||||
|
||||
You can use the Supabase CLI to run the entire Supabase stack locally on your machine, simply by running `supabase init` (to create a new local project) and then `supabase start`.
|
||||
The Supabase CLI enables you to run the entire Supabase stack locally, on your machine or in a CI environment. With just two commands, you can set up and start a new local project:
|
||||
|
||||
The Supabase CLI provides tools to develop your project locally, deploy to the Supabase Platform, handle database migrations, and generate types directly from your database schema.
|
||||
1. `supabase init` to create a new local project
|
||||
2. `supabase start` to launch the Supabase services
|
||||
|
||||
## Installing the Supabase CLI
|
||||
|
||||
@@ -125,27 +126,21 @@ npm update supabase --save-dev
|
||||
|
||||
If you have any Supabase containers running locally, stop them and delete their data volumes before proceeding with the upgrade. This ensures that Supabase managed services can apply new migrations on a clean state of the local database.
|
||||
|
||||
<Admonition type="tip" label="Logical backup">
|
||||
<Admonition type="tip" label="Backup and stop running containers">
|
||||
|
||||
Remember to save any local schema and data changes before stopping because the `--no-backup` flag will delete them.
|
||||
|
||||
```sh
|
||||
supabase db diff my_schema
|
||||
supabase db dump --local --data-only > supabase/seed.sql
|
||||
supabase stop --no-backup
|
||||
```
|
||||
|
||||
</Admonition>
|
||||
|
||||
```sh
|
||||
supabase stop --no-backup
|
||||
supabase start
|
||||
```
|
||||
|
||||
## Running Supabase locally
|
||||
|
||||
The Supabase CLI uses Docker containers to manage the local development stack. To get started,
|
||||
|
||||
- Install [Docker Desktop](https://docs.docker.com/desktop) and apply the following configurations
|
||||
The Supabase CLI uses Docker containers to manage the local development stack. Follow the official guide to install and configure [Docker Desktop](https://docs.docker.com/desktop):
|
||||
|
||||
<Tabs
|
||||
scrollable
|
||||
@@ -180,6 +175,17 @@ The Supabase CLI uses Docker containers to manage the local development stack. T
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
<Admonition type="note">
|
||||
|
||||
Alternately, you can use a different container tool that offers Docker compatible APIs.
|
||||
|
||||
- [Rancher Desktop](https://rancherdesktop.io/) (macOS, Windows, Linux)
|
||||
- [Podman](https://podman.io/) (macOS, Windows, Linux)
|
||||
- [OrbStack](https://orbstack.dev/) (macOS)
|
||||
- [colima](https://github.com/abiosoft/colima) (macOS)
|
||||
|
||||
</Admonition>
|
||||
|
||||
Inside the folder where you want to create your project, run:
|
||||
|
||||
```bash
|
||||
@@ -196,27 +202,113 @@ supabase start
|
||||
|
||||
This takes time on your first run because the CLI needs to download the Docker images to your local machine. The CLI includes the entire Supabase toolset, and a few additional images that are useful for local development (like a local SMTP server and a database diff tool).
|
||||
|
||||
The local development environment includes Supabase Studio, a graphical interface for working with your database, running by default on [localhost:54323](http://localhost:54323).
|
||||
## Access your project's services
|
||||
|
||||
Once all of the Supabase services are running, you'll see output containing your local Supabase credentials. It should look like this, with urls and keys that you'll use in your local project:
|
||||
|
||||
```
|
||||
|
||||
Started supabase local development setup.
|
||||
|
||||
API URL: http://localhost:54321
|
||||
DB URL: postgresql://postgres:postgres@localhost:54322/postgres
|
||||
Studio URL: http://localhost:54323
|
||||
Inbucket URL: http://localhost:54324
|
||||
anon key: eyJh......
|
||||
service_role key: eyJh......
|
||||
|
||||
```
|
||||
|
||||
<Tabs
|
||||
scrollable
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="studio"
|
||||
queryGroup="access-method"
|
||||
>
|
||||
<TabPanel id="studio" label="Studio">
|
||||
|
||||
```sh
|
||||
# Default URL:
|
||||
http://localhost:54323
|
||||
```
|
||||
|
||||
The local development environment includes Supabase Studio, a graphical interface for working with your database.
|
||||
|
||||

|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="postgres" label="Postgres">
|
||||
|
||||
```sh
|
||||
# Default URL:
|
||||
postgresql://postgres:postgres@localhost:54322/postgres
|
||||
```
|
||||
|
||||
The local Postgres instance can be accessed through [`psql`](https://www.postgresql.org/docs/current/app-psql.html) or any other Postgres client, such as [pgadmin](https://www.pgadmin.org/). For example:
|
||||
|
||||
```bash
|
||||
psql 'postgresql://postgres:postgres@localhost:54322/postgres'
|
||||
```
|
||||
|
||||
<Admonition type="note">
|
||||
|
||||
To access the database from an edge function in your local Supabase setup, replace `localhost` with `host.docker.internal`.
|
||||
|
||||
</Admonition>
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="kong" label="API Gateway">
|
||||
|
||||
```sh
|
||||
# Default URL:
|
||||
http://localhost:54321
|
||||
```
|
||||
|
||||
If you are accessing these services without the client libraries, you may need to pass the client keys as an `Authorization` header. Learn more about [JWT headers](/docs/learn/auth-deep-dive/auth-deep-dive-jwts).
|
||||
|
||||
```sh
|
||||
curl 'http://localhost:54321/rest/v1/' \
|
||||
-H "apikey: <anon key>" \
|
||||
-H "Authorization: Bearer <anon key>"
|
||||
|
||||
http://localhost:54321/rest/v1/ # REST (PostgREST)
|
||||
http://localhost:54321/realtime/v1/ # Realtime
|
||||
http://localhost:54321/storage/v1/ # Storage
|
||||
http://localhost:54321/auth/v1/ # Auth (GoTrue)
|
||||
```
|
||||
|
||||
<Admonition type="note">
|
||||
|
||||
`<anon key>` is provided when you run the command `supabase start`.
|
||||
|
||||
</Admonition>
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="analytics" label="Analytics">
|
||||
|
||||
Local logs rely on the Supabase Analytics Server which accesses the docker logging driver by either volume mounting `/var/run/docker.sock` domain socket on Linux and macOS, or exposing `tcp://localhost:2375` daemon socket on Windows. These settings must be configured manually after [installing](/docs/guides/cli/getting-started#installing-the-supabase-cli) the Supabase CLI.
|
||||
|
||||
<Admonition type="note">
|
||||
|
||||
For advanced logs analysis using the Logs Explorer, it is advised to use the BigQuery backend instead of the default Postgres backend. Read about the steps [here](/docs/reference/self-hosting-analytics/introduction#bigquery).
|
||||
|
||||
</Admonition>
|
||||
|
||||
All logs will be stored in the local database under the `_analytics` schema.
|
||||
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
|
||||
## Stopping local services
|
||||
|
||||
When you are finished working on your Supabase project, you can stop the stack with:
|
||||
When you are finished working on your Supabase project, you can stop the stack (without resetting your local database):
|
||||
|
||||
```bash
|
||||
supabase stop
|
||||
```
|
||||
|
||||
## Full command reference
|
||||
## Learn more
|
||||
|
||||
The CLI provides a number of commands to help you develop your project locally and deploy to the Supabase Platform. You can find all commands inside the [CLI Reference](/docs/reference/cli/introduction) docs, including:
|
||||
|
||||
- [Project](/docs/reference/cli/supabase-projects) and [Organization](/docs/reference/cli/supabase-orgs) management
|
||||
- [Database management](/docs/reference/cli/supabase-db)
|
||||
- [Database migrations](/docs/reference/cli/supabase-migration) and [Database Branching](/docs/reference/cli/supabase-branches)
|
||||
- [Database debugging tools](/docs/reference/cli/supabase-inspect-db-calls)
|
||||
- [Edge Function management](/docs/reference/cli/supabase-functions)
|
||||
- [Auth management](/docs/reference/cli/supabase-sso)
|
||||
- [Types Generators](/docs/reference/cli/supabase-gen)
|
||||
- [Testing](/docs/reference/cli/supabase-test)
|
||||
- [CLI configuration](/docs/guides/local-development/cli/config)
|
||||
- [CLI reference](/docs/reference/cli)
|
||||
@@ -1,169 +1,17 @@
|
||||
---
|
||||
id: 'local-development'
|
||||
title: 'Local Development'
|
||||
description: 'How to use Supabase on your local development machine.'
|
||||
subtitle: 'How to use Supabase on your local development machine.'
|
||||
id: 'overview'
|
||||
title: 'Local development with schema migrations'
|
||||
description: 'Develop locally with the Supabase CLI and schema migrations.'
|
||||
subtitle: 'Develop locally with the Supabase CLI and schema migrations.'
|
||||
video: 'https://www.youtube-nocookie.com/v/vyHyYpvjaks'
|
||||
tocVideo: 'vyHyYpvjaks'
|
||||
---
|
||||
|
||||
Supabase is a flexible platform that lets you decide how you want to build your projects. You can use the Dashboard directly to get up and running quickly, or use a proper local setup. We suggest you work locally and deploy your changes to a linked project on the [Supabase Platform](https://app.supabase.io/).
|
||||
|
||||
Doing things directly on the platform via the [Dashboard](https://app.supabase.io/) is fine when you're getting started, but it's a good idea to move to a proper local workflow before you get too far. Working locally, generating migrations as you change your tables, and applying those migrations to a linked project on the [Platform](https://app.supabase.io/) keeps everything nicely organized as you grow.
|
||||
Develop locally using the CLI to run a local Supabase stack. You can use the integrated Studio Dashboard to make changes, then capture your changes in schema migration files, which can be saved in version control.
|
||||
|
||||
## Why develop locally?
|
||||
|
||||
The Dashboard provides a wide range of features for setting up your project: creating tables, adding columns, changing existing columns, creating views, setting up RLS policies, and more. Given all of the Dashboard's capabilities, you might question the need to work locally. Here's a few advantages to working this way:
|
||||
|
||||
1. **Faster Development**: Developing locally allows you to work without any network latency or internet disruptions.
|
||||
|
||||
2. **Easier Collaboration**: Developing locally can make it easier to collaborate with others on the same project.
|
||||
|
||||
3. **Cost-Effective**: Supabase provides a generous Free Plan and gives you two free projects to get started. But what if you need more than two? When you develop locally, you can spin up unlimited local projects and link them with live projects when you're ready to launch.
|
||||
|
||||
4. **Configuration in code**: If you directly change your tables via the Dashboard, none of that gets captured in code. If you follow these local development practices, you'll store all of your table schemas in code.
|
||||
|
||||
5. **Work offline**: Need to work from a train? A plane? An automobile? No problem. Developing your project locally allows you to work offline.
|
||||
|
||||
## Log in to the Supabase CLI
|
||||
|
||||
Log in if you are planning to deploy your project to the Supabase Platform. This step is optional and is not required to use the Supabase CLI.
|
||||
|
||||
<CH.Code>
|
||||
|
||||
```bash Terminal
|
||||
supabase login
|
||||
```
|
||||
|
||||
```bash NPX
|
||||
npx supabase login
|
||||
```
|
||||
|
||||
</CH.Code>
|
||||
|
||||
## Initialize your project
|
||||
|
||||
Create a new folder for your project and start a new git repository:
|
||||
|
||||
```bash
|
||||
# create your project folder
|
||||
mkdir your-project
|
||||
|
||||
# move into the new folder
|
||||
cd your-project
|
||||
|
||||
# start a new git repository — important, don't skip this step
|
||||
git init
|
||||
```
|
||||
|
||||
## Start Supabase services
|
||||
|
||||
[Initialize](/docs/reference/cli/usage#supabase-init) Supabase to set up the configuration for developing your project locally:
|
||||
|
||||
```bash
|
||||
supabase init
|
||||
```
|
||||
|
||||
Make sure Docker is running.
|
||||
|
||||
<Admonition type="note">
|
||||
|
||||
There are a number of different projects available to download Docker from:
|
||||
|
||||
- [Docker Desktop](https://docs.docker.com/get-docker/) (macOS, Windows, Linux)
|
||||
- [Rancher Desktop](https://rancherdesktop.io/) (macOS, Windows, Linux)
|
||||
- [OrbStack](https://orbstack.dev/) (macOS)
|
||||
- [colima](https://github.com/abiosoft/colima) (macOS)
|
||||
|
||||
</Admonition>
|
||||
|
||||
The [start](/docs/reference/cli/usage#supabase-start) command uses Docker to start the Supabase [services](/docs/guides/getting-started/architecture).
|
||||
This command may take a while to run if this is the first time using the CLI.
|
||||
|
||||
```bash
|
||||
supabase start
|
||||
```
|
||||
|
||||
Once all of the Supabase services are running, you'll see output containing your local Supabase credentials. It should look like this, with urls and keys that you'll use in your local project:
|
||||
|
||||
```
|
||||
|
||||
Started supabase local development setup.
|
||||
|
||||
API URL: http://localhost:54321
|
||||
DB URL: postgresql://postgres:postgres@localhost:54322/postgres
|
||||
Studio URL: http://localhost:54323
|
||||
Inbucket URL: http://localhost:54324
|
||||
anon key: eyJh......
|
||||
service_role key: eyJh......
|
||||
|
||||
```
|
||||
|
||||
You can use the [`supabase stop`](/docs/reference/cli/usage#supabase-stop) command at any time to stop all services (without resetting your local database). Use `supabase stop --no-backup` to stop all services and reset your local database.
|
||||
|
||||
## Access your project's services
|
||||
|
||||
You can now visit your local Dashboard at [http://localhost:54323](http://localhost:54323), and access the database directly with any Postgres client via `postgresql://postgres:postgres@localhost:54322/postgres`.
|
||||
|
||||
<Tabs
|
||||
scrollable
|
||||
size="small"
|
||||
type="underlined"
|
||||
defaultActiveId="postgres"
|
||||
queryGroup="access-method"
|
||||
>
|
||||
<TabPanel id="postgres" label="Postgres">
|
||||
|
||||
```sh
|
||||
# Default URL:
|
||||
postgresql://postgres:postgres@localhost:54322/postgres
|
||||
```
|
||||
|
||||
The local Postgres instance can be accessed through [`psql`](https://www.postgresql.org/docs/current/app-psql.html)
|
||||
or any other Postgres client, such as [pgadmin](https://www.pgadmin.org/).
|
||||
|
||||
For example:
|
||||
|
||||
```bash
|
||||
psql 'postgresql://postgres:postgres@localhost:54322/postgres'
|
||||
```
|
||||
|
||||
<Admonition type="note">
|
||||
|
||||
To access the database from an edge function in your local Supabase setup, replace `localhost` with `host.docker.internal`.
|
||||
|
||||
</Admonition>
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel id="kong" label="API Gateway">
|
||||
|
||||
```sh
|
||||
# Default URL:
|
||||
http://localhost:54321
|
||||
```
|
||||
|
||||
If you are accessing these services without the client libraries, you may need to pass the client keys as an `Authorization` header.
|
||||
Learn more about [JWT headers](/docs/learn/auth-deep-dive/auth-deep-dive-jwts).
|
||||
|
||||
```sh
|
||||
curl 'http://localhost:54321/rest/v1/' \
|
||||
-H "apikey: <anon key>" \
|
||||
-H "Authorization: Bearer <anon key>"
|
||||
|
||||
http://localhost:54321/rest/v1/ # REST (PostgREST)
|
||||
http://localhost:54321/realtime/v1/ # Realtime
|
||||
http://localhost:54321/storage/v1/ # Storage
|
||||
http://localhost:54321/auth/v1/ # Auth (GoTrue)
|
||||
```
|
||||
|
||||
<Admonition type="note">
|
||||
|
||||
`<anon key>` is provided when you run the command `supabase start`.
|
||||
|
||||
</Admonition>
|
||||
|
||||
</TabPanel>
|
||||
</Tabs>
|
||||
Alternatively, if you're comfortable with migration files and SQL, you can write your own migrations and push them to the local database for testing before sharing your changes.
|
||||
|
||||
## Database migrations
|
||||
|
||||
@@ -372,6 +220,20 @@ The last step is deploying these changes to a live Supabase project.
|
||||
|
||||
You've been developing your project locally, making changes to your tables via migrations. It's time to deploy your project to the Supabase Platform and start scaling up to millions of users! Head over to [Supabase](https://supabase.com/dashboard) and create a new project to deploy to.
|
||||
|
||||
### Log in to the Supabase CLI
|
||||
|
||||
<CH.Code>
|
||||
|
||||
```bash Terminal
|
||||
supabase login
|
||||
```
|
||||
|
||||
```bash npx
|
||||
npx supabase login
|
||||
```
|
||||
|
||||
</CH.Code>
|
||||
|
||||
### Link your project
|
||||
|
||||
Associate your project with your remote project using [`supabase link`](/docs/reference/cli/usage#supabase-link).
|
||||
@@ -457,19 +319,21 @@ Your RLS policies on storage buckets can be pulled locally by specifying `storag
|
||||
supabase db pull --schema storage
|
||||
```
|
||||
|
||||
The buckets and objects themselves are rows in the storage schema so they won't be pulled automatically.
|
||||
The buckets and objects themselves are rows in the storage tables so they won't appear in your schema. You can instead define them via `supabase/config.toml` file. For example,
|
||||
|
||||
### Local logging
|
||||
```bash supabase/config.toml
|
||||
[storage.buckets.images]
|
||||
public = false
|
||||
file_size_limit = "50MiB"
|
||||
allowed_mime_types = ["image/png", "image/jpeg"]
|
||||
objects_path = "./images"
|
||||
```
|
||||
|
||||
Local logs rely on the Supabase Analytics Server which accesses the docker logging driver by either volume mounting `/var/run/docker.sock` domain socket on Linux and macOS, or exposing `tcp://localhost:2375` daemon socket on Windows. These settings must be configured manually after [installing](/docs/guides/cli/getting-started#installing-the-supabase-cli) the Supabase CLI.
|
||||
This will upload files from `supabase/images` directory to a bucket named `images` in your project with one command.
|
||||
|
||||
<Admonition type="note">
|
||||
|
||||
For advanced logs analysis using the Logs Explorer, it is advised to use the BigQuery backend instead of the default Postgres backend. Read about the steps [here](/docs/reference/self-hosting-analytics/introduction#bigquery).
|
||||
|
||||
</Admonition>
|
||||
|
||||
All logs will be stored in the local database under the `_analytics` schema.
|
||||
```bash
|
||||
supabase seed buckets
|
||||
```
|
||||
|
||||
## Limitations and considerations
|
||||
|
||||
9
apps/docs/content/guides/monitoring-troubleshooting.mdx
Normal file
9
apps/docs/content/guides/monitoring-troubleshooting.mdx
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
title: Monitoring & Troubleshooting
|
||||
---
|
||||
|
||||
Monitoring your project can help you identify issues and fix them quickly. This section provides guidance on:
|
||||
|
||||
- Monitoring errors
|
||||
- Working with logs in Supabase
|
||||
- Troubleshooting common issues with the platform
|
||||
19
apps/docs/content/guides/platform/migrating-to-supabase.mdx
Normal file
19
apps/docs/content/guides/platform/migrating-to-supabase.mdx
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
title: Migrating to Supabase
|
||||
---
|
||||
|
||||
Learn how to migrate to Supabase from another database service.
|
||||
|
||||
## Migration guides
|
||||
|
||||
<NavData data="migrationPages">
|
||||
{(migrationPages) => (
|
||||
<div className="grid grid-cols-[repeat(auto-fit,minmax(200px,1fr))] gap-6 mb-6 not-prose">
|
||||
{migrationPages.map((page) => (
|
||||
<Link href={`${page.url}`} key={page.url} passHref>
|
||||
<GlassPanel title={page.name} background={false} className="[&>div]:p-4" />
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</NavData>
|
||||
157
apps/docs/content/guides/platform/migrating-within-supabase.mdx
Normal file
157
apps/docs/content/guides/platform/migrating-within-supabase.mdx
Normal file
@@ -0,0 +1,157 @@
|
||||
---
|
||||
title: Migrating within Supabase
|
||||
subtitle: Migrate from one Supabase project to another
|
||||
---
|
||||
|
||||
Migrating projects can be achieved using the Supabase CLI. This is particularly useful for older projects (for example to use a newer Postgres version).
|
||||
|
||||
### Before you begin
|
||||
|
||||
- Install [Postgres](https://www.postgresql.org/download/) so you can run `psql` and `pg_dump`.
|
||||
- Install the latest version of [Supabase CLI](/docs/guides/cli#installation).
|
||||
- Create a new [Supabase project](https://supabase.com/dashboard).
|
||||
- Install [Docker Desktop](https://www.docker.com) for your platform.
|
||||
- Set environment variables for the old project's database URL as `$OLD_DB_URL` and the new project's as `$NEW_DB_URL`.
|
||||
To find the database URL for a project, go to the project's dashboard page [Project Settings/Database](https://supabase.com/dashboard/project/_/settings/database) and look under `Connection string`. If your network provider supports IPv6, you can disable `Use connection pooling`. Otherwise, enable `Use connection pooling`. For the pooler mode, `Transaction` will work.
|
||||
|
||||
### Backup your old database
|
||||
|
||||
1. Run the following command from your terminal:
|
||||
|
||||
```bash
|
||||
supabase db dump --db-url "$OLD_DB_URL" -f roles.sql --role-only
|
||||
supabase db dump --db-url "$OLD_DB_URL" -f schema.sql
|
||||
supabase db dump --db-url "$OLD_DB_URL" -f data.sql --use-copy --data-only
|
||||
```
|
||||
|
||||
### Restore to your new project
|
||||
|
||||
In your new project:
|
||||
|
||||
1. Enable [Database Webhooks](https://supabase.com/dashboard/project/_/database/hooks) if you enabled them in your old project.
|
||||
2. Enable any [extensions](https://supabase.com/dashboard/project/_/database/extensions) that were enabled in your old project.
|
||||
|
||||
If you use [column encryption](/docs/guides/database/column-encryption), first copy the root encryption key to your new project using your [Personal Access Token](https://supabase.com/dashboard/account/tokens).
|
||||
|
||||
```bash
|
||||
export OLD_PROJECT_REF="<old_project_ref>"
|
||||
export NEW_PROJECT_REF="<new_project_ref>"
|
||||
export SUPABASE_ACCESS_TOKEN="<personal_access_token>"
|
||||
|
||||
curl "https://api.supabase.com/v1/projects/$OLD_PROJECT_REF/pgsodium" \
|
||||
-H "Authorization: Bearer $SUPABASE_ACCESS_TOKEN" |
|
||||
curl "https://api.supabase.com/v1/projects/$NEW_PROJECT_REF/pgsodium" \
|
||||
-H "Authorization: Bearer $SUPABASE_ACCESS_TOKEN" \
|
||||
-X PUT --json @-
|
||||
```
|
||||
|
||||
Then run the following command from your terminal:
|
||||
|
||||
```bash
|
||||
psql \
|
||||
--single-transaction \
|
||||
--variable ON_ERROR_STOP=1 \
|
||||
--file roles.sql \
|
||||
--file schema.sql \
|
||||
--command 'SET session_replication_role = replica' \
|
||||
--file data.sql \
|
||||
--dbname "$NEW_DB_URL"
|
||||
```
|
||||
|
||||
Setting the `session_replication_role` to `replica` disables all triggers so that columns are not double encrypted.
|
||||
|
||||
Troubleshooting notes:
|
||||
|
||||
- If you have created any [custom roles](https://supabase.com/dashboard/project/_/database/roles) with `login` attribute, you have to manually set their passwords in the new project.
|
||||
- If you run into any permission errors related to `supabase_admin` during restore, edit the `schema.sql` file and comment out any lines containing `ALTER ... OWNER TO "supabase_admin"`.
|
||||
|
||||
### Preserving migration history
|
||||
|
||||
If you were using Supabase CLI for managing migrations on your old database and would like to preserve the migration history in your newly restored project, you need to insert the migration records separately using the following commands.
|
||||
|
||||
```bash
|
||||
supabase db dump --db-url "$OLD_DB_URL" -f history_schema.sql --schema supabase_migrations
|
||||
supabase db dump --db-url "$OLD_DB_URL" -f history_data.sql --use-copy --data-only --schema supabase_migrations
|
||||
psql \
|
||||
--single-transaction \
|
||||
--variable ON_ERROR_STOP=1 \
|
||||
--file history_schema.sql \
|
||||
--file history_data.sql \
|
||||
--dbname "$NEW_DB_URL"
|
||||
```
|
||||
|
||||
### Schema changes to `auth` and `storage`
|
||||
|
||||
If you have modified the `auth` and `storage` schemas in your old project, such as adding triggers or RLS policies, you have to restore them separately. The Supabase CLI can help you diff the changes to these schemas using the following commands.
|
||||
|
||||
```bash
|
||||
supabase link --project-ref "$OLD_PROJECT_REF"
|
||||
supabase db diff --linked --schema auth,storage > changes.sql
|
||||
```
|
||||
|
||||
### Enable publication on tables
|
||||
|
||||
Replication for Realtime is disabled for all tables in your new project. On the [Publications](https://supabase.com/dashboard/project/_/database/publications) page in the Dashboard, select your new project and enable replication for tables that were enabled in your old project.
|
||||
|
||||
### Migrate storage objects
|
||||
|
||||
The new project has the old project's Storage buckets, but the Storage objects need to be migrated manually. Use this script to move storage objects from one project to another.
|
||||
|
||||
```js
|
||||
// npm install @supabase/supabase-js@1
|
||||
const { createClient } = require('@supabase/supabase-js')
|
||||
|
||||
const OLD_PROJECT_URL = 'https://xxx.supabase.co'
|
||||
const OLD_PROJECT_SERVICE_KEY = 'old-project-service-key-xxx'
|
||||
|
||||
const NEW_PROJECT_URL = 'https://yyy.supabase.co'
|
||||
const NEW_PROJECT_SERVICE_KEY = 'new-project-service-key-yyy'
|
||||
|
||||
;(async () => {
|
||||
const oldSupabaseRestClient = createClient(OLD_PROJECT_URL, OLD_PROJECT_SERVICE_KEY, {
|
||||
db: {
|
||||
schema: 'storage',
|
||||
},
|
||||
})
|
||||
const oldSupabaseClient = createClient(OLD_PROJECT_URL, OLD_PROJECT_SERVICE_KEY)
|
||||
const newSupabaseClient = createClient(NEW_PROJECT_URL, NEW_PROJECT_SERVICE_KEY)
|
||||
|
||||
// make sure you update max_rows in postgrest settings if you have a lot of objects
|
||||
// or paginate here
|
||||
const { data: oldObjects, error } = await oldSupabaseRestClient.from('objects').select()
|
||||
if (error) {
|
||||
console.log('error getting objects from old bucket')
|
||||
throw error
|
||||
}
|
||||
|
||||
for (const objectData of oldObjects) {
|
||||
console.log(`moving ${objectData.id}`)
|
||||
try {
|
||||
const { data, error: downloadObjectError } = await oldSupabaseClient.storage
|
||||
.from(objectData.bucket_id)
|
||||
.download(objectData.name)
|
||||
if (downloadObjectError) {
|
||||
throw downloadObjectError
|
||||
}
|
||||
|
||||
const { _, error: uploadObjectError } = await newSupabaseClient.storage
|
||||
.from(objectData.bucket_id)
|
||||
.upload(objectData.name, data, {
|
||||
upsert: true,
|
||||
contentType: objectData.metadata.mimetype,
|
||||
cacheControl: objectData.metadata.cacheControl,
|
||||
})
|
||||
if (uploadObjectError) {
|
||||
throw uploadObjectError
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('error moving ', objectData)
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
})()
|
||||
```
|
||||
|
||||
### Transfer to a different organization
|
||||
|
||||
Note that project migration is for transferring your projects to different regions. If you need to move your project to a different organization without touching the infrastructure, see [project transfers](/docs/guides/platform/project-transfer).
|
||||
@@ -1,18 +1,20 @@
|
||||
---
|
||||
id: 'migrating-and-upgrading-projects'
|
||||
title: 'Migrating and Upgrading Projects'
|
||||
description: 'Upgrade your project to the latest version of Supabase.'
|
||||
sidebar_label: 'Migrating and upgrading'
|
||||
title: Upgrading
|
||||
---
|
||||
|
||||
Supabase ships fast and we endeavor to add all new features to existing projects wherever possible.
|
||||
In some cases, access to new features require upgrading or migrating your Supabase project.
|
||||
Supabase ships fast and we endeavor to add all new features to existing projects wherever possible. In some cases, access to new features require upgrading or migrating your Supabase project.
|
||||
|
||||
## Upgrade your project
|
||||
You can upgrade your project using `pg_upgrade` or by pausing and restoring your project.
|
||||
|
||||
There are a few methods available to upgrade your project.
|
||||
<ShowUntil date="2024-12-17">
|
||||
<Admonition type="tip">
|
||||
|
||||
### `pg_upgrade`
|
||||
The Migrating and Upgrading guide has been divided into two sections. To migrate between Supabase projects, see [Migrating within Supabase](/docs/guides/platform/migrating-within-supabase).
|
||||
|
||||
</Admonition>
|
||||
</ShowUntil>
|
||||
|
||||
## `pg_upgrade`
|
||||
|
||||
<Admonition type="note">
|
||||
|
||||
@@ -29,7 +31,7 @@ Additionally, if a pg_upgrade upgrade should fail, your original DB would be bro
|
||||
|
||||
As a rough rule of thumb, pg_upgrade operates at ~100mbps (when executing an upgrade on your data). Using the size of your database, you can use this metric to derive an approximate sense of the downtime window necessary for the upgrade. During this window, you should plan for your DB and associated services to be unavailable.
|
||||
|
||||
### Pause + restore
|
||||
## Pause and restore
|
||||
|
||||
<Admonition type="note">
|
||||
|
||||
@@ -193,158 +195,3 @@ As part of the upgrade process, maintenance operations such as [vacuuming](https
|
||||
#### Post-upgrade validation
|
||||
|
||||
Supabase performs extensive pre- and post-upgrade validations to ensure that the database has been correctly upgraded. However, you should plan for your own application-level validations, as there might be changes you might not have anticipated, and this should be budgeted for when planning your downtime window.
|
||||
|
||||
## Migrate your project
|
||||
|
||||
Migrating projects can be achieved using the Supabase CLI. This is particularly useful for older projects (for example to use a newer Postgres version).
|
||||
|
||||
### Before you begin
|
||||
|
||||
- Install [Postgres](https://www.postgresql.org/download/) so you can run `psql` and `pg_dump`.
|
||||
- Install the latest version of [Supabase CLI](/docs/guides/cli#installation).
|
||||
- Create a new [Supabase project](https://supabase.com/dashboard).
|
||||
- Install [Docker Desktop](https://www.docker.com) for your platform.
|
||||
- Set environment variables for the old project's database URL as `$OLD_DB_URL` and the new project's as `$NEW_DB_URL`.
|
||||
To find the database URL for a project, go to the project's dashboard page [Project Settings/Database](https://supabase.com/dashboard/project/_/settings/database) and look under `Connection string`. If your network provider supports IPv6, you can disable `Use connection pooling`. Otherwise, enable `Use connection pooling`. For the pooler mode, `Transaction` will work.
|
||||
|
||||
### Backup your old database
|
||||
|
||||
1. Run the following command from your terminal:
|
||||
|
||||
```bash
|
||||
supabase db dump --db-url "$OLD_DB_URL" -f roles.sql --role-only
|
||||
supabase db dump --db-url "$OLD_DB_URL" -f schema.sql
|
||||
supabase db dump --db-url "$OLD_DB_URL" -f data.sql --use-copy --data-only
|
||||
```
|
||||
|
||||
### Restore to your new project
|
||||
|
||||
In your new project:
|
||||
|
||||
1. Enable [Database Webhooks](https://supabase.com/dashboard/project/_/database/hooks) if you enabled them in your old project.
|
||||
2. Enable any [extensions](https://supabase.com/dashboard/project/_/database/extensions) that were enabled in your old project.
|
||||
|
||||
If you use [column encryption](/docs/guides/database/column-encryption), first copy the root encryption key to your new project using your [Personal Access Token](https://supabase.com/dashboard/account/tokens).
|
||||
|
||||
```bash
|
||||
export OLD_PROJECT_REF="<old_project_ref>"
|
||||
export NEW_PROJECT_REF="<new_project_ref>"
|
||||
export SUPABASE_ACCESS_TOKEN="<personal_access_token>"
|
||||
|
||||
curl "https://api.supabase.com/v1/projects/$OLD_PROJECT_REF/pgsodium" \
|
||||
-H "Authorization: Bearer $SUPABASE_ACCESS_TOKEN" |
|
||||
curl "https://api.supabase.com/v1/projects/$NEW_PROJECT_REF/pgsodium" \
|
||||
-H "Authorization: Bearer $SUPABASE_ACCESS_TOKEN" \
|
||||
-X PUT --json @-
|
||||
```
|
||||
|
||||
Then run the following command from your terminal:
|
||||
|
||||
```bash
|
||||
psql \
|
||||
--single-transaction \
|
||||
--variable ON_ERROR_STOP=1 \
|
||||
--file roles.sql \
|
||||
--file schema.sql \
|
||||
--command 'SET session_replication_role = replica' \
|
||||
--file data.sql \
|
||||
--dbname "$NEW_DB_URL"
|
||||
```
|
||||
|
||||
Setting the `session_replication_role` to `replica` disables all triggers so that columns are not double encrypted.
|
||||
|
||||
Troubleshooting notes:
|
||||
|
||||
- If you have created any [custom roles](https://supabase.com/dashboard/project/_/database/roles) with `login` attribute, you have to manually set their passwords in the new project.
|
||||
- If you run into any permission errors related to `supabase_admin` during restore, edit the `schema.sql` file and comment out any lines containing `ALTER ... OWNER TO "supabase_admin"`.
|
||||
|
||||
### Preserving migration history
|
||||
|
||||
If you were using Supabase CLI for managing migrations on your old database and would like to preserve the migration history in your newly restored project, you need to insert the migration records separately using the following commands.
|
||||
|
||||
```bash
|
||||
supabase db dump --db-url "$OLD_DB_URL" -f history_schema.sql --schema supabase_migrations
|
||||
supabase db dump --db-url "$OLD_DB_URL" -f history_data.sql --use-copy --data-only --schema supabase_migrations
|
||||
psql \
|
||||
--single-transaction \
|
||||
--variable ON_ERROR_STOP=1 \
|
||||
--file history_schema.sql \
|
||||
--file history_data.sql \
|
||||
--dbname "$NEW_DB_URL"
|
||||
```
|
||||
|
||||
### Schema changes to `auth` and `storage`
|
||||
|
||||
If you have modified the `auth` and `storage` schemas in your old project, such as adding triggers or RLS policies, you have to restore them separately. The Supabase CLI can help you diff the changes to these schemas using the following commands.
|
||||
|
||||
```bash
|
||||
supabase link --project-ref "$OLD_PROJECT_REF"
|
||||
supabase db diff --linked --schema auth,storage > changes.sql
|
||||
```
|
||||
|
||||
### Enable publication on tables
|
||||
|
||||
Replication for Realtime is disabled for all tables in your new project. On the [Publications](https://supabase.com/dashboard/project/_/database/publications) page in the Dashboard, select your new project and enable replication for tables that were enabled in your old project.
|
||||
|
||||
### Migrate storage objects
|
||||
|
||||
The new project has the old project's Storage buckets, but the Storage objects need to be migrated manually. Use this script to move storage objects from one project to another.
|
||||
|
||||
```js
|
||||
// npm install @supabase/supabase-js@1
|
||||
const { createClient } = require('@supabase/supabase-js')
|
||||
|
||||
const OLD_PROJECT_URL = 'https://xxx.supabase.co'
|
||||
const OLD_PROJECT_SERVICE_KEY = 'old-project-service-key-xxx'
|
||||
|
||||
const NEW_PROJECT_URL = 'https://yyy.supabase.co'
|
||||
const NEW_PROJECT_SERVICE_KEY = 'new-project-service-key-yyy'
|
||||
|
||||
;(async () => {
|
||||
const oldSupabaseRestClient = createClient(OLD_PROJECT_URL, OLD_PROJECT_SERVICE_KEY, {
|
||||
db: {
|
||||
schema: 'storage',
|
||||
},
|
||||
})
|
||||
const oldSupabaseClient = createClient(OLD_PROJECT_URL, OLD_PROJECT_SERVICE_KEY)
|
||||
const newSupabaseClient = createClient(NEW_PROJECT_URL, NEW_PROJECT_SERVICE_KEY)
|
||||
|
||||
// make sure you update max_rows in postgrest settings if you have a lot of objects
|
||||
// or paginate here
|
||||
const { data: oldObjects, error } = await oldSupabaseRestClient.from('objects').select()
|
||||
if (error) {
|
||||
console.log('error getting objects from old bucket')
|
||||
throw error
|
||||
}
|
||||
|
||||
for (const objectData of oldObjects) {
|
||||
console.log(`moving ${objectData.id}`)
|
||||
try {
|
||||
const { data, error: downloadObjectError } = await oldSupabaseClient.storage
|
||||
.from(objectData.bucket_id)
|
||||
.download(objectData.name)
|
||||
if (downloadObjectError) {
|
||||
throw downloadObjectError
|
||||
}
|
||||
|
||||
const { _, error: uploadObjectError } = await newSupabaseClient.storage
|
||||
.from(objectData.bucket_id)
|
||||
.upload(objectData.name, data, {
|
||||
upsert: true,
|
||||
contentType: objectData.metadata.mimetype,
|
||||
cacheControl: objectData.metadata.cacheControl,
|
||||
})
|
||||
if (uploadObjectError) {
|
||||
throw uploadObjectError
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('error moving ', objectData)
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
})()
|
||||
```
|
||||
|
||||
### Transfer to a different organization
|
||||
|
||||
Note that project migration is for transferring your projects to different regions. If you need to move your project to a different organization without touching the infrastructure, see [project transfers](/docs/guides/platform/project-transfer).
|
||||
@@ -1,173 +0,0 @@
|
||||
---
|
||||
id: 'examples'
|
||||
title: 'Examples and Resources'
|
||||
description: 'Examples you can use to get started with Supabase'
|
||||
video: 'https://www.youtube.com/v/7uKQBl9uZ00'
|
||||
---
|
||||
|
||||
{/* <!-- This page is outdated and should not be added to the sidebar until it has been reworked --> */}
|
||||
|
||||
We have a [set of examples](https://github.com/supabase/supabase/tree/master/examples) in our [main repository](https://github.com/supabase/supabase) to help you get started.
|
||||
|
||||
## Featured
|
||||
|
||||
## Build a Twitter clone with the Next.js App Router and Supabase
|
||||
|
||||
By [Jon Meyers](https://twitter.com/jonmeyers_io)
|
||||
|
||||
<a href="https://egghead.io/courses/build-a-twitter-clone-with-the-next-js-app-router-and-supabase-19bebadb">
|
||||
<img
|
||||
src="https://pbs.twimg.com/media/F2DEsxTaYAA1Coe?format=jpg&name=medium"
|
||||
alt="Build a Twitter Clone with the Next.js App Router and Supabase"
|
||||
width="100%"
|
||||
/>
|
||||
</a>
|
||||
|
||||
### Supabase crash course
|
||||
|
||||
By [Traversy Media](https://www.youtube.com/watch?v=7uKQBl9uZ00).
|
||||
|
||||
<div className="video-container">
|
||||
<iframe
|
||||
src="https://www.youtube-nocookie.com/embed/7uKQBl9uZ00"
|
||||
frameBorder="1"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
### Build an app with Supabase and Next.js
|
||||
|
||||
By [@jlengstorf](https://twitter.com/jlengstorf) and [@jonmeyers_io](https://twitter.com/jonmeyers_io).
|
||||
|
||||
<div className="video-container">
|
||||
<iframe
|
||||
src="https://www.youtube-nocookie.com/embed/8vqY1KT4TLU"
|
||||
frameBorder="1"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
### Is Supabase legit
|
||||
|
||||
By [Fireship](https://www.youtube.com/watch?v=WiwfiVdfRIc).
|
||||
|
||||
<div className="video-container">
|
||||
<iframe
|
||||
src="https://www.youtube-nocookie.com/embed/WiwfiVdfRIc"
|
||||
frameBorder="1"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
## Official examples
|
||||
|
||||
### Todo list
|
||||
|
||||
Build a basic Todo List with Supabase and your favorite frontend framework:
|
||||
|
||||
- [Expo Todo List.](https://github.com/supabase/examples/tree/main/supabase-js-v1/todo-list/expo-todo-list)
|
||||
- [Next.js Todo List.](https://github.com/supabase/supabase/tree/master/examples/todo-list/nextjs-todo-list)
|
||||
- [React Todo List.](https://github.com/supabase/examples/tree/main/supabase-js-v1/todo-list/react-todo-list)
|
||||
- [Svelte Todo List.](https://github.com/supabase/supabase/tree/master/examples/todo-list/sveltejs-todo-list)
|
||||
- [Vue 3 Todo List (Typescript).](https://github.com/supabase/examples/tree/main/supabase-js-v1/todo-list/vue3-ts-todo-list)
|
||||
- [Angular Todo List.](https://github.com/supabase/examples/tree/main/supabase-js-v1/todo-list/angular-todo-list)
|
||||
- [Nuxt 3 Todo List.](https://github.com/nuxt-modules/supabase/tree/main/demo)
|
||||
|
||||
### Auth examples
|
||||
|
||||
- [Supabase Auth with vanilla JavaScript.](https://github.com/supabase/examples/tree/main/supabase-js-v1/auth/javascript-auth). Use Supabase without any frontend frameworks.
|
||||
- [Supabase Auth with Next.js](https://github.com/supabase/supabase/tree/master/examples/user-management/nextjs-user-management).
|
||||
- [Supabase Auth with RedwoodJS.](https://redwood-playground-auth.netlify.app/supabase) Try out Supabase authentication in the [RedwoodJS](https://redwoodjs.com) Authentication Playground complete with OAuth support and code samples.
|
||||
|
||||
### Collaborative
|
||||
|
||||
- [Next.js Slack Clone.](https://github.com/supabase/examples/tree/main/supabase-js-v1/slack-clone/nextjs-slack-clone)
|
||||
|
||||
## Community
|
||||
|
||||
### Courses
|
||||
|
||||
- [Build a Twitter Clone with the Next.js App Router and Supabase - free egghead course](https://egghead.io/courses/build-a-twitter-clone-with-the-next-js-app-router-and-supabase-19bebadb)
|
||||
|
||||
### Libraries
|
||||
|
||||
- D (in development): [GitHub](https://github.com/csharpdf/dupabase)
|
||||
- Flutter (in development): [GitHub](https://github.com/supabase/supabase-flutter)
|
||||
- Python (in development): [GitHub](https://github.com/supabase/supabase-py)
|
||||
- C# (in development): [GitHub](https://github.com/supabase/supabase-csharp)
|
||||
- Kotlin (in development): [GitHub](https://github.com/supabase-community/supabase-kt)
|
||||
- `useSupabase`: Supabase React Hooks. [GitHub](https://github.com/gbibeaul/use-supabase)
|
||||
- `vue-supabase`: Supabase Vue wrapper. [GitHub](https://github.com/supabase/vue-supabase)
|
||||
- `vue-3-supabase`: Supabase Vue 3 wrapper. [GitHub](https://github.com/DidoMarchet/vue-3-supabase)
|
||||
- `nuxt-supabase`: Supabase Nuxt wrapper. [GitHub](https://github.com/supabase-community/nuxt-supabase)
|
||||
- `@nuxtjs/supabase`: Supabase Nuxt 3 module. [GitHub](https://github.com/nuxt-modules/supabase)
|
||||
- `react-supabase`: Supabase React Hooks. [Docs](https://react-supabase.vercel.app) [GitHub](https://github.com/tmm/react-supabase)
|
||||
- ` @triniwiz/nativescript-supabase`: Supabase NativeScript. [GitHub](https://github.com/triniwiz/nativescript-plugins/tree/master/packages/nativescript-supabase)
|
||||
|
||||
### Guides
|
||||
|
||||
- Supabase Auth with Redwood. [Docs](https://redwoodjs.com/tutorial/authentication)
|
||||
- Supabase Auth with Sapper SSR. [Blog](https://dev.to/jakobbouchard/how-to-setup-supabase-auth-with-sapper-ssr-13od)
|
||||
- Switch from Firebase Auth to Supabase Auth. [Blog](https://msyyn.medium.com/switch-from-firebase-auth-to-supabase-auth-the-open-source-firebase-alternative-509746952b1b)
|
||||
- Setting up Umami Analytics with Supabase. [Blog](https://dev.to/jakobbouchard/setting-up-umami-with-vercel-and-supabase-3a73)
|
||||
- Creating New Supabase Users In Next.js. [Blog](https://www.aboutmonica.com/blog/creating-new-supabase-users-in-next-js)
|
||||
- Creating Protected Routes In Next.js With Supabase. [Blog](https://www.aboutmonica.com/blog/creating-protected-routes-in-next-js-with-supabase)
|
||||
- Migrate from Google Cloud Storage (GCS) to Supabase Storage [Gist](https://gist.github.com/danalloway/86f79efd5ca336ff7364554ac3104014)
|
||||
- Subscriptions with Supabase and Stripe Billing [Blog](https://www.sandromaglione.com/2021/04/29/supabase-auth-create-stripe-customer-subscription-supabase-stripe-billing-part-1/)
|
||||
- Flutter Supabase Authentication [Blog](https://www.sandromaglione.com/2021/04/24/flutter-supabase-authentication/)
|
||||
- Supabase in 6 minutes [Video](https://www.youtube.com/watch?v=c8DNV9yl0mg)
|
||||
- Supabase React Auth UI Tutorial [Video](https://youtu.be/6ch1PtIqCUw)
|
||||
- Supabase React File Upload Tutorial [Video](https://youtu.be/HvOvdD2nX1k)
|
||||
- Let's build SupaAuth - Build an Authentication System using Supabase, Next.js and Typescript [6-part Blog Series](https://aalam.in/blog/supabase-auth-intro-setup-next)
|
||||
- In-depth self-hosting guide using Nginx [Blog](https://dev.to/chronsyn/self-hosting-with-supabase-1aii)
|
||||
- Build an Email and Social Auth for Next JS with Supabase, Tailwind CSS 3.0 and TypeScript [Blog](https://creativedesignsguru.com/next-js-supabase-auth/)
|
||||
- Link Shortener using Supabase and Ory [3-part Blog Series](https://www.ory.sh/tutorial-url-shortener-supabase-ory-integration-backend/)
|
||||
- Building a CRUD API with FastAPI and Supabase: A Step-by-Step Guide [Blog](https://blog.theinfosecguy.xyz/building-a-crud-api-with-fastapi-and-supabase-a-step-by-step-guide)
|
||||
|
||||
### Example apps
|
||||
|
||||
- Supabase + Stripe + Next.js. [GitHub](https://github.com/vercel/nextjs-subscription-payments)
|
||||
- Supabase + Svelte Trello clone. [GitHub](https://github.com/joshnuss/supabase-kanban)
|
||||
- Supabase + Expo Starter. [GitHub](https://github.com/codingki/react-native-expo-template/tree/master/template-typescript-bottom-tabs-supabase-auth-flow)
|
||||
- Supabase + Nest.js. [GitHub](https://github.com/hiro1107/nestjs-supabase-auth)
|
||||
- Supabase + Cloudflare Workers. [GitHub](https://github.com/supabase/examples/tree/main/supabase-js-v1/with-cloudflare-workers)
|
||||
- Supabase + Cloudflare Workers + Webpack. [GitHub](https://github.com/signalnerve/supabase-workers-proxy)
|
||||
- Realtime chat app with Supabase + React. [GitHub](https://github.com/shwosner/realtime-chat-supabase-react)
|
||||
- Repository.surf: GitHub insights dashboard. [GitHub](https://github.com/supabase/repository.surf)
|
||||
- Supabase + React Native Instagram Clone. [GitHub](https://github.com/NiketanG/instaclone)
|
||||
- KeepLink: Simple bookmark service with tags and archive. [GitHub](https://github.com/fengkx/keeplink)
|
||||
- Supabase + Next.js (Next.js Starter Kit) [GitHub](https://github.com/one-aalam/next-starter-kit/tree/auth-supabase)
|
||||
- Supabase + Svelte (Svelte Starter Kit) [GitHub](https://github.com/one-aalam/svelte-starter-kit)
|
||||
- Supabase + SolidJS (SolidJS Starter Kit) [GitHub](https://github.com/one-aalam/solid-starter-kit)
|
||||
- Supabase + Nuxt3 (Nuxt Starter Kit) [GitHub](https://github.com/one-aalam/nuxt-starter-kit)
|
||||
- Supabase + Remix (Remix Starter Kit) [GitHub](https://github.com/one-aalam/remix-starter-kit)
|
||||
- Supabase + Angular (Angular Starter Kit) [GitHub](https://github.com/one-aalam/ng-starter-kit)
|
||||
- Supabase + Nuxt3 + nuxtjs/supabase [Github](https://github.com/nuxt-modules/supabase/tree/main/demo)
|
||||
- Supabase + Ory Kratos & Ory Oathkeeper [Github](https://github.com/ory/examples/tree/master/kratos-keto-oathkeeper-supabase)
|
||||
- Supabase + Ory Cloud [Github](https://github.com/ory/examples/tree/master/supabase-ory-cloud)
|
||||
- Supabase Auth with React Native + Next.js (Monorepo) [Github](https://github.com/mateoguzmana/react-native-next-supabase-auth-monorepo)
|
||||
- Supabase Auth with Nuxt3 [Github](https://github.com/zackha/supaAuth)
|
||||
- Supabase Auth with Hono [Github](https://github.com/CarlosZiegler/hono-supabase)
|
||||
|
||||
### Blog posts
|
||||
|
||||
- Realtime Subscriptions using Vue + Supabase. [Blog](https://dev.to/ftonato/realtime-subscriptions-using-vue-supabase-1e11)
|
||||
- Creating a microblog using Vue + Supabase. [Blog](https://dev.to/ftonato/creating-a-microblog-using-vue-supabase-31p)
|
||||
- Track Real-time Page Views. [Blog](https://codebycorey.com/blog/page-views-nextjs-supabase)
|
||||
- Supabase as a Sentry alternative. [Blog](http://kopi.cloud/blog/2021/sentry-supabase/)
|
||||
- Using Supabase with Chartbrew. [Blog](https://chartbrew.com/blog/how-to-visualize-your-supabase-data-with-chartbrew/)
|
||||
- Authentication with Supabase and React. [Blog](https://hyperfoo.io/posts/supabase-authentication-react)
|
||||
- Supabase Schema Visualizer. [Blog](https://dev.to/zernonia/supabase-schema-visualizer-no-installation-login-49kg)
|
||||
- Create a real-time UI using Next.js + Supabase. [Blog](https://pablopunk.com/posts/how-to-create-a-real-time-ui-with-nextjs-and-supabase)
|
||||
- How to add Twitter auth quickly with Supabase to your Next.js site ⚡ [Blog](https://blog.avneesh.tech/how-to-add-twitter-auth-quickly-with-supabase-to-your-nextjs-site)
|
||||
- Under the hood: Architecture and Technology Stack of Supabase ⚡ [Blog](https://www.workingsoftware.dev/tech-stack-and-architecture-of-supabase/)
|
||||
|
||||
### Podcasts
|
||||
|
||||
- [Software Engineering Daily](https://softwareengineeringdaily.com/2020/10/15/supabase-open-source-firebase-with-paul-copplestone/)
|
||||
- [Heavy Bit](https://www.heavybit.com/library/podcasts/jamstack-radio/ep-71-open-source-firebase-alternative-with-paul-copplestone-of-supabase/)
|
||||
- [Log Rocket](https://podrocket.logrocket.com/9)
|
||||
- [FS Jam](https://fsjam.org/episodes/episode-33-supabase-with-paul-copplestone)
|
||||
@@ -1,4 +1,8 @@
|
||||
import matter from 'gray-matter'
|
||||
import { fromMarkdown } from 'mdast-util-from-markdown'
|
||||
import { gfmFromMarkdown, gfmToMarkdown } from 'mdast-util-gfm'
|
||||
import { toMarkdown } from 'mdast-util-to-markdown'
|
||||
import { gfm } from 'micromark-extension-gfm'
|
||||
import { type Metadata, type ResolvingMetadata } from 'next'
|
||||
import { notFound } from 'next/navigation'
|
||||
import { readFile, readdir } from 'node:fs/promises'
|
||||
@@ -22,11 +26,14 @@ const PUBLISHED_SECTIONS = [
|
||||
'ai',
|
||||
'api',
|
||||
'auth',
|
||||
'cli',
|
||||
'database',
|
||||
'deployment',
|
||||
'functions',
|
||||
'getting-started',
|
||||
// 'graphql', -- technically published, but completely federated
|
||||
'integrations',
|
||||
'local-development',
|
||||
'monitoring-troubleshooting',
|
||||
'platform',
|
||||
'realtime',
|
||||
'resources',
|
||||
@@ -143,4 +150,18 @@ const genGuideMeta =
|
||||
}
|
||||
}
|
||||
|
||||
export { getGuidesMarkdown, genGuidesStaticParams, genGuideMeta }
|
||||
function removeRedundantH1(content: string) {
|
||||
const mdxTree = fromMarkdown(content, 'utf-8', {
|
||||
extensions: [gfm()],
|
||||
mdastExtensions: [gfmFromMarkdown()],
|
||||
})
|
||||
|
||||
const maybeH1 = mdxTree.children[0]
|
||||
if (maybeH1 && maybeH1.type === 'heading' && maybeH1.depth === 1) {
|
||||
content = content.slice(maybeH1.position?.end?.offset)
|
||||
}
|
||||
|
||||
return content
|
||||
}
|
||||
|
||||
export { getGuidesMarkdown, genGuidesStaticParams, genGuideMeta, removeRedundantH1 }
|
||||
|
||||
@@ -38,6 +38,7 @@ import StepHikeCompact from '~/components/StepHikeCompact'
|
||||
import { CodeSampleWrapper } from '~/features/directives/CodeSample.client'
|
||||
import { Accordion, AccordionItem } from '~/features/ui/Accordion'
|
||||
import * as CH from '~/features/ui/CodeHike'
|
||||
import { ShowUntil } from '~/features/ui/ShowUntil'
|
||||
import { TabPanel, Tabs } from '~/features/ui/Tabs'
|
||||
|
||||
const components = {
|
||||
@@ -78,6 +79,7 @@ const components = {
|
||||
RealtimeLimitsEstimator,
|
||||
RegionsList,
|
||||
SharedData,
|
||||
ShowUntil,
|
||||
SocialProviderSettingsSupabase,
|
||||
SocialProviderSetup,
|
||||
SqlToRest,
|
||||
|
||||
12
apps/docs/features/ui/ShowUntil.tsx
Normal file
12
apps/docs/features/ui/ShowUntil.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import { type ReactNode } from 'react'
|
||||
|
||||
export function ShowUntil({ children, date }: { children: ReactNode; date: string }) {
|
||||
const currentDate = new Date()
|
||||
const untilDate = new Date(date)
|
||||
|
||||
if (isNaN(untilDate.getTime()) || currentDate < untilDate) {
|
||||
return <>{children}</>
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import { SidebarSkeleton } from './MainSkeleton'
|
||||
|
||||
const HomeLayout = ({ children }: PropsWithChildren) => {
|
||||
return (
|
||||
<SidebarSkeleton>
|
||||
<SidebarSkeleton hideSideNav>
|
||||
<article>
|
||||
<HomePageCover title="Supabase Documentation" />
|
||||
<LayoutMainContent>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import dynamic from 'next/dynamic'
|
||||
import { usePathname } from 'next/navigation'
|
||||
import { memo, useEffect, type PropsWithChildren, type ReactNode } from 'react'
|
||||
|
||||
import { cn } from 'ui'
|
||||
@@ -8,6 +9,8 @@ import { cn } from 'ui'
|
||||
import DefaultNavigationMenu, {
|
||||
MenuId,
|
||||
} from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import { getMenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu.utils'
|
||||
import { type NavMenuSection } from '~/components/Navigation/Navigation.types'
|
||||
import TopNavBar from '~/components/Navigation/NavigationMenu/TopNavBar'
|
||||
import { DOCS_CONTENT_CONTAINER_ID } from '~/features/ui/helpers.constants'
|
||||
import { menuState, useMenuMobileOpen } from '~/hooks/useMenuState'
|
||||
@@ -59,9 +62,9 @@ const levelsData = {
|
||||
icon: 'ai',
|
||||
name: 'AI & Vectors',
|
||||
},
|
||||
supabase_cli: {
|
||||
local_development: {
|
||||
icon: 'reference-cli',
|
||||
name: 'Supabase CLI',
|
||||
name: 'Local Development',
|
||||
},
|
||||
platform: {
|
||||
icon: 'platform',
|
||||
@@ -328,9 +331,11 @@ const NavContainer = memo(function NavContainer({ children }: PropsWithChildren)
|
||||
interface SkeletonProps extends PropsWithChildren {
|
||||
menuId?: MenuId
|
||||
menuName?: string
|
||||
hideSideNav?: boolean
|
||||
NavigationMenu?: ReactNode
|
||||
hideFooter?: boolean
|
||||
className?: string
|
||||
additionalNavItems?: Partial<NavMenuSection>[]
|
||||
}
|
||||
|
||||
function TopNavSkeleton({ children }) {
|
||||
@@ -346,19 +351,27 @@ function TopNavSkeleton({ children }) {
|
||||
|
||||
function SidebarSkeleton({
|
||||
children,
|
||||
menuId,
|
||||
menuId: _menuId,
|
||||
menuName,
|
||||
NavigationMenu,
|
||||
hideFooter = false,
|
||||
className,
|
||||
hideSideNav,
|
||||
additionalNavItems,
|
||||
}: SkeletonProps) {
|
||||
const pathname = usePathname()
|
||||
const menuId = _menuId ?? getMenuId(pathname)
|
||||
|
||||
const mobileMenuOpen = useMenuMobileOpen()
|
||||
const hideSideNav = !menuId && !NavigationMenu
|
||||
|
||||
return (
|
||||
<div className={cn('flex flex-row h-full relative', className)}>
|
||||
{!hideSideNav && (
|
||||
<NavContainer>{NavigationMenu ?? <DefaultNavigationMenu menuId={menuId} />}</NavContainer>
|
||||
<NavContainer>
|
||||
{NavigationMenu ?? (
|
||||
<DefaultNavigationMenu menuId={menuId} additionalNavItems={additionalNavItems} />
|
||||
)}
|
||||
</NavContainer>
|
||||
)}
|
||||
<Container>
|
||||
<div
|
||||
|
||||
@@ -1,40 +1,17 @@
|
||||
'use client'
|
||||
|
||||
import 'katex/dist/katex.min.css'
|
||||
import { type PropsWithChildren } from 'react'
|
||||
|
||||
import { type FC } from 'react'
|
||||
|
||||
import { FooterHelpCalloutType } from '~/components/FooterHelpCallout'
|
||||
import { type MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu'
|
||||
import { type NavMenuSection } from '~/components/Navigation/Navigation.types'
|
||||
import { LayoutMainContent } from '~/layouts/DefaultLayout'
|
||||
import { SidebarSkeleton } from '~/layouts/MainSkeleton'
|
||||
|
||||
interface Props {
|
||||
meta?: {
|
||||
title: string
|
||||
description?: string // used in meta tags
|
||||
hide_table_of_contents?: boolean
|
||||
breadcrumb?: string
|
||||
subtitle?: string // used on the page under the H1
|
||||
footerHelpType?: FooterHelpCalloutType
|
||||
video?: string
|
||||
tocVideo?: string
|
||||
canonical?: string
|
||||
}
|
||||
editLink?: string
|
||||
children: any
|
||||
toc?: any
|
||||
currentPage?: string
|
||||
hideToc?: boolean
|
||||
menuId: MenuId
|
||||
}
|
||||
|
||||
const Layout: FC<Props> = (props) => {
|
||||
const menuId = props.menuId
|
||||
|
||||
const Layout = ({
|
||||
children,
|
||||
additionalNavItems,
|
||||
}: PropsWithChildren<{ additionalNavItems?: Partial<NavMenuSection>[] }>) => {
|
||||
return (
|
||||
<SidebarSkeleton menuId={menuId}>
|
||||
<LayoutMainContent className="pb-0">{props.children}</LayoutMainContent>
|
||||
<SidebarSkeleton additionalNavItems={additionalNavItems}>
|
||||
<LayoutMainContent className="pb-0">{children}</LayoutMainContent>
|
||||
</SidebarSkeleton>
|
||||
)
|
||||
}
|
||||
|
||||
14
apps/docs/lib/supabaseMisc.ts
Normal file
14
apps/docs/lib/supabaseMisc.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { createClient, type SupabaseClient } from '@supabase/supabase-js'
|
||||
|
||||
let _supabaseMisc: SupabaseClient
|
||||
|
||||
export function supabaseMisc() {
|
||||
if (!_supabaseMisc) {
|
||||
_supabaseMisc = createClient(
|
||||
process.env.NEXT_PUBLIC_MISC_URL!,
|
||||
process.env.NEXT_PUBLIC_MISC_ANON_KEY!
|
||||
)
|
||||
}
|
||||
|
||||
return _supabaseMisc
|
||||
}
|
||||
@@ -60,16 +60,16 @@ const nextConfig = {
|
||||
'/api/crawlers': ['./features/docs/generated/**/*', './docs/ref/**/*'],
|
||||
},
|
||||
},
|
||||
/**
|
||||
* The SQL to REST API translator relies on libpg-query, which packages a
|
||||
* native Node.js module that wraps the Postgres query parser.
|
||||
*
|
||||
* The default webpack config can't load native modules, so we need a custom
|
||||
* loader for it, which calls process.dlopen to load C++ Addons.
|
||||
*
|
||||
* See https://github.com/eisberg-labs/nextjs-node-loader
|
||||
*/
|
||||
webpack: (config) => {
|
||||
webpack: (config, options) => {
|
||||
/**
|
||||
* The SQL to REST API translator relies on libpg-query, which packages a
|
||||
* native Node.js module that wraps the Postgres query parser.
|
||||
*
|
||||
* The default webpack config can't load native modules, so we need a custom
|
||||
* loader for it, which calls process.dlopen to load C++ Addons.
|
||||
*
|
||||
* See https://github.com/eisberg-labs/nextjs-node-loader
|
||||
*/
|
||||
config.module.rules.push({
|
||||
test: /\.node$/,
|
||||
use: [
|
||||
|
||||
@@ -12,11 +12,9 @@ import {
|
||||
realtime,
|
||||
storage,
|
||||
ai,
|
||||
supabase_cli,
|
||||
platform,
|
||||
resources,
|
||||
self_hosting,
|
||||
migrate,
|
||||
} from '../../components/Navigation/NavigationMenu/NavigationMenu.constants'
|
||||
|
||||
const DOCS_ROOT_DIR = join(__dirname, '..', '..')
|
||||
@@ -73,11 +71,9 @@ const main = async () => {
|
||||
realtime.items,
|
||||
storage.items,
|
||||
ai.items,
|
||||
supabase_cli.items,
|
||||
platform.items,
|
||||
resources.items,
|
||||
self_hosting.items,
|
||||
migrate.items,
|
||||
]
|
||||
.flatMap((items) => recGetUrl(items))
|
||||
// Remove initial slash
|
||||
|
||||
@@ -2658,6 +2658,156 @@ module.exports = [
|
||||
source: '/docs/guides/platform/enterprise-billing',
|
||||
destination: '/docs/guides/platform/org-based-billing',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/cli',
|
||||
destination: '/docs/guides/local-development',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/cli/getting-started',
|
||||
destination: '/docs/guides/local-development/cli/getting-started',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/cli/config',
|
||||
destination: '/docs/guides/local-development/cli/config',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/cli/local-development',
|
||||
destination: '/docs/guides/local-development/overview',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/cli/:path*',
|
||||
destination: '/docs/guides/local-development/cli/:path*',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/cli/managing-environments',
|
||||
destination: '/docs/guides/deployment/managing-environments',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/platform/branching',
|
||||
destination: '/docs/guides/deployment/branching',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/platform/terraform',
|
||||
destination: '/docs/guides/deployment/terraform',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/platform/terraform/:path*',
|
||||
destination: '/docs/guides/deployment/terraform/:path*',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/platform/going-into-prod',
|
||||
destination: '/docs/guides/deployment/going-into-prod',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/platform/maturity-model',
|
||||
destination: '/docs/guides/deployment/maturity-model',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/platform/shared-responsibility-model',
|
||||
destination: '/docs/guides/deployment/shared-responsibility-model',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/cli/github-actions/:path*',
|
||||
destination: '/docs/guides/deployment/ci/:path*',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/resources/migrating-to-supabase/:path*',
|
||||
destination: '/docs/guides/platform/migrating-to-supabase/:path*',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/platform/migrating-and-upgrading-projects',
|
||||
destination: '/docs/guides/platform/upgrading',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/platform/vercel-marketplace',
|
||||
destination: '/docs/guides/integrations/vercel-marketplace',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/platform/marketplace',
|
||||
destination: '/docs/guides/integrations/supabase-marketplace',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/platform/oauth-apps/build-a-supabase-integration',
|
||||
destination: '/docs/guides/integrations/build-a-supabase-integration',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/platform/oauth-apps/oauth-scopes',
|
||||
destination: '/docs/guides/integrations/build-a-supabase-integration/oauth-scopes',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/platform/logs',
|
||||
destination: '/docs/guides/monitoring-troubleshooting/logs',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/platform/metrics',
|
||||
destination: '/docs/guides/monitoring-troubleshooting/metrics',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/platform/sentry-monitoring',
|
||||
destination: '/docs/guides/monitoring-troubleshooting/sentry-monitoring',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/platform/advanced-log-filtering',
|
||||
destination: '/docs/guides/monitoring-troubleshooting/advanced-log-filtering',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/platform/exhaust-disk-io',
|
||||
destination: '/docs/guides/monitoring-troubleshooting/exhaust-disk-io',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/platform/exhaust-cpu',
|
||||
destination: '/docs/guides/monitoring-troubleshooting/exhaust-cpu',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/platform/exhaust-ram',
|
||||
destination: '/docs/guides/monitoring-troubleshooting/exhaust-ram',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/platform/exhaust-swap',
|
||||
destination: '/docs/guides/monitoring-troubleshooting/exhaust-swap',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/platform/http-status-codes',
|
||||
destination: '/docs/guides/monitoring-troubleshooting/http-status-codes',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/platform/troubleshooting',
|
||||
destination: '/docs/guides/monitoring-troubleshooting/troubleshooting',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/guides/platform/log-drains',
|
||||
destination: '/docs/guides/monitoring-troubleshooting/log-drains',
|
||||
},
|
||||
|
||||
// marketing
|
||||
|
||||
|
||||
54
package-lock.json
generated
54
package-lock.json
generated
@@ -15849,6 +15849,14 @@
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/parse-json": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz",
|
||||
"integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@types/parse-numeric-range": {
|
||||
"version": "0.0.1",
|
||||
"dev": true,
|
||||
@@ -17774,6 +17782,23 @@
|
||||
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-plugin-macros": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz",
|
||||
"integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"cosmiconfig": "^7.0.0",
|
||||
"resolve": "^1.19.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10",
|
||||
"npm": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-plugin-polyfill-corejs2": {
|
||||
"version": "0.4.11",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz",
|
||||
@@ -18987,6 +19012,35 @@
|
||||
"version": "1.0.3",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cosmiconfig": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
|
||||
"integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/parse-json": "^4.0.0",
|
||||
"import-fresh": "^3.2.1",
|
||||
"parse-json": "^5.0.0",
|
||||
"path-type": "^4.0.0",
|
||||
"yaml": "^1.10.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/cosmiconfig/node_modules/yaml": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
|
||||
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/create-jest": {
|
||||
"version": "29.7.0",
|
||||
"dev": true,
|
||||
|
||||
17
package.json
17
package.json
@@ -5,7 +5,13 @@
|
||||
"author": "Supabase, Inc.",
|
||||
"license": "Apache-2.0",
|
||||
"private": true,
|
||||
"workspaces": ["apps/*", "apps/docs/spec/parser", "tests", "playwright-tests", "packages/*"],
|
||||
"workspaces": [
|
||||
"apps/*",
|
||||
"apps/docs/spec/parser",
|
||||
"tests",
|
||||
"playwright-tests",
|
||||
"packages/*"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "turbo run build",
|
||||
"build:studio": "turbo run build --filter=studio",
|
||||
@@ -51,6 +57,13 @@
|
||||
"npm": "^10.0.0",
|
||||
"node": "^20.0.0"
|
||||
},
|
||||
"keywords": ["postgres", "firebase", "storage", "functions", "database", "auth"],
|
||||
"keywords": [
|
||||
"postgres",
|
||||
"firebase",
|
||||
"storage",
|
||||
"functions",
|
||||
"database",
|
||||
"auth"
|
||||
],
|
||||
"packageManager": "npm@10.7.0"
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import { cn } from 'ui'
|
||||
|
||||
interface Props {
|
||||
title: string
|
||||
span?: string
|
||||
icon?: string | React.ReactNode
|
||||
children?: React.ReactNode
|
||||
header?: string
|
||||
@@ -22,7 +21,6 @@ interface Props {
|
||||
|
||||
export const GlassPanel = ({
|
||||
title,
|
||||
span,
|
||||
icon,
|
||||
children,
|
||||
header,
|
||||
|
||||
Reference in New Issue
Block a user