Merge branch 'master' into chore/pricing-page-updates

This commit is contained in:
Terry Sutton committed 2023-02-14 11:01:11 -03:30
commit 02316634a2
256 files changed
+13960 -5169

No files matched your search

+3 -3
View File
@@ -12,9 +12,9 @@
- [x] Hosted Postgres Database. [Docs](https://supabase.com/docs/guides/database)
- [x] Authentication and Authorization. [Docs](https://supabase.com/docs/guides/auth)
- [x] Auto-generated APIs.
- [x] REST. [Docs](https://supabase.com/docs/guides/api#rest-api)
- [x] Realtime subscriptions. [Docs](https://supabase.com/docs/guides/api#realtime-api)
- [x] GraphQL (Beta). [Docs](https://supabase.com/docs/guides/api#graphql-api)
- [x] REST. [Docs](https://supabase.com/docs/guides/database/api#rest-api)
- [x] Realtime subscriptions. [Docs](https://supabase.com/docs/guides/database/api#realtime-api)
- [x] GraphQL (Beta). [Docs](https://supabase.com/docs/guides/database/api#graphql-api)
- [x] Functions.
- [x] Database Functions. [Docs](https://supabase.com/docs/guides/database/functions)
- [x] Edge Functions [Docs](https://supabase.com/docs/guides/functions)
+16 -48
View File
@@ -1,53 +1,21 @@
import providers from '../data/authProviders'
import ButtonCard from './ButtonCard'
import { IconPanel } from 'ui'
import Link from 'next/link'
export default function AuthProviders({ type }: { type: string }) {
const filterProviders = providers.filter((item) => item.authType === type)
export default function AuthProviders() {
return (
<div className="grid md:grid-cols-12 gap-4">
{providers.map((x) => (
<div key={x.name} className="col-span-6">
<ButtonCard to={x.href} title={x.name}>
<div className="px-6 py-4">
<div className="flex justify-between">
<p className="mt-0">{x.name}</p>
<p className="mt-0">
{x.official ? (
<span className={`badge badge--official`}>Official</span>
) : (
<span className={`badge badge--unofficial`}>Unofficial</span>
)}
</p>
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: 5 }}>
<div
className="code-block"
style={{
width: '100%',
display: 'flex',
justifyContent: 'space-between',
fontSize: '0.7rem',
}}
>
<span>Platform:</span>
<span>{x.platform.toString()}</span>
</div>
<div
className="code-block"
style={{
width: '100%',
display: 'flex',
justifyContent: 'space-between',
fontSize: '0.7rem',
}}
>
<span>Self-Hosted:</span>
<span>{x.selfHosted.toString()}</span>
</div>
</div>
</div>
</ButtonCard>
</div>
))}
</div>
<>
<div className="grid grid-cols-12 gap-10 not-prose py-8">
{filterProviders.map((x) => (
<Link href={`${x.href}`} key={x.name} passHref>
<a className="col-span-6 lg:col-span-4 xl:col-span-3">
<IconPanel title={x.name} icon={x.logo} />
</a>
</Link>
))}
</div>
</>
)
}
+3 -6
View File
@@ -7,24 +7,21 @@ import clippyImage from '../../public/img/clippy.png'
import ClippyBubble from './ClippyBubble'
import ClippyModal from './ClippyModal'
import { useClippy } from './ClippyProvider'
import { useFlag } from '~/hooks/useFlag'
const Clippy: FC = () => {
const { isDarkMode } = useTheme()
const { isOpen, open, close } = useClippy()
const enableClippy = useFlag('enableClippy')
return (
<>
{!isOpen && (
<div className="hidden md:flex flex-col items-end gap-1 md:gap-4">
{enableClippy && (
<>
{/* <>
<ClippyBubble onClick={open} />
<div className="w-[80px] lg:w-[120px] p-8 md:p-0">
<Image src={isDarkMode ? clippyImageDark : clippyImage} alt="Clippy" />
</div>
</>
)}
</> */}
</div>
)}
{isOpen && createPortal(<ClippyModal onClose={close} />, document.body)}
+3 -3
View File
@@ -30,12 +30,12 @@ const questions = [
'How do I connect to my database?',
'How do I run migrations? ',
'How do I listen to changes in a table?',
'How do I setup authentication?',
'How do I set up authentication?',
]
function getEdgeFunctionUrl() {
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL.replace(/\/$/, '')
const isPlatform = supabaseUrl.match(/(supabase\.co)|(supabase\.in)/)
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL?.replace(/\/$/, '')
const isPlatform = supabaseUrl?.match(/(supabase\.co)|(supabase\.in)/)
if (isPlatform) {
const [schemeAndProjectId, domain, tld] = supabaseUrl.split('.')
@@ -25,9 +25,10 @@ interface Props {
* expected tocList format (text, link,level).
*
* In tsx files, we can generate this tocList directly. For these files, we don't
* need to parse the <a> and generate anchors
* need to parse the <a> and generate anchors. Custom anchors are used in tsx files.
* (see: /pages/reference/cli/config.tsx)
*/
const Heading: React.FC<Props> = ({ tag, parseAnchors = false, customAnchor, children }) => {
const Heading: React.FC<Props> = ({ tag, customAnchor, children }) => {
const HeadingTag = `${tag}` as any
const anchor = customAnchor ? customAnchor : getAnchor(children)
const link = `#${anchor}`
@@ -43,7 +44,7 @@ const Heading: React.FC<Props> = ({ tag, parseAnchors = false, customAnchor, chi
return (
<HeadingTag id={anchor} ref={ref} className="group scroll-mt-24">
{parseAnchors ? removeAnchor(children) : children}
{removeAnchor(children)}
{anchor && (
<a href={link} className="ml-2 opacity-0 group-hover:opacity-100 transition">
#
+19 -20
View File
@@ -1,34 +1,33 @@
import { FC, useEffect, useState } from 'react'
import createConfigCatClient from 'configcat-js'
// import createConfigCatClient from 'configcat-js'
import FlagContext from './FlagContext'
const FlagProvider: FC = ({ children }) => {
const [store, setStore] = useState({})
const { Provider } = FlagContext
useEffect(() => {
getFlags()
}, [])
// useEffect(() => {
// getFlags()
// }, [])
const getFlags = async () => {
const setFlagValues = async () => {
const flagValues = await client.getAllValuesAsync()
const flagStore: any = {}
// const getFlags = async () => {
// const setFlagValues = async () => {
// const flagValues = await client.getAllValuesAsync()
// const flagStore: any = {}
flagValues.forEach((item: any) => {
flagStore[item.settingKey] = item.settingValue
})
setStore(flagStore)
}
// flagValues.forEach((item: any) => {
// flagStore[item.settingKey] = item.settingValue
// })
// setStore(flagStore)
// }
const client = createConfigCatClient(process.env.NEXT_PUBLIC_CONFIGCAT_SDK_KEY ?? '', {
configChanged: setFlagValues,
pollIntervalSeconds: 600,
})
// const client = createConfigCatClient(process.env.NEXT_PUBLIC_CONFIGCAT_SDK_KEY ?? '', {
// configChanged: setFlagValues,
// pollIntervalSeconds: 600,
// })
await setFlagValues()
}
// await setFlagValues()
// }
return <Provider value={store}>{children}</Provider>
}
+10 -32
View File
@@ -2,22 +2,19 @@ import UserManagementSQLTemplate from './user_management_quickstart_sql_template
import { Tabs } from 'ui'
export const TabPanel = Tabs.Panel
# Project set up
## Project setup
Before we start building we're going to set up our Database and API. This is as simple as starting a new Project in Supabase
and then creating a "schema" inside the database.
Before we start building we're going to set up our Database and API. This is as simple as starting a new Project in Supabase and then creating a "schema" inside the database.
## Create a project
### Create a project
1. Go to [app.supabase.com](https://app.supabase.com).
1. Click on "New Project".
1. [Create a new project](https://app.supabase.com) in the Supabase Dashboard.
1. Enter your project details.
1. Wait for the new database to launch.
## Set up the database schema
### Set up the database schema
Now we are going to set up the database schema. We can use the "User Management Starter" quickstart in the SQL Editor,
or you can just copy/paste the SQL from below and run it yourself.
Now we are going to set up the database schema. We can use the "User Management Starter" quickstart in the SQL Editor, or you can just copy/paste the SQL from below and run it yourself.
<Tabs
scrollable
@@ -31,15 +28,6 @@ or you can just copy/paste the SQL from below and run it yourself.
2. Click **User Management Starter**.
3. Click **Run**.
<video width="99%" muted playsInline controls="true">
<source
src="https://xguihxuzqibwxjnimxev.supabase.co/storage/v1/object/public/videos/docs/sql-user-management-starter.mp4"
type="video/mp4"
muted
playsInline
/>
</video>
</TabPanel>
<TabPanel id="sql" label="SQL">
@@ -48,20 +36,10 @@ or you can just copy/paste the SQL from below and run it yourself.
</TabPanel>
</Tabs>
## Get the API Keys
### Get the API Keys
Now that you've created some database tables, you are ready to insert data using the auto-generated API.
We just need to get the URL and `anon` key from the API settings.
We just need to get the Project URL and `anon` key from the API settings.
1. Go to the [Settings](https://app.supabase.com/project/_/settings) page in the Dashboard.
2. Click **API** in the sidebar.
3. Find your API `URL`, `anon`, and `service_role` keys on this page.
<video width="99%" muted playsInline controls="true">
<source
src="https://xguihxuzqibwxjnimxev.supabase.co/storage/v1/object/public/videos/docs/api/api-url-and-key.mp4"
type="video/mp4"
muted
playsInline
/>
</video>
1. Go to the [API Settings](https://app.supabase.com/project/_/settings/api) page in the Dashboard.
1. Find your Project `URL`, `anon`, and `service_role` keys on this page.
@@ -1,9 +1,5 @@
This example provides the steps to build a basic user management app. It includes:
This tutorial demonstrates how to build a basic user management app. The app authenticates and identifies the user, stores their profile information in the database, and allows the user to log in, update their profile details, and upload a profile photo. The app uses:
- Supabase [Database](/docs/guides/database): a Postgres database for storing your user data.
- Supabase [Auth](/docs/guides/auth): users can sign in with magic links (no passwords, only email).
- Supabase [Storage](/docs/guides/storage): users can upload a photo.
- [Row Level Security](/docs/guides/auth#row-level-security): data is protected so that individuals can only access their own data.
- Instant [APIs](/docs/guides/api): APIs will be automatically generated when you create your database tables.
By the end of this guide you'll have an app which allows users to login and update some basic profile details:
- [Supabase Database](/docs/guides/database) - a Postgres database for storing your user data and [Row Level Security](/docs/guides/auth#row-level-security) so data is protected and users can only access their own information.
- [Supabase Auth](/docs/guides/auth) - users log in through magic links sent to their email (without having to set up passwords).
- [Supabase Storage](/docs/guides/storage) - users can upload a profile photo.
@@ -178,8 +178,8 @@ export const menuItems: NavMenu = {
name: 'Serverless APIs',
url: undefined,
items: [
{ name: 'Overview', url: '/guides/api', items: [] },
{ name: 'Generating Types', url: '/guides/api/generating-types', items: [] },
{ name: 'Overview', url: '/guides/database/api', items: [] },
{ name: 'Generating Types', url: '/guides/database/api/generating-types', items: [] },
],
},
{
@@ -278,6 +278,7 @@ export const menuItems: NavMenu = {
{ name: 'Performance Tuning', url: '/guides/platform/performance', items: [] },
{ name: 'Permissions', url: '/guides/platform/permissions', items: [] },
{ name: 'Production Readiness', url: '/guides/platform/going-into-prod', items: [] },
{ name: 'SSL Enforcement', url: '/guides/platform/ssl-enforcement', items: [] },
{ name: 'Troubleshooting', url: '/guides/platform/troubleshooting', items: [] },
],
},
@@ -51,7 +51,7 @@ export const gettingstarted = {
{
name: 'Framework Quickstarts',
items: [
{ name: 'ReactJS', url: '/guides/getting-started/quickstarts/reactjs', items: [] },
{ name: 'React', url: '/guides/getting-started/quickstarts/reactjs', items: [] },
{ name: 'NextJS', url: '/guides/getting-started/quickstarts/nextjs', items: [] },
{ name: 'Flutter', url: '/guides/getting-started/quickstarts/flutter', items: [] },
{ name: 'SvelteKit', url: '/guides/getting-started/quickstarts/sveltekit', items: [] },
@@ -63,7 +63,7 @@ export const gettingstarted = {
name: 'Web app tutorials',
items: [
{
name: 'Next.js',
name: 'NextJS',
url: '/guides/getting-started/tutorials/with-nextjs',
items: [],
},
@@ -379,8 +379,8 @@ export const database = {
name: 'Serverless APIs',
url: undefined,
items: [
{ name: 'Overview', url: '/guides/api', items: [] },
{ name: 'Generating Types', url: '/guides/api/generating-types', items: [] },
{ name: 'Overview', url: '/guides/database/api', items: [] },
{ name: 'Generating Types', url: '/guides/database/api/generating-types', items: [] },
],
},
{
@@ -400,7 +400,7 @@ export const database = {
},
{ name: 'http: RESTful Client', url: '/guides/database/extensions/http', items: [] },
{
name: 'PGRoonga: Multilingual Full Text Search',
name: 'PGroonga: Multilingual Full Text Search',
url: '/guides/database/extensions/pgroonga',
items: [],
},
@@ -498,6 +498,7 @@ export const functions = {
{ name: 'Storage Caching', url: '/guides/functions/examples/storage-caching', items: [] },
{ name: 'Stripe Webhooks', url: '/guides/functions/examples/stripe-webhooks', items: [] },
{ name: 'Telegram Bot', url: '/guides/functions/examples/telegram-bot', items: [] },
{ name: 'Upstash Redis', url: '/guides/functions/examples/upstash-redis', items: [] },
],
},
],
@@ -586,6 +587,7 @@ export const platform = {
{ name: 'Network Restrictions', url: '/guides/platform/network-restrictions', items: [] },
{ name: 'Performance Tuning', url: '/guides/platform/performance', items: [] },
{ name: 'Permissions', url: '/guides/platform/permissions', items: [] },
{ name: 'SSL Enforcement', url: '/guides/platform/ssl-enforcement', items: [] },
],
},
{
@@ -656,6 +658,11 @@ export const resources = {
url: '/guides/resources/migrating-to-supabase/heroku',
items: [],
},
{
name: 'Render',
url: '/guides/resources/migrating-to-supabase/render',
items: [],
},
],
},
{
@@ -718,6 +725,7 @@ export const migrate = {
{ name: 'Firestore Data', url: '/guides/migrations/firestore-data', items: [] },
{ name: 'Firebase Storage', url: '/guides/migrations/firebase-storage', items: [] },
{ name: 'Heroku', url: '/guides/migrations/heroku', items: [] },
{ name: 'Render', url: '/guides/migrations/render', items: [] },
],
}
@@ -850,14 +858,14 @@ export const reference = {
export const reference_javascript_v1 = {
icon: 'reference-javascript',
title: 'javascript',
title: 'JavaScript',
url: '/guides/reference/javascript',
parent: '/reference',
}
export const reference_javascript_v2 = {
icon: 'reference-javascript',
title: 'javascript',
title: 'JavaScript',
url: '/guides/reference/javascript',
parent: '/reference',
}
@@ -878,7 +886,7 @@ export const reference_dart_v1 = {
export const reference_csharp_v0 = {
icon: 'reference-csharp',
title: 'c#',
title: 'C#',
url: 'guides/reference/csharp',
parent: '/reference',
}
@@ -11,14 +11,12 @@ import clippyImage from '../../../public/img/clippy.png'
import { getPageType } from '~/lib/helpers'
import { useClippy } from '~/components/Clippy/ClippyProvider'
import { useFlag } from '~/hooks/useFlag'
const TopNavBarRef: FC = () => {
const { isDarkMode, toggleTheme } = useTheme()
const [mounted, setMounted] = useState(false)
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
const { open: openClippy } = useClippy()
const enableClippy = useFlag('enableClippy')
const { asPath, push } = useRouter()
const pathSegments = asPath.split('/')
@@ -91,18 +89,7 @@ const TopNavBarRef: FC = () => {
</div>
<div className="flex items-center gap-6">
{enableClippy && (
<div className="flex md:hidden cursor-pointer">
<Image
onClick={openClippy}
width={26}
height={29}
src={isDarkMode ? clippyImageDark : clippyImage}
alt="Clippy"
/>
</div>
)}
<SearchButton className="md:w-full lg:w-96">
<SearchButton className="md:w-full lg:w-96 order-2 lg:order-1">
<div
className="
flex
@@ -130,6 +117,16 @@ const TopNavBarRef: FC = () => {
</div>
</div>
</SearchButton>
<div className="flex cursor-pointer order-1 lg:order-2">
<Image
onClick={openClippy}
width={26}
height={29}
src={isDarkMode ? clippyImageDark : clippyImage}
alt="Clippy"
/>
</div>
</div>
<div className="hidden lg:flex grow items-center justify-end gap-3">
<Button
+38 -17
View File
@@ -1,172 +1,193 @@
const authProviders = [
{
name: 'Apple',
// logo: '/img/libraries/dart-icon.svg',
logo: '/docs/img/icons/apple-icon',
href: '/guides/auth/social-login/auth-apple',
official: true,
supporter: 'Supabase',
platform: true,
selfHosted: true,
authType: 'social',
},
{
name: 'Azure',
// logo: '/img/libraries/dart-icon.svg',
logo: '/docs/img/icons/microsoft-icon',
href: '/guides/auth/social-login/auth-azure',
official: false,
supporter: 'TBD',
platform: true,
selfHosted: true,
authType: 'social',
},
{
name: 'Bitbucket',
// logo: '/img/libraries/dart-icon.svg',
logo: '/docs/img/icons/bitbucket-icon',
href: '/guides/auth/social-login/auth-bitbucket',
official: true,
supporter: 'Supabase',
platform: true,
selfHosted: true,
authType: 'social',
},
{
name: 'Discord',
// logo: '/img/libraries/dart-icon.svg',
logo: '/docs/img/icons/discord-icon',
href: '/guides/auth/social-login/auth-discord',
official: true,
supporter: 'Supabase',
platform: true,
selfHosted: true,
authType: 'social',
},
{
name: 'Facebook',
// logo: '/img/libraries/dart-icon.svg',
logo: '/docs/img/icons/facebook-icon',
href: '/guides/auth/social-login/auth-facebook',
official: true,
supporter: 'Supabase',
platform: true,
selfHosted: true,
authType: 'social',
},
{
name: 'GitHub',
// logo: '/img/libraries/dart-icon.svg',
logo: '/docs/img/icons/github-icon',
href: '/guides/auth/social-login/auth-github',
official: true,
supporter: 'Supabase',
platform: true,
selfHosted: true,
authType: 'social',
},
{
name: 'GitLab',
// logo: '/img/libraries/dart-icon.svg',
logo: '/docs/img/icons/gitlab-icon',
href: '/guides/auth/social-login/auth-gitlab',
official: true,
supporter: 'Supabase',
platform: true,
selfHosted: true,
authType: 'social',
},
{
name: 'Google',
// logo: '/img/libraries/dart-icon.svg',
logo: '/docs/img/icons/google-icon',
href: '/guides/auth/social-login/auth-google',
official: true,
supporter: 'Supabase',
platform: true,
selfHosted: true,
authType: 'social',
},
{
name: 'Keycloak',
logo: '/docs/img/icons/keycloak-icon',
href: '/guides/auth/social-login/auth-keycloak',
official: true,
supporter: 'Supabase',
platform: true,
selfHosted: true,
authType: 'social',
},
{
name: 'LinkedIn',
// logo: '/img/libraries/dart-icon.svg',
logo: '/docs/img/icons/linkedin-icon',
href: '/guides/auth/social-login/auth-linkedin',
official: true,
supporter: 'Supabase',
platform: true,
selfHosted: true,
authType: 'social',
},
{
name: 'MessageBird',
// logo: '/img/libraries/dart-icon.svg',
logo: '/docs/img/icons/messagebird-icon',
href: '/guides/auth/phone-login/messagebird',
official: false,
supporter: 'MessageBird',
platform: true,
selfHosted: true,
authType: 'phone'
},
{
name: 'Notion',
// logo: '/img/libraries/notion-icon.svg',
logo: '/docs/img/icons/notion-icon',
href: '/guides/auth/social-login/auth-notion',
official: true,
supporter: 'Supabase',
platform: true,
selfHosted: true,
authType: 'social',
},
{
name: 'Slack',
// logo: '/img/libraries/dart-icon.svg',
logo: '/docs/img/icons/slack-icon',
href: '/guides/auth/social-login/auth-slack',
official: true,
supporter: 'Supabase',
platform: true,
selfHosted: true,
authType: 'social',
},
{
name: 'Spotify',
// logo: '/img/libraries/dart-icon.svg',
logo: '/docs/img/icons/spotify-icon',
href: '/guides/auth/social-login/auth-spotify',
official: true,
supporter: 'Supabase',
platform: true,
selfHosted: true,
authType: 'social',
},
{
name: 'Twitter',
// logo: '/img/libraries/dart-icon.svg',
logo: '/docs/img/icons/twitter-icon',
href: '/guides/auth/social-login/auth-twitter',
official: true,
supporter: 'Supabase',
platform: true,
selfHosted: true,
authType: 'social',
},
{
name: 'Twitch',
// logo: '/img/libraries/dart-icon.svg',
logo: '/docs/img/icons/twitch-icon',
href: '/guides/auth/social-login/auth-twitch',
official: true,
supporter: 'Supabase',
platform: true,
selfHosted: true,
authType: 'social',
},
{
name: 'Zoom',
// logo: '/img/libraries/dart-icon.svg',
logo: '/docs/img/icons/zoom-icon',
href: '/guides/auth/social-login/auth-zoom',
official: true,
supporter: 'Supabase',
platform: true,
selfHosted: true,
authType: 'social',
},
{
name: 'Twilio',
// logo: '/img/libraries/dart-icon.svg',
logo: '/docs/img/icons/twilio-icon',
href: '/guides/auth/phone-login/twilio',
official: true,
supporter: 'Supabase',
platform: true,
selfHosted: true,
authType: 'phone',
},
{
name: 'Vonage',
logo: '/docs/img/icons/vonage-icon',
href: '/guides/auth/phone-login/vonage',
official: false,
supporter: 'Supabase',
platform: true,
selfHosted: true,
authType: 'phone',
},
]
@@ -8,7 +8,7 @@ custom_edit_url: https://github.com/supabase/supabase/edit/master/spec/supabase_
import Tabs from '@theme/Tabs'
import TabItem from '@theme/TabItem'
Supabase will soon release native type generators that dump your database types for various languages. For now, we support TypeScript [through third-party tools](/docs/guides/api/generating-types).
Supabase will soon release native type generators that dump your database types for various languages. For now, we support TypeScript [through third-party tools](/docs/guides/database/api/generating-types).
## Usage with TypeScript
+1
View File
@@ -53,6 +53,7 @@ const nextConfig = {
'github.com',
'user-images.githubusercontent.com',
'raw.githubusercontent.com',
'weweb-changelog.ghost.io',
],
},
experimental: {
+34 -37
View File
@@ -10,7 +10,6 @@ import { SearchProvider } from '~/components/DocSearch'
import Favicons from '~/components/Favicons'
import SiteLayout from '~/layouts/SiteLayout'
import { post } from '~/lib/fetchWrappers'
import FlagProvider from 'components/Flag/FlagProvider'
import '../styles/algolia-search.scss'
import '../styles/ch.scss'
import '../styles/docsearch.scss'
@@ -63,42 +62,40 @@ function MyApp({ Component, pageProps }: AppPropsWithLayout) {
return (
<>
<FlagProvider>
<Favicons />
<DefaultSeo
title={SITE_TITLE}
description={SITE_DESCRIPTION}
openGraph={{
type: 'website',
url: 'https://supabase.com/docs',
site_name: SITE_TITLE,
images: [
{
url: `https://supabase.com${basePath}/img/supabase-og-image.png`,
width: 800,
height: 600,
alt: 'Supabase Og Image',
},
],
}}
twitter={{
handle: '@supabase',
site: '@supabase',
cardType: 'summary_large_image',
}}
/>
<SessionContextProvider supabaseClient={supabase}>
<ThemeProvider>
<SearchProvider>
<ClippyProvider>
<SiteLayout>
<Component {...pageProps} />
</SiteLayout>
</ClippyProvider>
</SearchProvider>
</ThemeProvider>
</SessionContextProvider>
</FlagProvider>
<Favicons />
<DefaultSeo
title={SITE_TITLE}
description={SITE_DESCRIPTION}
openGraph={{
type: 'website',
url: 'https://supabase.com/docs',
site_name: SITE_TITLE,
images: [
{
url: `https://supabase.com${basePath}/img/supabase-og-image.png`,
width: 800,
height: 600,
alt: 'Supabase Og Image',
},
],
}}
twitter={{
handle: '@supabase',
site: '@supabase',
cardType: 'summary_large_image',
}}
/>
<SessionContextProvider supabaseClient={supabase}>
<ThemeProvider>
<SearchProvider>
<ClippyProvider>
<SiteLayout>
<Component {...pageProps} />
</SiteLayout>
</ClippyProvider>
</SearchProvider>
</ThemeProvider>
</SessionContextProvider>
</>
)
}
@@ -109,6 +109,8 @@ This will be used any time we need to create a Supabase client _server-side_ - i
Next, we need a middleware file to refresh the user's session on navigation.
> If you were using Middleware prior to 12.2, see the [upgrade guide](https://nextjs.org/docs/messages/middleware-upgrade-guide).
<Tabs
scrollable
size="small"
@@ -117,7 +119,7 @@ Next, we need a middleware file to refresh the user's session on navigation.
>
<TabPanel id="js" label="JavaScript">
Create a new `/app/middleware.js` file and populate with the following:
Create a new `middleware.js` file at the same level as your `app` (in the root or `src` directory) and populate with the following:
```jsx title="middleware.js"
import { createMiddlewareSupabaseClient } from '@supabase/auth-helpers-nextjs'
@@ -140,7 +142,7 @@ export async function middleware(req) {
<TabPanel id="ts" label="TypeScript">
Create a new `/app/middleware.ts` file and populate with the following:
Create a new `middleware.ts` file at the same level as your `app` (in the root or `src` directory) and populate with the following:
```tsx title="middleware.ts"
import { createMiddlewareSupabaseClient } from '@supabase/auth-helpers-nextjs'
@@ -257,7 +257,7 @@ Wrap an Action to check that the user has a valid session. If they're not logged
```ts title=src/routes/posts/+page.server.ts
import type { Actions } from './$types'
import { getSupabase } from '@supabase/auth-helpers-sveltekit'
import { error, invalid } from '@sveltejs/kit'
import { error, fail } from '@sveltejs/kit'
export const actions: Actions = {
createPost: async (event) => {
@@ -276,7 +276,7 @@ export const actions: Actions = {
.insert({ content })
if (createPostError) {
return invalid(500, {
return fail(500, {
supabaseErrorMessage: createPostError.message,
})
}
@@ -293,7 +293,7 @@ If you try to submit a form with the action `?/createPost` without a valid sessi
```ts
import type { Actions } from './$types'
import { invalid, redirect } from '@sveltejs/kit'
import { fail, redirect } from '@sveltejs/kit'
import { getSupabase } from '@supabase/auth-helpers-sveltekit'
import { AuthApiError } from '@supabase/supabase-js'
@@ -313,14 +313,14 @@ export const actions: Actions = {
if (error) {
if (error instanceof AuthApiError && error.status === 400) {
return invalid(400, {
return fail(400, {
error: 'Invalid credentials.',
values: {
email,
},
})
}
return invalid(500, {
return fail(500, {
error: 'Server error. Try again later.',
values: {
email,
+9 -1
View File
@@ -44,8 +44,16 @@ You can authenticate your users in several ways:
We provide a suite of Providers and login methods, as well as [Auth helpers](/docs/guides/auth/auth-helpers/).
#### Social Auth
<div className="container" style={{ padding: 0 }}>
<AuthProviders />
<AuthProviders type="social" />
</div>
#### Phone Auth
<div className="container" style={{ padding: 0 }}>
<AuthProviders type="phone" />
</div>
### Configure third-party providers
@@ -209,12 +209,12 @@ curl '<SUPABASE_URL>/rest/v1/todos' \
</TabPanel>
</Tabs>
JS Reference: [select()](../reference/javascript/select),
[insert()](../reference/javascript/insert),
[update()](../reference/javascript/update),
[upsert()](../reference/javascript/upsert),
[delete()](../reference/javascript/delete),
[rpc()](../reference/javascript/rpc) (call Postgres functions).
JS Reference: [select()](/reference/javascript/select),
[insert()](/reference/javascript/insert),
[update()](/reference/javascript/update),
[upsert()](/reference/javascript/upsert),
[delete()](/reference/javascript/delete),
[rpc()](/reference/javascript/rpc) (call Postgres functions).
### GraphQL API
@@ -28,15 +28,15 @@ You can use these simple questions to determine which connection method to use:
## API
Supabase provides an auto-updating [API](/docs/guides/api). This is the easiest way to get started if you are managing data (fetching, inserting, updating).
Supabase provides an auto-updating [API](/docs/guides/database/api). This is the easiest way to get started if you are managing data (fetching, inserting, updating).
### Interfaces
We provides several types of API to suit your preferences and use-case:
- [REST](/docs/guides/api#rest-api): interact with your database through a REST interface.
- [GraphQL](/docs/guides/api#graphql-api): interact with your database through a GraphQL interface.
- [Realtime](/docs/guides/api#realtime-api): listen to database changes over websockets.
- [REST](/docs/guides/database/api#rest-api): interact with your database through a REST interface.
- [GraphQL](/docs/guides/database/api#graphql-api): interact with your database through a GraphQL interface.
- [Realtime](/docs/guides/database/api#realtime-api): listen to database changes over websockets.
You cannot manage the database schema via the API (for security reasons). To do that you can use the dashboard or connect directly to your database.
+1 -1
View File
@@ -172,7 +172,7 @@ create table movies (
## Loading data
There are several ways to load data in Supabase. You can load data directly into the database or using the [APIs](../../guides/api).
There are several ways to load data in Supabase. You can load data directly into the database or using the [APIs](../../guides/database/api).
Use the "Bulk Loading" instructions if you are loading large data sets.
### Basic data loading
@@ -0,0 +1,90 @@
import Layout from '~/layouts/DefaultGuideLayout'
export const meta = {
title: 'Upstash Redis',
description: 'Build an Edge Functions Counter with Upstash Redis.',
}
A Redis counter example that stores a [hash](https://redis.io/commands/hincrby/) of function invocation count per region.
## Redis database setup
Create a Redis database using the [Upstash Console](https://console.upstash.com/) or [Upstash CLI](https://github.com/upstash/cli).
Select the `Global` type to minimize the latency from all edge locations. Copy the `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN` to your .env file.
You'll find them under **Details > REST API > .env**.
```bash
cp supabase/functions/upstash-redis-counter/.env.example supabase/functions/upstash-redis-counter/.env
```
## Code
Make sure you have the latest version of the [Supabase CLI installed](/docs/guides/cli#installation).
Create a new function in your project:
```bash
supabase functions new upstash-redis-counter
```
And add the code to the `index.ts` file:
```ts index.ts
import { serve } from 'https://deno.land/std@0.177.0/http/server.ts'
import { Redis } from 'https://deno.land/x/upstash_redis@v1.19.3/mod.ts'
console.log(`Function "upstash-redis-counter" up and running!`)
serve(async (_req) => {
try {
const redis = new Redis({
url: Deno.env.get('UPSTASH_REDIS_REST_URL')!,
token: Deno.env.get('UPSTASH_REDIS_REST_TOKEN')!,
})
const deno_region = Deno.env.get('DENO_REGION')
if (deno_region) {
// Increment region counter
await redis.hincrby('supa-edge-counter', deno_region, 1)
} else {
// Increment localhost counter
await redis.hincrby('supa-edge-counter', 'localhost', 1)
}
// Get all values
const counterHash: Record<string, number> | null = await redis.hgetall('supa-edge-counter')
const counters = Object.entries(counterHash!)
.sort(([, a], [, b]) => b - a) // sort desc
.reduce((r, [k, v]) => ({ total: r.total + v, regions: { ...r.regions, [k]: v } }), {
total: 0,
regions: {},
})
return new Response(JSON.stringify({ counters }), { status: 200 })
} catch (error) {
return new Response(JSON.stringify({ error: error.message }), { status: 200 })
}
})
```
## Run locally
```bash
supabase start
supabase functions serve upstash-redis-counter --no-verify-jwt --env-file supabase/functions/upstash-redis-counter/.env
```
Navigate to http://localhost:54321/functions/v1/upstash-redis-counter.
## Deploy
```bash
supabase functions deploy upstash-redis-counter --no-verify-jwt
supabase secrets set --env-file supabase/functions/upstash-redis-counter/.env
```
export const Page = ({ children }) => <Layout meta={meta} children={children} />
export default Page
@@ -127,7 +127,7 @@ Edge Functions supports `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, and `OPTIONS`.
- Deno Deploy limitations
- Deno does not support outgoing connections to ports `25`, `465`, and `587`.
- Cannot write to File System
- Cannot read or write to File System
- Edge Functions
- Local development - only one function at a time
- Serving of HTML content is not supported (`GET` requests that return `text/html` will be rewritten to `text/plain`).
@@ -6,6 +6,15 @@ export const meta = {
description: 'Schedule Edge Functions with pg_cron.',
}
<div class="video-container">
<iframe
src="https://www.youtube-nocookie.com/embed/-U6DJcjVvGo"
frameBorder="1"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
></iframe>
</div>
The hosted Supabase Platform supports the [`pg_cron` extension](/docs/guides/database/extensions/pgcron), a simple cron-based job scheduler for PostgreSQL that runs inside the database.
In combination with the [`pg_net` extension](/docs/guides/database/extensions/pgnet), this allows us to invoke Edge Functions periodically on a set schedule.
+60 -1
View File
@@ -36,7 +36,23 @@ export const meta = {
</div>
### Tutorials
### Framework Quickstarts
<div className="grid lg:grid-cols-12 gap-6 not-prose">
{quickstarts.map((item) => {
return (
<Link href={`/${item.href}`} key={item.title} passHref>
<a className={'col-span-4'}>
<GlassPanel title={item.title} span="col-span-6" background={false} icon={item.icon}>
{item.description}
</GlassPanel>
</a>
</Link>
)
})}
</div>
### Web App Tutorials
<div className="grid lg:grid-cols-12 gap-6 not-prose">
{webapps.map((item) => {
@@ -52,6 +68,46 @@ export const meta = {
})}
</div>
### Mobile Tutorials
<div className="grid lg:grid-cols-12 gap-6 not-prose">
{mobile.map((item) => {
return (
<Link href={`/${item.href}`} key={item.title} passHref>
<a className={'col-span-4'}>
<GlassPanel title={item.title} span="col-span-6" background={false} icon={item.icon}>
{item.description}
</GlassPanel>
</a>
</Link>
)
})}
</div>
export const quickstarts = [
{
title: 'React',
href: '/guides/getting-started/quickstarts/reactjs',
description:
'Learn how to create a Supabase project, add some sample data to your database, and query the data from a React app.',
icon: '/docs/img/icons/react-icon',
},
{
title: 'NextJS',
href: '/guides/getting-started/quickstarts/nextjs',
description:
'Learn how to create a Supabase project, add some sample data to your database, and query the data from a NextJS app.',
icon: '/docs/img/icons/nextjs-icon',
},
{
title: 'Flutter',
href: '/guides/getting-started/quickstarts/flutter',
description:
'Learn how to create a Supabase project, add some sample data to your database, and query the data from a Flutter app.',
icon: '/docs/img/icons/flutter-icon',
},
]
export const webapps = [
{
title: 'NextJS',
@@ -109,6 +165,9 @@ export const webapps = [
'Learn how to build a user management app with SvelteKit and Supabase Database, Auth, and Storage functionality.',
icon: '/docs/img/icons/svelte-icon',
},
]
export const mobile = [
{
title: 'Flutter',
href: '/guides/getting-started/tutorials/with-flutter',
@@ -84,11 +84,11 @@ Build login and registration pages with custom themes. [Docs](/docs/guides/auth/
### Auto-generated REST API
RESTful APIs are autogenerated from your database, without a single line of code. [Docs](/docs/guides/api#rest-api-overview).
RESTful APIs are autogenerated from your database, without a single line of code. [Docs](/docs/guides/database/api#rest-api-overview).
### Auto-generated GraphQL API
Fast GraphQL APIs using our custom Postgres GraphQL extension. [Docs](/docs/guides/api#graphql-api-overview).
Fast GraphQL APIs using our custom Postgres GraphQL extension. [Docs](/docs/guides/database/api#graphql-api-overview).
### Realtime Database changes
@@ -67,7 +67,7 @@ export const meta = {
<StepHikeCompact.Code>
```bash Terminal
cd my-app && npm install @supabase/supabase-js
cd myapp && npm install @supabase/supabase-js
```
</StepHikeCompact.Code>
@@ -1,19 +1,18 @@
import Layout from '~/layouts/DefaultGuideLayout'
export const meta = {
id: 'with-angular',
title: 'Quickstart: Angular',
title: 'Build a User Management App with Angular',
description: 'Learn how to use Supabase in your Angular App.',
sidebar_label: 'Angular',
}
<QuickstartIntro />
![Supabase User Management example](/docs/img/user-management-demo.png)
### GitHub
Should you get stuck while working through the guide, refer to [this repo](https://github.com/supabase/supabase/tree/master/examples/user-management/angular-user-management).
<Admonition type="note">
If you get stuck while working through this guide, refer to the [full example on
GitHub](https://github.com/supabase/supabase/tree/master/examples/user-management/angular-user-management).
</Admonition>
<ProjectSetup />
@@ -192,11 +191,7 @@ export class AuthComponent {
/>
</div>
<div>
<button
type="submit"
class="button block"
[disabled]="loading"
>
<button type="submit" class="button block" [disabled]="loading">
{{ loading ? 'Loading' : 'Send magic link' }}
</button>
</div>
@@ -529,13 +524,8 @@ export class AccountComponent implements OnInit {
<StorageManagement />
## Next steps
At this stage you have a fully functional application!
- Got a question? [Ask here](https://github.com/supabase/supabase/discussions).
- Sign in: [app.supabase.com](https://app.supabase.com)
export const Page = ({ children }) => <Layout meta={meta} children={children} />
export default Page
@@ -1,20 +1,18 @@
import Layout from '~/layouts/DefaultGuideLayout'
export const meta = {
id: 'with-expo',
title: 'Quickstart: Expo',
title: 'Build a User Management App with Expo',
description: 'Learn how to use Supabase in your React Native App.',
sidebar_label: 'Expo',
hide_table_of_contents: false,
}
<QuickstartIntro />
![Supabase User Management example](/docs/img/supabase-flutter-demo.png)
### GitHub
Should you get stuck while working through the guide, refer to [this repo](https://github.com/supabase/supabase/tree/master/examples/user-management/expo-user-management).
<Admonition type="note">
If you get stuck while working through this guide, refer to the [full example on
GitHub](https://github.com/supabase/supabase/tree/master/examples/user-management/expo-user-management).
</Admonition>
<ProjectSetup />
@@ -504,13 +502,8 @@ expo prebuild
<StorageManagement />
## Next steps
At this stage you have a fully functional application!
- Got a question? [Ask here](https://github.com/supabase/supabase/discussions).
- Sign in: [app.supabase.com](https://app.supabase.com)
export const Page = ({ children }) => <Layout meta={meta} children={children} />
export default Page
@@ -1,19 +1,18 @@
import Layout from '~/layouts/DefaultGuideLayout'
export const meta = {
id: 'with-flutter',
title: 'Quickstart: Flutter',
title: 'Build a User Management App with Flutter',
description: 'Learn how to use Supabase in your Flutter App.',
sidebar_label: 'Flutter',
}
<QuickstartIntro />
![Supabase User Management example](/docs/img/supabase-flutter-demo.png)
### GitHub
Should you get stuck while working through the guide, refer to [this repo](https://github.com/supabase/supabase/tree/master/examples/user-management/flutter-user-management).
<Admonition type="note">
If you get stuck while working through this guide, refer to the [full example on
GitHub](https://github.com/supabase/supabase/tree/master/examples/user-management/flutter-user-management).
</Admonition>
<ProjectSetup />
@@ -77,7 +76,7 @@ Add an intent-filter to enable deep linking:
</manifest>
```
For iOS, edit the ios/Runner/Info.plist file.
For iOS, edit the ios/Runner/Info.plist file.
Add CFBundleURLTypes to enable deep linking:
@@ -797,14 +796,13 @@ class _AccountPageState extends State<AccountPage> {
<StorageManagement />
Congratulations, that is it! You have now built a fully functional user management app using Flutter and Supabase!
Congratulations, you've built a fully functional user management app using Flutter and Supabase!
## See also
- [Flutter Tutorial: building a Flutter chat app](https://supabase.com/blog/flutter-tutorial-building-a-chat-app)
- [Flutter Tutorial - Part 2: Authentication and Authorization with RLS](https://supabase.com/blog/flutter-authentication-and-authorization-with-rls)
export const Page = ({ children }) => <Layout meta={meta} children={children} />
export default Page
@@ -1,19 +1,18 @@
import Layout from '~/layouts/DefaultGuideLayout'
export const meta = {
id: 'with-ionic-angular',
title: 'Quickstart: Ionic Angular',
title: 'Build a User Management App with Ionic Angular',
description: 'Learn how to use Supabase in your Ionic Angular App.',
sidebar_label: 'Ionic Angular',
}
<QuickstartIntro />
![Supabase User Management example](/docs/img/ionic-demos/ionic-angular-account.png)
### GitHub
Should you get stuck while working through the guide, refer to [this repo](https://github.com/mhartington/supabase-ionic-angular).
<Admonition type="note">
If you get stuck while working through this guide, refer to the [full example on
GitHub](https://github.com/mhartington/supabase-ionic-angular).
</Admonition>
<ProjectSetup />
@@ -526,14 +525,9 @@ template: `
<StorageManagement />
## Next steps
At this stage you have a fully functional application!
- Got a question? [Ask here](https://github.com/supabase/supabase/discussions).
- Sign in: [app.supabase.com](https://app.supabase.com)
## Resources
## See also
- [Authentication in Ionic Angular with Supabase](https://supabase.com/blog/authentication-in-ionic-angular)
@@ -1,19 +1,18 @@
import Layout from '~/layouts/DefaultGuideLayout'
export const meta = {
id: 'with-ionic-react',
title: 'Quickstart: Ionic React',
title: 'Build a User Management App with Ionic React',
description: 'Learn how to use Supabase in your Ionic React App.',
sidebar_label: 'Ionic React',
}
<QuickstartIntro />
![Supabase User Management example](/docs/img/ionic-demos/ionic-angular-account.png)
### GitHub
Should you get stuck while working through the guide, refer to [this repo](https://github.com/mhartington/supabase-ionic-react).
<Admonition type="note">
If you get stuck while working through this guide, refer to the [full example on
GitHub](https://github.com/mhartington/supabase-ionic-react).
</Admonition>
<ProjectSetup />
@@ -499,13 +498,8 @@ return (
<StorageManagement />
## Next steps
At this stage you have a fully functional application!
- Got a question? [Ask here](https://github.com/supabase/supabase/discussions).
- Sign in: [app.supabase.com](https://app.supabase.com)
export const Page = ({ children }) => <Layout meta={meta} children={children} />
export default Page
@@ -1,19 +1,18 @@
import Layout from '~/layouts/DefaultGuideLayout'
export const meta = {
id: 'with-ionic-vue',
title: 'Quickstart: Ionic Vue',
title: 'Build a User Management App with Ionic Vue',
description: 'Learn how to use Supabase in your Ionic Vue App.',
sidebar_label: 'Ionic Vue',
}
<QuickstartIntro />
![Supabase User Management example](/docs/img/ionic-demos/ionic-angular-account.png)
### GitHub
Should you get stuck while working through the guide, refer to [this repo](https://github.com/mhartington/supabase-ionic-vue).
<Admonition type="note">
If you get stuck while working through this guide, refer to the [full example on
GitHub](https://github.com/mhartington/supabase-ionic-vue).
</Admonition>
<ProjectSetup />
@@ -559,13 +558,8 @@ export default defineComponent({
<StorageManagement />
## Next steps
At this stage you have a fully functional application!
- Got a question? [Ask here](https://github.com/supabase/supabase/discussions).
- Sign in: [app.supabase.com](https://app.supabase.com)
export const Page = ({ children }) => <Layout meta={meta} children={children} />
export default Page
@@ -1,10 +1,8 @@
import Layout from '~/layouts/DefaultGuideLayout'
export const meta = {
id: 'with-nextjs',
title: 'Quickstart: Next.js',
title: 'Build a User Management App with NextJS',
description: 'Learn how to use Supabase in your Next App.',
sidebar_label: 'Next.js',
video: 'https://www.youtube.com/v/0Fs96oZ4se0',
}
@@ -12,7 +10,7 @@ export const meta = {
![Supabase User Management example](/docs/img/user-management-demo.png)
### Video Guide
## Video Guide
<div class="video-container">
<iframe
@@ -23,9 +21,10 @@ export const meta = {
></iframe>
</div>
### GitHub
Should you get stuck while working through the guide, refer to [this repo](https://github.com/supabase/supabase/tree/master/examples/user-management/nextjs-ts-user-management).
<Admonition type="note">
If you get stuck while working through this guide, refer to the [full example on
GitHub](https://github.com/supabase/supabase/tree/master/examples/user-management/nextjs-ts-user-management).
</Admonition>
<ProjectSetup />
@@ -723,17 +722,15 @@ return (
<StorageManagement />
## Next steps
At this stage you have a fully functional application!
- See the complete [example on GitHub](https://github.com/supabase/supabase/tree/master/examples/user-management/nextjs-ts-user-management) and deploy it to Vercel.
- Explore the [pre-built Auth UI for React](/docs/guides/auth/auth-helpers/auth-ui).
- Explore the [Auth Helpers for Next.js](/docs/guides/auth/auth-helpers/nextjs).
- Explore the [Supabase Cache Helpers](https://github.com/psteinroe/supabase-cache-helpers).
- See the [Next.js Subscription Payments Starter](https://github.com/vercel/nextjs-subscription-payments) template on GitHub.
- Got a question? [Ask here](https://github.com/supabase/supabase/discussions).
- Sign in: [app.supabase.com](https://app.supabase.com)
## See also
- See the complete [example on GitHub](https://github.com/supabase/supabase/tree/master/examples/user-management/nextjs-ts-user-management) and deploy it to Vercel
- Explore the [pre-built Auth UI for React](/docs/guides/auth/auth-helpers/auth-ui)
- Explore the [Auth Helpers for Next.js](/docs/guides/auth/auth-helpers/nextjs)
- Explore the [Supabase Cache Helpers](https://github.com/psteinroe/supabase-cache-helpers)
- See the [Next.js Subscription Payments Starter](https://github.com/vercel/nextjs-subscription-payments) template on GitHub
export const Page = ({ children }) => <Layout meta={meta} children={children} />
@@ -1,19 +1,18 @@
import Layout from '~/layouts/DefaultGuideLayout'
export const meta = {
id: 'with-nuxt-3',
title: 'Quickstart: Nuxt 3',
title: 'Build a User Management App with Nuxt 3',
description: 'Learn how to use Supabase in your Nuxt 3 App.',
sidebar_label: 'Nuxt 3',
}
<QuickstartIntro />
![Supabase User Management example](/docs/img/user-management-demo.png)
### Github
Should you get stuck while working through the guide, refer to [this repo](https://github.com/supabase/supabase/tree/master/examples/user-management/nuxt3-user-management).
<Admonition type="note">
If you get stuck while working through this guide, refer to the [full example on
GitHub](https://github.com/supabase/supabase/tree/master/examples/user-management/nuxt3-user-management).
</Admonition>
<ProjectSetup />
@@ -66,7 +65,27 @@ export default defineNuxtConfig({
Let's set up a Vue component to manage logins and sign ups. We'll use Magic Links, so users can sign in with their email without using passwords.
```html title=/components/Auth.vue
```vue title=/components/Auth.vue
<script setup>
const supabase = useSupabaseClient()
const loading = ref(false)
const email = ref('')
const handleLogin = async () => {
try {
loading.value = true
const { error } = await supabase.auth.signInWithOtp({ email: email.value })
if (error) throw error
alert('Check your email for the login link!')
} catch (error) {
alert(error.error_description || error.message)
} finally {
loading.value = false
}
}
</script>
<template>
<form class="row flex-center flex" @submit.prevent="handleLogin">
<div class="col-6 form-widget">
@@ -86,25 +105,6 @@ Let's set up a Vue component to manage logins and sign ups. We'll use Magic Link
</div>
</form>
</template>
<script setup>
const supabase = useSupabaseClient()
const loading = ref(false)
const email = ref('')
const handleLogin = async () => {
try {
loading.value = true
const { error } = await supabase.auth.signInWithOtp({ email: email.value })
if (error) throw error
alert('Check your email for the login link!')
} catch (error) {
alert(error.error_description || error.message)
} finally {
loading.value = false
}
}
</script>
```
### User state
@@ -116,7 +116,70 @@ To access the user information, use the composable [useSupabaseUser](https://sup
After a user is signed in we can allow them to edit their profile details and manage their account.
Let's create a new component for that called `Account.vue`.
```html title=components/Account.vue
```vue title=components/Account.vue
<script setup>
const supabase = useSupabaseClient()
const loading = ref(true)
const username = ref('')
const website = ref('')
const avatar_path = ref('')
loading.value = true
const user = useSupabaseUser()
let { data } = await supabase
.from('profiles')
.select(`username, website, avatar_url`)
.eq('id', user.value.id)
.single()
if (data) {
username.value = data.username
website.value = data.website
avatar_path.value = data.avatar_url
}
loading.value = false
async function updateProfile() {
try {
loading.value = true
const user = useSupabaseUser()
const updates = {
id: user.value.id,
username: username.value,
website: website.value,
avatar_url: avatar_path.value,
updated_at: new Date(),
}
let { error } = await supabase.from('profiles').upsert(updates, {
returning: 'minimal', // Don't return the value after inserting
})
if (error) throw error
} catch (error) {
alert(error.message)
} finally {
loading.value = false
}
}
async function signOut() {
try {
loading.value = true
let { error } = await supabase.auth.signOut()
if (error) throw error
user.value = null
} catch (error) {
alert(error.message)
} finally {
loading.value = false
}
}
</script>
<template>
<form class="form-widget" @submit.prevent="updateProfile">
<div>
@@ -146,82 +209,23 @@ Let's create a new component for that called `Account.vue`.
</div>
</form>
</template>
<script setup>
const supabase = useSupabaseClient()
const loading = ref(true)
const username = ref('')
const website = ref('')
const avatar_path = ref('')
loading.value = true
const user = useSupabaseUser();
let { data } = await supabase
.from('profiles')
.select(`username, website, avatar_url`)
.eq('id', user.value.id)
.single()
if (data) {
username.value = data.username
website.value = data.website
avatar_path.value = data.avatar_url
}
loading.value = false
async function updateProfile() {
try {
loading.value = true
const user = useSupabaseUser();
const updates = {
id: user.value.id,
username: username.value,
website: website.value,
avatar_url: avatar_path.value,
updated_at: new Date(),
}
let { error } = await supabase.from('profiles').upsert(updates, {
returning: 'minimal', // Don't return the value after inserting
})
if (error) throw error
} catch (error) {
alert(error.message)
} finally {
loading.value = false
}
}
async function signOut() {
try {
loading.value = true
let { error } = await supabase.auth.signOut()
if (error) throw error
user.value = null
} catch (error) {
alert(error.message)
} finally {
loading.value = false
}
}
</script>
```
### Launch!
Now that we have all the components in place, let's update `app.vue`:
```html title=app.vue
```vue title=app.vue
<script setup>
const user = useSupabaseUser()
</script>
<template>
<div class="container" style="padding: 50px 0 100px 0">
<Account v-if="user" />
<Auth v-else />
</div>
</template>
<script setup>
const user = useSupabaseUser()
</script>
```
Once that's done, run this in a terminal window:
@@ -242,7 +246,65 @@ Every Supabase project is configured with [Storage](/docs/guides/storage) for ma
Let's create an avatar for the user so that they can upload a profile photo. We can start by creating a new component:
```html title=components/Avatar.vue
```vue title=components/Avatar.vue
<script setup>
const props = defineProps(['path'])
const { path } = toRefs(props)
const emit = defineEmits(['update:path', 'upload'])
const supabase = useSupabaseClient()
const uploading = ref(false)
const src = ref('')
const files = ref()
const downloadImage = async () => {
try {
const { data, error } = await supabase.storage.from('avatars').download(path.value)
if (error) throw error
src.value = URL.createObjectURL(data)
} catch (error) {
console.error('Error downloading image: ', error.message)
}
}
const uploadAvatar = async (evt) => {
files.value = evt.target.files
try {
uploading.value = true
if (!files.value || files.value.length === 0) {
throw new Error('You must select an image to upload.')
}
const file = files.value[0]
const fileExt = file.name.split('.').pop()
const fileName = `${Math.random()}.${fileExt}`
const filePath = `${fileName}`
let { error: uploadError } = await supabase.storage.from('avatars').upload(filePath, file)
if (uploadError) throw uploadError
emit('update:path', filePath)
emit('upload')
} catch (error) {
alert(error.message)
} finally {
uploading.value = false
}
}
downloadImage()
watch(path, () => {
if (path.value) {
downloadImage()
}
})
</script>
<template>
<div>
<img
@@ -256,7 +318,7 @@ Let's create an avatar for the user so that they can upload a profile photo. We
<div style="width: 10em; position: relative;">
<label class="button primary block" for="single">
{{ uploading ? "Uploading ..." : "Upload" }}
{{ uploading ? 'Uploading ...' : 'Upload' }}
</label>
<input
style="position: absolute; visibility: hidden;"
@@ -269,65 +331,76 @@ Let's create an avatar for the user so that they can upload a profile photo. We
</div>
</div>
</template>
<script setup>
const props = defineProps(['path'])
const { path } = toRefs(props)
const emit = defineEmits(['update:path', 'upload'])
const supabase = useSupabaseClient()
const uploading = ref(false)
const src = ref('')
const files = ref()
const downloadImage = async () => {
try {
const { data, error } = await supabase.storage.from('avatars').download(path.value)
if (error) throw error
src.value = URL.createObjectURL(data)
} catch (error) {
console.error('Error downloading image: ', error.message)
}
}
const uploadAvatar = async (evt) => {
files.value = evt.target.files
try {
uploading.value = true
if (!files.value || files.value.length === 0) {
throw new Error('You must select an image to upload.')
}
const file = files.value[0]
const fileExt = file.name.split('.').pop()
const fileName = `${Math.random()}.${fileExt}`
const filePath = `${fileName}`
let { error: uploadError } = await supabase.storage.from('avatars').upload(filePath, file)
if (uploadError) throw uploadError
emit('update:path', filePath)
emit('upload')
} catch (error) {
alert(error.message)
} finally {
uploading.value = false
}
}
downloadImage()
watch(path, () => {
if (path.value) {
downloadImage()
}
})
</script>
```
### Add the new widget
And then we can add the widget to the Account page:
```html title=components/Account.vue
```vue title=components/Account.vue
<script setup>
const supabase = useSupabaseClient()
const loading = ref(true)
const username = ref('')
const website = ref('')
const avatar_path = ref('')
loading.value = true
const user = useSupabaseUser()
let { data } = await supabase
.from('profiles')
.select(`username, website, avatar_url`)
.eq('id', user.value.id)
.single()
if (data) {
username.value = data.username
website.value = data.website
avatar_path.value = data.avatar_url
}
loading.value = false
async function updateProfile() {
try {
loading.value = true
const user = useSupabaseUser()
const updates = {
id: user.value.id,
username: username.value,
website: website.value,
avatar_url: avatar_path.value,
updated_at: new Date(),
}
let { error } = await supabase.from('profiles').upsert(updates, {
returning: 'minimal', // Don't return the value after inserting
})
if (error) throw error
} catch (error) {
alert(error.message)
} finally {
loading.value = false
}
}
async function signOut() {
try {
loading.value = true
let { error } = await supabase.auth.signOut()
if (error) throw error
} catch (error) {
alert(error.message)
} finally {
loading.value = false
}
}
</script>
<template>
<form class="form-widget" @submit.prevent="updateProfile">
<Avatar v-model:path="avatar_path" @upload="updateProfile" />
@@ -358,78 +431,13 @@ And then we can add the widget to the Account page:
</div>
</form>
</template>
<script setup>
const supabase = useSupabaseClient()
const loading = ref(true)
const username = ref('')
const website = ref('')
const avatar_path = ref('')
loading.value = true
const user = useSupabaseUser();
let { data } = await supabase
.from('profiles')
.select(`username, website, avatar_url`)
.eq('id', user.value.id)
.single()
if (data) {
username.value = data.username
website.value = data.website
avatar_path.value = data.avatar_url
}
loading.value = false
async function updateProfile() {
try {
loading.value = true
const user = useSupabaseUser();
const updates = {
id: user.value.id,
username: username.value,
website: website.value,
avatar_url: avatar_path.value,
updated_at: new Date(),
}
let { error } = await supabase.from('profiles').upsert(updates, {
returning: 'minimal', // Don't return the value after inserting
})
if (error) throw error
} catch (error) {
alert(error.message)
} finally {
loading.value = false
}
}
async function signOut() {
try {
loading.value = true
let { error } = await supabase.auth.signOut()
if (error) throw error
} catch (error) {
alert(error.message)
} finally {
loading.value = false
}
}
</script>
```
That is it! You should now be able to upload a profile photo to Supabase Storage.
### Storage management
<StorageManagement />
## Next steps
At this stage you have a fully functional application!
- Got a question? [Ask here](https://github.com/supabase/supabase/discussions).
- Sign in: [app.supabase.com](https://app.supabase.com)
That is it! You should now be able to upload a profile photo to Supabase Storage and you have a fully functional application.
export const Page = ({ children }) => <Layout meta={meta} children={children} />
@@ -1,19 +1,18 @@
import Layout from '~/layouts/DefaultGuideLayout'
export const meta = {
id: 'with-react',
title: 'Quickstart: React',
title: 'Build a User Management App with React',
description: 'Learn how to use Supabase in your React App.',
sidebar_label: 'React',
}
<QuickstartIntro />
![Supabase User Management example](/docs/img/user-management-demo.png)
### GitHub
Should you get stuck while working through the guide, refer to [this repo](https://github.com/supabase/supabase/tree/master/examples/user-management/react-user-management).
<Admonition type="note">
If you get stuck while working through this guide, refer to the [full example on
GitHub](https://github.com/supabase/supabase/tree/master/examples/user-management/react-user-management).
</Admonition>
<ProjectSetup />
@@ -401,13 +400,8 @@ return (
<StorageManagement />
## Next steps
At this stage you have a fully functional application!
- Got a question? [Ask here](https://github.com/supabase/supabase/discussions).
- Sign in: [app.supabase.com](https://app.supabase.com)
export const Page = ({ children }) => <Layout meta={meta} children={children} />
export default Page
@@ -1,49 +1,19 @@
import Layout from '~/layouts/DefaultGuideLayout'
export const meta = {
id: 'with-redwoodjs',
title: 'Quickstart: RedwoodJS',
title: 'Build a User Management App with RedwoodJS',
description: 'Learn how to use Supabase in your RedwoodJS App.',
sidebar_label: 'RedwoodJS',
}
## Intro
For the sake of consistency with the other framework Quickstart examples, we'll build a RedwoodJS a little differently than normal.
We **_won't use_** Prisma to connect to the Supabase Postgres database or [Prisma migrations](https://redwoodjs.com/docs/cli-commands#prisma-migrate) as one typically might in a Redwood app.
Instead, we'll rely on the Supabase client to do some of the work on the **web** side and use the client again on the **API** side to do data fetching as well.
That means you will want to refrain from running any `yarn rw prisma migrate` commands and also double check your build commands on deployment to ensure Prisma won't reset your database.
<Admonition type="note">
TLDR; Prisma currently doesn't support cross-schema foreign keys, so introspecting the schema fails due to how your Supabase `public` schema references the `auth.users`.
</Admonition>
This example provides the steps to build a simple user management app (from scratch!) using Supabase and [RedwoodJS](https://redwoodjs.com/docs/introduction). It includes:
- Supabase [Database](/docs/guides/database): a Postgres database for storing your user data.
- Supabase [Auth](/docs/guides/auth): users can sign in with magic links (no passwords, only email).
- Supabase [Storage](/docs/guides/storage): users can upload a photo.
- Instant [APIs](/docs/guides/api): APIs will be automatically generated when you create your database tables.
- [Row Level Security](/docs/guides/auth#row-level-security): data is protected so that individuals can only access their own data.
By the end of this guide you'll have an app which allows users to login and update some basic profile details:
<QuickstartIntro />
![Supabase User Management example](/docs/img/user-management-demo.png)
<Admonition type="note">
Note: For RedwoodJS apps, port will be 8910
If you get stuck while working through this guide, refer to the [full example on
GitHub](https://github.com/redwoodjs/redwoodjs-supabase-quickstart).
</Admonition>
### GitHub
If you get stuck at any point, take a look at [this repo](https://github.com/redwoodjs/redwoodjs-supabase-quickstart).
{/* ## Video demo */}
{/* Coming soon. */}
@@ -84,138 +54,14 @@ The **`web side`** is built with React. Redwood's router makes it simple to map
Pages may contain a "Layout" component to wrap content. They also contain "Cells" and regular React components.
Cells allow you to declaratively manage the lifecycle of a component that fetches and displays data.
<Admonition type="note">
For the sake of consistency with the other framework Quickstart examples, we'll build a RedwoodJS a little differently than normal.
For the sake of consistency with the other framework tutorials, we'll build this app a little differently than normal.
We **_won't use_** Prisma to connect to the Supabase Postgres database or [Prisma migrations](https://redwoodjs.com/docs/cli-commands#prisma-migrate) as one typically might in a Redwood app.
Instead, we'll rely on the Supabase client to do some of the work on the **`web`** side and use the client again on the **`api`** side to do data fetching as well.
</Admonition>
That means you will want to refrain from running any `yarn rw prisma migrate` commands and also double check your build commands on deployment to ensure Prisma won't reset your database. Prisma currently doesn't support cross-schema foreign keys, so introspecting the schema fails due
to how your Supabase `public` schema references the `auth.users`.
## Project set up
Before we start building we're going to set up our Database and API. This is as simple as starting a new Project in Supabase
and then creating a "schema" inside the database.
<Admonition type="note">
When setting up Supabase, you'll interact with your project dashboard. However, most of the RedwoodJS setup steps will interact with the [Redwood CLI](https://redwoodjs.com/docs/cli-commands) to generate routes, pages, components, and more.
So be sure to have a terminal at the ready and in your project directory.
</Admonition>
### Create a project
1. Go to [app.supabase.com](https://app.supabase.com).
1. Click on "New Project".
1. Enter your project details.
1. Wait for the new database to launch.
### Set up the database schema
Now we are going to set up the database schema. We can use the "User Management Starter" quickstart in the SQL Editor,
or you can just copy/paste the SQL from below and run it yourself.
<Tabs
scrollable
size="small"
type="underlined"
defaultActiveId="dashboard"
>
<TabPanel id="dashboard" label="Dashboard">
1. Go to the [SQL Editor](https://app.supabase.com/project/_/sql) page in the Dashboard.
2. Click **User Management Starter**.
3. Click **Run**.
<video width="99%" muted playsInline controls="true">
<source
src="https://xguihxuzqibwxjnimxev.supabase.co/storage/v1/object/public/videos/docs/sql-user-management-starter.mp4"
type="video/mp4"
muted
playsInline
/>
</video>
</TabPanel>
<TabPanel id="sql" label="SQL">
```sql
-- Create a table for public "profiles"
create table profiles (
id uuid references auth.users not null,
updated_at timestamp with time zone,
username text unique,
avatar_url text,
website text,
primary key (id),
unique(username),
constraint username_length check (char_length(username) >= 3)
);
alter table profiles enable row level security;
create policy "Public profiles are viewable by everyone."
on profiles for select
using ( true );
create policy "Users can insert their own profile."
on profiles for insert
with check ( auth.uid() = id );
create policy "Users can update own profile."
on profiles for update
using ( auth.uid() = id );
-- Set up Realtime!
begin;
drop publication if exists supabase_realtime;
create publication supabase_realtime;
commit;
alter publication supabase_realtime add table profiles;
-- Set up Storage!
insert into storage.buckets (id, name)
values ('avatars', 'avatars');
create policy "Avatar images are publicly accessible."
on storage.objects for select
using ( bucket_id = 'avatars' );
create policy "Anyone can upload an avatar."
on storage.objects for insert
with check ( bucket_id = 'avatars' );
```
</TabPanel>
</Tabs>
#### Important Note about Prisma and Migrations
<Admonition type="note">
Because this Quick Start does not use Prisma to manage the database schema, seed it, or run migrations, you **need** to take extra care when running some of the typical Redwood CLI commands.
</Admonition>
### Get the API Keys
Now that you've created some database tables, you are ready to insert data using the auto-generated API.
We just need to get the URL as well as the `anon`, `service_role` and `JWT_SECRET` keys from the API settings.
1. Go to the [API Settings](https://app.supabase.com/project/_/settings/api) page in the Dashboard.
2. Find your API `URL`, `anon`, and `service_role` keys on this page.
<video width="99%" muted playsInline controls="true">
<source
src="https://xguihxuzqibwxjnimxev.supabase.co/storage/v1/object/public/videos/docs/api/api-url-and-key.mp4"
type="video/mp4"
muted
playsInline
/>
</video>
<ProjectSetup />
## Building the App
@@ -291,7 +137,7 @@ And finally, you will also need to save **just** the `web side` environment vari
```bash title=redwood.toml
[web]
title = "Supabase Redwood Quickstart"
title = "Supabase Redwood Tutorial"
port = 8910
apiProxyPath = "/.redwood/functions"
includeEnvironmentVariables = ["SUPABASE_URL", "SUPABASE_KEY"]
@@ -343,9 +189,7 @@ yarn rw dev
```
<Admonition type="note">
Note: You can also use the alias `rw` for `redwood`, as in `yarn rw` to run Redwood CLI commands
`rw` is an alias for `redwood`, as in `yarn rw` to run Redwood CLI commands.
</Admonition>
You should see a "Welcome to RedwoodJS" page and a message about not having any pages yet.
@@ -365,7 +209,7 @@ yarn rw generate page home /
<Admonition type="note">
Note: the slash `/` is important here as it creates a root level route.
The `/` is important here as it creates a root level route.
</Admonition>
@@ -601,14 +445,10 @@ const Account = () => {
export default Account
```
<Admonition type="note">
Note: You'll see the use of `useAuth()` several times in the quickstart. Redwood's `useAuth` hook provides convenient ways to access
You'll see the use of `useAuth()` several times. Redwood's `useAuth` hook provides convenient ways to access
logIn, logOut, currentUser, and access the `supabase` authenticate client. We'll use it to get an instance
of the supabase client to interact with your API.
</Admonition>
### Update Home Page
Now that we have all the components in place, let's update your `HomePage` page to use them:
@@ -785,12 +625,10 @@ return (
<StorageManagement />
## Next steps
At this stage you have a fully functional application!
- Got a question? [Ask here](https://github.com/supabase/supabase/discussions).
- Sign in: [app.supabase.com](https://app.supabase.com)
## See also
- Learn more about [RedwoodJS](https://redwoodjs.com)
- Visit the [RedwoodJS Discourse Community](https://community.redwoodjs.com)
@@ -1,19 +1,18 @@
import Layout from '~/layouts/DefaultGuideLayout'
export const meta = {
id: 'with-solidjs',
title: 'Quickstart: SolidJS',
title: 'Build a User Management App with SolidJS',
description: 'Learn how to use Supabase in your SolidJS App.',
sidebar_label: 'SolidJS',
}
<QuickstartIntro />
![Supabase User Management example](/docs/img/user-management-demo.png)
### GitHub
Should you get stuck while working through the guide, refer to [this repo](https://github.com/supabase/supabase/tree/master/examples/user-management/solid-user-management).
<Admonition type="note">
If you get stuck while working through this guide, refer to the [full example on
GitHub](https://github.com/supabase/supabase/tree/master/examples/user-management/solid-user-management).
</Admonition>
<ProjectSetup />
@@ -419,13 +418,8 @@ return (
<StorageManagement />
## Next steps
At this stage you have a fully functional application!
- Got a question? [Ask here](https://github.com/supabase/supabase/discussions).
- Sign in: [app.supabase.com](https://app.supabase.com)
export const Page = ({ children }) => <Layout meta={meta} children={children} />
export default Page
@@ -1,19 +1,18 @@
import Layout from '~/layouts/DefaultGuideLayout'
export const meta = {
id: 'with-svelte',
title: 'Quickstart: Svelte',
title: 'Build a User Management App with Svelte',
description: 'Learn how to use Supabase in your Svelte App.',
sidebar_label: 'Svelte',
}
<QuickstartIntro />
![Supabase User Management example](/docs/img/user-management-demo.png)
### GitHub
Should you get stuck while working through the guide, refer to [this repo](https://github.com/supabase/supabase/tree/master/examples/user-management/svelte-user-management).
<Admonition type="note">
If you get stuck while working through this guide, refer to the [full example on
GitHub](https://github.com/supabase/supabase/tree/master/examples/user-management/svelte-user-management).
</Admonition>
<ProjectSetup />
@@ -372,13 +371,8 @@ And then we can add the widget to the Account page:
<StorageManagement />
## Next steps
At this stage you have a fully functional application!
- Got a question? [Ask here](https://github.com/supabase/supabase/discussions).
- Sign in: [app.supabase.com](https://app.supabase.com)
export const Page = ({ children }) => <Layout meta={meta} children={children} />
export default Page
@@ -1,19 +1,18 @@
import Layout from '~/layouts/DefaultGuideLayout'
export const meta = {
id: 'with-sveltekit',
title: 'Quickstart: SvelteKit',
title: 'Build a User Management App with SvelteKit',
description: 'Learn how to use Supabase in your SvelteKit App.',
sidebar_label: 'SvelteKit',
}
<QuickstartIntro />
![Supabase User Management example](/docs/img/user-management-demo.png)
### GitHub
Should you get stuck while working through the guide, refer to [this repo](https://github.com/supabase/supabase/tree/master/examples/user-management/sveltekit-user-management).
<Admonition type="note">
If you get stuck while working through this guide, refer to the [full example on
GitHub](https://github.com/supabase/supabase/tree/master/examples/user-management/sveltekit-user-management).
</Admonition>
<ProjectSetup />
@@ -438,13 +437,8 @@ And then we can add the widget to the Account page:
<StorageManagement />
## Next steps
At this stage you have a fully functional application!
- Got a question? [Ask here](https://github.com/supabase/supabase/discussions).
- Sign in: [app.supabase.com](https://app.supabase.com)
export const Page = ({ children }) => <Layout meta={meta} children={children} />
export default Page
@@ -1,19 +1,18 @@
import Layout from '~/layouts/DefaultGuideLayout'
export const meta = {
id: 'with-vue-3',
title: 'Quickstart: Vue 3',
title: 'Build a User Management App with Vue 3',
description: 'Learn how to use Supabase in your Vue 3 App.',
sidebar_label: 'Vue 3',
}
<QuickstartIntro />
![Supabase User Management example](/docs/img/user-management-demo.png)
### GitHub
Should you get stuck while working through the guide, refer to [this repo](https://github.com/supabase/supabase/tree/master/examples/user-management/vue3-user-management).
<Admonition type="note">
If you get stuck while working through this guide, refer to the [full example on
GitHub](https://github.com/supabase/supabase/tree/master/examples/user-management/vue3-user-management).
</Admonition>
<ProjectSetup />
@@ -68,30 +67,30 @@ Optionally, update [src/style.css](https://raw.githubusercontent.com/supabase/su
Set up an `src/components/Auth.vue` component to manage logins and sign ups. We'll use Magic Links, so users can sign in with their email without using passwords.
```html title=/src/components/Auth.vue
```vue title=/src/components/Auth.vue
<script setup>
import { ref } from 'vue'
import { supabase } from '../supabase'
import { ref } from 'vue'
import { supabase } from '../supabase'
const loading = ref(false)
const email = ref('')
const loading = ref(false)
const email = ref('')
const handleLogin = async () => {
try {
loading.value = true
const { error } = await supabase.auth.signInWithOtp({
email: email.value,
})
if (error) throw error
alert('Check your email for the login link!')
} catch (error) {
if (error instanceof Error) {
alert(error.message)
}
} finally {
loading.value = false
const handleLogin = async () => {
try {
loading.value = true
const { error } = await supabase.auth.signInWithOtp({
email: email.value,
})
if (error) throw error
alert('Check your email for the login link!')
} catch (error) {
if (error instanceof Error) {
alert(error.message)
}
} finally {
loading.value = false
}
}
</script>
<template>
@@ -120,82 +119,82 @@ Set up an `src/components/Auth.vue` component to manage logins and sign ups. We'
After a user is signed in we can allow them to edit their profile details and manage their account.
Create a new `src/components/Account.vue` component to handle this.
```html title=src/components/Account.vue
```vue title=src/components/Account.vue
<script setup>
import { supabase } from '../supabase'
import { onMounted, ref, toRefs } from 'vue'
import { supabase } from '../supabase'
import { onMounted, ref, toRefs } from 'vue'
const props = defineProps(['session'])
const { session } = toRefs(props)
const props = defineProps(['session'])
const { session } = toRefs(props)
const loading = ref(true)
const username = ref('')
const website = ref('')
const avatar_url = ref('')
const loading = ref(true)
const username = ref('')
const website = ref('')
const avatar_url = ref('')
onMounted(() => {
getProfile()
})
onMounted(() => {
getProfile()
})
async function getProfile() {
try {
loading.value = true
const { user } = session.value
async function getProfile() {
try {
loading.value = true
const { user } = session.value
let { data, error, status } = await supabase
.from('profiles')
.select(`username, website, avatar_url`)
.eq('id', user.id)
.single()
let { data, error, status } = await supabase
.from('profiles')
.select(`username, website, avatar_url`)
.eq('id', user.id)
.single()
if (error && status !== 406) throw error
if (error && status !== 406) throw error
if (data) {
username.value = data.username
website.value = data.website
avatar_url.value = data.avatar_url
}
} catch (error) {
alert(error.message)
} finally {
loading.value = false
if (data) {
username.value = data.username
website.value = data.website
avatar_url.value = data.avatar_url
}
} catch (error) {
alert(error.message)
} finally {
loading.value = false
}
}
async function updateProfile() {
try {
loading.value = true
const { user } = session.value
async function updateProfile() {
try {
loading.value = true
const { user } = session.value
const updates = {
id: user.id,
username: username.value,
website: website.value,
avatar_url: avatar_url.value,
updated_at: new Date(),
}
let { error } = await supabase.from('profiles').upsert(updates)
if (error) throw error
} catch (error) {
alert(error.message)
} finally {
loading.value = false
const updates = {
id: user.id,
username: username.value,
website: website.value,
avatar_url: avatar_url.value,
updated_at: new Date(),
}
}
async function signOut() {
try {
loading.value = true
let { error } = await supabase.auth.signOut()
if (error) throw error
} catch (error) {
alert(error.message)
} finally {
loading.value = false
}
let { error } = await supabase.from('profiles').upsert(updates)
if (error) throw error
} catch (error) {
alert(error.message)
} finally {
loading.value = false
}
}
async function signOut() {
try {
loading.value = true
let { error } = await supabase.auth.signOut()
if (error) throw error
} catch (error) {
alert(error.message)
} finally {
loading.value = false
}
}
</script>
<template>
@@ -233,24 +232,24 @@ Create a new `src/components/Account.vue` component to handle this.
Now that we have all the components in place, let's update `App.vue`:
```html title=src/App.vue
```vue title=src/App.vue
<script setup>
import { onMounted, ref } from 'vue'
import Account from './components/Account.vue'
import Auth from './components/Auth.vue'
import { supabase } from './supabase'
import { onMounted, ref } from 'vue'
import Account from './components/Account.vue'
import Auth from './components/Auth.vue'
import { supabase } from './supabase'
const session = ref()
const session = ref()
onMounted(() => {
supabase.auth.getSession().then(({ data }) => {
session.value = data.session
})
supabase.auth.onAuthStateChange((_, _session) => {
session.value = _session
})
onMounted(() => {
supabase.auth.getSession().then(({ data }) => {
session.value = data.session
})
supabase.auth.onAuthStateChange((_, _session) => {
session.value = _session
})
})
</script>
<template>
@@ -279,56 +278,56 @@ Every Supabase project is configured with [Storage](/docs/guides/storage) for ma
Create a new `src/components/Avatar.vue` component that allows users to upload profile photos:
```html title=src/components/Avatar.vue
```vue title=src/components/Avatar.vue
<script setup>
import { ref, toRefs, watch } from 'vue'
import { supabase } from '../supabase'
import { ref, toRefs, watch } from 'vue'
import { supabase } from '../supabase'
const prop = defineProps(['path', 'size'])
const { path, size } = toRefs(prop)
const prop = defineProps(['path', 'size'])
const { path, size } = toRefs(prop)
const emit = defineEmits(['upload', 'update:path'])
const uploading = ref(false)
const src = ref('')
const files = ref()
const emit = defineEmits(['upload', 'update:path'])
const uploading = ref(false)
const src = ref('')
const files = ref()
const downloadImage = async () => {
try {
const { data, error } = await supabase.storage.from('avatars').download(path.value)
if (error) throw error
src.value = URL.createObjectURL(data)
} catch (error) {
console.error('Error downloading image: ', error.message)
}
const downloadImage = async () => {
try {
const { data, error } = await supabase.storage.from('avatars').download(path.value)
if (error) throw error
src.value = URL.createObjectURL(data)
} catch (error) {
console.error('Error downloading image: ', error.message)
}
}
const uploadAvatar = async (evt) => {
files.value = evt.target.files
try {
uploading.value = true
if (!files.value || files.value.length === 0) {
throw new Error('You must select an image to upload.')
}
const file = files.value[0]
const fileExt = file.name.split('.').pop()
const filePath = `${Math.random()}.${fileExt}`
let { error: uploadError } = await supabase.storage.from('avatars').upload(filePath, file)
if (uploadError) throw uploadError
emit('update:path', filePath)
emit('upload')
} catch (error) {
alert(error.message)
} finally {
uploading.value = false
const uploadAvatar = async (evt) => {
files.value = evt.target.files
try {
uploading.value = true
if (!files.value || files.value.length === 0) {
throw new Error('You must select an image to upload.')
}
}
watch(path, () => {
if (path.value) downloadImage()
})
const file = files.value[0]
const fileExt = file.name.split('.').pop()
const filePath = `${Math.random()}.${fileExt}`
let { error: uploadError } = await supabase.storage.from('avatars').upload(filePath, file)
if (uploadError) throw uploadError
emit('update:path', filePath)
emit('upload')
} catch (error) {
alert(error.message)
} finally {
uploading.value = false
}
}
watch(path, () => {
if (path.value) downloadImage()
})
</script>
<template>
@@ -344,7 +343,7 @@ Create a new `src/components/Avatar.vue` component that allows users to upload p
<div :style="{ width: size + 'em' }">
<label class="button primary block" for="single">
{{ uploading ? "Uploading ..." : "Upload" }}
{{ uploading ? 'Uploading ...' : 'Upload' }}
</label>
<input
style="visibility: hidden; position: absolute"
@@ -363,10 +362,10 @@ Create a new `src/components/Avatar.vue` component that allows users to upload p
And then we can add the widget to the Account page in `src/components/Account.vue`:
```html title=src/components/Account.vue
```vue title=src/components/Account.vue
<script>
// Import the new component
import Avatar from './Avatar.vue'
// Import the new component
import Avatar from './Avatar.vue'
</script>
<template>
@@ -383,13 +382,8 @@ And then we can add the widget to the Account page in `src/components/Account.vu
<StorageManagement />
## Next steps
At this stage you have a fully functional application!
- Got a question? [Ask here](https://github.com/supabase/supabase/discussions).
- Sign in: [app.supabase.com](https://app.supabase.com)
export const Page = ({ children }) => <Layout meta={meta} children={children} />
export default Page
@@ -16,8 +16,8 @@ The Supabase Marketplace brings together all the tools you need to extend your S
Supabase provides several integration points:
- The [Postgres connection](/docs/guides/database/connecting-to-postgres). Anything that works with Postgres also works with Supabase projects.
- The [Project REST API](/docs/guides/api#rest-api) & client libraries.
- The [Project GraphQL API](/docs/guides/api#graphql-api).
- The [Project REST API](/docs/guides/database/api#rest-api) & client libraries.
- The [Project GraphQL API](/docs/guides/database/api#graphql-api).
- The [Platform API](/docs/reference/api).
## List your integration
+1 -1
View File
@@ -16,7 +16,7 @@ Visit [app.supabase.com](https://app.supabase.com) and sign in to start creating
Each project on Supabase comes with:
- A dedicated [Postgres database](/docs/guides/database)
- [Auto-generated APIs](/docs/guides/api)
- [Auto-generated APIs](/docs/guides/database/api)
- [Auth and user management](/docs/guides/auth)
- [Edge Functions](/docs/guides/functions)
- [Realtime API](/docs/guides/realtime)
@@ -6,37 +6,52 @@ export const meta = {
description: 'Understanding how database usage applies to your subscription.',
}
Database storage refers to the _monthly average storage usage_, as reported by Postgres. This metric is reported in your project's [billing usage](https://app.supabase.com/project/_/settings/billing/usage) and is updated daily.
Database size refers to the _monthly average storage usage_, as reported by Postgres. This metric is reported in your project's [billing usage](https://app.supabase.com/project/_/settings/billing/usage) and is updated daily.
Database size is the total size of used storage from your database, whereas disk size describes the size of the underlying available storage.
For an instantaneous live view of the DB storage usage, you can execute in Postgres:
For an instantaneous live view of the DB size, you can execute in Postgres:
```sql
select sum(pg_database_size(pg_database.datname)) / (1024 * 1024) as db_size_mb
from pg_database;
select
sum(pg_database_size (pg_database.datname)) / (1024 * 1024) as db_size_mb
from
pg_database;
```
This value is also reported in the [database settings page](https://app.supabase.com/project/_/settings/database).
## Database storage management
Supabase uses network-attached storage to balance performance with scalability. For Pro and Enterprise projects, database storage expands ~1.5x automatically (e.g., 8GB -> 12GB) when you reach 90% of the database storage quota. Automatic database storage expansion can only occur once every six hours. Pro projects can store up to 1024TB.
Supabase uses network-attached storage to balance performance with scalability.
For Pro and Enterprise projects, disk size expands ~1.5x automatically (e.g., 8GB -> 12GB) when you reach 90% of the disk size.
Automatic disk size expansion can only occur once every six hours.
Pro projects can store up to 1024TB.
All projects enter read-only mode when you reach 95% of the database storage quota. In read-only mode, clients will encounter errors such as `cannot execute INSERT in a read-only transaction`. Regular operation (read-write mode) is automatically re-enabled once usage is below 95% of the database storage quota.
All projects enter read-only mode when you reach 95% of the disk size. In read-only mode, clients will encounter errors such as `cannot execute INSERT in a read-only transaction`.
Regular operation (read-write mode) is automatically re-enabled once usage is below 95% of the disk size.
If you need more than 1024TB of database storage or require multiple storage expansions in a short period of time, [contact us](https://app.supabase.com/support/new) to learn more about the Enterprise plan.
If you need more than 1024TB of disk size or require multiple storage expansions in a short period of time, [contact us](https://app.supabase.com/support/new) to learn more about the Enterprise plan.
### Increasing available database storage
### Increasing available disk size
1. [Upgrade to the Pro or Enterprise plan](https://app.supabase.com/project/_/settings/billing/subscription) to increase your storage quota.
1. [Upgrade to the Pro or Enterprise plan](https://app.supabase.com/project/_/settings/billing/subscription) to increase your quota and expand your disk size automatically.
2. Delete data from your project's database to lower its disk usage. If your database is already in read-only mode, run the following command to change the transaction mode to read-write for your session:
```sql
SET default_transaction_read_only = 'off';
SET
default_transaction_read_only = 'off';
```
This allows you to delete data from within the session.
### Preoccupied Space
When launching a new project, your database size will be roughly ~40-60mb.
The space is used up by preinstalled extensions, schema/data used by our services that are offered with each project and default Postgres data.
When installing additional extensions, even if you don't actively use them, additional database size is used.
## Vacuum operations
Postgres does not immediately reclaim the physical space used by dead tuples (i.e., deleted rows) in the DB. Instead, they are internally marked as removed until a [vacuum operation](https://www.postgresql.org/docs/current/routine-vacuuming.html) is executed.
+1 -1
View File
@@ -29,7 +29,7 @@ Supabase provides a logging interface specific to each product. You can use simp
>
<TabPanel id="api" label="API">
[API logs](https://app.supabase.com/project/_/database/api-logs) show all network requests and response for the REST and GraphQL [APIs](../../guides/api).
[API logs](https://app.supabase.com/project/_/database/api-logs) show all network requests and response for the REST and GraphQL [APIs](../../guides/database/api).
![API Logs](/docs/img/guides/platform/logs/logs-api.png)
@@ -8,9 +8,7 @@ export const meta = {
<Admonition type="note">
Network Restrictions are currently in beta and are being slowly made available to all projects.
The current iteration of Network Restrictions applies to connections to Postgres and PgBouncer. Support for restricting connections to PostgREST, Storage, and Auth will be added at a later date.
Network Restrictions is currently in beta and is slowly being made available to all projects. [Contact support](https://app.supabase.com/support/new) if you'd like to request early access.
</Admonition>
@@ -20,6 +18,7 @@ To get started:
1. [Install](/docs/guides/cli) the Supabase CLI 1.22.0+.
1. [Log in](/docs/guides/cli/local-development#log-in-to-the-supabase-cli) to your Supabase account using the CLI.
1. If your project was created before 23rd December 2022, it will need to be [upgraded to the latest Supabase version](/docs/guides/platform/migrating-and-upgrading-projects) before Network Restrictions can be used.
1. Ensure that you have [Owner or Admin permissions](/docs/guides/platform/access-control#manage-team-members) for the project that you are enabling network restrictions.
## Check restrictions
@@ -67,8 +66,8 @@ Restrictions applied successfully: true
## Limitations
1. Network Restrictions do not currently apply to APIs offered over HTTPS (e.g. PostgREST, Storage, Auth).
1. Network Restrictions should not be used if you require you need to connect to your Postgres database using Edge Functions.
- The current iteration of Network Restrictions applies to connections to Postgres and PgBouncer and doesn't currently apply to APIs offered over HTTPS (e.g., PostgREST, Storage, and Auth).
- Network Restrictions should not be used if you need to connect to your Postgres database using Edge Functions.
export const Page = ({ children }) => <Layout meta={meta} children={children} />
@@ -0,0 +1,58 @@
import Layout from '~/layouts/DefaultGuideLayout'
export const meta = {
title: 'Postgres SSL Enforcement',
description: 'Enforce SSL usage for all Postgres connections',
}
<Admonition type="note">
Postgres SSL Enforcement is currently in beta and is slowly being made available to all projects. [Contact support](https://app.supabase.com/support/new) if you'd like to request early access.
</Admonition>
Your Supabase project supports connecting to the Postgres DB without SSL enabled to maximize client compatibility. For increased security, you can prevent clients from connecting if they're not using SSL.
SSL enforcement only applies to connections to both Postgres and PgBouncer ("Connection Pooler"); all HTTP APIs offered by Supabase (e.g., PostgREST, Storage, Auth) automatically enforce SSL on all incoming connections.
To get started:
1. [Install](/docs/guides/cli) the Supabase CLI 1.37.0+.
1. [Log in](/docs/guides/cli/local-development#log-in-to-the-supabase-cli) to your Supabase account using the CLI.
1. Ensure that you have [Owner or Admin permissions](/docs/guides/platform/access-control#manage-team-members) for the project that you are enabling SSL enforcement.
## Check enforcement status
You can use the `get` subcommand of the CLI to check whether SSL is currently being enforced:
```bash
> supabase ssl-enforcement --project-ref {ref} get --experimental
SSL is being enforced.
```
Or similarly, if SSL is not being enforced, you will see:
```bash
> supabase ssl-enforcement --project-ref {ref} get --experimental
SSL is *NOT* being enforced.
```
## Update enforcement
The `update` subcommand is used to change the SSL enforcement status for your project:
```bash
> supabase ssl-enforcement --project-ref {ref} update --enable-db-ssl-enforcement --experimental
SSL is now being enforced.
```
Similarly, to disable SSL enforcement:
```bash
> supabase ssl-enforcement --project-ref {ref} update --disable-db-ssl-enforcement --experimental
SSL is *NOT* being enforced.
```
export const Page = ({ children }) => <Layout meta={meta} children={children} />
export default Page
+6
View File
@@ -135,6 +135,12 @@ export const migrationGuides = [
href: '/guides/resources/migrating-to-supabase/heroku',
description: 'Migrate your Heroku Postgres database to Supabase.',
},
{
title: 'Render',
icon: '/docs/img/icons/render-icon',
href: '/guides/resources/migrating-to-supabase/render',
description: 'Migrate your Render Postgres database to Supabase.',
},
]
export const postgres = [
@@ -0,0 +1,88 @@
import Layout from '~/layouts/DefaultGuideLayout'
export const meta = {
title: 'Migrate from Render to Supabase',
description: 'Migrate your Render Postgres database to Supabase.',
}
Render is a popular Web Hosting service in the online services category that also has a managed Postgres service. Render has a great developer experience, allowing users to deploy straight from GitHub or GitLab. This is the core of their product and they do it really well. However, when it comes to Postgres databases, it may not be the best option.
Supabase is one of the best free alternative to Render Postgres. Supabase provide all the backend features developers need to build a product: a Postgres database, authentication, instant APIs, edge functions, realtime subscriptions, and storage. Postgres is the core of Supabase—for example, you can use row-level security and there are more than 40 Postgres extensions available.
This guide demonstrates how to migrate from Render to Supabase to get the most out of Postgres while gaining access to all the features you need to build a project.
## Retrieve your Render database credentials [#retrieve-render-credentials]
1. Log in to your [Render account](https://render.com) and select the project you want to migrate.
1. Click **Dashboard** in the menu and click in your **Postgres** database.
1. Scroll down in the **Info** tab.
1. Click on **PSQL Command** and edit it adding the content after `PSQL_COMMAND=`.
![Copying PSQL command from Render dashboard](/docs/img/guides/resources/migrating-to-supabase/render/render_dashboard.png)
Example:
```bash
%env PSQL_COMMAND=PGPASSWORD=RgaMDfTS_password_FTPa7 psql -h dpg-a_server_in.oregon-postgres.render.com -U my_db_pxl0_user my_db_pxl0
```
## Retrieve your Supabase Host [#retrieve-supabase-host]
1. If you're new to Supabase, [create a project](https://app.supabase.com).
1. Go to the [Database settings](https://app.supabase.com/project/_/settings/database) for your project in the Supabase Dashboard.
1. Under **Connection Info**, note your Host (`$SUPABASE_HOST`).
1. Save your password or [reset it](https://app.supabase.com/project/_/settings/database) if you forgot it.
![Finding Supabase host address](/docs/img/guides/resources/migrating-to-supabase/render/supabase_dashboard.png)
## Migrate the database
The fastest way to migrate your database is with the Supabase migration tool on [Google Colab](https://colab.research.google.com/github/mansueli/Supa-Migrate/blob/main/Migrate_Postgres_Supabase.ipynb). Alternatively, you can use the [pg_dump](https://www.postgresql.org/docs/current/app-pgdump.html) and [psql](https://www.postgresql.org/docs/current/app-psql.html) command line tools, which are included in a full PostgreSQL installation.
<Tabs
scrollable
size="small"
type="underlined"
defaultActiveId="colab"
>
<TabPanel id="colab" label="Migrate using Colab">
1. Set the environment variables (`PSQL_COMMAND`, `SUPABASE_HOST`, `SUPABASE_PASSWORD`) in the Colab notebook.
1. Run the first two steps in [the notebook](https://colab.research.google.com/github/mansueli/Supa-Migrate/blob/main/Migrate_Postgres_Supabase.ipynb) in order. The first sets the variables and the second installs PSQL and the migration script.
1. Run the third step to start the migration. This will take a few minutes.
</TabPanel>
<TabPanel id="cli" label="Migrate using CLI tools">
### Export your Render database to a file in console [#export-render-database]
Use `pg_dump` with your Render credentials to export your Render database to a file (e.g., `render_dump.sql`).
```bash
pg_dump --clean --if-exists --quote-all-identifiers \
-h $RENDER_HOST -U $RENDER_USER -d $RENDER_DATABASE \
--no-owner --no-privileges > render_dump.sql
```
### Import the database to your Supabase project [#import-database-to-supabase]
Use `psql` to import the Render database file to your Supabase project.
```bash
psql -h $SUPA_URL -U postgres --file render_dump.sql -p 6543 -d postgres
```
### Additional options
- To only migrate a single database schema, add the `--schema=PATTERN` parameter to your `pg_dump` command.
- To exclude a schema: `--exclude-schema=PATTERN`.
- To only migrate a single table: `--table=PATTERN`.
- To exclude a table: `--exclude-table=PATTERN`.
Run `pg_dump --help` for a full list of options.
</TabPanel>
</Tabs>
export const Page = ({ children }) => <Layout meta={meta} children={children} />
export default Page
+1 -1
View File
@@ -125,7 +125,7 @@ export const meta = {
md:items-center md:gap-3
">
<h2 className="text-sm lg:text-base text-scale-1200 m-0">Ready to make a fully working app?</h2>
<p className="text-sm lg:text-base text-scale-1100 m-0">Follow the step-by-step <Link href="/guides/getting-started#tutorials"><a className="m-0 text-scale-1200 underline">tutorials</a></Link>.</p>
<p className="text-sm lg:text-base text-scale-1100 m-0">Follow the step-by-step <Link href="/guides/getting-started#web-app-tutorials"><a className="m-0 text-scale-1200 underline">tutorials</a></Link>.</p>
</div>
</div>
-2
View File
@@ -13,12 +13,10 @@ Bo Lu
Bobbie Soedirgo
Chase Granberry
Chris Copplestone
Danny Ng
Dave Wilson
Div Arora
Egor Romanov
Fabrizio Fenoglio
Francisco Mazzoni
Haydn Maley
Hieu Pham
Inian P
Binary file not shown.

After

Width:  |  Height:  |  Size: 789 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 764 KiB

@@ -0,0 +1,13 @@
<svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="17.4653" y="17.6948" width="2.81974" height="2.81974" fill="#46E7AA"/>
<rect x="13.1709" y="17.6948" width="2.81974" height="2.81974" fill="#46E7AA"/>
<rect x="13.1709" y="0.828125" width="2.81974" height="2.81974" fill="#46E7AA"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M0.285156 7.2979C0.285156 3.72312 3.18309 0.825195 6.75786 0.825195H11.6109V3.65042H6.75786C4.74341 3.65042 3.11038 5.28345 3.11038 7.2979V16.259H0.285156V7.2979Z" fill="#46E7AA"/>
<rect x="8.87671" y="17.6948" width="2.81974" height="2.81974" fill="#46E7AA"/>
<rect x="4.58228" y="17.6948" width="2.81974" height="2.81974" fill="#46E7AA"/>
<rect x="0.288086" y="17.6948" width="2.81974" height="2.81974" fill="#46E7AA"/>
<rect x="17.4653" y="13.478" width="2.81974" height="2.81974" fill="#46E7AA"/>
<rect x="17.4653" y="9.26123" width="2.81974" height="2.81974" fill="#46E7AA"/>
<rect x="17.4653" y="5.04492" width="2.81974" height="2.81974" fill="#46E7AA"/>
<rect x="17.4653" y="0.828125" width="2.81974" height="2.81974" fill="#46E7AA"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 18 KiB

+15 -312
View File
@@ -19,7 +19,7 @@
</url>
<url>
<loc>https://supabase.com/docs/guides/api</loc>
<loc>https://supabase.com/docs/guides/database/api</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
@@ -91,15 +91,12 @@
</url>
<url>
<<<<<<< HEAD
=======
<loc>https://supabase.com/docs/reference/index</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
>>>>>>> @{-1}
<loc>https://supabase.com/docs/handbook/contributing</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
@@ -112,16 +109,25 @@
</url>
<url>
<<<<<<< HEAD
<loc>https://supabase.com/docs/new/auth</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/reference/index</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
=======
>>>>>>> @{-1}
<loc>https://supabase.com/docs/guides/api/generating-types</loc>
<loc>https://supabase.com/docs/tutorials/nextjs</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/database/api/generating-types</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
@@ -307,8 +313,6 @@
</url>
<url>
<<<<<<< HEAD
=======
<loc>https://supabase.com/docs/guides/getting-started/features</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
@@ -321,7 +325,6 @@
</url>
<url>
>>>>>>> @{-1}
<loc>https://supabase.com/docs/guides/functions/cicd-workflow</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
@@ -359,21 +362,6 @@
<url>
<loc>https://supabase.com/docs/guides/functions/schedule-functions</loc>
<<<<<<< HEAD
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/functions/secrets</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/getting-started/architecture</loc>
=======
>>>>>>> @{-1}
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
@@ -445,15 +433,12 @@
</url>
<url>
<<<<<<< HEAD
=======
<loc>https://supabase.com/docs/guides/integrations/flutterflow</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
>>>>>>> @{-1}
<loc>https://supabase.com/docs/guides/integrations/illa</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
@@ -730,29 +715,18 @@
</url>
<url>
<<<<<<< HEAD
<loc>https://supabase.com/docs/guides/auth/phone-login/messagebird</loc>
=======
<loc>https://supabase.com/docs/guides/database/extensions/http</loc>
>>>>>>> @{-1}
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<<<<<<< HEAD
<loc>https://supabase.com/docs/guides/auth/phone-login/twilio</loc>
=======
<loc>https://supabase.com/docs/guides/database/extensions/pgcron</loc>
>>>>>>> @{-1}
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<<<<<<< HEAD
<loc>https://supabase.com/docs/guides/auth/phone-login/vonage</loc>
=======
<loc>https://supabase.com/docs/guides/database/extensions/pgnet</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
@@ -910,7 +884,6 @@
<url>
<loc>https://supabase.com/docs/guides/getting-started/tutorials/with-vue-3</loc>
>>>>>>> @{-1}
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
@@ -946,8 +919,6 @@
</url>
<url>
<<<<<<< HEAD
=======
<loc>https://supabase.com/docs/guides/auth/phone-login/messagebird</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
@@ -1068,7 +1039,6 @@
</url>
<url>
>>>>>>> @{-1}
<loc>https://supabase.com/docs/guides/auth/social-login/auth-apple</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
@@ -1171,273 +1141,6 @@
</url>
<url>
<<<<<<< HEAD
<loc>https://supabase.com/docs/guides/functions/examples/cloudflare-turnstile</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/functions/examples/github-actions</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/functions/examples/og-image</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/functions/examples/storage-caching</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/functions/examples/stripe-webhooks</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/functions/examples/telegram-bot</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/getting-started/quickstarts/flutter</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/getting-started/quickstarts/nextjs</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/getting-started/quickstarts/nuxtjs</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/getting-started/quickstarts/reactjs</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/getting-started/quickstarts/solidjs</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/getting-started/quickstarts/sveltekit</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/getting-started/quickstarts/vue</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/platform/sso/azure</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/platform/sso/gsuite</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/platform/sso/okta</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/getting-started/tutorials/with-angular</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/getting-started/tutorials/with-expo</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/getting-started/tutorials/with-flutter</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/getting-started/tutorials/with-ionic-angular</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/getting-started/tutorials/with-ionic-react</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/getting-started/tutorials/with-ionic-vue</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/getting-started/tutorials/with-nextjs</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/getting-started/tutorials/with-nuxt-3</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/getting-started/tutorials/with-react</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/getting-started/tutorials/with-redwoodjs</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/getting-started/tutorials/with-solidjs</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/getting-started/tutorials/with-svelte</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/getting-started/tutorials/with-sveltekit</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/getting-started/tutorials/with-vue-3</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/resources/migrating-to-supabase/firebase-auth</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/resources/migrating-to-supabase/firebase-storage</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/resources/migrating-to-supabase/firestore-data</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/resources/migrating-to-supabase/heroku</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/database/extensions/http</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/database/extensions/pgcron</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/database/extensions/pgnet</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/database/extensions/pgtap</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/database/extensions/plv8</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/database/extensions/postgis</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/database/extensions/uuid-ossp</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/self-hosting/auth/config</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/self-hosting/realtime/config</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
<loc>https://supabase.com/docs/guides/self-hosting/storage/config</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
<url>
=======
>>>>>>> @{-1}
<loc>https://supabase.com/docs/reference/javascript/initializing</loc>
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
@@ -4164,4 +3867,4 @@
<changefreq>weekly</changefreq>
<changefreq>0.5</changefreq>
</url>
</urlset>
</urlset>
+1
View File
@@ -7,6 +7,7 @@
.DocSearch-Container {
background: rgba(0, 0, 0, 0.3);
@apply fixed top-0 left-0 z-[200] flex h-screen w-screen flex-col p-4 backdrop-blur-sm sm:p-6 md:p-[10vh] lg:p-[12vh];
@apply cursor-auto #{!important};
}
.DocSearch-LoadingIndicator svg {
@@ -28,7 +28,7 @@ Supabase is an open source firebase alternative, but instead of being built arou
At Supabase we’ve always been huge fans of Firebase - so we started adding a few things on top of PostgreSQL in an attempt to reach feature parity, including:
- Auto-generated API - [query your data straight from the client](https://supabase.com/docs/guides/api#rest-api-2).
- Auto-generated API - [query your data straight from the client](https://supabase.com/docs/guides/database/api#rest-api-2).
- Realtime - [changes in your data will be streamed directly to your application](https://supabase.com/docs/reference/dart/subscribe).
- Auth - [a simple to integrate auth system and SQL based rules engine](https://supabase.com/auth).
- Functions - [javascript and typescript functions that deploy out globally](https://supabase.com/edge-functions).
@@ -12,12 +12,11 @@ toc_depth: 3
Heroku is a cloud application platform that offers managed PostgreSQL as a service. They offer 5 levels of Postgres support from the Hobby Tier up to the Shield Tier, each with different levels of features and pricing. Heroku announced that starting November 28, 2022, they will [stop offering free product plans and will shut down free dynos and data services](https://blog.heroku.com/next-chapter). Since the announcement, developers started migrating their projects to Supabase.
## What is Supabase?
Supabase also offers managed Postgres, the main difference is that with each deployment you also get:
- Auto-generated API - [never write an API again](https://supabase.com/docs/guides/api#rest-api-2)
- Auto-generated API - [never write an API again](https://supabase.com/docs/guides/database/api#rest-api-2)
- Realtime - [subscribe to data changes via websockets](https://supabase.com/docs/reference/dart/subscribe)
- Auth - [users can log in and out of your application](https://supabase.com/auth)
- Functions - [deploy custom logic to the edge](https://supabase.com/edge-functions)
@@ -44,7 +43,7 @@ These are some of the key differences between Heroku Postgres and Supabase in te
- Supabase is more than just the raw database, it also comes with:
- [Connection pooling](https://supabase.com/docs/guides/database/connecting-to-postgres#connection-pool) so that you won’t run out of connections in a serverless environment.
- [Auto-generated APIs](https://supabase.com/docs/guides/api#rest-api-2) based on your schema, so you can communicate with your database directly from the client.
- [Auto-generated APIs](https://supabase.com/docs/guides/database/api#rest-api-2) based on your schema, so you can communicate with your database directly from the client.
- [Realtime API](https://supabase.com/docs/reference/dart/subscribe) is useful for when you want to subscribe to changes to your database over websockets.
- [Auth API](https://supabase.com/auth) can be used to leverage Postgres’s Row Level Security model, and control access to sensitive data on a per user, or per group level.
- [Functions](https://supabase.com/edge-functions) can be deployed out to the edge directly from the Supabase CLI, which means you can run sensitive business logic or transformations in a serverless fashion.
@@ -217,7 +217,7 @@ User-facing applications usually require tools beyond just a database and fronte
- **File Storage:** for large images and media.
Supabase makes all of this easy. Beyond the database we offer [Auth](/docs/guides/auth),
RESTful and Realtime [APIs](/docs/guides/api), a [Storage](/docs/guides/storage)
RESTful and Realtime [APIs](/docs/guides/database/api), a [Storage](/docs/guides/storage)
system for large files, and a bunch of other tools - all wrapped up into a simple-to-use Dashboard.
![Supabase Dashboard](/images/blog/series-a/dashboard.png)
@@ -89,7 +89,7 @@ Learn about all the exciting features of Auth within Supabase. [Docs](https://su
### API Features
Learn more about the power of PostgREST for RESTful APIs. [Docs](https://supabase.com/docs/guides/api#restful-api).
Learn more about the power of PostgREST for RESTful APIs. [Docs](https://supabase.com/docs/guides/database/api#restful-api).
<iframe
className="video-with-border w-full"
+9 -16
View File
@@ -27,7 +27,6 @@ Today we're open sourcing [`pg_graphql`](https://github.com/supabase/pg_graphql)
Interested? You're [3 commands away](https://supabase.github.io/pg_graphql/quickstart/) from a live [GraphiQL](https://graphql-dotnet.github.io/docs/getting-started/graphiql/) demo.
## Motivation
The Supabase stack is centered around PostgreSQL as the single source of truth. All data, configuration, and security are housed in the database so any GraphQL solution needed to be equivalently SQL-centric.
@@ -35,18 +34,18 @@ The Supabase stack is centered around PostgreSQL as the single source of truth.
With that in mind, we took a look at the landscape and considered two excellent technologies, [Graphile](https://www.graphile.org/postgraphile/), and [Hasura](https://hasura.io/).
| Requirements | Graphile | Hasura |
|--------------------------|----------|--------|
| Open Source | ✅ | ✅ |
| Reflected GraphQL Schema | ✅ | ✅ |
| Reflected Resolvers | ✅ | ✅ |
| Always up-to-date | ✅ | ✅ |
| Performant | ✅ | ✅ |
| ------------------------ | -------- | ------ |
| Open Source | ✅ | ✅ |
| Reflected GraphQL Schema | ✅ | ✅ |
| Reflected Resolvers | ✅ | ✅ |
| Always up-to-date | ✅ | ✅ |
| Performant | ✅ | ✅ |
We found both options to be largely viable for the core feature set.
We found both options to be largely viable for the core feature set.
Which left us with one final hang-up: we host free-tier projects on VMs with 1 GB of memory. After tallying the resources reserved for PostgreSQL, PostgREST, Kong, GoTrue, and a handful of smaller services, we were left with a total memory budget of ... 0 MB 😬. Unsurprisingly, our pathological memory target disqualified any option that required launching another process in those VMs.
For that reason, we decided to invest in a lightweight alternative that runs in the database, and can be exposed over HTTP using the existing [PostgREST](https://supabase.com/docs/guides/api) deployments' [RPC functionality.](https://postgrest.org/en/v8.0/api.html#stored-procedures)
For that reason, we decided to invest in a lightweight alternative that runs in the database, and can be exposed over HTTP using the existing [PostgREST](https://supabase.com/docs/guides/database/api) deployments' [RPC functionality.](https://postgrest.org/en/v8.0/api.html#stored-procedures)
By our most conservative estimate, that reduces the platform's memory requirements by 525 TB/hours every month, saving 💰 and 🌳.
@@ -103,12 +102,7 @@ type PageInfo {
type Query {
account(nodeId: ID!): Account
allAccounts(
after: Cursor,
before: Cursor,
first: Int,
last: Int
): AccountConnection
allAccounts(after: Cursor, before: Cursor, first: Int, last: Int): AccountConnection
}
type Account {
@@ -195,5 +189,4 @@ Full steps to reproduce this output are available in [the docs](https://supabase
`pg_graphql` is [open source software](https://github.com/supabase/pg_graphql/). As always, Issues and PRs are welcome.
[Try `pg_graphql`](https://supabase.github.io/pg_graphql/quickstart/) today to see a live [GraphiQL](https://graphql-dotnet.github.io/docs/getting-started/graphiql/) demo.
@@ -266,7 +266,7 @@ Or how many gigabytes of video a user streamed from [Supabase Storage](/storage)
Querying huge datasets can be time-consuming, especially when you are aggregating billions of rows of historical logs. Supabase will make this simple with auto-updating views,
saved to disk for increased performance. These views update periodically at a cadence that you decide. You'll even be able to fetch these views with your
[Supabase API](/docs/guides/api)!
[Supabase API](/docs/guides/database/api)!
## Next steps
@@ -67,7 +67,7 @@ The primary goal of this architecture is to reduce the amount of work done in th
Supabase Edge Functions are deployed to one region - Earth (and we're exploring Mars as an additional region 👽). Edge Functions are deployed to over 30 data centers in a matter of seconds, ensuring fast response times no matter where your users are located.
[Database Functions](https://supabase.com/docs/guides/database/functions) (also served via our [REST and GraphQL APIs](https://supabase.com/docs/guides/api)) are colocated with your Postgres database, making them ideal for DB-intensive operations. These APIs can also be called seamlessly from your Supabase Edge Functions, making for a powerful combination.
[Database Functions](https://supabase.com/docs/guides/database/functions) (also served via our [REST and GraphQL APIs](https://supabase.com/docs/guides/database/api)) are colocated with your Postgres database, making them ideal for DB-intensive operations. These APIs can also be called seamlessly from your Supabase Edge Functions, making for a powerful combination.
### Scale to zero
@@ -2,7 +2,7 @@
title: Supabase Beta October 2022
description: New SDKs, quickstarts, Functions tricks, and more. But, more importantly, Launch Week 6️ has a date!
author: ant_wilson
image: 2022-october/monthly-update-october-2022.jpg
image: 2022-october/monthly-update-october-2022.jpg
thumb: 2022-october/monthly-update-october-2022.jpg
tags:
- release-notes
@@ -25,11 +25,11 @@ The new versions of our two most popular SDKs have been fully released. It could
![New Next.js quickstart & Next.js 13 example](/images/blog/2022-october/next-header.jpg)
Next.js is all the rage right now 🔥 
Next.js is all the rage right now 🔥
Next.js Conf raised the bar for dev conferences. We had the honor of being a Gold Sponsor, so we revamped our [Next.js Quickstart guide](https://supabase.com/docs/guides/with-nextjs) to include our pre-built Auth UI and [Auth Helpers.](https://supabase.com/docs/guides/auth/auth-helpers/nextjs)
And Next.js 13 was announced! Making it extremely easy to fetch and cache data from our [Serverless API](https://supabase.com/docs/guides/api). So we put together an [example to try it out](https://github.com/supabase/supabase/tree/master/examples/caching/with-nextjs-13).
And Next.js 13 was announced! Making it extremely easy to fetch and cache data from our [Serverless API](https://supabase.com/docs/guides/database/api). So we put together an [example to try it out](https://github.com/supabase/supabase/tree/master/examples/caching/with-nextjs-13).
## Supabase Auth and Server-Side Rendering
@@ -43,7 +43,7 @@ The Auth team published an in-depth doc explaining how Supabase Auth supports se
![Database Testing with pgTAP](/images/blog/2022-october/database-testing-postgres-pgtap.jpg)
Do you have 100% code coverage? Probably not, because that’s usually the last thing you think of, but *definitely* not if you don’t have database tests. We just shipped a framework for Database Tests which makes it incredibly easy to test your database using pgTAP and pg_prove.
Do you have 100% code coverage? Probably not, because that’s usually the last thing you think of, but _definitely_ not if you don’t have database tests. We just shipped a framework for Database Tests which makes it incredibly easy to test your database using pgTAP and pg_prove.
[Learn how it works](https://supabase.com/docs/guides/database/testing).
@@ -51,7 +51,7 @@ Do you have 100% code coverage? Probably not, because that’s usually the last
![Edge Functions Update](/images/blog/2022-october/functions-new-methods.jpg)
Functions now support GET requests! Other HTTP verbs such as PUT, PATCH, and DELETE are supported too.
Functions now support GET requests! Other HTTP verbs such as PUT, PATCH, and DELETE are supported too.
[Check this example](https://github.com/supabase/supabase/blob/master/examples/edge-functions/supabase/functions/restful-tasks/index.ts)
@@ -86,7 +86,7 @@ Today released pg_graphql 1.0 release and its general availability on our platfo
- Read the [announcement](/blog/pg-graphql-v1)
- Browse the [GitHub repo](https://github.com/supabase/pg_graphql/)
- View the [docs](/docs/guides/api#graphql-api)
- View the [docs](/docs/guides/database/api#graphql-api)
## Postgres Point-in-Time Recovery
@@ -119,9 +119,9 @@ begin
select
id,
content,
(documents.embedding <=> query_embedding) as similarity
1 - (documents.embedding <=> query_embedding) as similarity
from documents
where (documents.embedding <=> query_embedding) > similarity_threshold
where 1 - (documents.embedding <=> query_embedding) > similarity_threshold
order by documents.embedding <=> query_embedding
limit match_count;
end;
@@ -34,7 +34,7 @@ Developers have recently gained an the ability to trust a bot. Where Clippy fail
This is convenient timing for us, since our documentation content is more than the average developer wants to consume in one go. Today we're providing a similar interface to ChatGPT which is trained on our own docs.
<video width="99%" autoPlay="" loop="" muted="" playsInline="" controls="true">
<video width="100%" autoPlay="" loop="" muted="" playsInline="" controls="true">
<source src="/images/blog/embeddings/embeddings.mp4" type="video/mp4" />
</video>
@@ -54,15 +54,15 @@ It's built with Supabase/Postgres, and consists of several key parts:
All the changes we made are in [this](https://github.com/supabase/supabase/pull/12056) Pull Request. Greg is here to explain every step in full detail:
<div class="video-container">
<iframe
width="560"
height="315"
src="https://www.youtube-nocookie.com/embed/Yhtjd7yGGGA"
title="ClippyGPT"
frameborder="0"
src="https://www.youtube-nocookie.com/embed/Yhtjd7yGGGA"
frameborder="1"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen
></iframe>
</div>
You can find a full write up in our previous blog post: [Storing OpenAI embeddings in Postgres with pgvector](https://supabase.com/blog/openai-embeddings-postgres-vector).
@@ -89,15 +89,15 @@ A few weeks ago I received an email, drawing our attention to a [Pull Request](h
After we merged the PR, I reached out to see if Greg was interested in helping with some documentation or a blog post to help the community to use pgvector. On the call, Greg surprised me with an initial prototype where he had ingested the Supabase docs for a ChatGPT-like experience. I was suitably impressed and suggested that we could explore ways to work together to build it into the Supabase docs. He wasted no time:
<div class="video-container">
<iframe
width="560"
height="315"
src="https://www.youtube-nocookie.com/embed/yAsR7oe5vng"
title="ClippyGPT"
src="https://www.youtube-nocookie.com/embed/yAsR7oe5vng"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen
></iframe>
</div>
### A friendly collaboration
@@ -113,4 +113,4 @@ While you're at it, consider supporting [@ankane](https://github.com/ankane)'s g
Want to try Supabase Clippy? It's a hidden feature while in MVP - visit [supabase.com/docs](/docs) and hit `cmd` + `/` to pull up the search box (sorry mobile users).
{/* If you have any comments we'd love to hear them in our ShowHN: */}
If you have any comments we'd love to hear them in our [ShowHN](https://news.ycombinator.com/item?id=34695306).
@@ -0,0 +1,135 @@
---
title: Supabase Beta January 2023
description: New Postgres extensions, pg_graphql updates, changes to Edge Functions, and more!
author: ant_wilson
image: 2023-02-08-january-beta-update/supabase-beta-update-january-2023.jpg
thumb: 2023-02-08-january-beta-update/supabase-beta-update-january-2023.jpg
tags:
- release-notes
date: '2023-02-08'
toc_depth: 3
---
We have so much good stuff this month that it’s hard to fit in a single blog post 🚢.
We’ve got some new Postgres extensions, GraphQL updates, changes to Edge Functions, and more!
## Storing OpenAI embeddings in Postgres with pgvector
![Storing OpenAI embeddings in Postgres with pgvector](/images/blog/2023-02-08-january-beta-update/pgvector.png)
pgvector is a popular PostgreSQL extension for storing embeddings and performing vector similarity search. It was one of the most requested extensions by the AI/ML community and is now available thanks to [gregnr](https://github.com/gregnr).
[Read the announcement](https://supabase.com/blog/openai-embeddings-postgres-vector)
## Meet Supabase Clippy: ChatGPT for Docs
![Meet Supabase Clippy: ChatGPT for Docs](/images/blog/2023-02-08-january-beta-update/chatgpt-for-supabase-docs.png)
Greg wasted no time and took pgvector for a spin, he combined it with OpenAI to build Supabase Clippy, a next-generation doc search. The first implementation is a 1-week MVP and fully open source, so you can build on top of it.
- [Read the blog post](https://supabase.com/blog/chatgpt-supabase-docs)
- [Watch the video tutorial](https://www.youtube.com/watch?v=Yhtjd7yGGGA)
## Client library reference: Python and C#
![Client library reference: Python and C#](/images/blog/2023-02-08-january-beta-update/references.png)
We have released extensive reference docs for C# and Python, detailing every object and method. What are you going to build?
- [C# Client Library](https://supabase.com/docs/reference/csharp/)
- [Python Client Library](https://supabase.com/docs/reference/python/initializing)
## pg_graphql now supports Views, Materialized Views, and Foreign Tables
![pg_graphql now supports Views, Materialized Views, and Foreign Tables](/images/blog/2023-02-08-january-beta-update/pg-graphql.png)
Views, Materialized Views, and Foreign Tables are three database objects that provide a powerful way to access and organize and transform data without duplication.
[Read the docs](https://supabase.github.io/pg_graphql/views/)
## Automatic WebP detection for Image Transformation
![Automatic WebP detection for Image Transformation](/images/blog/2023-02-08-january-beta-update/image-transformation.png)
WebP is a modern image format that provides superior lossless and lossy compression for images on the web. We are enabling format conversion by default for anyone who has Image Transformations. You can opt out by including format: origin in the transformation parameters.
[Read the docs](https://supabase.com/docs/guides/storage/image-transformations#automatic-image-optimisation-webp)
## Quick product updates
-  Postgres Extension: Another powerful and time-tested extension, pg_repack, is added to Supabase. [[PR]](https://github.com/supabase/postgres/pull/492)
- Auth: Multi-tab session support using the new browser BroadcastChannel API. If a user logs out on one tab, they will now be logged out on all tabs. [[PR]](https://github.com/supabase/gotrue-js/pull/566)
- Postgres: Superior speed with lz4 database compression. [[PR]](https://github.com/supabase/postgres/pull/490)
- Postgres: Use ICU locales and collations for text attribute ordering in database queries. [[PR]](https://github.com/supabase/postgres/pull/491)
- Docs: New guide on scheduling functions with pg_cron. [[Guide]](https://supabase.com/docs/guides/functions/schedule-functions)
- Edge Functions: You can now download source codes of deployed edge functions from the CLI. [[Doc]](https://supabase.com/docs/reference/cli/supabase-functions-download)
- Edge Functions: building a Discord Slash Bot. [[Video Tutorial]](https://www.youtube.com/watch?v=J24Bvo_m7DM)
## Deploy Supabase on DigitalOcean
![Deploy Supabase on DigitalOcean](/images/blog/2023-02-08-january-beta-update/self-host-supabase-digital-ocean.png)
We teamed up with DigitalOcean to level up self-hosted Supabase. This guide shows how to host Supabase on DigitalOcean using Sendgrid, Packer, and Terraform. More collaborations coming soon!
[Get started](https://docs.digitalocean.com/developer-center/hosting-supabase-on-digitalocean/).
## 45k Github stars (and counting!)
![45k Github stars (and counting!)](/images/blog/2023-02-08-january-beta-update/github-45k.png)
We hit two big milestones: 45k stars and Supabase is one the top 200 most-popular repos on Github 💥
Massive thanks to the community for all the support 👁️⚡️👁️
[Supabase Repo.](https://github.com/supabase/supabase)
## Made with Supabase
![Made with Supabase](/images/blog/2022-12-07-november-beta-update/madewithsupabase.jpg)
[supermeme.ai](https://www.supermeme.ai/) | Two things that we are fans of are memes and AI. Just describe your thoughts and let AI create original memes for you. Available in 110+ languages!
Discover other great projects: [Made with Supabase](https://www.madewithsupabase.com/).
## Extended Community Highlights
![Community](/images/blog/2022-june/community.jpg)
- JWT Helper for Supabase by Zuplo. [Tool](https://zuplo.com/blog/2023/01/05/supabase-jwt-auth-helper/) <br/>
- ClickHouse and PostgreSQL - a Match Made in Data Heaven - Part 2. [Blog Post](https://clickhouse.com/blog/migrating-data-between-clickhouse-postgres-part-2)
- Building a Startup from Scratch: My Mistakes as CTO. [Blog Post](https://egor-romanov.medium.com/building-a-startup-from-scratch-my-mistakes-as-cto-b20b463e0058)
- We are sponsoring TreeHacks, Stanford University's premier hackathon and one of the largest hackathons in the USA. [Hackathon](https://www.treehacks.com)
- Set up a Svelte to-do list on self-hosted Supabase + authentication. [Tutorial](https://blog.cpbprojects.me/set-up-a-svelte-todo-list-on-self-hosted-supabase-email-sign-up-google-facebook-auth-host-on-github-pages)
- Vercel wrote a case study about how much we love TurboRepo (and Vercel in general 🖤). [Case Study](https://vercel.com/customers/how-supabase-elevated-their-developer-experience-with-turborepo)
- A Very Basic Scraper/Aggregator Site in Next.js with Go Cloud Functions and Supabase. [Article](https://chriscoyier.net/2023/01/23/a-very-basic-scraper-aggregator-site-in-next-js-with-go-cloud-functions-and-supabase/)
- Supabase CDC Webhooks to Memphis REST Gateway. [Article](https://memphis.dev/blog/supabase-cdc-webhooks-to-memphis-rest-gateway/)
- How I Replaced Revue With a Custom-Built Newsletter Service Using Nuxt 3, Supabase, Serverless, and Amazon SES. [Article](https://mokkapps.de/blog/how-i-replaced-revue-with-a-custom-built-newsletter-service-using-nuxt-3-supabase-serverless-and-amazon-ses/)
- Nuxt 3, Tailwind, and Supabase Crash Course. [Video Course](https://www.youtube.com/watch?v=A-G6lPHctPs)
- WhatsApp in React Native. [Part 1](https://dev.to/jacksbridger/whatsapp-ui-in-react-native-part-1-4nbm), [Part 2](https://dev.to/nsmet/chat-backend-with-supabase-socketio-55nn), [Part 3](https://dev.to/jacksbridger/whatsapp-in-react-native-part-3-1gmf)
- Distributed GraphQL with Hasura and Supabase. [Docs](https://www.section.io/docs/tutorials/distributed-apis/distributed-hasura-supabase/)
## We're Hiring
Come join one of the fastest-growing open source projects ever 🤗
- [Integrations / Marketplace Lead](https://boards.greenhouse.io/supabase/jobs/4775849004) <br/>
- [Cloud Platform / Site Reliability Engineer](https://boards.greenhouse.io/supabase/jobs/4307459004) <br/>
- [Social Media and Community Manager](https://boards.greenhouse.io/supabase/jobs/4777008004)
We've redesigned our [Careers page](https://supabase.com/careers) to better reflect our mission, values, and culture.
## Meme Zone
As always, one of our favorite memes from last month. [Follow us on Twitter](https://twitter.com/supabase) for more.
![Best meme from January 2023](/images/blog/2023-02-08-january-beta-update/beta-update-january-meme.jpeg)
See you next month!
+1 -1
View File
@@ -23,7 +23,7 @@
}
},
{
"title": "Database space",
"title": "Database size",
"tooltips": {
"main": "Billing is based on the average database size in GB throughout the billing period.",
"pro": "8 GB included, then $0.125 per GB"
+15
View File
@@ -1827,6 +1827,16 @@ module.exports = [
source: '/legal/soc2',
destination: 'https://forms.supabase.com/soc2',
},
{
permanent: true,
source: '/docs/guides/api',
destination: '/docs/guides/database/api',
},
{
permanent: true,
source: '/docs/guides/api/generating-types',
destination: '/docs/guides/database/api/generating-types',
},
{
permanent: true,
source: '/docs/reference/javascript/upgrade-guide',
@@ -1842,4 +1852,9 @@ module.exports = [
source: '/docs/guides/examples',
destination: '/docs/guides/resources/examples',
},
{
permanent: true,
source: '/docs/reference/javascript/v0/rpc',
destination: '/docs/reference/javascript/rpc',
},
]
+1 -1
View File
@@ -786,7 +786,7 @@ export default function launchweek() {
</span>
</div>
<SectionButtons
docs="/docs/guides/api#graphql-api"
docs="/docs/guides/database/api#graphql-api"
blog="/blog/pg-graphql-v1"
/>
</div>
Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 530 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 667 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 270 KiB

After

Width:  |  Height:  |  Size: 630 KiB

+164 -157
View File
File diff suppressed because it is too large. Load diff
@@ -2,7 +2,7 @@ import { Application, Router } from 'https://deno.land/x/oak/mod.ts'
const router = new Router()
router
// Note: path will be prefixed with function name
// Note: path should be prefixed with function name
.get('/oak-server', (context) => {
context.response.body = 'This is an example Oak server running on Edge Functions!'
})
@@ -0,0 +1,2 @@
#Use PolyScale connection string with application_name parameter to get code-free database caching
DATABASE_URL="postgresql:/DB_USERNAME:DB_PASSWORD@psedge.global:5432/postgres?application_name=POLYSCALE_CACHE_ID"
@@ -0,0 +1,18 @@
# postgres-on-the-edge
This function allows you to access your Supabase database directly via TCP from an edge function.
You can add a global cache to your database for fast access to your data, globally by simply connecting your Supabase database to [PolyScale](https://polyscale.ai).
## Setup
1. Rename `.env.example` to `.env`
2. Insert Supabase database connection string for `DATABASE_URL` in `.env` file
3. (Optional) Create PolyScale cache - see [instructions](https://supabase.com/docs/guides/integrations/polyscale) for adding a PolyScale cache.
4. Replace `DATABASE_URL` with PolyScale connection string.
## Deploy
1. Run `supabase functions deploy --no-verify-jwt postgres-on-the-edge`
2. Run `supabase secrets set --env-file supabase/functions/postgres-on-the-edge/.env`
Learn more about creating this function [here](https://www.youtube.com/watch?v=cl7EuF1-RsY).
@@ -0,0 +1,43 @@
import * as postgres from 'https://deno.land/x/postgres@v0.14.2/mod.ts'
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'
// Get the connection string from the environment variable "DATABASE_URL"
const databaseUrl = Deno.env.get('DATABASE_URL')!
// Create a database pool with three connections that are lazily established
const pool = new postgres.Pool(databaseUrl, 3, true)
serve(async (_req) => {
try {
// Grab a connection from the pool
const connection = await pool.connect()
try {
// Run a query
const result = await connection.queryObject`SELECT * FROM animals`
const animals = result.rows // [{ id: 1, name: "Lion" }, ...]
console.log(animals)
// Encode the result as pretty printed JSON
const body = JSON.stringify(
animals,
(_key, value) => (typeof value === 'bigint' ? value.toString() : value),
2
)
// Return the response with the correct content type header
return new Response(body, {
status: 200,
headers: {
'Content-Type': 'application/json; charset=utf-8',
},
})
} finally {
// Release the connection back into the pool
connection.release()
}
} catch (err) {
console.error(err)
return new Response(String(err?.message ?? err), { status: 500 })
}
})
@@ -0,0 +1,2 @@
UPSTASH_REDIS_REST_URL=
UPSTASH_REDIS_REST_TOKEN=
@@ -0,0 +1,31 @@
# Upstash Redis in Supabase Edge Functions
A Redis counter example that stores a [hash](https://redis.io/commands/hincrby/) of function invocation count per region.
## Redis database setup
Create a Redis database using the [Upstash Console](https://console.upstash.com/) or [Upstash CLI](https://github.com/upstash/cli).
Select the `Global` type to minimize the latency from all edge locations. Copy the `UPSTASH_REDIS_REST_URL` and `UPSTASH_REDIS_REST_TOKEN` to your .env file. You'll find them under **Details > REST API > .env**.
```bash
cp supabase/functions/upstash-redis-counter/.env.example supabase/functions/upstash-redis-counter/.env
```
## Run locally
Make sure you have the latest version of the [Supabase CLI installed](https://supabase.com/docs/guides/cli#installation).
```bash
supabase start
supabase functions serve upstash-redis-counter --no-verify-jwt --env-file supabase/functions/upstash-redis-counter/.env
```
Navigate to http://localhost:54321/functions/v1/upstash-redis-counter.
## Deploy
```bash
supabase functions deploy upstash-redis-counter --no-verify-jwt
supabase secrets set --env-file supabase/functions/upstash-redis-counter/.env
```
@@ -0,0 +1,41 @@
// Follow this setup guide to integrate the Deno language server with your editor:
// https://deno.land/manual/getting_started/setup_your_environment
// This enables autocomplete, go to definition, etc.
import { serve } from 'https://deno.land/std@0.177.0/http/server.ts'
import { Redis } from 'https://deno.land/x/upstash_redis@v1.19.3/mod.ts'
console.log(`Function "upstash-redis-counter" up and running!`)
serve(async (_req) => {
try {
const redis = new Redis({
url: Deno.env.get('UPSTASH_REDIS_REST_URL')!,
token: Deno.env.get('UPSTASH_REDIS_REST_TOKEN')!,
})
const deno_region = Deno.env.get('DENO_REGION')
if (deno_region) {
// Increment region counter
await redis.hincrby('supa-edge-counter', deno_region, 1)
} else {
// Increment localhost counter
await redis.hincrby('supa-edge-counter', 'localhost', 1)
}
// Get all values
const counterHash: Record<string, number> | null = await redis.hgetall('supa-edge-counter')
const counters = Object.entries(counterHash!)
.sort(([, a], [, b]) => b - a) // sort desc
.reduce((r, [k, v]) => ({ total: r.total + v, regions: { ...r.regions, [k]: v } }), {
total: 0,
regions: {},
})
return new Response(JSON.stringify({ counters }), { status: 200 })
} catch (error) {
return new Response(JSON.stringify({ error: error.message }), { status: 200 })
}
})
// To invoke, navigate to 'http://localhost:54321/functions/v1/upstash-redis-counter'.
@@ -0,0 +1,46 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.buildlog/
.history
.svn/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.packages
.pub-cache/
.pub/
/build/
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release
/pubspec.lock
@@ -0,0 +1,48 @@
# Flutter Real-time Multiplayer Shooting Game
A real-time shooting game built with [Flutter](https://flutter.dev/), [Flame](https://flame-engine.org/) and [Supabase](https://supabase.com).
You can find a step by step guide on how to build this app on [How to build a real-time multiplayer game with Flutter Flame](https://supabase.com/blog/flutter-real-time-game) article.
## Getting Started
### 1. Create new project
Sign up to Supabase - [app.supabase.io](https://app.supabase.io) and create a new project. Wait for your database to start.
### 2. Get the URL and Key
Go to the Project Settings (the cog icon), open the API tab, and find your API URL and `anon` key, you'll need these in the next step.
The `anon` key is your client-side API key. It allows "anonymous access" to your database, until the user has logged in. Once they have logged in, the keys will switch to the user's own login token.
![Supabase Anon Key](supabase_anon_key.jpg?raw=true 'Supabase Anon Key')
### 3. Pull this example git repository
`git clone <<this repository url>> `
### 4. Paste the Supabase URL and Anon Key
Copy and paste the Supabase URL and Anon key in `lib/main.dart` file
```dart
void main() async {
await Supabase.initialize(
url: 'supabaseUrl',
anonKey: 'supabaseAnonKey',
realtimeClientOptions: const RealtimeClientOptions(eventsPerSecond: 40),
);
runApp(const MyApp());
}
```
### 5. Run the Flutter App
Now run
```bash
flutter run
```
This app can run on any environment that runs Flutter.
@@ -0,0 +1,29 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at
# https://dart-lang.github.io/linter/lints/index.html.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options
@@ -0,0 +1,13 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
# Remember to never publicly share your keystore.
# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
key.properties
**/*.keystore
**/*.jks
@@ -0,0 +1,71 @@
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
localPropertiesFile.withReader('UTF-8') { reader ->
localProperties.load(reader)
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion flutter.compileSdkVersion
ndkVersion flutter.ndkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.flame_realtime_shooting"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion flutter.minSdkVersion
targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
}
}
flutter {
source '../..'
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}
@@ -0,0 +1,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.flame_realtime_shooting">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>
@@ -0,0 +1,34 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.flame_realtime_shooting">
<application
android:label="flame_realtime_shooting"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
</manifest>
@@ -0,0 +1,6 @@
package com.example.flame_realtime_shooting
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity() {
}
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>
Loaded 100 of 256 files, more files were not shown because too many files have changed in this diff. Show more