No files matched your search
@@ -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)
|
||||
|
||||
@@ -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)}
|
||||
|
||||
@@ -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: [] },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -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: [] },
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 />
|
||||
|
||||

|
||||
|
||||
### 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 />
|
||||
|
||||

|
||||
|
||||
### 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 />
|
||||
|
||||

|
||||
|
||||
### 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 />
|
||||
|
||||

|
||||
|
||||
### 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 />
|
||||
|
||||

|
||||
|
||||
### 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 />
|
||||
|
||||

|
||||
|
||||
### 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 = {
|
||||
|
||||

|
||||
|
||||
### 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 />
|
||||
|
||||

|
||||
|
||||
### 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 />
|
||||
|
||||
@@ -434,18 +433,11 @@ async function signOut() {
|
||||
</template>
|
||||
```
|
||||
|
||||
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 />
|
||||
|
||||

|
||||
|
||||
### 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 />
|
||||
|
||||

|
||||
|
||||
<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 />
|
||||
|
||||

|
||||
|
||||
### 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 />
|
||||
|
||||

|
||||
|
||||
### 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 />
|
||||
|
||||

|
||||
|
||||
### 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 />
|
||||
|
||||

|
||||
|
||||
### 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 />
|
||||
|
||||
@@ -383,13 +382,8 @@ import Avatar from './Avatar.vue'
|
||||
|
||||
<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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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).
|
||||
|
||||

|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -109,7 +109,25 @@
|
||||
</url>
|
||||
|
||||
<url>
|
||||
<loc>https://supabase.com/docs/guides/api/generating-types</loc>
|
||||
<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>
|
||||
<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>
|
||||
|
||||
@@ -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.
|
||||
|
||||

|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||

|
||||
|
||||
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
|
||||
|
||||

|
||||
|
||||
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
|
||||
|
||||

|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||

|
||||
|
||||
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
|
||||
|
||||

|
||||
|
||||
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#
|
||||
|
||||

|
||||
|
||||
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
|
||||
|
||||

|
||||
|
||||
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
|
||||
|
||||

|
||||
|
||||
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
|
||||
|
||||

|
||||
|
||||
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!)
|
||||
|
||||

|
||||
|
||||
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
|
||||
|
||||

|
||||
|
||||
[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
|
||||
|
||||

|
||||
|
||||
- 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.
|
||||
|
||||

|
||||
|
||||
See you next month!
|
||||
@@ -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',
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
After Width: | Height: | Size: 137 KiB |
|
After Width: | Height: | Size: 530 KiB |
|
After Width: | Height: | Size: 96 KiB |
|
After Width: | Height: | Size: 138 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 127 KiB |
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 89 KiB |
|
After Width: | Height: | Size: 661 KiB |
@@ -5,9 +5,16 @@
|
||||
<link>https://supabase.com</link>
|
||||
<description>Latest news from Supabase</description>
|
||||
<language>en</language>
|
||||
<lastBuildDate>Mon, 06 Feb 2023 03:03:30 +0000</lastBuildDate>
|
||||
<lastBuildDate>Tue, 07 Feb 2023 03:03:30 +0000</lastBuildDate>
|
||||
<atom:link href="https://supabase.com/rss.xml" rel="self" type="application/rss+xml"/>
|
||||
<item>
|
||||
<guid>https://supabase.com/blog/supabase-beta-january-2023</guid>
|
||||
<title>Supabase Beta January 2023</title>
|
||||
<link>https://supabase.com/blog/supabase-beta-january-2023</link>
|
||||
<description>New Postgres extensions, pg_graphql updates, changes to Edge Functions, and more!</description>
|
||||
<pubDate>Tue, 07 Feb 2023 03:03:30 +0000</pubDate>
|
||||
</item>
|
||||
<item>
|
||||
<guid>https://supabase.com/blog/chatgpt-supabase-docs</guid>
|
||||
<title>Supabase Clippy: ChatGPT for Supabase Docs</title>
|
||||
<link>https://supabase.com/blog/chatgpt-supabase-docs</link>
|
||||
|
||||
@@ -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'.
|
||||
@@ -1,4 +1,4 @@
|
||||
# Supabase Next.js User Management
|
||||
# Supabase Next.js Auth & User Management Starter
|
||||
|
||||
This example will set you up for a very common situation: users can sign up or sign in and then update their account with public profile information, including a profile image.
|
||||
|
||||
@@ -27,7 +27,13 @@ The Vercel deployment will guide you through creating a Supabase account and pro
|
||||
|
||||
[](https://vercel.com/new/git/external?repository-url=https%3A%2F%2Fgithub.com%2Fsupabase%2Fsupabase%2Ftree%2Fmaster%2Fexamples%2Fuser-management%2Fnextjs-ts-user-management&project-name=supabase-user-management&repository-name=supabase-user-management&demo-title=Supabase%20User%20Management&demo-description=An%20example%20web%20app%20using%20Supabase%20and%20Next.js&demo-url=https%3A%2F%2Fsupabase-nextjs-ts-user-management.vercel.app&demo-image=https%3A%2F%2Fi.imgur.com%2FZ3HkQqe.png&integration-ids=oac_jUduyjQgOyzev1fjrW83NYOv&external-id=nextjs-user-management)
|
||||
|
||||
## Build from scratch
|
||||
## Build locally
|
||||
|
||||
Or create a new projec locally with `create-next-app`:
|
||||
|
||||
```bash
|
||||
npx create-next-app -e with-supabase
|
||||
```
|
||||
|
||||
### 1. Create new project
|
||||
|
||||
@@ -129,6 +135,23 @@ create policy "Anyone can update their own avatar." on storage.objects
|
||||
for update using ( auth.uid() = owner ) with check (bucket_id = 'avatars');
|
||||
```
|
||||
|
||||
## More Supabase Examples & Resources
|
||||
|
||||
## Examples
|
||||
|
||||
These official examples are maintained by the Supabase team:
|
||||
|
||||
- [Next.js Subscription Payments Starter](https://github.com/vercel/nextjs-subscription-payments)
|
||||
- [Next.js Slack Clone](https://github.com/supabase/supabase/tree/master/examples/slack-clone/nextjs-slack-clone)
|
||||
- [Next.js 13 Data Fetching](https://github.com/supabase/supabase/tree/master/examples/caching/with-nextjs-13)
|
||||
- [And more...](https://github.com/supabase/supabase/tree/master/examples)
|
||||
|
||||
## Other resources
|
||||
|
||||
- [[Docs] Next.js User Management Quickstart](https://supabase.com/docs/guides/getting-started/tutorials/with-nextjs)
|
||||
- [[Egghead.io] Build a SaaS product with Next.js, Supabase and Stripe](https://egghead.io/courses/build-a-saas-product-with-next-js-supabase-and-stripe-61f2bc20)
|
||||
- [[Blog] Fetching and caching Supabase data in Next.js 13 Server Components](https://supabase.com/blog/fetching-and-caching-supabase-data-in-next-js-server-components)
|
||||
|
||||
## Authors
|
||||
|
||||
- [Supabase](https://supabase.com)
|
||||
|
||||
@@ -14,36 +14,36 @@ export default function Account({ session }: { session: Session }) {
|
||||
const [avatar_url, setAvatarUrl] = useState<Profiles['avatar_url']>(null)
|
||||
|
||||
useEffect(() => {
|
||||
getProfile()
|
||||
}, [session])
|
||||
async function getProfile() {
|
||||
try {
|
||||
setLoading(true)
|
||||
if (!user) throw new Error('No user')
|
||||
|
||||
async function getProfile() {
|
||||
try {
|
||||
setLoading(true)
|
||||
if (!user) throw new Error('No user')
|
||||
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) {
|
||||
setUsername(data.username)
|
||||
setWebsite(data.website)
|
||||
setAvatarUrl(data.avatar_url)
|
||||
}
|
||||
} catch (error) {
|
||||
alert('Error loading user data!')
|
||||
console.log(error)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
if (data) {
|
||||
setUsername(data.username)
|
||||
setWebsite(data.website)
|
||||
setAvatarUrl(data.avatar_url)
|
||||
}
|
||||
} catch (error) {
|
||||
alert('Error loading user data!')
|
||||
console.log(error)
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
getProfile()
|
||||
}, [session, user, supabase])
|
||||
|
||||
async function updateProfile({
|
||||
username,
|
||||
|
||||
@@ -19,21 +19,21 @@ export default function Avatar({
|
||||
const [uploading, setUploading] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (url) downloadImage(url)
|
||||
}, [url])
|
||||
|
||||
async function downloadImage(path: string) {
|
||||
try {
|
||||
const { data, error } = await supabase.storage.from('avatars').download(path)
|
||||
if (error) {
|
||||
throw error
|
||||
async function downloadImage(path: string) {
|
||||
try {
|
||||
const { data, error } = await supabase.storage.from('avatars').download(path)
|
||||
if (error) {
|
||||
throw error
|
||||
}
|
||||
const url = URL.createObjectURL(data)
|
||||
setAvatarUrl(url)
|
||||
} catch (error) {
|
||||
console.log('Error downloading image: ', error)
|
||||
}
|
||||
const url = URL.createObjectURL(data)
|
||||
setAvatarUrl(url)
|
||||
} catch (error) {
|
||||
console.log('Error downloading image: ', error)
|
||||
}
|
||||
}
|
||||
|
||||
if (url) downloadImage(url)
|
||||
}, [url, supabase.storage])
|
||||
|
||||
const uploadAvatar: React.ChangeEventHandler<HTMLInputElement> = async (event) => {
|
||||
try {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export default function Footer({}) {
|
||||
export default function Footer() {
|
||||
return (
|
||||
<div className="footer">
|
||||
<div className=""></div>
|
||||
@@ -9,6 +9,7 @@ export default function Footer({}) {
|
||||
<div className="flex-end flex">
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href="https://vercel.com/new/git/external?repository-url=https%3A%2F%2Fgithub.com%2Fsupabase%2Fsupabase%2Ftree%2Fmaster%2Fexamples%2Fuser-management%2Fnextjs-ts-user-management&project-name=supabase-user-management&repository-name=supabase-user-management&demo-title=Supabase%20User%20Management&demo-description=An%20example%20web%20app%20using%20Supabase%20and%20Next.js&demo-url=https%3A%2F%2Fsupabase-nextjs-ts-user-management.vercel.app&demo-image=https%3A%2F%2Fi.imgur.com%2FZ3HkQqe.png&integration-ids=oac_jUduyjQgOyzev1fjrW83NYOv&external-id=nextjs-user-management"
|
||||
>
|
||||
<img src="https://vercel.com/button" alt="vercel button" />
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@supabase/auth-helpers-nextjs": "^0.4.2",
|
||||
"@supabase/auth-helpers-nextjs": "^0.5.4",
|
||||
"@supabase/auth-helpers-react": "^0.3.1",
|
||||
"@supabase/auth-ui-react": "^0.2.2",
|
||||
"@supabase/supabase-js": "^2.0.4",
|
||||
"@supabase/auth-ui-react": "^0.2.6",
|
||||
"@supabase/supabase-js": "^2.5.0",
|
||||
"next": "12.3.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0"
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
- [x] Хоствана Postgres база данни. [Docs](https://supabase.com/docs/guides/database)
|
||||
- [x] Автентикация и оторизация [Docs](https://supabase.com/docs/guides/auth)
|
||||
- [x] Автоматично генерирани APIs (Приложно-програмен интерфейс).
|
||||
- [x] REST. [Docs](https://supabase.com/docs/guides/api#rest-api)
|
||||
- [x] Абониране в реално време. [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] Абониране в реално време. [Docs](https://supabase.com/docs/guides/database/api#realtime-api)
|
||||
- [x] GraphQL (Beta). [Docs](https://supabase.com/docs/guides/database/api#graphql-api)
|
||||
- [x] Функции.
|
||||
- [x] Функции за база данни. [Docs](https://supabase.com/docs/guides/database/functions)
|
||||
- [x] Edge Functions [Docs](https://supabase.com/docs/guides/functions)
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
- [x] হোস্ট করা পোস্টগ্রেস ডাটাবেস. [ডক্স](https://supabase.com/docs/guides/database)
|
||||
- [x] অথেনটিকেশন এবং অথরাইজড . [ডক্স](https://supabase.com/docs/guides/auth)
|
||||
- [x] স্বয়ংক্রিয়ভাবে তৈরি এপিআই.
|
||||
- [x] রেস্ট. [ডক্স](https://supabase.com/docs/guides/api#rest-api)
|
||||
- [x] রিয়েলটাইম সাবস্ক্রিপশন. [ডক্স](https://supabase.com/docs/guides/api#realtime-api)
|
||||
- [x] গ্রাফকিউএল (বেটা). [ডক্স](https://supabase.com/docs/guides/api#graphql-api)
|
||||
- [x] রেস্ট. [ডক্স](https://supabase.com/docs/guides/database/api#rest-api)
|
||||
- [x] রিয়েলটাইম সাবস্ক্রিপশন. [ডক্স](https://supabase.com/docs/guides/database/api#realtime-api)
|
||||
- [x] গ্রাফকিউএল (বেটা). [ডক্স](https://supabase.com/docs/guides/database/api#graphql-api)
|
||||
- [x] ফাংশনস.
|
||||
- [x] ডাটাবেস ফাংশনস. [ডক্স](https://supabase.com/docs/guides/database/functions)
|
||||
- [x] এজ ফাংশনস. [ডক্স](https://supabase.com/docs/guides/functions)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
<div style="direction: rtl;" dir="rtl">
|
||||
|
||||
<p align="center">
|
||||
<img width="300" src="https://raw.githubusercontent.com/supabase/supabase/master/packages/common/assets/images/supabase-logo-wordmark--light.svg#gh-light-mode-only">
|
||||
<img width="300" src="https://raw.githubusercontent.com/supabase/supabase/master/packages/common/assets/images/supabase-logo-wordmark--dark.svg#gh-dark-mode-only">
|
||||
@@ -87,3 +89,5 @@
|
||||
[](https://github.com/sponsors/supabase)
|
||||
|
||||
</p>
|
||||
|
||||
</div>
|
||||
@@ -12,9 +12,9 @@
|
||||
- [x] Isännöity Postgres-tietokanta [Docs](https://supabase.com/docs/guides/database)
|
||||
- [x] Autentikointi ja valtuutus [Docs](https://supabase.com/docs/guides/auth)
|
||||
- [x] Automaattisesti luodut rajapinnat
|
||||
- [x] REST [Docs](https://supabase.com/docs/guides/api#rest-api)
|
||||
- [x] Reaaliaikaiset tilaukset [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] Reaaliaikaiset tilaukset [Docs](https://supabase.com/docs/guides/database/api#realtime-api)
|
||||
- [x] GraphQL (Beta) [Docs](https://supabase.com/docs/guides/database/api#graphql-api)
|
||||
- [x] Funktiot
|
||||
- [x] Tietokantatoiminnot [Docs](https://supabase.com/docs/guides/database/functions)
|
||||
- [x] Reunatoiminnot [Docs](https://supabase.com/docs/guides/functions)
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
- [x] होस्टेड पोस्टग्रेज डेटाबेस। [प्रलेखन](https://supabase.com/docs/guides/database)
|
||||
- [x] प्रमाणीकरण और प्राधिकरण। [प्रलेखन](https://supabase.com/docs/guides/auth)
|
||||
- [x] उत्पन्न एपीआईस।
|
||||
- [x] रेस्ट। [प्रलेखन](https://supabase.com/docs/guides/api#rest-api)
|
||||
- [x] रीयलटाइम सदस्यता। [प्रलेखन](https://supabase.com/docs/guides/api#realtime-api)
|
||||
- [x] ग्राफ़क्यूएल (प्रयोगात्मक)। [प्रलेखन](https://supabase.com/docs/guides/api#graphql-api)
|
||||
- [x] रेस्ट। [प्रलेखन](https://supabase.com/docs/guides/database/api#rest-api)
|
||||
- [x] रीयलटाइम सदस्यता। [प्रलेखन](https://supabase.com/docs/guides/database/api#realtime-api)
|
||||
- [x] ग्राफ़क्यूएल (प्रयोगात्मक)। [प्रलेखन](https://supabase.com/docs/guides/database/api#graphql-api)
|
||||
- [x] फ़ंक्शंस।
|
||||
- [x] डेटाबेस फ़ंक्शंस। [प्रलेखन](https://supabase.com/docs/guides/database/functions)
|
||||
- [x] एज फ़ंक्शंस। [प्रलेखन](https://supabase.com/docs/guides/functions)
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
- [x] ホスティングされた Postgres データベース [Docs](https://supabase.com/docs/guides/database)
|
||||
- [x] 認証・認可 [Docs](https://supabase.com/docs/guides/auth)
|
||||
- [x] API を自動生成
|
||||
- [x] REST [Docs](https://supabase.com/docs/guides/api#rest-api)
|
||||
- [x] リアルタイムサブスクリプション [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] リアルタイムサブスクリプション [Docs](https://supabase.com/docs/guides/database/api#realtime-api)
|
||||
- [x] GraphQL (Beta) [Docs](https://supabase.com/docs/guides/database/api#graphql-api)
|
||||
- [x] 関数
|
||||
- [x] データベース関数 [Docs](https://supabase.com/docs/guides/database/functions)
|
||||
- [x] Edge Functions [Docs](https://supabase.com/docs/guides/functions)
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
- [x] 호스팅 된 Postgres 데이터베이스. [Docs](https://supabase.com/docs/guides/database)
|
||||
- [x] 사용자 인증 및 권한 부여. [Docs](https://supabase.com/docs/guides/auth)
|
||||
- [x] 자동생성 API.
|
||||
- [x] REST. [Docs](https://supabase.com/docs/guides/api#rest-api)
|
||||
- [x] 실시간 구독. [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] 실시간 구독. [Docs](https://supabase.com/docs/guides/database/api#realtime-api)
|
||||
- [x] GraphQL (Beta). [Docs](https://supabase.com/docs/guides/database/api#graphql-api)
|
||||
- [x] 함수.
|
||||
- [x] 데이터베이스 함수. [Docs](https://supabase.com/docs/guides/database/functions)
|
||||
- [x] 엣지 함수 [Docs](https://supabase.com/docs/guides/functions)
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
- [x] Banco de dados hospedado de Postgres. [Docs](https://supabase.com/docs/guides/database)
|
||||
- [x] Autenticação e Autorização. [Docs](https://supabase.com/docs/guides/auth)
|
||||
- [x] APIs auto-geradas.
|
||||
- [x] REST. [Docs](https://supabase.com/docs/guides/api#rest-api)
|
||||
- [x] Assinaturas em tempo real. [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] Assinaturas em tempo real. [Docs](https://supabase.com/docs/guides/database/api#realtime-api)
|
||||
- [x] GraphQL (Beta). [Docs](https://supabase.com/docs/guides/database/api#graphql-api)
|
||||
- [x] Funções.
|
||||
- [x] Funções do Banco de Dados [Docs]https://supabase.com/docs/guides/database/functions)
|
||||
- [x] Funções de borda [Docs](https://supabase.com/docs/guides/functions)
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
- [x] Hostovana Postgres Baza. [Dokumentacija](https://supabase.com/docs/guides/database)
|
||||
- [x] Autentifikacija i Autorizacija. [Dokumentacija](https://supabase.com/docs/guides/auth)
|
||||
- [x] Auto-generisani API-ji.
|
||||
- [x] REST. [Dokumentacija](https://supabase.com/docs/guides/api#rest-api)
|
||||
- [x] Subskripcije u realnom vremenu. [Dokumentacija](https://supabase.com/docs/guides/api#realtime-api)
|
||||
- [x] GraphQL (Beta). [Dokumentacija](https://supabase.com/docs/guides/api#graphql-api)
|
||||
- [x] REST. [Dokumentacija](https://supabase.com/docs/guides/database/api#rest-api)
|
||||
- [x] Subskripcije u realnom vremenu. [Dokumentacija](https://supabase.com/docs/guides/database/api#realtime-api)
|
||||
- [x] GraphQL (Beta). [Dokumentacija](https://supabase.com/docs/guides/database/api#graphql-api)
|
||||
- [x] Funkcije.
|
||||
- [x] Funkcije u bazi. [Dokumentacija](https://supabase.com/docs/guides/database/functions)
|
||||
- [x] Edge Funkcije [Dokumentacija](https://supabase.com/docs/guides/functions)
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
- [x] ஹோஸ்ட் செய்யப்பட்ட பூஸ்ட்ஜீஆர்இஎஸ் தரவுத்தளம். [ஆவணம்](https://supabase.com/docs/guides/database)
|
||||
- [x] அங்கீகாரம் மற்றும் அங்கீகாரம்.. [ஆவணம்](https://supabase.com/docs/guides/auth)
|
||||
- [x] தானாக உருவாக்கப்பட்ட ஏபிஐ கள்.
|
||||
- [x] ராஸ்ட். [ஆவணம்](https://supabase.com/docs/guides/api#rest-api)
|
||||
- [x] நிகழ்நேர சந்தாக்கள். [ஆவணம்](https://supabase.com/docs/guides/api#realtime-api)
|
||||
- [x] கிராப்க்யூஎல் (பீட்டா). [ஆவணம்](https://supabase.com/docs/guides/api#graphql-api)
|
||||
- [x] ராஸ்ட். [ஆவணம்](https://supabase.com/docs/guides/database/api#rest-api)
|
||||
- [x] நிகழ்நேர சந்தாக்கள். [ஆவணம்](https://supabase.com/docs/guides/database/api#realtime-api)
|
||||
- [x] கிராப்க்யூஎல் (பீட்டா). [ஆவணம்](https://supabase.com/docs/guides/database/api#graphql-api)
|
||||
- [x] செயல்பாடுகள்.
|
||||
- [x] தரவுத்தளம் செயல்பாடுகள். [ஆவணம்](https://supabase.com/docs/guides/database/functions)
|
||||
- [x] விளிம்பு செயல்பாடுகள் [ஆவணம்](https://supabase.com/docs/guides/functions)
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
- [x] Cơ sở dữ liệu Postgres tự quản lý. [Tài liệu](https://supabase.com/docs/guides/database)
|
||||
- [x] Xác thực và uỷ quyền. [Tài liệu](https://supabase.com/docs/guides/auth)
|
||||
- [x] APIs tự động khởi tạo.
|
||||
- [x] REST. [Tài liệu](https://supabase.com/docs/guides/api#rest-api)
|
||||
- [x] Lắng nghe thay đổi thời gian thực. [Tài liệu](https://supabase.com/docs/guides/api#realtime-api)
|
||||
- [x] GraphQL (Thử nghiệm). [Tài liệu](https://supabase.com/docs/guides/api#graphql-api)
|
||||
- [x] REST. [Tài liệu](https://supabase.com/docs/guides/database/api#rest-api)
|
||||
- [x] Lắng nghe thay đổi thời gian thực. [Tài liệu](https://supabase.com/docs/guides/database/api#realtime-api)
|
||||
- [x] GraphQL (Thử nghiệm). [Tài liệu](https://supabase.com/docs/guides/database/api#graphql-api)
|
||||
- [x] Chức năng hàm.
|
||||
- [x] Hàm dành cho cơ sở dữ liệu (Database functions). [Tài liệu](https://supabase.com/docs/guides/database/functions)
|
||||
- [x] Hàm được phân phối trên toàn cầu (Edge Functions). [Tài liệu](https://supabase.com/docs/guides/functions)
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
- [x] Postgres 数据库托管。[文档](https://supabase.com/docs/guides/database)
|
||||
- [x] 身份验证和授权。[文档](https://supabase.com/docs/guides/auth)
|
||||
- [x] 自动生成的 API。
|
||||
- [x] REST。[文档](https://supabase.com/docs/guides/api#rest-api)
|
||||
- [x] 实时订阅。[文档](https://supabase.com/docs/guides/api#realtime-api)
|
||||
- [x] GraphQL(测试版)。[文档](https://supabase.com/docs/guides/api#graphql-api)
|
||||
- [x] REST。[文档](https://supabase.com/docs/guides/database/api#rest-api)
|
||||
- [x] 实时订阅。[文档](https://supabase.com/docs/guides/database/api#realtime-api)
|
||||
- [x] GraphQL(测试版)。[文档](https://supabase.com/docs/guides/database/api#graphql-api)
|
||||
- [x] 函数。
|
||||
- [x] 数据库函数。[文档](https://supabase.com/docs/guides/database/functions)
|
||||
- [x] 边缘函数。[文档](https://supabase.com/docs/guides/functions)
|
||||
|
||||
@@ -46181,7 +46181,7 @@
|
||||
"@sinclair/typebox": "^0.25.1",
|
||||
"pg": "^8.7.1",
|
||||
"pg-format": "^1.0.4",
|
||||
"pgsql-parser": "^13.3.0",
|
||||
"pgsql-parser": "13.4.0",
|
||||
"postgres-array": "^3.0.1",
|
||||
"prettier": "^2.6.0",
|
||||
"prettier-plugin-sql": "^0.12.1"
|
||||
|
||||
@@ -1,14 +1,3 @@
|
||||
// module.exports = {
|
||||
// content: [
|
||||
// "../../packages/ui/components/**/*.{ts,tsx}",
|
||||
// "./src/**/*.{ts,tsx}",
|
||||
// ],
|
||||
// theme: {
|
||||
// extend: {},
|
||||
// },
|
||||
// plugins: [],
|
||||
// }
|
||||
|
||||
const ui = require('./ui.config.js')
|
||||
const svgToDataUri = require('mini-svg-data-uri')
|
||||
|
||||
@@ -25,8 +14,7 @@ module.exports = ui({
|
||||
'./_blog/*.mdx',
|
||||
// purge styles from supabase ui theme
|
||||
],
|
||||
darkMode: 'class', // 'media' or 'class'
|
||||
// mode: 'jit',
|
||||
darkMode: 'class',
|
||||
theme: {
|
||||
borderColor: (theme) => ({
|
||||
...theme('colors'),
|
||||
@@ -216,89 +204,11 @@ module.exports = ui({
|
||||
}),
|
||||
screens: {
|
||||
xs: '480px',
|
||||
// sm: '640px',
|
||||
// // => @media (min-width: 640px) { ... }
|
||||
// md: '768px',
|
||||
// // => @media (min-width: 768px) { ... }
|
||||
// lg: '1024px',
|
||||
// // => @media (min-width: 1024px) { ... }
|
||||
// xl: '1280px',
|
||||
// // => @media (min-width: 1280px) { ... }
|
||||
// '2xl': '1536px',
|
||||
// // => @media (min-width: 1536px) { ... }
|
||||
},
|
||||
// colors: {
|
||||
// 'gray-light': '#7B7F86',
|
||||
// 'gray-dark': '#7B7F86',
|
||||
// 'accent-1': '#FAFAFA',
|
||||
// 'accent-2': '#EAEAEA',
|
||||
// 'accent-7': '#333',
|
||||
// success: '#0070f3',
|
||||
// cyan: '#79FFE1',
|
||||
// // brand: {
|
||||
// // 100: '#82dab0',
|
||||
// // 200: '#69d3a0',
|
||||
// // 300: '#50cb90',
|
||||
// // 400: '#C5F1DD',
|
||||
// // 500: '#9FE7C7',
|
||||
// // 600: '#65D9A5',
|
||||
// // 700: '#3ECF8E',
|
||||
// // 800: '#38BC81',
|
||||
// // 900: '#10633E',
|
||||
// // },
|
||||
// // Joshen TODO: At the end just rearrange the values
|
||||
// dark: {
|
||||
// 100: '#eeeeee',
|
||||
// 200: '#e0e0e0',
|
||||
// 300: '#bbbbbb',
|
||||
// 400: '#666666',
|
||||
// 500: '#444444',
|
||||
// 600: '#2a2a2a',
|
||||
// 700: '#1f1f1f',
|
||||
// 800: '#181818',
|
||||
// 900: '#0f0f0f',
|
||||
// },
|
||||
// // gray: {
|
||||
// // 100: '#eeeeee',
|
||||
// // 200: '#e0e0e0',
|
||||
// // 300: '#bbbbbb',
|
||||
// // 400: '#666666',
|
||||
// // 500: '#444444',
|
||||
// // 600: '#2a2a2a',
|
||||
// // 700: '#1f1f1f',
|
||||
// // 800: '#181818',
|
||||
// // 900: '#0f0f0f',
|
||||
// // },
|
||||
// },
|
||||
// spacing: {
|
||||
// 28: '7rem',
|
||||
// },
|
||||
// letterSpacing: {
|
||||
// tighter: '-.04em',
|
||||
// },
|
||||
// lineHeight: {
|
||||
// tight: 1.2,
|
||||
// },
|
||||
// fontSize: {
|
||||
// '5xl': '2.5rem',
|
||||
// '6xl': '2.75rem',
|
||||
// '7xl': '4.5rem',
|
||||
// '8xl': '6.25rem',
|
||||
// },
|
||||
// boxShadow: {
|
||||
// 'light-small': '0px 4px 8px 2px rgba(107, 114, 128, 0.08)',
|
||||
// small: '0 5px 10px rgba(0, 0, 0, 0.12)',
|
||||
// medium: '0 8px 30px rgba(0, 0, 0, 0.12)',
|
||||
// override: '0px 0px 0px rgba(0, 0, 0, 0)',
|
||||
// },
|
||||
fontFamily: {
|
||||
sans: ['custom-font', 'Helvetica Neue', 'Helvetica', 'Arial', 'sans-serif'],
|
||||
mono: ['Office Code Pro', 'Source Code Pro', 'Menlo', 'monospace'],
|
||||
},
|
||||
// stroke: (theme) => ({
|
||||
// white: theme('colors.white'),
|
||||
// black: theme('colors.black'),
|
||||
// }),
|
||||
backgroundImage: (theme) => ({
|
||||
squiggle: `url("${svgToDataUri(
|
||||
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 6 3" enable-background="new 0 0 6 3" width="6" height="3" fill="${theme(
|
||||
@@ -318,13 +228,6 @@ module.exports = ui({
|
||||
},
|
||||
},
|
||||
},
|
||||
// variants: {
|
||||
// extend: {
|
||||
// inset: ['group-hover'],
|
||||
// stroke: ['dark'],
|
||||
// height: ['hover'],
|
||||
// },
|
||||
// },
|
||||
plugins: [
|
||||
require('@tailwindcss/typography'),
|
||||
function ({ addUtilities, addVariant }) {
|
||||
|
||||
@@ -4992,7 +4992,7 @@ functions:
|
||||
title: 'on().subscribe()'
|
||||
$ref: '@supabase/realtime-js.RealtimeChannel.on'
|
||||
notes: |
|
||||
- Realtime is disabled by default for new Projects for better database performance and security. You can turn it on by [managing replication](/docs/guides/api#managing-realtime).
|
||||
- Realtime is disabled by default for new Projects for better database performance and security. You can turn it on by [managing replication](/docs/guides/database/api#managing-realtime).
|
||||
- Row level security is not applied to delete statements.
|
||||
- If you want to receive the "previous" data for updates and deletes, you will need to set `REPLICA IDENTITY` to `FULL`, like this: `ALTER TABLE your_table REPLICA IDENTITY FULL;`
|
||||
- When a delete occurs, the contents of old_record will be broadcast to all subscribers to that table so ensure that each table's replica identity only contains information that is safe to expose publicly.
|
||||
|
||||
@@ -685,7 +685,7 @@ functions:
|
||||
Subscribe to realtime changes in your database.
|
||||
title: 'on().subscribe()'
|
||||
notes: |
|
||||
- Realtime is disabled by default for new Projects for better database performance and security. You can turn it on by [managing replication](/docs/guides/api#managing-realtime).
|
||||
- Realtime is disabled by default for new Projects for better database performance and security. You can turn it on by [managing replication](/docs/guides/database/api#managing-realtime).
|
||||
- If you want to receive the "previous" data for updates and deletes, you will need to set `REPLICA IDENTITY` to `FULL`, like this: `ALTER TABLE your_table REPLICA IDENTITY FULL;`
|
||||
examples:
|
||||
- id: listen-to-all-database-changes
|
||||
|
||||
@@ -715,7 +715,7 @@ functions:
|
||||
Subscribe to realtime changes in your database.
|
||||
title: 'on().subscribe()'
|
||||
notes: |
|
||||
- Realtime is disabled by default for new Projects for better database performance and security. You can turn it on by [managing replication](/docs/guides/api#managing-realtime).
|
||||
- Realtime is disabled by default for new Projects for better database performance and security. You can turn it on by [managing replication](/docs/guides/database/api#managing-realtime).
|
||||
- If you want to receive the "previous" data for updates and deletes, you will need to set `REPLICA IDENTITY` to `FULL`, like this: `ALTER TABLE your_table REPLICA IDENTITY FULL;`
|
||||
examples:
|
||||
- id: listen-to-all-database-changes
|
||||
|
||||
@@ -1123,7 +1123,7 @@ functions:
|
||||
title: 'on().subscribe()'
|
||||
$ref: '@supabase/supabase-js.lib/SupabaseQueryBuilder.SupabaseQueryBuilder.on'
|
||||
notes: |
|
||||
- Realtime is disabled by default for new Projects for better database performance and security. You can turn it on by [managing replication](/docs/guides/api#managing-realtime).
|
||||
- Realtime is disabled by default for new Projects for better database performance and security. You can turn it on by [managing replication](/docs/guides/database/api#managing-realtime).
|
||||
- If you want to receive the "previous" data for updates and deletes, you will need to set `REPLICA IDENTITY` to `FULL`, like this: `ALTER TABLE your_table REPLICA IDENTITY FULL;`
|
||||
examples:
|
||||
- id: listen-to-all-database-changes
|
||||
|
||||
@@ -4168,7 +4168,7 @@ functions:
|
||||
$ref: '@supabase/realtime-js.RealtimeChannel.on'
|
||||
notes: |
|
||||
- By default, Broadcast and Presence are enabled for all projects.
|
||||
- By default, listening to database changes is disabled for new projects due to database performance and security concerns. You can turn it on by managing Realtime's [replication](/docs/guides/api#realtime-api-overview).
|
||||
- By default, listening to database changes is disabled for new projects due to database performance and security concerns. You can turn it on by managing Realtime's [replication](/docs/guides/database/api#realtime-api-overview).
|
||||
- You can receive the "previous" data for updates and deletes by setting the table's `REPLICA IDENTITY` to `FULL` (e.g., `ALTER TABLE your_table REPLICA IDENTITY FULL;`).
|
||||
- Row level security is not applied to delete statements. When RLS is enabled and replica identity is set to full, only the primary key is sent to clients.
|
||||
examples:
|
||||
|
||||
@@ -257,7 +257,7 @@ const NewProjectPanel: FC<Props> = ({}) => {
|
||||
<Button type="default">View API settings</Button>
|
||||
</a>
|
||||
</Link>
|
||||
<Link href="https://supabase.com/docs/guides/api">
|
||||
<Link href="https://supabase.com/docs/guides/database/api">
|
||||
<a target="_blank" rel="noreferrer">
|
||||
<Button className="translate-y-[1px]" type="default" icon={<IconExternalLink />}>
|
||||
About APIs
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
import { FC } from 'react'
|
||||
import { Input, Tabs } from 'ui'
|
||||
import { pluckObjectFields } from 'lib/helpers'
|
||||
import { useProjectSettingsQuery } from 'data/config/project-settings-query'
|
||||
|
||||
import Panel from 'components/ui/Panel'
|
||||
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
|
||||
import ResetDbPassword from './ResetDbPassword'
|
||||
|
||||
const DatabaseSettings: FC<any> = ({ projectRef }) => {
|
||||
const { data, isLoading, isError } = useProjectSettingsQuery({ projectRef })
|
||||
|
||||
if (isError) {
|
||||
return (
|
||||
<div className="mx-auto p-6 text-center sm:w-full md:w-3/4">
|
||||
<p className="text-scale-1000">Error loading database settings</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="space-y-10">
|
||||
<section className="space-y-6">
|
||||
<h3 className="text-scale-1200 mb-2 text-xl">Database Settings</h3>
|
||||
<Panel
|
||||
title={
|
||||
<h5 key="panel-title" className="mb-0">
|
||||
Connection info
|
||||
</h5>
|
||||
}
|
||||
className="!m-0"
|
||||
>
|
||||
<Panel.Content className="space-y-8">
|
||||
{Array.from({ length: 5 }).map((_, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="grid gap-2 items-center md:grid md:grid-cols-12 md:gap-x-4 w-full"
|
||||
>
|
||||
<ShimmeringLoader className="h-4 w-1/3 col-span-4" delayIndex={i} />
|
||||
<ShimmeringLoader className="h-8 w-full col-span-8" delayIndex={i} />
|
||||
</div>
|
||||
))}
|
||||
</Panel.Content>
|
||||
</Panel>
|
||||
</section>
|
||||
|
||||
<ResetDbPassword disabled={true} />
|
||||
|
||||
<section className="space-y-6">
|
||||
<Panel
|
||||
title={
|
||||
<h5 key="panel-title" className="mb-0">
|
||||
Connection string
|
||||
</h5>
|
||||
}
|
||||
className="!m-0"
|
||||
>
|
||||
<Panel.Content>
|
||||
<Tabs type="underlined" size="small">
|
||||
<Tabs.Panel id="psql" label="PSQL">
|
||||
<ShimmeringLoader className="h-8 w-full" />
|
||||
</Tabs.Panel>
|
||||
|
||||
<Tabs.Panel id="uri" label="URI">
|
||||
<ShimmeringLoader className="h-8 w-full" />
|
||||
</Tabs.Panel>
|
||||
|
||||
<Tabs.Panel id="golang" label="Golang">
|
||||
<ShimmeringLoader className="h-8 w-full" />
|
||||
</Tabs.Panel>
|
||||
|
||||
<Tabs.Panel id="jdbc" label="JDBC">
|
||||
<ShimmeringLoader className="h-8 w-full" />
|
||||
</Tabs.Panel>
|
||||
|
||||
<Tabs.Panel id="dotnet" label=".NET">
|
||||
<ShimmeringLoader className="h-8 w-full" />
|
||||
</Tabs.Panel>
|
||||
|
||||
<Tabs.Panel id="nodejs" label="Nodejs">
|
||||
<ShimmeringLoader className="h-8 w-full" />
|
||||
</Tabs.Panel>
|
||||
|
||||
<Tabs.Panel id="php" label="PHP">
|
||||
<ShimmeringLoader className="h-8 w-full" />
|
||||
</Tabs.Panel>
|
||||
|
||||
<Tabs.Panel id="python" label="Python">
|
||||
<ShimmeringLoader className="h-8 w-full" />
|
||||
</Tabs.Panel>
|
||||
</Tabs>
|
||||
</Panel.Content>
|
||||
</Panel>
|
||||
</section>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const { project } = data
|
||||
|
||||
const DB_FIELDS = ['db_host', 'db_name', 'db_port', 'db_user', 'inserted_at']
|
||||
const connectionInfo = pluckObjectFields(project, DB_FIELDS)
|
||||
|
||||
const uriConnString =
|
||||
`postgresql://${connectionInfo.db_user}:[YOUR-PASSWORD]@` +
|
||||
`${connectionInfo.db_host}:${connectionInfo.db_port.toString()}` +
|
||||
`/${connectionInfo.db_name}`
|
||||
const golangConnString =
|
||||
`user=${connectionInfo.db_user} password=[YOUR-PASSWORD] ` +
|
||||
`host=${connectionInfo.db_host} port=${connectionInfo.db_port.toString()}` +
|
||||
` dbname=${connectionInfo.db_name}`
|
||||
const psqlConnString =
|
||||
`psql -h ${connectionInfo.db_host} -p ` +
|
||||
`${connectionInfo.db_port.toString()} -d ${connectionInfo.db_name} ` +
|
||||
`-U ${connectionInfo.db_user}`
|
||||
|
||||
return (
|
||||
<div className="space-y-10">
|
||||
<section className="space-y-6">
|
||||
<h3 className="text-scale-1200 mb-2 text-xl">Database Settings</h3>
|
||||
<Panel
|
||||
title={
|
||||
<h5 key="panel-title" className="mb-0">
|
||||
Connection info
|
||||
</h5>
|
||||
}
|
||||
className="!m-0"
|
||||
>
|
||||
<Panel.Content className="space-y-6">
|
||||
<Input
|
||||
className="input-mono"
|
||||
layout="horizontal"
|
||||
readOnly
|
||||
copy
|
||||
disabled
|
||||
value={connectionInfo.db_host}
|
||||
label="Host"
|
||||
/>
|
||||
|
||||
<Input
|
||||
className="input-mono"
|
||||
layout="horizontal"
|
||||
readOnly
|
||||
copy
|
||||
disabled
|
||||
value={connectionInfo.db_name}
|
||||
label="Database name"
|
||||
/>
|
||||
|
||||
<Input
|
||||
className="input-mono"
|
||||
layout="horizontal"
|
||||
readOnly
|
||||
copy
|
||||
disabled
|
||||
value={connectionInfo.db_port.toString()}
|
||||
label="Port"
|
||||
/>
|
||||
|
||||
<Input
|
||||
layout="horizontal"
|
||||
className="input-mono table-input-cell text-base"
|
||||
readOnly
|
||||
copy
|
||||
disabled
|
||||
value={connectionInfo.db_user}
|
||||
label="User"
|
||||
/>
|
||||
|
||||
<Input
|
||||
className="input-mono"
|
||||
layout="horizontal"
|
||||
disabled
|
||||
readOnly
|
||||
value={'[The password you provided when you created this project]'}
|
||||
label="Password"
|
||||
/>
|
||||
</Panel.Content>
|
||||
</Panel>
|
||||
</section>
|
||||
|
||||
<ResetDbPassword />
|
||||
|
||||
<section className="space-y-6">
|
||||
<Panel
|
||||
title={
|
||||
<h5 key="panel-title" className="mb-0">
|
||||
Connection string
|
||||
</h5>
|
||||
}
|
||||
className="!m-0"
|
||||
>
|
||||
<Panel.Content>
|
||||
<Tabs type="underlined" size="small">
|
||||
<Tabs.Panel id="psql" label="PSQL">
|
||||
<Input copy readOnly disabled value={psqlConnString} />
|
||||
</Tabs.Panel>
|
||||
|
||||
<Tabs.Panel id="uri" label="URI">
|
||||
<Input copy readOnly disabled value={uriConnString} />
|
||||
</Tabs.Panel>
|
||||
|
||||
<Tabs.Panel id="golang" label="Golang">
|
||||
<Input copy readOnly disabled value={golangConnString} />
|
||||
</Tabs.Panel>
|
||||
|
||||
<Tabs.Panel id="jdbc" label="JDBC">
|
||||
<Input
|
||||
copy
|
||||
readOnly
|
||||
disabled
|
||||
value={
|
||||
`jdbc:postgresql://${
|
||||
connectionInfo.db_host
|
||||
}:${connectionInfo.db_port.toString()}` +
|
||||
`/${connectionInfo.db_name}?user=${connectionInfo.db_user}&password=[YOUR-PASSWORD]`
|
||||
}
|
||||
/>
|
||||
</Tabs.Panel>
|
||||
|
||||
<Tabs.Panel id="dotnet" label=".NET">
|
||||
<Input
|
||||
copy
|
||||
readOnly
|
||||
disabled
|
||||
value={
|
||||
`User Id=${connectionInfo.db_user};Password=[YOUR-PASSWORD];` +
|
||||
`Server=${connectionInfo.db_host};Port=${connectionInfo.db_port.toString()};` +
|
||||
`Database=${connectionInfo.db_name}`
|
||||
}
|
||||
/>
|
||||
</Tabs.Panel>
|
||||
|
||||
<Tabs.Panel id="nodejs" label="Nodejs">
|
||||
<Input copy readOnly disabled value={uriConnString} />
|
||||
</Tabs.Panel>
|
||||
|
||||
<Tabs.Panel id="php" label="PHP">
|
||||
<Input copy readOnly disabled value={golangConnString} />
|
||||
</Tabs.Panel>
|
||||
|
||||
<Tabs.Panel id="python" label="Python">
|
||||
<Input
|
||||
copy
|
||||
readOnly
|
||||
disabled
|
||||
value={
|
||||
`user=${connectionInfo.db_user} password=[YOUR-PASSWORD]` +
|
||||
` host=${connectionInfo.db_host} port=${connectionInfo.db_port.toString()}` +
|
||||
` database=${connectionInfo.db_name}`
|
||||
}
|
||||
/>
|
||||
</Tabs.Panel>
|
||||
</Tabs>
|
||||
</Panel.Content>
|
||||
</Panel>
|
||||
</section>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default DatabaseSettings
|
||||
@@ -0,0 +1,180 @@
|
||||
import * as Tooltip from '@radix-ui/react-tooltip'
|
||||
import { FC, useState, useRef, useEffect } from 'react'
|
||||
import { debounce } from 'lodash'
|
||||
import generator from 'generate-password'
|
||||
import { Input, Button, Modal } from 'ui'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
|
||||
import { checkPermissions, useParams, useStore } from 'hooks'
|
||||
import { patch } from 'lib/common/fetch'
|
||||
import { passwordStrength } from 'lib/helpers'
|
||||
import { API_URL, DEFAULT_MINIMUM_PASSWORD_STRENGTH } from 'lib/constants'
|
||||
|
||||
import Panel from 'components/ui/Panel'
|
||||
import PasswordStrengthBar from 'components/ui/PasswordStrengthBar'
|
||||
|
||||
const ResetDbPassword: FC<any> = ({ disabled = false }) => {
|
||||
const { ui, app, meta } = useStore()
|
||||
const { ref } = useParams()
|
||||
|
||||
const canResetDbPassword = checkPermissions(PermissionAction.UPDATE, 'projects')
|
||||
|
||||
const [showResetDbPass, setShowResetDbPass] = useState<boolean>(false)
|
||||
const [isUpdatingPassword, setIsUpdatingPassword] = useState<boolean>(false)
|
||||
|
||||
const [password, setPassword] = useState<string>('')
|
||||
const [passwordStrengthMessage, setPasswordStrengthMessage] = useState<string>('')
|
||||
const [passwordStrengthWarning, setPasswordStrengthWarning] = useState<string>('')
|
||||
const [passwordStrengthScore, setPasswordStrengthScore] = useState<number>(0)
|
||||
|
||||
useEffect(() => {
|
||||
if (showResetDbPass) {
|
||||
setIsUpdatingPassword(false)
|
||||
setPassword('')
|
||||
setPasswordStrengthMessage('')
|
||||
setPasswordStrengthWarning('')
|
||||
setPasswordStrengthScore(0)
|
||||
}
|
||||
}, [showResetDbPass])
|
||||
|
||||
async function checkPasswordStrength(value: any) {
|
||||
const { message, warning, strength } = await passwordStrength(value)
|
||||
setPasswordStrengthScore(strength)
|
||||
setPasswordStrengthWarning(warning)
|
||||
setPasswordStrengthMessage(message)
|
||||
}
|
||||
|
||||
const delayedCheckPasswordStrength = useRef(
|
||||
debounce((value) => checkPasswordStrength(value), 300)
|
||||
).current
|
||||
|
||||
const onDbPassChange = (e: any) => {
|
||||
const value = e.target.value
|
||||
setPassword(value)
|
||||
if (value == '') {
|
||||
setPasswordStrengthScore(-1)
|
||||
setPasswordStrengthMessage('')
|
||||
} else delayedCheckPasswordStrength(value)
|
||||
}
|
||||
|
||||
const confirmResetDbPass = async () => {
|
||||
if (!ref) return
|
||||
|
||||
if (passwordStrengthScore >= DEFAULT_MINIMUM_PASSWORD_STRENGTH) {
|
||||
setIsUpdatingPassword(true)
|
||||
const res = await patch(`${API_URL}/projects/${ref}/db-password`, { password })
|
||||
if (!res.error) {
|
||||
await app.projects.fetchDetail(ref, (project) => meta.setProjectDetails(project))
|
||||
ui.setNotification({ category: 'success', message: res.message })
|
||||
setShowResetDbPass(false)
|
||||
} else {
|
||||
ui.setNotification({ category: 'error', message: 'Failed to reset password' })
|
||||
}
|
||||
setIsUpdatingPassword(false)
|
||||
}
|
||||
}
|
||||
|
||||
function generateStrongPassword() {
|
||||
const password = generator.generate({
|
||||
length: 16,
|
||||
numbers: true,
|
||||
uppercase: true,
|
||||
})
|
||||
setPassword(password)
|
||||
delayedCheckPasswordStrength(password)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Panel className="!m-0">
|
||||
<Panel.Content>
|
||||
<div className="grid grid-cols-1 items-center lg:grid-cols-3">
|
||||
<div className="col-span-2 space-y-1">
|
||||
<p className="block">Database password</p>
|
||||
<p className="text-sm opacity-50">
|
||||
You can use this password to connect directly to your Postgres database.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-end justify-end">
|
||||
<Tooltip.Root delayDuration={0}>
|
||||
<Tooltip.Trigger>
|
||||
<Button
|
||||
type="default"
|
||||
disabled={!canResetDbPassword || disabled}
|
||||
onClick={() => setShowResetDbPass(true)}
|
||||
>
|
||||
Reset Database Password
|
||||
</Button>
|
||||
</Tooltip.Trigger>
|
||||
{!canResetDbPassword && (
|
||||
<Tooltip.Content side="bottom">
|
||||
<Tooltip.Arrow className="radix-tooltip-arrow" />
|
||||
<div
|
||||
className={[
|
||||
'rounded bg-scale-100 py-1 px-2 leading-none shadow', // background
|
||||
'border border-scale-200 ', //border
|
||||
].join(' ')}
|
||||
>
|
||||
<span className="text-xs text-scale-1200">
|
||||
You need additional permissions to reset the database password
|
||||
</span>
|
||||
</div>
|
||||
</Tooltip.Content>
|
||||
)}
|
||||
</Tooltip.Root>
|
||||
</div>
|
||||
</div>
|
||||
</Panel.Content>
|
||||
</Panel>
|
||||
<Modal
|
||||
hideFooter
|
||||
header={<h5 className="text-sm text-scale-1200">Reset database password</h5>}
|
||||
confirmText="Reset password"
|
||||
alignFooter="right"
|
||||
size="medium"
|
||||
visible={showResetDbPass}
|
||||
loading={isUpdatingPassword}
|
||||
onCancel={() => setShowResetDbPass(false)}
|
||||
>
|
||||
<Modal.Content>
|
||||
<div className="w-full space-y-8 py-8">
|
||||
<Input
|
||||
type="password"
|
||||
value={password}
|
||||
copy={password.length > 0}
|
||||
onChange={onDbPassChange}
|
||||
error={passwordStrengthWarning}
|
||||
// @ts-ignore
|
||||
descriptionText={
|
||||
<PasswordStrengthBar
|
||||
passwordStrengthScore={passwordStrengthScore}
|
||||
passwordStrengthMessage={passwordStrengthMessage}
|
||||
password={password}
|
||||
generateStrongPassword={generateStrongPassword}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</Modal.Content>
|
||||
<Modal.Separator />
|
||||
<Modal.Content>
|
||||
<div className="flex space-x-2 pb-2">
|
||||
<Button type="default" onClick={() => setShowResetDbPass(false)}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
loading={isUpdatingPassword}
|
||||
disabled={isUpdatingPassword}
|
||||
onClick={() => confirmResetDbPass()}
|
||||
>
|
||||
Reset password
|
||||
</Button>
|
||||
</div>
|
||||
</Modal.Content>
|
||||
</Modal>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default ResetDbPassword
|
||||
@@ -7,7 +7,6 @@ import { useStore, useParams } from 'hooks'
|
||||
import InformationBox from 'components/ui/InformationBox'
|
||||
import { checkIfPrivate, getAddressEndRange } from './NetworkRestrictions.utils'
|
||||
import { useNetworkRestrictionsApplyMutation } from 'data/network-restrictions/network-retrictions-apply-mutation'
|
||||
import { get } from 'lib/common/fetch'
|
||||
|
||||
interface Props {
|
||||
restrictedIps: string[]
|
||||
|
||||
@@ -40,7 +40,7 @@ const NetworkRestrictions = ({}) => {
|
||||
title="Network Restrictions"
|
||||
description="Allow specific IP ranges to have access to your database."
|
||||
/>
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="flex items-center space-x-2 mb-6">
|
||||
<Link href="https://supabase.com/docs/guides/platform/network-restrictions">
|
||||
<a target="_blank">
|
||||
<Button type="default" icon={<IconExternalLink />}>
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
import Link from 'next/link'
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useParams, useStore } from 'hooks'
|
||||
import * as Tooltip from '@radix-ui/react-tooltip'
|
||||
import { Button, IconDownload, Toggle, IconExternalLink, IconLoader, Alert } from 'ui'
|
||||
import {
|
||||
FormHeader,
|
||||
FormPanel,
|
||||
FormSection,
|
||||
FormSectionContent,
|
||||
FormSectionLabel,
|
||||
} from 'components/ui/Forms'
|
||||
import { useProjectSettingsQuery } from 'data/config/project-settings-query'
|
||||
import { useSSLEnforcementQuery } from 'data/ssl-enforcement/ssl-enforcement-query'
|
||||
import { useSSLEnforcementUpdateMutation } from 'data/ssl-enforcement/ssl-enforcement-update-mutation'
|
||||
|
||||
const SSLConfiguration = () => {
|
||||
const { ui } = useStore()
|
||||
const { ref } = useParams()
|
||||
const [isEnforced, setIsEnforced] = useState(false)
|
||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||
const { data: projectSettings } = useProjectSettingsQuery({ projectRef: ref })
|
||||
const { data: sslEnforcementConfiguration, isLoading } = useSSLEnforcementQuery({
|
||||
projectRef: ref,
|
||||
})
|
||||
const { mutateAsync: updateSSLEnforcement } = useSSLEnforcementUpdateMutation()
|
||||
|
||||
const hasAccessToSSLEnforcement = !sslEnforcementConfiguration?.isNotAllowed
|
||||
const env = process.env.NEXT_PUBLIC_ENVIRONMENT === 'prod' ? 'prod' : 'staging'
|
||||
const hasSSLCertificate =
|
||||
projectSettings?.project !== undefined &&
|
||||
new Date(projectSettings.project.inserted_at) >= new Date('2021-04-30')
|
||||
|
||||
useEffect(() => {
|
||||
if (!isLoading && sslEnforcementConfiguration) {
|
||||
setIsEnforced(
|
||||
sslEnforcementConfiguration.appliedSuccessfully &&
|
||||
sslEnforcementConfiguration.currentConfig.database
|
||||
)
|
||||
}
|
||||
}, [isLoading])
|
||||
|
||||
const toggleSSLEnforcement = async () => {
|
||||
if (!ref) return console.error('Project ref is required')
|
||||
|
||||
setIsEnforced(!isEnforced)
|
||||
setIsSubmitting(true)
|
||||
|
||||
try {
|
||||
await updateSSLEnforcement({
|
||||
projectRef: ref,
|
||||
requestedConfig: { database: !isEnforced },
|
||||
})
|
||||
} catch (error: any) {
|
||||
ui.setNotification({
|
||||
category: 'error',
|
||||
message: `Failed to update SSL enforcement: ${error.message}`,
|
||||
})
|
||||
setIsEnforced(isEnforced)
|
||||
} finally {
|
||||
setIsSubmitting(false)
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasAccessToSSLEnforcement) return <></>
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="flex items-center justify-between">
|
||||
<FormHeader title="SSL Configuration" description="" />
|
||||
<div className="flex items-center space-x-2 mb-6">
|
||||
<Link href="https://supabase.com/docs/guides/platform/ssl-enforcement">
|
||||
<a target="_blank">
|
||||
<Button type="default" icon={<IconExternalLink />}>
|
||||
Documentation
|
||||
</Button>
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<FormPanel>
|
||||
<FormSection
|
||||
header={
|
||||
<FormSectionLabel
|
||||
className="lg:col-span-7"
|
||||
description={
|
||||
<div className="space-y-4">
|
||||
<p className="text-sm text-scale-1000">
|
||||
Reject non-SSL connections to your database
|
||||
</p>
|
||||
{!sslEnforcementConfiguration?.appliedSuccessfully && (
|
||||
<Alert
|
||||
withIcon
|
||||
variant="warning"
|
||||
title="SSL enforcement was not updated successfully"
|
||||
>
|
||||
Please try updating again, or contact{' '}
|
||||
<Link href="/support/new">
|
||||
<a target="_blank" className="underline">
|
||||
support
|
||||
</a>
|
||||
</Link>{' '}
|
||||
if this error persists
|
||||
</Alert>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
Enforce SSL on incoming connections
|
||||
</FormSectionLabel>
|
||||
}
|
||||
>
|
||||
<FormSectionContent loading={false} className="lg:!col-span-5">
|
||||
<div className="flex items-center justify-end mt-2.5 space-x-2">
|
||||
{(isLoading || isSubmitting) && (
|
||||
<IconLoader className="animate-spin" strokeWidth={1.5} size={16} />
|
||||
)}
|
||||
<Toggle
|
||||
checked={isEnforced}
|
||||
disabled={isLoading || isSubmitting}
|
||||
onChange={toggleSSLEnforcement}
|
||||
/>
|
||||
</div>
|
||||
</FormSectionContent>
|
||||
</FormSection>
|
||||
|
||||
<div className="grid grid-cols-1 items-center lg:grid-cols-2 p-8">
|
||||
<div className="space-y-2">
|
||||
<p className="block text-sm">SSL Certificate</p>
|
||||
<div style={{ maxWidth: '420px' }}>
|
||||
<p className="text-sm opacity-50">
|
||||
Use this certificate when connecting to your database to prevent snooping and
|
||||
man-in-the-middle attacks.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-end justify-end">
|
||||
<Tooltip.Root delayDuration={0}>
|
||||
<Tooltip.Trigger>
|
||||
<Button type="default" disabled={!hasSSLCertificate} icon={<IconDownload />}>
|
||||
<a
|
||||
href={`https://supabase-downloads.s3-ap-southeast-1.amazonaws.com/${env}/ssl/${env}-ca-2021.crt`}
|
||||
>
|
||||
Download Certificate
|
||||
</a>
|
||||
</Button>
|
||||
</Tooltip.Trigger>
|
||||
{!hasSSLCertificate && (
|
||||
<Tooltip.Content align="center" side="bottom">
|
||||
<Tooltip.Arrow className="radix-tooltip-arrow" />
|
||||
<div
|
||||
className={[
|
||||
'rounded bg-scale-100 py-1 px-2 leading-none shadow',
|
||||
'border border-scale-200 w-[250px]',
|
||||
].join(' ')}
|
||||
>
|
||||
<span className="text-xs text-scale-1200">
|
||||
Projects before 15:08 (GMT+08), 29th April 2021 do not have SSL certificates
|
||||
installed
|
||||
</span>
|
||||
</div>
|
||||
</Tooltip.Content>
|
||||
)}
|
||||
</Tooltip.Root>
|
||||
</div>
|
||||
</div>
|
||||
</FormPanel>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default SSLConfiguration
|
||||
@@ -1,4 +1,5 @@
|
||||
import ConnectionPooling from './ConnectionPooling'
|
||||
import NetworkRestrictions from './NetworkRestrictions/NetworkRestrictions'
|
||||
import DatabaseSettings from './DatabaseSettings/DatabaseSettings'
|
||||
|
||||
export { ConnectionPooling, NetworkRestrictions }
|
||||
export { ConnectionPooling, DatabaseSettings, NetworkRestrictions }
|
||||
@@ -106,7 +106,7 @@ const AccountLayout: FC<Props> = ({ children, title, breadcrumbs }) => {
|
||||
key: 'ext-guides',
|
||||
icon: '/img/book-open.svg',
|
||||
label: 'API Reference',
|
||||
href: 'https://supabase.com/docs/guides/api',
|
||||
href: 'https://supabase.com/docs/guides/database/api',
|
||||
isExternal: true,
|
||||
},
|
||||
],
|
||||
|
||||
@@ -72,7 +72,7 @@ export const generateDocsMenu = (
|
||||
{
|
||||
name: 'API Reference',
|
||||
key: 'api-reference',
|
||||
url: `https://supabase.com/docs/guides/api`,
|
||||
url: `https://supabase.com/docs/guides/database/api`,
|
||||
icon: <IconBookOpen size={14} strokeWidth={2} />,
|
||||
items: [],
|
||||
isExternal: true,
|
||||
|
||||
@@ -67,7 +67,7 @@ const Introduction: FC<Props> = ({ selectedLang }) => {
|
||||
|
||||
<h2 className="doc-heading flex items-center justify-between">
|
||||
<span>Generating types</span>
|
||||
<Link href="https://supabase.com/docs/guides/api/generating-types">
|
||||
<Link href="https://supabase.com/docs/guides/database/api/generating-types">
|
||||
<a target="_blank">
|
||||
<Button type="default" icon={<IconExternalLink />}>
|
||||
Documentation
|
||||
@@ -83,7 +83,7 @@ const Introduction: FC<Props> = ({ selectedLang }) => {
|
||||
</p>
|
||||
<p>
|
||||
You can generate types from your database either through the{' '}
|
||||
<Link href="https://supabase.com/docs/guides/api/generating-types">Supabase CLI</Link>,
|
||||
<Link href="https://supabase.com/docs/guides/database/api/generating-types">Supabase CLI</Link>,
|
||||
or by downloading the types file via the button on the right and importing it in your
|
||||
application within <code>src/index.ts</code>.
|
||||
</p>
|
||||
|
||||
@@ -39,7 +39,7 @@ const FormSectionLabel = ({
|
||||
}) => {
|
||||
if (description !== undefined) {
|
||||
return (
|
||||
<div className={`flex flex-col space-y-4 col-span-12 lg:col-span-5 ${className}`}>
|
||||
<div className={`flex flex-col space-y-2 col-span-12 lg:col-span-5 ${className}`}>
|
||||
<label className="text-scale-1200 text-sm">{children}</label>
|
||||
{description}
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export const sslEnforcementKeys = {
|
||||
list: (projectRef: string | undefined) => ['projects', projectRef, 'ssl-enforcement'] as const,
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import { useQuery, useQueryClient, UseQueryOptions } from '@tanstack/react-query'
|
||||
import { get } from 'lib/common/fetch'
|
||||
import { API_ADMIN_URL } from 'lib/constants'
|
||||
import { useCallback } from 'react'
|
||||
import { sslEnforcementKeys } from './keys'
|
||||
|
||||
export type SSLEnforcementVariables = { projectRef?: string }
|
||||
|
||||
export type SSLEnforcementResponse = {
|
||||
appliedSuccessfully: boolean
|
||||
currentConfig: { database: boolean }
|
||||
error?: any
|
||||
isNotAllowed?: boolean
|
||||
}
|
||||
|
||||
export async function getSSLEnforcementConfiguration(
|
||||
{ projectRef }: SSLEnforcementVariables,
|
||||
signal?: AbortSignal
|
||||
) {
|
||||
if (!projectRef) throw new Error('projectRef is required')
|
||||
|
||||
const response = (await get(`${API_ADMIN_URL}/projects/${projectRef}/ssl-enforcement`, {
|
||||
signal,
|
||||
})) as SSLEnforcementResponse
|
||||
|
||||
// Not allowed error is a valid response to denote if a project
|
||||
// has access to the SSL enforcement UI, so we'll handle it here
|
||||
if (response.error) {
|
||||
const isNotAllowedError =
|
||||
(response.error as any)?.code === 400 &&
|
||||
(response.error as any)?.message?.includes('not allowed to configure SSL enforcements')
|
||||
|
||||
if (isNotAllowedError) {
|
||||
return {
|
||||
appliedSuccessfully: false,
|
||||
currentConfig: { database: false },
|
||||
isNotAllowed: true,
|
||||
} as SSLEnforcementResponse
|
||||
} else {
|
||||
throw response.error
|
||||
}
|
||||
}
|
||||
|
||||
return response as SSLEnforcementResponse
|
||||
}
|
||||
|
||||
export type SSLEnforcementData = Awaited<ReturnType<typeof getSSLEnforcementConfiguration>>
|
||||
export type SSLEnforcementError = unknown
|
||||
|
||||
export const useSSLEnforcementQuery = <TData = SSLEnforcementData>(
|
||||
{ projectRef }: SSLEnforcementVariables,
|
||||
{
|
||||
enabled = true,
|
||||
...options
|
||||
}: UseQueryOptions<SSLEnforcementData, SSLEnforcementError, TData> = {}
|
||||
) =>
|
||||
useQuery<SSLEnforcementData, SSLEnforcementError, TData>(
|
||||
sslEnforcementKeys.list(projectRef),
|
||||
({ signal }) => getSSLEnforcementConfiguration({ projectRef }, signal),
|
||||
{ enabled: enabled && typeof projectRef !== 'undefined', ...options }
|
||||
)
|
||||
|
||||
export const useSSLEnforcementPrefetch = ({ projectRef }: SSLEnforcementVariables) => {
|
||||
const client = useQueryClient()
|
||||
|
||||
return useCallback(() => {
|
||||
if (projectRef) {
|
||||
client.prefetchQuery(sslEnforcementKeys.list(projectRef), ({ signal }) =>
|
||||
getSSLEnforcementConfiguration({ projectRef }, signal)
|
||||
)
|
||||
}
|
||||
}, [projectRef])
|
||||
}
|
||||